diff --git a/.dockerignore b/.dockerignore index 91b5220c669b..8268fb1049e6 100644 --- a/.dockerignore +++ b/.dockerignore @@ -31,12 +31,11 @@ contracts/.git !infrastructure/zk !sdk/zksync-rs !contracts/system-contracts/bootloader/build/artifacts -!contracts/system-contracts/contracts/artifacts -!contracts/system-contracts/contracts/precompiles/artifacts +!contracts/system-contracts/contracts-preprocessed/artifacts +!contracts/system-contracts/contracts-preprocessed/precompiles/artifacts !contracts/system-contracts/artifacts-zk !etc/multivm_bootloaders !cargo !bellman-cuda -!core/bin/verification_key_generator_and_server/data/ !prover/vk_setup_data_generator_server_fri/data/ !.github/release-please/manifest.json diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 7b828d1ca895..223da1507052 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -18,4 +18,5 @@ - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. -- [ ] Spellcheck has been run via `cargo spellcheck --cfg=./spellcheck/era.cfg --code 1`. +- [ ] Spellcheck has been run via `zk spellcheck`. +- [ ] Linkcheck has been run via `zk linkcheck`. diff --git a/.github/release-please/manifest.json b/.github/release-please/manifest.json index aca464aef9fa..6f87987f04e6 100644 --- a/.github/release-please/manifest.json +++ b/.github/release-please/manifest.json @@ -1,5 +1,5 @@ { "sdk/zksync-rs": "0.4.0", - "core": "18.12.0", - "prover": "10.0.2" + "core": "20.5.2", + "prover": "11.0.0" } diff --git a/.github/workflows/build-contracts.yml b/.github/workflows/build-contracts.yml new file mode 100644 index 000000000000..c0699d002683 --- /dev/null +++ b/.github/workflows/build-contracts.yml @@ -0,0 +1,83 @@ +name: Build contracts +on: + workflow_call: + inputs: + compilers: + description: 'JSON of required compilers and their versions' + type: string + required: false + default: '[{ "zksolc": ["1.3.14", "1.3.16", "1.3.17", "1.3.1", "1.3.7", "1.3.18", "1.3.19", "1.3.21"] } , { "zkvyper": ["1.3.13"] }]' + +jobs: + build-images: + name: Build and upload contracts + runs-on: [matterlabs-ci-runner] + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 + with: + submodules: "recursive" + - name: setup-env + run: | + echo ZKSYNC_HOME=$(pwd) >> $GITHUB_ENV + echo CI=1 >> $GITHUB_ENV + echo $(pwd)/bin >> $GITHUB_PATH + echo CI=1 >> .env + echo IN_DOCKER=1 >> .env + + # TODO: Remove after when we can upgrade hardhat-plugins + - name: pre-download compiilers + run: | + # Download needed versions of vyper compiler + # Not sanitized due to unconventional path and tags + mkdir -p ./hardhat-nodejs/compilers-v2/vyper/linux + wget -nv -O ./hardhat-nodejs/compilers-v2/vyper/linux/0.3.10 https://github.com/vyperlang/vyper/releases/download/v0.3.10/vyper.0.3.10+commit.91361694.linux + wget -nv -O ./hardhat-nodejs/compilers-v2/vyper/linux/0.3.3 https://github.com/vyperlang/vyper/releases/download/v0.3.3/vyper.0.3.3+commit.48e326f0.linux + chmod +x ./hardhat-nodejs/compilers-v2/vyper/linux/0.3.10 + chmod +x ./hardhat-nodejs/compilers-v2/vyper/linux/0.3.3 + + COMPILERS_JSON='${{ inputs.compilers }}' + echo "$COMPILERS_JSON" | jq -r '.[] | to_entries[] | .key as $compiler | .value[] | "\(.),\($compiler)"' | while IFS=, read -r version compiler; do + mkdir -p "./hardhat-nodejs/compilers-v2/$compiler" + wget -nv -O "./hardhat-nodejs/compilers-v2/$compiler/${compiler}-v${version}" "https://github.com/matter-labs/${compiler}-bin/releases/download/v${version}/${compiler}-linux-amd64-musl-v${version}" + chmod +x "./hardhat-nodejs/compilers-v2/$compiler/${compiler}-v${version}" + done + + - name: start-services + run: | + echo "IMAGE_TAG_SUFFIX=${{ env.IMAGE_TAG_SUFFIX }}" >> .env + mkdir -p ./volumes/postgres + docker compose up -d zk postgres + ci_run sccache --start-server + + - name: build contracts + run: | + ci_run git config --global --add safe.directory /usr/src/zksync + ci_run git config --global --add safe.directory /usr/src/zksync/sdk/binaryen + ci_run git config --global --add safe.directory /usr/src/zksync/contracts/system-contracts + ci_run git config --global --add safe.directory /usr/src/zksync/contracts + ci_run zk + ci_run zk clean --all + ci_run zk run yarn + ci_run cp etc/tokens/{test,localhost}.json + ci_run zk compiler all + ci_run zk contract build + ci_run zk f yarn run l2-contracts build + + - name: upload contracts + uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 + with: + name: contracts + path: | + ./contracts/system-contracts/**/artifacts/ + ./contracts/system-contracts/**/artifacts-zk/ + ./contracts/l1-contracts/**/artifacts/ + ./contracts/l1-contracts/**/artifacts-zk/ + ./contracts/l2-contracts/**/artifacts/ + ./contracts/l2-contracts/**/artifacts-zk/ + compression-level: 0 + + - name: Show sccache stats + if: always() + run: | + ci_run sccache --show-stats + ci_run cat /tmp/sccache_log.txt diff --git a/.github/workflows/build-core-template.yml b/.github/workflows/build-core-template.yml index 320b0ead1b03..7853867e426f 100644 --- a/.github/workflows/build-core-template.yml +++ b/.github/workflows/build-core-template.yml @@ -9,10 +9,6 @@ on: description: "DOCKERHUB_TOKEN" required: true inputs: - image_tag: - description: "Tag of a built image to deploy" - type: string - required: true image_tag_suffix: description: "Optional suffix to override tag name generation" type: string @@ -22,27 +18,25 @@ on: type: string default: "push" required: false - compilers: - description: 'JSON of required compilers and their versions' - type: string - required: false - default: '[{ "zksolc": ["1.3.14", "1.3.16", "1.3.17", "1.3.1", "1.3.7", "1.3.18"] } , { "zkvyper": ["1.3.13"] }]' - jobs: build-images: name: Build and Push Docker Images env: - image_tag: ${{ inputs.image_tag }} IMAGE_TAG_SUFFIX: ${{ inputs.image_tag_suffix }} - runs-on: [matterlabs-ci-runner] + runs-on: ${{ fromJSON('["matterlabs-ci-runner", "matterlabs-ci-runner-arm"]')[contains(matrix.platforms, 'arm')] }} strategy: matrix: - component: - - server-v2 - - external-node - - contract-verifier - - cross-external-nodes-checker - - snapshots-creator + components: + - server-v2 + - external-node + - contract-verifier + - snapshots-creator + platforms: + - linux/amd64 + include: + - components: external-node + platforms: linux/arm64 + steps: - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 with: @@ -56,23 +50,11 @@ jobs: echo CI=1 >> .env echo IN_DOCKER=1 >> .env - # TODO: Remove after when we can upgrade hardhat-plugins - - name: pre-download compiilers - run: | - # Download needed versions of vyper compiler - # Not sanitized due to unconventional path and tags - mkdir -p ./hardhat-nodejs/compilers-v2/vyper/linux - wget -nv -O ./hardhat-nodejs/compilers-v2/vyper/linux/0.3.10 https://github.com/vyperlang/vyper/releases/download/v0.3.10/vyper.0.3.10+commit.91361694.linux - wget -nv -O ./hardhat-nodejs/compilers-v2/vyper/linux/0.3.3 https://github.com/vyperlang/vyper/releases/download/v0.3.3/vyper.0.3.3+commit.48e326f0.linux - chmod +x ./hardhat-nodejs/compilers-v2/vyper/linux/0.3.10 - chmod +x ./hardhat-nodejs/compilers-v2/vyper/linux/0.3.3 - - COMPILERS_JSON='${{ inputs.compilers }}' - echo "$COMPILERS_JSON" | jq -r '.[] | to_entries[] | .key as $compiler | .value[] | "\(.),\($compiler)"' | while IFS=, read -r version compiler; do - mkdir -p "./hardhat-nodejs/compilers-v2/$compiler" - wget -nv -O "./hardhat-nodejs/compilers-v2/$compiler/${compiler}-v${version}" "https://github.com/matter-labs/${compiler}-bin/releases/download/v${version}/${compiler}-linux-amd64-musl-v${version}" - chmod +x "./hardhat-nodejs/compilers-v2/$compiler/${compiler}-v${version}" - done + - name: Download contracts + uses: actions/download-artifact@v4 + with: + name: contracts + path: ./contracts/ - name: start-services run: | @@ -87,30 +69,70 @@ jobs: ci_run git config --global --add safe.directory /usr/src/zksync/sdk/binaryen ci_run git config --global --add safe.directory /usr/src/zksync/contracts/system-contracts ci_run git config --global --add safe.directory /usr/src/zksync/contracts - ci_run zk - ci_run zk clean --all - ci_run zk run yarn - ci_run cp etc/tokens/{test,localhost}.json - ci_run zk compiler all - ci_run zk contract build - ci_run zk f yarn run l2-contracts build + ci_run zk || true + ci_run yarn zk build ci_run curl -LO https://storage.googleapis.com/matterlabs-setup-keys-us/setup-keys/setup_2\^26.key - - name: login to Docker registries - if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')) + - name: Login to Docker registries + if: ${{ inputs.action == 'push' }} run: | ci_run docker login -u ${{ secrets.DOCKERHUB_USER }} -p ${{ secrets.DOCKERHUB_TOKEN }} - ci_run gcloud auth configure-docker us-docker.pkg.dev,asia-docker.pkg.dev,europe-docker.pkg.dev -q + ci_run gcloud auth configure-docker us-docker.pkg.dev -q - name: update-images env: DOCKER_ACTION: ${{ inputs.action }} - COMPONENT: ${{ matrix.component }} + COMPONENT: ${{ matrix.components }} + PLATFORM: ${{ matrix.platforms }} run: | ci_run rustup default nightly-2023-08-21 - ci_run zk docker $DOCKER_ACTION $COMPONENT + platform=$(echo $PLATFORM | tr '/' '-') + ci_run zk docker $DOCKER_ACTION --custom-tag=${IMAGE_TAG_SUFFIX} --platform=${PLATFORM} $COMPONENT - name: Show sccache stats if: always() run: | ci_run sccache --show-stats ci_run cat /tmp/sccache_log.txt + + create_manifest: + name: Create release manifest + runs-on: matterlabs-ci-runner + needs: build-images + if: ${{ inputs.action == 'push' }} + strategy: + matrix: + component: + - name: server-v2 + platform: linux/amd64 + - name: external-node + platform: linux/amd64,linux/arm64 + - name: contract-verifier + platform: linux/amd64 + - name: snapshots-creator + platform: linux/amd64 + env: + IMAGE_TAG_SUFFIX: ${{ inputs.image_tag_suffix }} + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 + with: + submodules: "recursive" + - name: login to Docker registries + run: | + docker login -u ${{ secrets.DOCKERHUB_USER }} -p ${{ secrets.DOCKERHUB_TOKEN }} + gcloud auth configure-docker us-docker.pkg.dev -q + + - name: Create Docker manifest + run: | + docker_repositories=("matterlabs/${{ matrix.component.name }}" "us-docker.pkg.dev/matterlabs-infra/matterlabs-docker/${{ matrix.component.name }}") + platforms=${{ matrix.component.platform }} + for repo in "${docker_repositories[@]}"; do + platform_tags="" + for platform in ${platforms//,/ }; do + platform=$(echo $platform | tr '/' '-') + platform_tags+=" --amend ${repo}:${IMAGE_TAG_SUFFIX}-${platform}" + done + for manifest in "${repo}:${IMAGE_TAG_SUFFIX}" "${repo}:2.0-${IMAGE_TAG_SUFFIX}" "${repo}:latest" "${repo}:latest2.0"; do + docker manifest create ${manifest} ${platform_tags} + docker manifest push ${manifest} + done + done diff --git a/.github/workflows/build-docker-from-tag.yml b/.github/workflows/build-docker-from-tag.yml index 45ffdd77de3c..023aff6cd95a 100644 --- a/.github/workflows/build-docker-from-tag.yml +++ b/.github/workflows/build-docker-from-tag.yml @@ -49,16 +49,20 @@ jobs: run: | ./prover/extract-setup-data-keys.sh >> $GITHUB_OUTPUT + build-contracts: + name: Build contracts + if: contains(github.ref_name, 'core') + uses: ./.github/workflows/build-contracts.yml + build-push-core-images: name: Build and push image - needs: [setup] + needs: [setup, build-contracts] uses: ./.github/workflows/build-core-template.yml if: contains(github.ref_name, 'core') secrets: DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }} DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} with: - image_tag: ${{ needs.setup.outputs.image_tag }} image_tag_suffix: ${{ needs.setup.outputs.image_tag_suffix }} build-push-prover-images: @@ -67,7 +71,6 @@ jobs: uses: ./.github/workflows/build-prover-template.yml if: contains(github.ref_name, 'prover') with: - image_tag: ${{ needs.setup.outputs.image_tag }} image_tag_suffix: ${{ needs.setup.outputs.image_tag_suffix }} ERA_BELLMAN_CUDA_RELEASE: ${{ vars.ERA_BELLMAN_CUDA_RELEASE }} CUDA_ARCH: "60;70;75;89" diff --git a/.github/workflows/build-local-node-docker.yml b/.github/workflows/build-local-node-docker.yml index 5d9d01327b1e..4e48fc5c88f0 100644 --- a/.github/workflows/build-local-node-docker.yml +++ b/.github/workflows/build-local-node-docker.yml @@ -11,7 +11,7 @@ on: description: 'JSON of required compilers and their versions' type: string required: false - default: '[{ "zksolc": ["1.3.14", "1.3.16", "1.3.17", "1.3.1", "1.3.7", "1.3.18"] } , { "zkvyper": ["1.3.13"] }]' + default: '[{ "zksolc": ["1.3.14", "1.3.16", "1.3.17", "1.3.1", "1.3.7", "1.3.18", "1.3.19", "1.3.21"] } , { "zkvyper": ["1.3.13"] }]' jobs: build-images: diff --git a/.github/workflows/build-prover-template.yml b/.github/workflows/build-prover-template.yml index ca8792a62054..c1a46a55ed21 100644 --- a/.github/workflows/build-prover-template.yml +++ b/.github/workflows/build-prover-template.yml @@ -13,10 +13,6 @@ on: description: "ERA_BELLMAN_CUDA_RELEASE" type: string required: true - image_tag: - description: "Tag of a built image to deploy" - type: string - required: true image_tag_suffix: description: "Optional suffix to override tag name generation" type: string @@ -41,7 +37,6 @@ jobs: build-images: name: Build and Push Docker Images env: - image_tag: ${{ inputs.image_tag }} IMAGE_TAG_SUFFIX: ${{ inputs.image_tag_suffix }} RUNNER_COMPOSE_FILE: "docker-compose-runner-nightly.yml" ERA_BELLMAN_CUDA_RELEASE: ${{ inputs.ERA_BELLMAN_CUDA_RELEASE }} @@ -93,7 +88,7 @@ jobs: if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')) run: | ci_run docker login -u ${{ secrets.DOCKERHUB_USER }} -p ${{ secrets.DOCKERHUB_TOKEN }} - ci_run gcloud auth configure-docker us-docker.pkg.dev,asia-docker.pkg.dev,europe-docker.pkg.dev -q + ci_run gcloud auth configure-docker us-docker.pkg.dev -q # We need to run this only when ERA_BELLMAN_CUDA_RELEASE is not available # In our case it happens only when PR is created from fork @@ -180,3 +175,41 @@ jobs: run: | ci_run sccache --show-stats ci_run cat /tmp/sccache_log.txt + + copy-images: + name: Copy images between docker registries + env: + IMAGE_TAG_SUFFIX: ${{ inputs.image_tag_suffix }} + runs-on: matterlabs-ci-runner + needs: build-images + if: ${{ inputs.action == 'push' }} + strategy: + matrix: + component: + - witness-vector-generator + steps: + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to us-central1 GAR + run: | + gcloud auth print-access-token --lifetime=7200 --impersonate-service-account=gha-ci-runners@matterlabs-infra.iam.gserviceaccount.com | docker login -u oauth2accesstoken --password-stdin https://us-docker.pkg.dev + + - name: Login and push to Asia GAR + run: | + gcloud auth print-access-token --lifetime=7200 --impersonate-service-account=gha-ci-runners@matterlabs-infra.iam.gserviceaccount.com | docker login -u oauth2accesstoken --password-stdin https://asia-docker.pkg.dev + docker buildx imagetools create \ + --tag asia-docker.pkg.dev/matterlabs-infra/matterlabs-docker/${{ matrix.component }}:2.0-${{ inputs.image_tag_suffix }} \ + us-docker.pkg.dev/matterlabs-infra/matterlabs-docker/${{ matrix.component }}:2.0-${{ inputs.image_tag_suffix }} + + - name: Login and push to Europe GAR + run: | + gcloud auth print-access-token --lifetime=7200 --impersonate-service-account=gha-ci-runners@matterlabs-infra.iam.gserviceaccount.com | docker login -u oauth2accesstoken --password-stdin https://europe-docker.pkg.dev + docker buildx imagetools create \ + --tag europe-docker.pkg.dev/matterlabs-infra/matterlabs-docker/${{ matrix.component }}:2.0-${{ inputs.image_tag_suffix }} \ + us-docker.pkg.dev/matterlabs-infra/matterlabs-docker/${{ matrix.component }}:2.0-${{ inputs.image_tag_suffix }} + diff --git a/.github/workflows/check-links.yml b/.github/workflows/check-links.yml new file mode 100644 index 000000000000..ef0dbdc12f51 --- /dev/null +++ b/.github/workflows/check-links.yml @@ -0,0 +1,41 @@ +name: Check Links + +on: + push: + branches: + - main + pull_request: + merge_group: + +env: + CARGO_TERM_COLOR: always + +jobs: + linkcheck: + runs-on: [matterlabs-ci-runner] + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 + with: + submodules: "recursive" + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Setup environment + run: | + echo ZKSYNC_HOME=$(pwd) >> $GITHUB_ENV + echo $(pwd)/bin >> $GITHUB_PATH + echo IN_DOCKER=1 >> .env + + - name: Start services + run: | + docker compose up -d zk + + - name: Build zk + run: | + ci_run zk + + - name: Run zk linkcheck + run: | + ci_run zk linkcheck diff --git a/.github/workflows/check-spelling.yml b/.github/workflows/check-spelling.yml index 9073401eab9e..0a3bce24cb7e 100644 --- a/.github/workflows/check-spelling.yml +++ b/.github/workflows/check-spelling.yml @@ -12,14 +12,30 @@ env: jobs: spellcheck: - runs-on: ubuntu-latest + runs-on: [matterlabs-ci-runner] steps: - - name: Install cargo-spellcheck - uses: taiki-e/install-action@v2 + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 with: - tool: cargo-spellcheck + submodules: "recursive" + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Setup environment + run: | + echo ZKSYNC_HOME=$(pwd) >> $GITHUB_ENV + echo $(pwd)/bin >> $GITHUB_PATH + echo IN_DOCKER=1 >> .env + + - name: Start services + run: | + docker compose up -d zk - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4 + - name: Build zk + run: | + ci_run zk - - name: Run cargo-spellcheck - run: cargo spellcheck --cfg=./spellcheck/era.cfg --code 1 + - name: Run spellcheck + run: | + ci_run zk spellcheck diff --git a/.github/workflows/ci-common-reusable.yml b/.github/workflows/ci-common-reusable.yml new file mode 100644 index 000000000000..ce8884f00f6e --- /dev/null +++ b/.github/workflows/ci-common-reusable.yml @@ -0,0 +1,37 @@ +name: Workflow template for CI jobs to be ran on both Prover and Core Components +on: + workflow_call: + +jobs: + build: + runs-on: [matterlabs-ci-runner] + env: + RUNNER_COMPOSE_FILE: "docker-compose-runner-nightly.yml" + + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 + with: + submodules: "recursive" + + - name: Setup environment + run: | + echo ZKSYNC_HOME=$(pwd) >> $GITHUB_ENV + echo $(pwd)/bin >> $GITHUB_PATH + echo IN_DOCKER=1 >> .env + + - name: Start services + run: | + docker-compose -f ${RUNNER_COMPOSE_FILE} pull + mkdir -p ./volumes/postgres + docker-compose -f ${RUNNER_COMPOSE_FILE} up --build -d zk postgres + ci_run sccache --start-server + + - name: Init + run: | + ci_run zk + ci_run zk db setup + + # This does both linting and "building". We're using `zk lint prover` as it's common practice within our repo + # `zk lint prover` = cargo clippy, which does cargo check behind the scenes, which is a lightweight version of cargo build + - name: Lints + run: ci_run zk lint prover diff --git a/.github/workflows/ci-core-lint-reusable.yml b/.github/workflows/ci-core-lint-reusable.yml index f0155168c592..541049cdeb0c 100644 --- a/.github/workflows/ci-core-lint-reusable.yml +++ b/.github/workflows/ci-core-lint-reusable.yml @@ -37,4 +37,3 @@ jobs: ci_run zk lint ts --check ci_run zk lint md --check ci_run zk db check-sqlx-data - diff --git a/.github/workflows/ci-core-reusable.yml b/.github/workflows/ci-core-reusable.yml index 6e28f85e3c01..6a0fc7a07377 100644 --- a/.github/workflows/ci-core-reusable.yml +++ b/.github/workflows/ci-core-reusable.yml @@ -6,7 +6,7 @@ on: description: 'JSON of required compilers and their versions' type: string required: false - default: '[{ "zksolc": ["1.3.14", "1.3.16", "1.3.17", "1.3.1", "1.3.7", "1.3.18"] } , { "zkvyper": ["1.3.13"] }]' + default: '[{ "zksolc": ["1.3.14", "1.3.16", "1.3.17", "1.3.1", "1.3.7", "1.3.18", "1.3.19", "1.3.21"] } , { "zkvyper": ["1.3.13"] }]' jobs: lint: @@ -27,7 +27,7 @@ jobs: echo IN_DOCKER=1 >> .env # TODO: Remove when we after upgrade of hardhat-plugins - - name: pre-download compiilers + - name: pre-download compilers run: | # Download needed versions of vyper compiler # Not sanitized due to unconventional path and tags @@ -118,8 +118,13 @@ jobs: ci_run sccache --show-stats ci_run cat /tmp/sccache_log.txt integration: - runs-on: [matterlabs-ci-runner] + strategy: + matrix: + consensus: [false,true] + env: + SERVER_COMPONENTS: "api,tree,eth,state_keeper,housekeeper,basic_witness_input_producer${{ matrix.consensus && ',consensus' || '' }}" + runs-on: [matterlabs-ci-runner] steps: - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 with: @@ -141,11 +146,15 @@ jobs: wget https://github.com/ethereum/solc-bin/raw/gh-pages/linux-amd64/solc-linux-amd64-v0.8.23%2Bcommit.f704f362 mv solc-linux-amd64-v0.8.23+commit.f704f362 $(pwd)/etc/solc-bin/0.8.23/solc chmod +x $(pwd)/etc/solc-bin/0.8.23/solc + + mkdir -p $(pwd)/etc/solc-bin/zkVM-0.8.23-1.0.0 + wget https://github.com/matter-labs/era-solidity/releases/download/0.8.23-1.0.0/solc-linux-amd64-0.8.23-1.0.0 -O $(pwd)/etc/solc-bin/zkVM-0.8.23-1.0.0/solc + chmod +x $(pwd)/etc/solc-bin/zkVM-0.8.23-1.0.0/solc - mkdir -p $(pwd)/etc/zksolc-bin/v1.3.18 - wget https://github.com/matter-labs/zksolc-bin/raw/main/linux-amd64/zksolc-linux-amd64-musl-v1.3.18 - mv zksolc-linux-amd64-musl-v1.3.18 $(pwd)/etc/zksolc-bin/v1.3.18/zksolc - chmod +x $(pwd)/etc/zksolc-bin/v1.3.18/zksolc + mkdir -p $(pwd)/etc/zksolc-bin/v1.3.21 + wget https://github.com/matter-labs/zksolc-bin/raw/main/linux-amd64/zksolc-linux-amd64-musl-v1.3.21 + mv zksolc-linux-amd64-musl-v1.3.21 $(pwd)/etc/zksolc-bin/v1.3.21/zksolc + chmod +x $(pwd)/etc/zksolc-bin/v1.3.21/zksolc mkdir -p $(pwd)/etc/vyper-bin/0.3.10 wget -O vyper0.3.10 https://github.com/vyperlang/vyper/releases/download/v0.3.10/vyper.0.3.10%2Bcommit.91361694.linux @@ -175,7 +184,7 @@ jobs: # `sleep 5` because we need to wait until server started properly - name: Run server run: | - ci_run zk server &>server.log & + ci_run zk server --components=$SERVER_COMPONENTS &>server.log & ci_run sleep 5 - name: Run contract verifier @@ -193,7 +202,7 @@ jobs: run: | ci_run pkill zksync_server || true ci_run sleep 2 - ci_run zk test i revert + ENABLE_CONSENSUS=${{ matrix.consensus }} PASSED_ENV_VARS=ENABLE_CONSENSUS ci_run zk test i revert # This test should be the last one as soon as it # finished bootloader will be different @@ -226,7 +235,14 @@ jobs: ci_run cat /tmp/sccache_log.txt external-node: + strategy: + matrix: + consensus: [false,true] runs-on: [matterlabs-ci-runner] + + env: + SERVER_COMPONENTS: "api,tree,eth,state_keeper,housekeeper,basic_witness_input_producer${{ matrix.consensus && ',consensus' || '' }}" + EXT_NODE_FLAGS: "${{ matrix.consensus && '--enable-consensus' || '' }}" steps: - name: Checkout code # Checks out the repository under $GITHUB_WORKSPACE, so the job can access it. @@ -250,11 +266,15 @@ jobs: wget https://github.com/ethereum/solc-bin/raw/gh-pages/linux-amd64/solc-linux-amd64-v0.8.23%2Bcommit.f704f362 mv solc-linux-amd64-v0.8.23+commit.f704f362 $(pwd)/etc/solc-bin/0.8.23/solc chmod +x $(pwd)/etc/solc-bin/0.8.23/solc + + mkdir -p $(pwd)/etc/solc-bin/zkVM-0.8.23-1.0.0 + wget https://github.com/matter-labs/era-solidity/releases/download/0.8.23-1.0.0/solc-linux-amd64-0.8.23-1.0.0 -O $(pwd)/etc/solc-bin/zkVM-0.8.23-1.0.0/solc + chmod +x $(pwd)/etc/solc-bin/zkVM-0.8.23-1.0.0/solc - mkdir -p $(pwd)/etc/zksolc-bin/v1.3.18 - wget https://github.com/matter-labs/zksolc-bin/raw/main/linux-amd64/zksolc-linux-amd64-musl-v1.3.18 - mv zksolc-linux-amd64-musl-v1.3.18 $(pwd)/etc/zksolc-bin/v1.3.18/zksolc - chmod +x $(pwd)/etc/zksolc-bin/v1.3.18/zksolc + mkdir -p $(pwd)/etc/zksolc-bin/v1.3.21 + wget https://github.com/matter-labs/zksolc-bin/raw/main/linux-amd64/zksolc-linux-amd64-musl-v1.3.21 + mv zksolc-linux-amd64-musl-v1.3.21 $(pwd)/etc/zksolc-bin/v1.3.21/zksolc + chmod +x $(pwd)/etc/zksolc-bin/v1.3.21/zksolc mkdir -p $(pwd)/etc/vyper-bin/0.3.10 wget -O vyper0.3.10 https://github.com/vyperlang/vyper/releases/download/v0.3.10/vyper.0.3.10%2Bcommit.91361694.linux @@ -283,23 +303,20 @@ jobs: # `sleep 30` because we need to wait until server started properly - name: Run server run: | - ci_run zk server &>server.log & + ci_run zk server --components=$SERVER_COMPONENTS &>server.log & ci_run sleep 30 - + - name: Run external node run: | ci_run zk env ext-node-docker ci_run zk db setup - ci_run zk external-node &>ext-node.log & + ci_run zk external-node $EXT_NODE_FLAGS &>ext-node.log & ci_run sleep 30 # TODO(PLA-653): Restore bridge tests for EN. - name: Integration tests run: ci_run zk test i server --testPathIgnorePatterns 'contract-verification|custom-erc20-bridge|snapshots-creator' - - name: Run Cross EN Checker - run: ci_run zk run cross-en-checker - - name: Run revert test run: | ci_run zk env @@ -307,14 +324,14 @@ jobs: ci_run pkill zksync_server || true ci_run sleep 2 ci_run zk env - ci_run zk test i revert + ENABLE_CONSENSUS=${{ matrix.consensus }} PASSED_ENV_VARS=ENABLE_CONSENSUS ci_run zk test i revert # Check that the rollback was performed on the EN ci_run sleep 20 ci_run grep -q 'Rollback successfully completed' ext-node.log # Restart the EN - ci_run zk server &>>server.log & + ci_run zk server --components=$SERVER_COMPONENTS &>>server.log & ci_run sleep 30 - ZKSYNC_ENV=ext-node-docker ci_run zk external-node &>>ext-node.log & + ZKSYNC_ENV=ext-node-docker ci_run zk external-node $EXT_NODE_FLAGS &>>ext-node.log & ci_run sleep 30 - name: Run upgrade test @@ -326,6 +343,10 @@ jobs: if: always() run: ci_run cat server.log || true + - name: Show ext-node.log logs + if: always() + run: ci_run cat ext-node.log || true + - name: Show contract_verifier.log logs if: always() run: ci_run cat ext-node.log || true diff --git a/.github/workflows/ci-prover-reusable.yml b/.github/workflows/ci-prover-reusable.yml index cc1246cbf9a6..ee6d5da99843 100644 --- a/.github/workflows/ci-prover-reusable.yml +++ b/.github/workflows/ci-prover-reusable.yml @@ -34,9 +34,6 @@ jobs: - name: Formatting run: ci_run bash -c "cd prover && cargo fmt --check" - - name: Lints - run: ci_run zk lint prover - unit-tests: runs-on: [matterlabs-ci-runner] env: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 58dd0b579eb2..cfa752171f5a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,6 @@ jobs: - 'core/**' - '!core/CHANGELOG.md' - 'docker/contract-verifier/**' - - 'docker/cross-external-nodes-checker/**' - 'docker/external-node/**' - 'docker/server/**' - '.github/workflows/build-core-template.yml' @@ -96,13 +95,25 @@ jobs: name: CI for Docs uses: ./.github/workflows/ci-docs-reusable.yml + # What needs to be ran for both core and prover + ci-for-common: + needs: changed_files + if: ${{ (needs.changed_files.outputs.prover == 'true' || needs.changed_files.outputs.core == 'true' || needs.changed_files.outputs.all == 'true') && !contains(github.ref_name, 'release-please--branches') }} + name: CI for Common Components (prover or core) + uses: ./.github/workflows/ci-common-reusable.yml + + build-contracts: + name: Build contracts + needs: changed_files + if: ${{ (needs.changed_files.outputs.core == 'true' || needs.changed_files.outputs.all == 'true') && !contains(github.ref_name, 'release-please--branches') }} + uses: ./.github/workflows/build-contracts.yml + build-core-images: name: Build core images - needs: changed_files + needs: build-contracts if: ${{ (needs.changed_files.outputs.core == 'true' || needs.changed_files.outputs.all == 'true') && !contains(github.ref_name, 'release-please--branches') }} uses: ./.github/workflows/build-core-template.yml with: - image_tag: ${{ needs.setup.outputs.image_tag }} image_tag_suffix: ${{ needs.setup.outputs.image_tag_suffix }} action: "build" secrets: @@ -115,7 +126,6 @@ jobs: if: ${{ (needs.changed_files.outputs.prover == 'true' || needs.changed_files.outputs.all == 'true') && !contains(github.ref_name, 'release-please--branches') }} uses: ./.github/workflows/build-prover-template.yml with: - image_tag: ${{ needs.setup.outputs.image_tag }} image_tag_suffix: ${{ needs.setup.outputs.image_tag_suffix }} action: "build" ERA_BELLMAN_CUDA_RELEASE: ${{ vars.ERA_BELLMAN_CUDA_RELEASE }} @@ -128,7 +138,7 @@ jobs: name: Github Status Check runs-on: ubuntu-latest if: always() && !cancelled() - needs: [ci-for-core-lint, ci-for-core, ci-for-prover, ci-for-docs, build-core-images, build-prover-images] + needs: [ci-for-core-lint, ci-for-core, ci-for-prover, ci-for-docs, build-contracts, build-core-images, build-prover-images] steps: - name: Status run: | diff --git a/.github/workflows/nodejs-license.yaml b/.github/workflows/nodejs-license.yaml index 5980eaae5449..80a2eb276b3f 100644 --- a/.github/workflows/nodejs-license.yaml +++ b/.github/workflows/nodejs-license.yaml @@ -19,8 +19,9 @@ env: Public Domain; WTFPL; Unlicense; + BlueOak-1.0.0; # It has to be one line, there must be no space between packages. - EXCLUDE_PACKAGES: testrpc@0.0.1;uuid@2.0.1; + EXCLUDE_PACKAGES: testrpc@0.0.1;uuid@2.0.1;@cspell/dict-en-common-misspellings@2.0.0; jobs: generate-matrix: diff --git a/.github/workflows/release-test-stage.yml b/.github/workflows/release-test-stage.yml index 9962ba01e508..fae77fca0b53 100644 --- a/.github/workflows/release-test-stage.yml +++ b/.github/workflows/release-test-stage.yml @@ -62,13 +62,18 @@ jobs: run: | ./prover/extract-setup-data-keys.sh >> $GITHUB_OUTPUT + build-contracts: + name: Build contracts + needs: changed_files + if: needs.changed_files.outputs.core == 'true' || needs.changed_files.outputs.all == 'true' + uses: ./.github/workflows/build-contracts.yml + build-push-core-images: name: Build and push images - needs: [setup, changed_files] + needs: [setup, build-contracts] uses: ./.github/workflows/build-core-template.yml if: needs.changed_files.outputs.core == 'true' || needs.changed_files.outputs.all == 'true' with: - image_tag: ${{ needs.setup.outputs.image_tag }} image_tag_suffix: ${{ needs.setup.outputs.image_tag_suffix }} secrets: DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }} @@ -80,7 +85,6 @@ jobs: uses: ./.github/workflows/build-prover-template.yml if: needs.changed_files.outputs.prover == 'true' || needs.changed_files.outputs.all == 'true' with: - image_tag: ${{ needs.setup.outputs.image_tag }} image_tag_suffix: ${{ needs.setup.outputs.image_tag_suffix }} ERA_BELLMAN_CUDA_RELEASE: ${{ vars.ERA_BELLMAN_CUDA_RELEASE }} CUDA_ARCH: "60;70;75;89" diff --git a/.github/workflows/vm-perf-comparison.yml b/.github/workflows/vm-perf-comparison.yml index e49adfd12b57..52f65a801d30 100644 --- a/.github/workflows/vm-perf-comparison.yml +++ b/.github/workflows/vm-perf-comparison.yml @@ -46,6 +46,7 @@ jobs: ci_run zk ci_run zk compiler system-contracts ci_run cargo bench --package vm-benchmark --bench iai | tee base-iai + ci_run yarn workspace system-contracts clean - name: checkout PR run: git checkout --force FETCH_HEAD --recurse-submodules diff --git a/.github/workflows/zk-environment-publish.yml b/.github/workflows/zk-environment-publish.yml index 44768241ccda..0551b15aac50 100644 --- a/.github/workflows/zk-environment-publish.yml +++ b/.github/workflows/zk-environment-publish.yml @@ -5,14 +5,14 @@ on: branches: - main paths: - - "docker/zk-environment/*" - - ".github/workflows/zk-environment.publish.yml" + - "docker/zk-environment/**" + - ".github/workflows/zk-environment-publish.yml" pull_request: branches: - main paths: - - "docker/zk-environment/*" - - ".github/workflows/zk-environment.publish.yml" + - "docker/zk-environment/**" + - ".github/workflows/zk-environment-publish.yml" concurrency: group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.sha }} @@ -23,7 +23,7 @@ jobs: outputs: zk_environment: ${{ steps.changed-files-yaml.outputs.zk_env_any_changed }} zk_environment_cuda_11_8: ${{ steps.changed-files-yaml.outputs.zk_env_cuda_11_8_any_changed }} - zk_environment_cuda_12: ${{ steps.changed-files-yaml.outputs.zk_env_cuda_12_any_changed }} + zk_environment_cuda_12_0: ${{ steps.changed-files-yaml.outputs.zk_env_cuda_12_any_changed }} runs-on: ubuntu-latest steps: - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 @@ -37,13 +37,13 @@ jobs: files_yaml: | zk_env: - docker/zk-environment/Dockerfile - - .github/workflows/zk-environment.publish.yml + - .github/workflows/zk-environment-publish.yml zk_env_cuda_11_8: - docker/zk-environment/20.04_amd64_cuda_11_8.Dockerfile - - .github/workflows/zk-environment.publish.yml + - .github/workflows/zk-environment-publish.yml zk_env_cuda_12: - docker/zk-environment/20.04_amd64_cuda_12_0.Dockerfile - - .github/workflows/zk-environment.publish.yml + - .github/workflows/zk-environment-publish.yml get_short_sha: if: needs.changed_files.outputs.zk_environment == 'true' diff --git a/.gitignore b/.gitignore index eff8079e75db..c2878f7f734a 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,6 @@ todo Cargo.lock !/Cargo.lock -!/core/bin/verification_key_generator_and_server/Cargo.lock !/infrastructure/zksync-crypto/Cargo.lock !/prover/Cargo.lock @@ -36,6 +35,8 @@ Cargo.lock !/etc/env/docker.toml !/etc/env/ext-node.toml !/etc/env/ext-node-docker.toml +!/etc/env/consensus_config.json +!/etc/env/en_consensus_config.json /etc/tokens/localhost.json /etc/zksolc-bin/* /etc/zkvyper-bin/* diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 766e6e2bf0f5..67b472d70d98 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -35,7 +35,7 @@ and suggestions here too. Some resources to help: 1. [In-repo docs aimed at developers](docs) 2. [zkSync Era docs!](https://era.zksync.io/docs/) -3. Company links can be found in the [repo's readme](README.md) +3. Company links can be found in the [repositories' readme](README.md) ## Code of Conduct diff --git a/Cargo.lock b/Cargo.lock index c794cc5fe803..f9152a0f6838 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,7 +44,7 @@ dependencies = [ "actix-rt", "actix-service", "actix-utils", - "ahash 0.8.5", + "ahash 0.8.7", "base64 0.21.5", "bitflags 2.4.1", "brotli", @@ -160,7 +160,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web-codegen", - "ahash 0.8.5", + "ahash 0.8.7", "bytes", "bytestring", "cfg-if 1.0.0", @@ -233,17 +233,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "aes" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" -dependencies = [ - "aes-soft", - "aesni", - "cipher 0.2.5", -] - [[package]] name = "aes" version = "0.8.3" @@ -251,22 +240,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" dependencies = [ "cfg-if 1.0.0", - "cipher 0.4.4", + "cipher", "cpufeatures", ] -[[package]] -name = "aes-ctr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7729c3cde54d67063be556aeac75a81330d802f0259500ca40cb52967f975763" -dependencies = [ - "aes-soft", - "aesni", - "cipher 0.2.5", - "ctr 0.6.0", -] - [[package]] name = "aes-gcm" version = "0.10.3" @@ -274,52 +251,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" dependencies = [ "aead", - "aes 0.8.3", - "cipher 0.4.4", - "ctr 0.9.2", + "aes", + "cipher", + "ctr", "ghash", "subtle", ] -[[package]] -name = "aes-soft" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" -dependencies = [ - "cipher 0.2.5", - "opaque-debug", -] - -[[package]] -name = "aesni" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" -dependencies = [ - "cipher 0.2.5", - "opaque-debug", -] - [[package]] name = "ahash" version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" dependencies = [ - "getrandom 0.2.10", + "getrandom", "once_cell", "version_check", ] [[package]] name = "ahash" -version = "0.8.5" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7d5a2cecb58716e47d67d5703a249964b14c7be1ec3cad3affc295b2d1c35d" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" dependencies = [ "cfg-if 1.0.0", - "getrandom 0.2.10", + "getrandom", "once_cell", "version_check", "zerocopy", @@ -349,6 +306,12 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -549,13 +512,23 @@ dependencies = [ [[package]] name = "atoi" -version = "0.4.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" dependencies = [ "num-traits", ] +[[package]] +name = "atomic-write-file" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436" +dependencies = [ + "nix", + "rand 0.8.5", +] + [[package]] name = "atty" version = "0.2.14" @@ -567,15 +540,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "autocfg" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" -dependencies = [ - "autocfg 1.1.0", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -630,18 +594,6 @@ dependencies = [ "tower-service", ] -[[package]] -name = "backon" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c1a6197b2120bb2185a267f6515038558b019e92b832bb0320e96d66268dcf9" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "pin-project", - "tokio", -] - [[package]] name = "backtrace" version = "0.3.69" @@ -663,6 +615,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.13.1" @@ -738,11 +696,11 @@ dependencies = [ [[package]] name = "bigdecimal" -version = "0.2.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1e50562e37200edf7c6c43e54a08e64a5553bfb59d9c297d5572512aa517256" +checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" dependencies = [ - "num-bigint 0.3.3", + "num-bigint 0.4.4", "num-integer", "num-traits", "serde", @@ -798,6 +756,9 @@ name = "bitflags" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +dependencies = [ + "serde", +] [[package]] name = "bitmaps" @@ -808,28 +769,16 @@ dependencies = [ "typenum", ] -[[package]] -name = "bitvec" -version = "0.20.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7774144344a4faa177370406a7ff5f1da24303817368584c6206c8303eb07848" -dependencies = [ - "funty 1.1.0", - "radium 0.6.2", - "tap", - "wyz 0.2.0", -] - [[package]] name = "bitvec" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ - "funty 2.0.0", - "radium 0.7.0", + "funty", + "radium", "tap", - "wyz 0.5.1", + "wyz", ] [[package]] @@ -838,7 +787,7 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" dependencies = [ - "crypto-mac 0.8.0", + "crypto-mac", "digest 0.9.0", "opaque-debug", ] @@ -921,16 +870,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-modes" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a0e8073e8baa88212fb5823574c02ebccb395136ba9a164ab89379ec6072f0" -dependencies = [ - "block-padding", - "cipher 0.2.5", -] - [[package]] name = "block-padding" version = "0.2.1" @@ -979,9 +918,9 @@ dependencies = [ "crypto-bigint 0.5.3", "cs_derive 0.1.0 (git+https://github.com/matter-labs/era-boojum.git?branch=main)", "derivative", - "ethereum-types 0.14.1", + "ethereum-types", "firestorm", - "itertools", + "itertools 0.10.5", "lazy_static", "num-modular", "num_cpus", @@ -996,6 +935,30 @@ dependencies = [ "unroll", ] +[[package]] +name = "borsh" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d4d6dafc1a3bb54687538972158f07b2c948bc57d5890df22c0739098b3028" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4918709cc4dd777ad2b6303ed03cb37f3ca0ccede8c1b0d28ac6db8f4710e0" +dependencies = [ + "once_cell", + "proc-macro-crate 2.0.1", + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 2.0.38", + "syn_derive", +] + [[package]] name = "brotli" version = "3.4.0" @@ -1029,6 +992,28 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" +[[package]] +name = "bytecheck" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 1.0.109", +] + [[package]] name = "bytecount" version = "0.6.5" @@ -1135,6 +1120,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "chacha20" version = "0.9.1" @@ -1142,7 +1133,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if 1.0.0", - "cipher 0.4.4", + "cipher", "cpufeatures", ] @@ -1154,7 +1145,7 @@ checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" dependencies = [ "aead", "chacha20", - "cipher 0.4.4", + "cipher", "poly1305", "zeroize", ] @@ -1201,15 +1192,6 @@ dependencies = [ "half", ] -[[package]] -name = "cipher" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" -dependencies = [ - "generic-array", -] - [[package]] name = "cipher" version = "0.4.4" @@ -1224,14 +1206,29 @@ dependencies = [ [[package]] name = "circuit_definitions" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.0#43aeb53d7d9c909508a98f9fc140edff0e9d2357" +source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.0#de2ecad62ac8c12777e576dca20311ad8ec770d1" dependencies = [ "crossbeam 0.8.2", "derivative", + "seq-macro", "serde", "snark_wrapper", "zk_evm 1.4.0", - "zkevm_circuits", + "zkevm_circuits 1.4.0", +] + +[[package]] +name = "circuit_definitions" +version = "0.1.0" +source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1#ef77c44f919ba161df5976ec3899cf57a1585e7c" +dependencies = [ + "crossbeam 0.8.2", + "derivative", + "seq-macro", + "serde", + "snark_wrapper", + "zk_evm 1.4.1", + "zkevm_circuits 1.4.1", ] [[package]] @@ -1329,21 +1326,12 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "codegen" version = "0.1.0" source = "git+https://github.com/matter-labs/solidity_plonk_verifier.git?branch=dev#82f96b7156551087f1c9bfe4f0ea68845b6debfc" dependencies = [ - "ethereum-types 0.14.1", + "ethereum-types", "franklin-crypto 0.0.5 (git+https://github.com/matter-labs/franklin-crypto?branch=dev)", "handlebars", "hex", @@ -1369,16 +1357,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" -[[package]] -name = "combine" -version = "4.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" -dependencies = [ - "bytes", - "memchr", -] - [[package]] name = "compile-fmt" version = "0.1.0" @@ -1490,18 +1468,18 @@ dependencies = [ [[package]] name = "crc" -version = "2.1.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" dependencies = [ "crc-catalog", ] [[package]] name = "crc-catalog" -version = "1.1.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" @@ -1524,7 +1502,7 @@ dependencies = [ "ciborium", "clap 3.2.25", "criterion-plot", - "itertools", + "itertools 0.10.5", "lazy_static", "num-traits", "oorandom", @@ -1545,25 +1523,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", - "itertools", -] - -[[package]] -name = "cross_external_nodes_checker" -version = "0.1.0" -dependencies = [ - "anyhow", - "ctrlc", - "envy", - "futures 0.3.28", - "serde", - "serde_json", - "tokio", - "tracing", - "vlog", - "zksync_types", - "zksync_utils", - "zksync_web3_decl", + "itertools 0.10.5", ] [[package]] @@ -1642,7 +1602,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" dependencies = [ - "autocfg 1.1.0", + "autocfg", "cfg-if 0.1.10", "crossbeam-utils 0.7.2", "lazy_static", @@ -1657,7 +1617,7 @@ version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ - "autocfg 1.1.0", + "autocfg", "cfg-if 1.0.0", "crossbeam-utils 0.8.16", "memoffset 0.9.0", @@ -1691,7 +1651,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ - "autocfg 1.1.0", + "autocfg", "cfg-if 0.1.10", "lazy_static", ] @@ -1729,8 +1689,10 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" dependencies = [ + "generic-array", "rand_core 0.6.4", "subtle", + "zeroize", ] [[package]] @@ -1754,16 +1716,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "crypto-mac" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4857fd85a0c34b3c3297875b747c1e02e06b6a0ea32dd892d8192b9ce0813ea6" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "cs_derive" version = "0.1.0" @@ -1787,22 +1739,13 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "ctr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" -dependencies = [ - "cipher 0.2.5", -] - [[package]] name = "ctr" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ - "cipher 0.4.4", + "cipher", ] [[package]] @@ -1815,6 +1758,36 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "curl" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22" +dependencies = [ + "curl-sys", + "libc", + "openssl-probe", + "openssl-sys", + "schannel", + "socket2 0.4.10", + "winapi", +] + +[[package]] +name = "curl-sys" +version = "0.4.70+curl-8.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c0333d8849afe78a4c8102a429a446bfdd055832af071945520e835ae2d841e" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", + "windows-sys 0.48.0", +] + [[package]] name = "curve25519-dalek" version = "4.1.1" @@ -1888,7 +1861,7 @@ dependencies = [ "hashbrown 0.14.2", "lock_api", "once_cell", - "parking_lot_core 0.9.9", + "parking_lot_core", ] [[package]] @@ -1956,6 +1929,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "digest" version = "0.9.0" @@ -1972,35 +1951,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", + "const-oid", "crypto-common", "subtle", ] [[package]] -name = "dirs" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "dotenv" -version = "0.15.0" +name = "dotenvy" +version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] name = "dtoa" @@ -2015,11 +1975,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" dependencies = [ "der 0.6.1", - "elliptic-curve", - "rfc6979", + "elliptic-curve 0.12.3", + "rfc6979 0.3.1", "signature 1.6.4", ] +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der 0.7.8", + "digest 0.10.7", + "elliptic-curve 0.13.7", + "rfc6979 0.4.0", + "signature 2.2.0", + "spki 0.7.2", +] + [[package]] name = "ed25519" version = "2.2.3" @@ -2059,16 +2033,35 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" dependencies = [ - "base16ct", + "base16ct 0.1.1", "crypto-bigint 0.4.9", "der 0.6.1", "digest 0.10.7", - "ff", + "ff 0.12.1", "generic-array", - "group", + "group 0.12.1", "pkcs8 0.9.0", "rand_core 0.6.4", - "sec1", + "sec1 0.3.0", + "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9775b22bc152ad86a0cf23f0f348b884b26add12bf741e7ffc4d4ab2ab4d205" +dependencies = [ + "base16ct 0.2.0", + "crypto-bigint 0.5.3", + "digest 0.10.7", + "ff 0.13.0", + "generic-array", + "group 0.13.0", + "pkcs8 0.10.2", + "rand_core 0.6.4", + "sec1 0.7.3", "subtle", "zeroize", ] @@ -2158,12 +2151,23 @@ dependencies = [ ] [[package]] -name = "ethabi" +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if 1.0.0", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "ethabi" version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" dependencies = [ - "ethereum-types 0.14.1", + "ethereum-types", "hex", "once_cell", "regex", @@ -2174,19 +2178,6 @@ dependencies = [ "uint", ] -[[package]] -name = "ethbloom" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb684ac8fa8f6c5759f788862bb22ec6fe3cb392f6bfd08e3c64b603661e3f8" -dependencies = [ - "crunchy", - "fixed-hash 0.7.0", - "impl-rlp", - "impl-serde 0.3.2", - "tiny-keccak 2.0.2", -] - [[package]] name = "ethbloom" version = "0.13.0" @@ -2194,37 +2185,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" dependencies = [ "crunchy", - "fixed-hash 0.8.0", + "fixed-hash", "impl-rlp", - "impl-serde 0.4.0", + "impl-serde", "tiny-keccak 2.0.2", ] -[[package]] -name = "ethereum-types" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05136f7057fe789f06e6d41d07b34e6f70d8c86e5693b60f97aaa6553553bdaf" -dependencies = [ - "ethbloom 0.11.1", - "fixed-hash 0.7.0", - "impl-rlp", - "impl-serde 0.3.2", - "primitive-types 0.10.1", - "uint", -] - [[package]] name = "ethereum-types" version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" dependencies = [ - "ethbloom 0.13.0", - "fixed-hash 0.8.0", + "ethbloom", + "fixed-hash", "impl-rlp", - "impl-serde 0.4.0", - "primitive-types 0.12.2", + "impl-serde", + "primitive-types", "uint", ] @@ -2255,15 +2232,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - [[package]] name = "fastrand" version = "2.0.1" @@ -2280,6 +2248,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "ff_ce" version = "0.14.3" @@ -2338,18 +2316,6 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c5f6c2c942da57e2aaaa84b8a521489486f14e75e7fa91dab70aba913975f98" -[[package]] -name = "fixed-hash" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" -dependencies = [ - "byteorder", - "rand 0.8.5", - "rustc-hex", - "static_assertions", -] - [[package]] name = "fixed-hash" version = "0.8.0" @@ -2378,6 +2344,17 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "futures-core", + "futures-sink", + "spin 0.9.8", +] + [[package]] name = "fnv" version = "1.0.7" @@ -2423,7 +2400,7 @@ dependencies = [ "digest 0.9.0", "hex", "indexmap 1.9.3", - "itertools", + "itertools 0.10.5", "lazy_static", "num-bigint 0.4.4", "num-derive 0.2.5", @@ -2455,7 +2432,7 @@ dependencies = [ "digest 0.9.0", "hex", "indexmap 1.9.3", - "itertools", + "itertools 0.10.5", "lazy_static", "num-bigint 0.4.4", "num-derive 0.2.5", @@ -2476,12 +2453,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -[[package]] -name = "funty" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" - [[package]] name = "funty" version = "2.0.0" @@ -2539,13 +2510,13 @@ dependencies = [ [[package]] name = "futures-intrusive" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604f7a68fbf8103337523b1fadc8ade7361ee3f112f7c680ad179651616aed5" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" dependencies = [ "futures-core", "lock_api", - "parking_lot 0.11.2", + "parking_lot", ] [[package]] @@ -2614,17 +2585,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", + "zeroize", ] [[package]] @@ -2790,7 +2751,7 @@ dependencies = [ "futures-timer", "no-std-compat", "nonzero_ext", - "parking_lot 0.12.1", + "parking_lot", "quanta 0.9.3", "rand 0.8.5", "smallvec", @@ -2802,16 +2763,27 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ - "ff", + "ff 0.12.1", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", "rand_core 0.6.4", "subtle", ] [[package]] name = "h2" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" dependencies = [ "bytes", "fnv", @@ -2819,7 +2791,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -2834,9 +2806,9 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "handlebars" -version = "4.4.0" +version = "5.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39b3bc2a8f715298032cf5087e58573809374b08160aa7d750582bdb82d2683" +checksum = "c73166c591e67fb4bf9bc04011b4e35f12e89fe8d676193aa263df065955a379" dependencies = [ "log", "pest", @@ -2848,26 +2820,20 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ "ahash 0.7.7", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038" dependencies = [ - "ahash 0.8.5", + "ahash 0.8.7", ] [[package]] @@ -2875,14 +2841,18 @@ name = "hashbrown" version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +dependencies = [ + "ahash 0.8.7", + "allocator-api2", +] [[package]] name = "hashlink" -version = "0.7.0" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.11.2", + "hashbrown 0.14.2", ] [[package]] @@ -2964,17 +2934,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" dependencies = [ - "hmac 0.12.1", -] - -[[package]] -name = "hmac" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" -dependencies = [ - "crypto-mac 0.10.0", - "digest 0.9.0", + "hmac", ] [[package]] @@ -3164,22 +3124,13 @@ dependencies = [ "version_check", ] -[[package]] -name = "impl-codec" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161ebdfec3c8e3b52bf61c4f3550a1eea4f9579d10dc1b936f3171ebdcd6c443" -dependencies = [ - "parity-scale-codec 2.3.1", -] - [[package]] name = "impl-codec" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" dependencies = [ - "parity-scale-codec 3.6.5", + "parity-scale-codec", ] [[package]] @@ -3191,15 +3142,6 @@ dependencies = [ "rlp", ] -[[package]] -name = "impl-serde" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" -dependencies = [ - "serde", -] - [[package]] name = "impl-serde" version = "0.4.0" @@ -3226,7 +3168,7 @@ version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ - "autocfg 1.1.0", + "autocfg", "hashbrown 0.12.3", ] @@ -3263,15 +3205,6 @@ dependencies = [ "yaml-rust", ] -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if 1.0.0", -] - [[package]] name = "ipnet" version = "2.9.0" @@ -3280,9 +3213,12 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "ipnetwork" -version = "0.17.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c3eaab3ac0ede60ffa41add21970a7df7d91772c03383aac6c2c3d53cc716b" +checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" +dependencies = [ + "serde", +] [[package]] name = "iri-string" @@ -3314,6 +3250,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.9" @@ -3409,7 +3354,7 @@ dependencies = [ "futures-util", "hyper", "jsonrpsee-types", - "parking_lot 0.12.1", + "parking_lot", "pin-project", "rand 0.8.5", "rustc-hash", @@ -3537,9 +3482,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" dependencies = [ "cfg-if 1.0.0", - "ecdsa", - "elliptic-curve", + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", + "sha2 0.10.8", +] + +[[package]] +name = "k256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f01b677d82ef7a676aa37e099defd83a28e15687112cafdd112d60236b6115b" +dependencies = [ + "cfg-if 1.0.0", + "ecdsa 0.16.9", + "elliptic-curve 0.13.7", + "once_cell", "sha2 0.10.8", + "signature 2.2.0", ] [[package]] @@ -3562,6 +3521,9 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] [[package]] name = "lazycell" @@ -3611,6 +3573,17 @@ dependencies = [ "libz-sys", ] +[[package]] +name = "libsqlite3-sys" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "libz-sys" version = "1.1.12" @@ -3618,6 +3591,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" dependencies = [ "cc", + "libc", "pkg-config", "vcpkg", ] @@ -3711,7 +3685,7 @@ version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ - "autocfg 1.1.0", + "autocfg", "scopeguard", ] @@ -3826,7 +3800,7 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" dependencies = [ - "autocfg 1.1.0", + "autocfg", ] [[package]] @@ -3835,7 +3809,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" dependencies = [ - "autocfg 1.1.0", + "autocfg", ] [[package]] @@ -3859,7 +3833,7 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fde3af1a009ed76a778cb84fdef9e7dbbdf5775ae3e4cc1f434a6a307f6f76c5" dependencies = [ - "ahash 0.8.5", + "ahash 0.8.7", "metrics-macros", "portable-atomic", ] @@ -4002,7 +3976,7 @@ dependencies = [ "anyhow", "ethabi", "hex", - "itertools", + "itertools 0.10.5", "once_cell", "thiserror", "tokio", @@ -4011,6 +3985,10 @@ dependencies = [ "zk_evm 1.3.1", "zk_evm 1.3.3 (git+https://github.com/matter-labs/era-zk_evm.git?tag=v1.3.3-rc2)", "zk_evm 1.4.0", + "zk_evm 1.4.1", + "zkevm_test_harness 1.3.3", + "zkevm_test_harness 1.4.0", + "zkevm_test_harness 1.4.1", "zksync_contracts", "zksync_eth_signer", "zksync_state", @@ -4121,7 +4099,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" dependencies = [ - "autocfg 1.1.0", + "autocfg", "num-integer", "num-traits", "serde", @@ -4133,12 +4111,29 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ - "autocfg 1.1.0", + "autocfg", "num-integer", "num-traits", "serde", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", +] + [[package]] name = "num-complex" version = "0.3.1" @@ -4156,6 +4151,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" dependencies = [ "num-traits", + "serde", ] [[package]] @@ -4186,7 +4182,7 @@ version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ - "autocfg 1.1.0", + "autocfg", "num-traits", ] @@ -4196,7 +4192,7 @@ version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" dependencies = [ - "autocfg 1.1.0", + "autocfg", "num-integer", "num-traits", ] @@ -4217,7 +4213,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" dependencies = [ - "autocfg 1.1.0", + "autocfg", "num-bigint 0.3.3", "num-integer", "num-traits", @@ -4230,10 +4226,11 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ - "autocfg 1.1.0", + "autocfg", "num-bigint 0.4.4", "num-integer", "num-traits", + "serde", ] [[package]] @@ -4242,7 +4239,7 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ - "autocfg 1.1.0", + "autocfg", "libm", ] @@ -4427,44 +4424,6 @@ dependencies = [ "serde", ] -[[package]] -name = "parity-crypto" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b92ea9ddac0d6e1db7c49991e7d397d34a9fd814b4c93cda53788e8eef94e35" -dependencies = [ - "aes 0.6.0", - "aes-ctr", - "block-modes", - "digest 0.9.0", - "ethereum-types 0.12.1", - "hmac 0.10.1", - "lazy_static", - "pbkdf2 0.7.5", - "ripemd160", - "rustc-hex", - "scrypt", - "secp256k1 0.20.3", - "sha2 0.9.9", - "subtle", - "tiny-keccak 2.0.2", - "zeroize", -] - -[[package]] -name = "parity-scale-codec" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" -dependencies = [ - "arrayvec 0.7.4", - "bitvec 0.20.4", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive 2.3.1", - "serde", -] - [[package]] name = "parity-scale-codec" version = "3.6.5" @@ -4472,25 +4431,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" dependencies = [ "arrayvec 0.7.4", - "bitvec 1.0.1", + "bitvec", "byte-slice-cast", "impl-trait-for-tuples", - "parity-scale-codec-derive 3.6.5", + "parity-scale-codec-derive", "serde", ] -[[package]] -name = "parity-scale-codec-derive" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 1.0.109", -] - [[package]] name = "parity-scale-codec-derive" version = "3.6.5" @@ -4509,17 +4456,6 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - [[package]] name = "parking_lot" version = "0.12.1" @@ -4527,21 +4463,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.9", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if 1.0.0", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -4557,16 +4479,6 @@ dependencies = [ "windows-targets 0.48.5", ] -[[package]] -name = "password-hash" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54986aa4bfc9b98c6a5f40184223658d187159d7b3c6af33f2b2aa25ae1db0fa" -dependencies = [ - "base64ct", - "rand_core 0.6.4", -] - [[package]] name = "paste" version = "1.0.14" @@ -4574,32 +4486,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] -name = "pbkdf2" -version = "0.6.0" +name = "peeking_take_while" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3b8c0d71734018084da0c0354193a5edfb81b20d2d57a92c5b154aefc554a4a" -dependencies = [ - "crypto-mac 0.10.0", -] - -[[package]] -name = "pbkdf2" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf916dd32dd26297907890d99dc2740e33f6bd9073965af4ccff2967962f5508" -dependencies = [ - "base64ct", - "crypto-mac 0.10.0", - "hmac 0.10.1", - "password-hash", - "sha2 0.9.9", -] - -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "pem" @@ -4627,9 +4517,9 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c022f1e7b65d6a24c0dbbd5fb344c66881bc01f3e5ae74a1c8100f2f985d98a4" +checksum = "1f200d8d83c44a45b21764d1916299752ca035d15ecd46faca3e9a2a2bf6ad06" dependencies = [ "memchr", "thiserror", @@ -4638,9 +4528,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35513f630d46400a977c4cb58f78e1bfbe01434316e60c37d27b9ad6139c66d8" +checksum = "bcd6ab1236bbdb3a49027e920e693192ebfe8913f6d60e294de57463a493cfde" dependencies = [ "pest", "pest_generator", @@ -4648,9 +4538,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc9fc1b9e7057baba189b5c626e2d6f40681ae5b6eb064dc7c7834101ec8123a" +checksum = "2a31940305ffc96863a735bef7c7994a00b325a7138fdbc5bda0f1a0476d3275" dependencies = [ "pest", "pest_meta", @@ -4661,9 +4551,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df74e9e7ec4053ceb980e7c0c8bd3594e977fde1af91daba9c928e8e8c6708d" +checksum = "a7ff62f5259e53b78d1af898941cdcdccfae7385cf7d793a6e55de5d05bb4b7d" dependencies = [ "once_cell", "pest", @@ -4712,6 +4602,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der 0.7.8", + "pkcs8 0.10.2", + "spki 0.7.2", +] + [[package]] name = "pkcs8" version = "0.9.0" @@ -4814,26 +4715,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] -name = "prettyplease" -version = "0.2.15" +name = "pretty_assertions" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" dependencies = [ - "proc-macro2 1.0.69", - "syn 2.0.38", + "diff", + "yansi", ] [[package]] -name = "primitive-types" -version = "0.10.1" +name = "prettyplease" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" +checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ - "fixed-hash 0.7.0", - "impl-codec 0.5.1", - "impl-rlp", - "impl-serde 0.3.2", - "uint", + "proc-macro2 1.0.69", + "syn 2.0.38", ] [[package]] @@ -4842,10 +4740,10 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ - "fixed-hash 0.8.0", - "impl-codec 0.6.0", + "fixed-hash", + "impl-codec", "impl-rlp", - "impl-serde 0.4.0", + "impl-serde", "uint", ] @@ -4925,7 +4823,7 @@ checksum = "3c99afa9a01501019ac3a14d71d9f94050346f55ca471ce90c799a15c58f61e2" dependencies = [ "dtoa", "itoa", - "parking_lot 0.12.1", + "parking_lot", "prometheus-client-derive-encode", ] @@ -4970,7 +4868,7 @@ checksum = "8bdf592881d821b83d471f8af290226c8d51402259e9bb5be7f9f8bdebbb11ac" dependencies = [ "bytes", "heck 0.4.1", - "itertools", + "itertools 0.10.5", "log", "multimap", "once_cell", @@ -4991,7 +4889,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32" dependencies = [ "anyhow", - "itertools", + "itertools 0.10.5", "proc-macro2 1.0.69", "quote 1.0.33", "syn 2.0.38", @@ -5049,6 +4947,26 @@ dependencies = [ "thiserror", ] +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 1.0.109", +] + [[package]] name = "pulldown-cmark" version = "0.9.3" @@ -5119,12 +5037,6 @@ dependencies = [ "proc-macro2 1.0.69", ] -[[package]] -name = "radium" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" - [[package]] name = "radium" version = "0.7.0" @@ -5144,36 +5056,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -dependencies = [ - "autocfg 0.1.8", - "libc", - "rand_chacha 0.1.1", - "rand_core 0.4.2", - "rand_hc 0.1.0", - "rand_isaac", - "rand_jitter", - "rand_os", - "rand_pcg", - "rand_xorshift", - "winapi", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc 0.2.0", -] - [[package]] name = "rand" version = "0.8.5" @@ -5181,30 +5063,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha 0.3.1", + "rand_chacha", "rand_core 0.6.4", ] -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -dependencies = [ - "autocfg 0.1.8", - "rand_core 0.3.1", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - [[package]] name = "rand_chacha" version = "0.3.1" @@ -5230,93 +5092,13 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.10", -] - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -dependencies = [ - "libc", - "rand_core 0.4.2", - "winapi", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -dependencies = [ - "cloudabi", - "fuchsia-cprng", - "libc", - "rand_core 0.4.2", - "rdrand", - "winapi", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -dependencies = [ - "autocfg 0.1.8", - "rand_core 0.4.2", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -dependencies = [ - "rand_core 0.3.1", + "getrandom", ] [[package]] @@ -5366,15 +5148,6 @@ dependencies = [ "rand_core 0.3.1", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.3.5" @@ -5393,17 +5166,6 @@ dependencies = [ "bitflags 1.3.2", ] -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom 0.2.10", - "redox_syscall 0.2.16", - "thiserror", -] - [[package]] name = "regex" version = "1.10.2" @@ -5457,6 +5219,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "rend" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2571463863a6bd50c32f94402933f03457a3fbaf697a707c5be741e459f08fd" +dependencies = [ + "bytecheck", +] + [[package]] name = "reqwest" version = "0.11.22" @@ -5552,10 +5323,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" dependencies = [ "crypto-bigint 0.4.9", - "hmac 0.12.1", + "hmac", "zeroize", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "ring" version = "0.16.20" @@ -5578,7 +5359,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", - "getrandom 0.2.10", + "getrandom", "libc", "spin 0.9.8", "untrusted 0.9.0", @@ -5586,14 +5367,32 @@ dependencies = [ ] [[package]] -name = "ripemd160" -version = "0.9.1" +name = "rkyv" +version = "0.7.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eca4ecc81b7f313189bf73ce724400a07da2a6dac19588b03c8bd76a2dcc251" +checksum = "527a97cdfef66f65998b5f3b637c26f5a5ec09cc52a3f9932313ac645f4190f5" dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "opaque-debug", + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5c462a1328c8e67e4d6dbad1eb0355dd43e8ab432c6e227a43657f16ade5033" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 1.0.109", ] [[package]] @@ -5622,6 +5421,42 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" +[[package]] +name = "rsa" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af6c4b23d99685a1408194da11270ef8e9809aff951cc70ec9b17350b087e474" +dependencies = [ + "const-oid", + "digest 0.10.7", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8 0.10.2", + "rand_core 0.6.4", + "signature 2.2.0", + "spki 0.7.2", + "subtle", + "zeroize", +] + +[[package]] +name = "rust_decimal" +version = "1.33.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06676aec5ccb8fc1da723cc8c0f9a46549f21ebb8753d3915c6c41db1e7f1dc4" +dependencies = [ + "arrayvec 0.7.4", + "borsh", + "bytes", + "num-traits", + "rand 0.8.5", + "rkyv", + "serde", + "serde_json", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -5771,15 +5606,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" -[[package]] -name = "salsa20" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "399f290ffc409596022fce5ea5d4138184be4784f2b28c62c59f0d8389059a15" -dependencies = [ - "cipher 0.2.5", -] - [[package]] name = "same-file" version = "1.0.6" @@ -5804,22 +5630,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "scrypt" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da492dab03f925d977776a0b7233d7b934d6dc2b94faead48928e2e9bacedb9" -dependencies = [ - "base64 0.13.1", - "hmac 0.10.1", - "pbkdf2 0.6.0", - "rand 0.7.3", - "rand_core 0.5.1", - "salsa20", - "sha2 0.9.9", - "subtle", -] - [[package]] name = "sct" version = "0.7.0" @@ -5830,13 +5640,19 @@ dependencies = [ "untrusted 0.7.1", ] +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + [[package]] name = "sec1" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ - "base16ct", + "base16ct 0.1.1", "der 0.6.1", "generic-array", "pkcs8 0.9.0", @@ -5845,13 +5661,17 @@ dependencies = [ ] [[package]] -name = "secp256k1" -version = "0.20.3" +name = "sec1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d03ceae636d0fed5bae6a7f4f664354c5f4fcedf6eef053fef17e49f837d0a" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ - "rand 0.6.5", - "secp256k1-sys 0.4.2", + "base16ct 0.2.0", + "der 0.7.8", + "generic-array", + "pkcs8 0.10.2", + "subtle", + "zeroize", ] [[package]] @@ -5860,16 +5680,7 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" dependencies = [ - "secp256k1-sys 0.8.1", -] - -[[package]] -name = "secp256k1-sys" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957da2573cde917463ece3570eab4a0b3f19de6f1646cde62e6fd3868f566036" -dependencies = [ - "cc", + "secp256k1-sys", ] [[package]] @@ -6027,6 +5838,12 @@ dependencies = [ "uuid", ] +[[package]] +name = "seq-macro" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" + [[package]] name = "serde" version = "1.0.189" @@ -6127,17 +5944,6 @@ dependencies = [ "opaque-debug", ] -[[package]] -name = "sha-1" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" -dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.10.7", -] - [[package]] name = "sha1" version = "0.10.6" @@ -6225,9 +6031,9 @@ dependencies = [ [[package]] name = "shlex" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" @@ -6254,9 +6060,16 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ + "digest 0.10.7", "rand_core 0.6.4", ] +[[package]] +name = "simdutf8" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" + [[package]] name = "similar" version = "2.3.0" @@ -6312,7 +6125,7 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ - "autocfg 1.1.0", + "autocfg", ] [[package]] @@ -6341,7 +6154,6 @@ dependencies = [ "zksync_env_config", "zksync_object_store", "zksync_types", - "zksync_utils", ] [[package]] @@ -6403,7 +6215,7 @@ dependencies = [ "httparse", "log", "rand 0.8.5", - "sha-1 0.9.8", + "sha-1", ] [[package]] @@ -6417,6 +6229,9 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] [[package]] name = "spki" @@ -6446,85 +6261,94 @@ checksum = "c85070f382340e8b23a75808e83573ddf65f9ad9143df9573ca37c1ed2ee956a" [[package]] name = "sqlformat" -version = "0.1.8" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" +checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" dependencies = [ - "itertools", + "itertools 0.12.0", "nom", "unicode_categories", ] [[package]] name = "sqlx" -version = "0.5.13" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551873805652ba0d912fec5bbb0f8b4cdd96baf8e2ebf5970e5671092966019b" +checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf" dependencies = [ "sqlx-core", "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", ] [[package]] name = "sqlx-core" -version = "0.5.13" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48c61941ccf5ddcada342cd59e3e5173b007c509e1e8e990dafc830294d9dc5" +checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd" dependencies = [ - "ahash 0.7.7", + "ahash 0.8.7", "atoi", - "base64 0.13.1", "bigdecimal", - "bitflags 1.3.2", "byteorder", "bytes", "chrono", "crc", "crossbeam-queue 0.3.8", - "dirs", + "dotenvy", "either", "event-listener 2.5.3", "futures-channel", "futures-core", "futures-intrusive", + "futures-io", "futures-util", "hashlink", "hex", - "hkdf", - "hmac 0.12.1", - "indexmap 1.9.3", + "indexmap 2.1.0", "ipnetwork", - "itoa", - "libc", "log", - "md-5", "memchr", - "num-bigint 0.3.3", + "native-tls", "once_cell", "paste", "percent-encoding", - "rand 0.8.5", + "rust_decimal", "serde", "serde_json", - "sha-1 0.10.1", "sha2 0.10.8", "smallvec", "sqlformat", - "sqlx-rt", - "stringprep", "thiserror", + "tokio", "tokio-stream", + "tracing", "url", - "whoami", ] [[package]] name = "sqlx-macros" -version = "0.5.13" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0fba2b0cae21fc00fe6046f8baa4c7fcb49e379f0f592b04696607f69ed2e1" +checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5" dependencies = [ - "dotenv", + "proc-macro2 1.0.69", + "quote 1.0.33", + "sqlx-core", + "sqlx-macros-core", + "syn 1.0.109", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841" +dependencies = [ + "atomic-write-file", + "dotenvy", "either", "heck 0.4.1", "hex", @@ -6535,21 +6359,126 @@ dependencies = [ "serde_json", "sha2 0.10.8", "sqlx-core", - "sqlx-rt", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", "syn 1.0.109", + "tempfile", + "tokio", "url", ] [[package]] -name = "sqlx-rt" -version = "0.5.13" +name = "sqlx-mysql" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4db708cd3e459078f85f39f96a00960bd841f66ee2a669e90bf36907f5a79aae" +checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4" dependencies = [ - "native-tls", + "atoi", + "base64 0.21.5", + "bigdecimal", + "bitflags 2.4.1", + "byteorder", + "bytes", + "chrono", + "crc", + "digest 0.10.7", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", "once_cell", - "tokio", - "tokio-native-tls", + "percent-encoding", + "rand 0.8.5", + "rsa", + "rust_decimal", + "serde", + "sha1", + "sha2 0.10.8", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24" +dependencies = [ + "atoi", + "base64 0.21.5", + "bigdecimal", + "bitflags 2.4.1", + "byteorder", + "chrono", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "ipnetwork", + "itoa", + "log", + "md-5", + "memchr", + "num-bigint 0.4.4", + "once_cell", + "rand 0.8.5", + "rust_decimal", + "serde", + "serde_json", + "sha1", + "sha2 0.10.8", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490" +dependencies = [ + "atoi", + "chrono", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "tracing", + "url", + "urlencoding", ] [[package]] @@ -6684,6 +6613,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 2.0.38", +] + [[package]] name = "sync_vm" version = "1.3.3" @@ -6694,7 +6635,7 @@ dependencies = [ "derivative", "franklin-crypto 0.0.5 (git+https://github.com/matter-labs/franklin-crypto?branch=dev)", "hex", - "itertools", + "itertools 0.10.5", "num-bigint 0.4.4", "num-derive 0.3.3", "num-integer", @@ -6743,6 +6684,7 @@ dependencies = [ "once_cell", "serde", "serde_json", + "zkevm_test_harness 1.3.3", "zksync_contracts", "zksync_state", "zksync_types", @@ -6778,7 +6720,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ "cfg-if 1.0.0", - "fastrand 2.0.1", + "fastrand", "redox_syscall 0.3.5", "rustix", "windows-sys 0.48.0", @@ -6981,7 +6923,7 @@ dependencies = [ "libc", "mio", "num_cpus", - "parking_lot 0.12.1", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2 0.5.5", @@ -7063,17 +7005,6 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" -[[package]] -name = "toml_edit" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5376256e44f2443f8896ac012507c19a012df0fe8758b55246ae51a2279db51f" -dependencies = [ - "combine", - "indexmap 1.9.3", - "itertools", -] - [[package]] name = "toml_edit" version = "0.19.15" @@ -7415,7 +7346,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" dependencies = [ - "getrandom 0.2.10", + "getrandom", "serde", ] @@ -7516,15 +7447,30 @@ dependencies = [ ] [[package]] -name = "vm-benchmark-harness" +name = "vm-benchmark-harness" +version = "0.1.0" +dependencies = [ + "multivm", + "once_cell", + "zk_evm 1.3.3 (git+https://github.com/matter-labs/era-zk_evm.git?tag=v1.3.3-rc2)", + "zksync_contracts", + "zksync_state", + "zksync_system_constants", + "zksync_types", + "zksync_utils", +] + +[[package]] +name = "vm_utils" version = "0.1.0" dependencies = [ + "anyhow", "multivm", - "once_cell", - "zk_evm 1.3.3 (git+https://github.com/matter-labs/era-zk_evm.git?tag=v1.3.3-rc2)", + "tokio", + "tracing", "zksync_contracts", + "zksync_dal", "zksync_state", - "zksync_system_constants", "zksync_types", "zksync_utils", ] @@ -7548,12 +7494,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" @@ -7666,7 +7606,7 @@ dependencies = [ "bytes", "derive_more", "ethabi", - "ethereum-types 0.14.1", + "ethereum-types", "futures 0.3.28", "futures-timer", "headers", @@ -7675,11 +7615,11 @@ dependencies = [ "jsonrpc-core", "log", "once_cell", - "parking_lot 0.12.1", + "parking_lot", "pin-project", "reqwest", "rlp", - "secp256k1 0.27.0", + "secp256k1", "serde", "serde_json", "tiny-keccak 2.0.2", @@ -7718,10 +7658,6 @@ name = "whoami" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" -dependencies = [ - "wasm-bindgen", - "web-sys", -] [[package]] name = "winapi" @@ -7914,12 +7850,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" - [[package]] name = "wyz" version = "0.5.1" @@ -7938,6 +7868,12 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + [[package]] name = "zerocopy" version = "0.7.31" @@ -7984,7 +7920,7 @@ version = "1.3.1" source = "git+https://github.com/matter-labs/era-zk_evm.git?tag=v1.3.1-rc2#0a7c775932db4839ff6b7fb0db9bdb3583ab54c0" dependencies = [ "blake2 0.10.6 (git+https://github.com/RustCrypto/hashes.git?rev=1f727ce37ff40fa0cce84eb8543a45bdd3ca4a4e)", - "k256", + "k256 0.11.6", "lazy_static", "num 0.4.1", "serde", @@ -8006,7 +7942,7 @@ dependencies = [ "serde", "serde_json", "static_assertions", - "zk_evm_abstractions", + "zk_evm_abstractions 0.1.0", "zkevm_opcode_defs 1.3.2", ] @@ -8021,7 +7957,7 @@ dependencies = [ "serde", "serde_json", "static_assertions", - "zk_evm_abstractions", + "zk_evm_abstractions 0.1.0", "zkevm_opcode_defs 1.3.2", ] @@ -8036,21 +7972,49 @@ dependencies = [ "serde", "serde_json", "static_assertions", - "zk_evm_abstractions", + "zk_evm_abstractions 0.1.0", "zkevm_opcode_defs 1.3.2", ] +[[package]] +name = "zk_evm" +version = "1.4.1" +source = "git+https://github.com/matter-labs/era-zk_evm.git?branch=v1.4.1#6250dbf64b2d14ced87a127735da559f27a432d5" +dependencies = [ + "anyhow", + "lazy_static", + "num 0.4.1", + "serde", + "serde_json", + "static_assertions", + "zk_evm_abstractions 1.4.1", + "zkevm_opcode_defs 1.4.1", +] + [[package]] name = "zk_evm_abstractions" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-zk_evm_abstractions.git#15a2af404902d5f10352e3d1fac693cc395fcff9" +source = "git+https://github.com/matter-labs/era-zk_evm_abstractions.git#32dd320953841aa78579d9da08abbc70bcaed175" dependencies = [ "anyhow", + "num_enum", "serde", "static_assertions", "zkevm_opcode_defs 1.3.2", ] +[[package]] +name = "zk_evm_abstractions" +version = "1.4.1" +source = "git+https://github.com/matter-labs/era-zk_evm_abstractions.git?branch=v1.4.1#0aac08c3b097ee8147e748475117ac46bddcdcef" +dependencies = [ + "anyhow", + "num_enum", + "serde", + "static_assertions", + "zkevm_opcode_defs 1.4.1", +] + [[package]] name = "zkevm-assembly" version = "1.3.2" @@ -8070,6 +8034,25 @@ dependencies = [ "zkevm_opcode_defs 1.3.2", ] +[[package]] +name = "zkevm-assembly" +version = "1.3.2" +source = "git+https://github.com/matter-labs/era-zkEVM-assembly.git?branch=v1.4.1#50282016d01bd2fd147021dd558209778db2268b" +dependencies = [ + "env_logger 0.9.3", + "hex", + "lazy_static", + "log", + "nom", + "num-bigint 0.4.4", + "num-traits", + "sha3 0.10.8", + "smallvec", + "structopt", + "thiserror", + "zkevm_opcode_defs 1.4.1", +] + [[package]] name = "zkevm_circuits" version = "1.4.0" @@ -8081,7 +8064,7 @@ dependencies = [ "cs_derive 0.1.0 (git+https://github.com/matter-labs/era-boojum.git?branch=main)", "derivative", "hex", - "itertools", + "itertools 0.10.5", "rand 0.4.6", "rand 0.8.5", "serde", @@ -8090,13 +8073,34 @@ dependencies = [ "zkevm_opcode_defs 1.3.2", ] +[[package]] +name = "zkevm_circuits" +version = "1.4.1" +source = "git+https://github.com/matter-labs/era-zkevm_circuits.git?branch=v1.4.1#70234e99c2492740226b9f40091e7fccc7ef28e9" +dependencies = [ + "arrayvec 0.7.4", + "bincode", + "boojum", + "cs_derive 0.1.0 (git+https://github.com/matter-labs/era-boojum.git?branch=main)", + "derivative", + "hex", + "itertools 0.10.5", + "rand 0.4.6", + "rand 0.8.5", + "seq-macro", + "serde", + "serde_json", + "smallvec", + "zkevm_opcode_defs 1.4.1", +] + [[package]] name = "zkevm_opcode_defs" version = "1.3.1" source = "git+https://github.com/matter-labs/era-zkevm_opcode_defs.git?branch=v1.3.1#00d4ad2292bd55374a0fa10fe11686d7a109d8a0" dependencies = [ "bitflags 1.3.2", - "ethereum-types 0.14.1", + "ethereum-types", "lazy_static", "sha2 0.10.8", ] @@ -8108,13 +8112,27 @@ source = "git+https://github.com/matter-labs/era-zkevm_opcode_defs.git?branch=v1 dependencies = [ "bitflags 2.4.1", "blake2 0.10.6 (git+https://github.com/RustCrypto/hashes.git?rev=1f727ce37ff40fa0cce84eb8543a45bdd3ca4a4e)", - "ethereum-types 0.14.1", - "k256", + "ethereum-types", + "k256 0.11.6", "lazy_static", "sha2 0.10.6", "sha3 0.10.6", ] +[[package]] +name = "zkevm_opcode_defs" +version = "1.4.1" +source = "git+https://github.com/matter-labs/era-zkevm_opcode_defs.git?branch=v1.4.1#ba8228ff0582d21f64d6a319d50d0aec48e9e7b6" +dependencies = [ + "bitflags 2.4.1", + "blake2 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types", + "k256 0.13.2", + "lazy_static", + "sha2 0.10.8", + "sha3 0.10.8", +] + [[package]] name = "zkevm_test_harness" version = "1.3.3" @@ -8125,7 +8143,7 @@ dependencies = [ "codegen 0.2.0", "crossbeam 0.8.2", "derivative", - "env_logger 0.10.0", + "env_logger 0.9.3", "hex", "num-bigint 0.4.4", "num-integer", @@ -8139,16 +8157,16 @@ dependencies = [ "test-log", "tracing", "zk_evm 1.3.3 (git+https://github.com/matter-labs/era-zk_evm.git?branch=v1.3.3)", - "zkevm-assembly", + "zkevm-assembly 1.3.2 (git+https://github.com/matter-labs/era-zkEVM-assembly.git?branch=v1.3.2)", ] [[package]] name = "zkevm_test_harness" version = "1.4.0" -source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.0#43aeb53d7d9c909508a98f9fc140edff0e9d2357" +source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.0#de2ecad62ac8c12777e576dca20311ad8ec770d1" dependencies = [ "bincode", - "circuit_definitions", + "circuit_definitions 0.1.0 (git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.0)", "codegen 0.2.0", "crossbeam 0.8.2", "derivative", @@ -8162,7 +8180,36 @@ dependencies = [ "structopt", "test-log", "tracing", - "zkevm-assembly", + "zkevm-assembly 1.3.2 (git+https://github.com/matter-labs/era-zkEVM-assembly.git?branch=v1.3.2)", +] + +[[package]] +name = "zkevm_test_harness" +version = "1.4.1" +source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1#ef77c44f919ba161df5976ec3899cf57a1585e7c" +dependencies = [ + "bincode", + "circuit_definitions 0.1.0 (git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1)", + "codegen 0.2.0", + "crossbeam 0.8.2", + "curl", + "derivative", + "env_logger 0.9.3", + "hex", + "lazy_static", + "rand 0.4.6", + "rayon", + "reqwest", + "rescue_poseidon 0.4.1 (git+https://github.com/matter-labs/rescue-poseidon.git?branch=poseidon2)", + "serde", + "serde_json", + "smallvec", + "snark_wrapper", + "structopt", + "test-log", + "tracing", + "walkdir", + "zkevm-assembly 1.3.2 (git+https://github.com/matter-labs/era-zkEVM-assembly.git?branch=v1.4.1)", ] [[package]] @@ -8199,8 +8246,6 @@ dependencies = [ "anyhow", "assert_matches", "async-trait", - "backon", - "convert_case 0.6.0", "futures 0.3.28", "hex", "metrics", @@ -8211,7 +8256,6 @@ dependencies = [ "zksync_config", "zksync_contracts", "zksync_dal", - "zksync_eth_client", "zksync_types", ] @@ -8219,7 +8263,11 @@ dependencies = [ name = "zksync_commitment_utils" version = "0.1.0" dependencies = [ + "multivm", + "zk_evm 1.3.3 (git+https://github.com/matter-labs/era-zk_evm.git?tag=v1.3.3-rc2)", + "zk_evm 1.4.1", "zkevm_test_harness 1.4.0", + "zkevm_test_harness 1.4.1", "zksync_types", "zksync_utils", ] @@ -8227,7 +8275,7 @@ dependencies = [ [[package]] name = "zksync_concurrency" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=84cdd9e45fd84bc1fac0b394c899ae33aef91afa#84cdd9e45fd84bc1fac0b394c899ae33aef91afa" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=5b3d383d7a65b0fbe2a771fecf4313f5083be9ae#5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" dependencies = [ "anyhow", "once_cell", @@ -8247,6 +8295,7 @@ name = "zksync_config" version = "0.1.0" dependencies = [ "anyhow", + "rand 0.8.5", "serde", "zksync_basic_types", ] @@ -8254,7 +8303,7 @@ dependencies = [ [[package]] name = "zksync_consensus_bft" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=84cdd9e45fd84bc1fac0b394c899ae33aef91afa#84cdd9e45fd84bc1fac0b394c899ae33aef91afa" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=5b3d383d7a65b0fbe2a771fecf4313f5083be9ae#5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" dependencies = [ "anyhow", "async-trait", @@ -8275,7 +8324,7 @@ dependencies = [ [[package]] name = "zksync_consensus_crypto" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=84cdd9e45fd84bc1fac0b394c899ae33aef91afa#84cdd9e45fd84bc1fac0b394c899ae33aef91afa" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=5b3d383d7a65b0fbe2a771fecf4313f5083be9ae#5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" dependencies = [ "anyhow", "blst", @@ -8293,10 +8342,9 @@ dependencies = [ [[package]] name = "zksync_consensus_executor" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=84cdd9e45fd84bc1fac0b394c899ae33aef91afa#84cdd9e45fd84bc1fac0b394c899ae33aef91afa" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=5b3d383d7a65b0fbe2a771fecf4313f5083be9ae#5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" dependencies = [ "anyhow", - "prost", "rand 0.8.5", "tracing", "vise", @@ -8309,13 +8357,12 @@ dependencies = [ "zksync_consensus_sync_blocks", "zksync_consensus_utils", "zksync_protobuf", - "zksync_protobuf_build", ] [[package]] name = "zksync_consensus_network" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=84cdd9e45fd84bc1fac0b394c899ae33aef91afa#84cdd9e45fd84bc1fac0b394c899ae33aef91afa" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=5b3d383d7a65b0fbe2a771fecf4313f5083be9ae#5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" dependencies = [ "anyhow", "async-trait", @@ -8331,6 +8378,7 @@ dependencies = [ "zksync_concurrency", "zksync_consensus_crypto", "zksync_consensus_roles", + "zksync_consensus_storage", "zksync_consensus_utils", "zksync_protobuf", "zksync_protobuf_build", @@ -8339,7 +8387,7 @@ dependencies = [ [[package]] name = "zksync_consensus_roles" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=84cdd9e45fd84bc1fac0b394c899ae33aef91afa#84cdd9e45fd84bc1fac0b394c899ae33aef91afa" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=5b3d383d7a65b0fbe2a771fecf4313f5083be9ae#5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" dependencies = [ "anyhow", "bit-vec", @@ -8359,7 +8407,7 @@ dependencies = [ [[package]] name = "zksync_consensus_storage" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=84cdd9e45fd84bc1fac0b394c899ae33aef91afa#84cdd9e45fd84bc1fac0b394c899ae33aef91afa" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=5b3d383d7a65b0fbe2a771fecf4313f5083be9ae#5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" dependencies = [ "anyhow", "async-trait", @@ -8367,6 +8415,7 @@ dependencies = [ "rand 0.8.5", "thiserror", "tracing", + "vise", "zksync_concurrency", "zksync_consensus_roles", "zksync_protobuf", @@ -8376,7 +8425,7 @@ dependencies = [ [[package]] name = "zksync_consensus_sync_blocks" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=84cdd9e45fd84bc1fac0b394c899ae33aef91afa#84cdd9e45fd84bc1fac0b394c899ae33aef91afa" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=5b3d383d7a65b0fbe2a771fecf4313f5083be9ae#5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" dependencies = [ "anyhow", "thiserror", @@ -8391,7 +8440,7 @@ dependencies = [ [[package]] name = "zksync_consensus_utils" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=84cdd9e45fd84bc1fac0b394c899ae33aef91afa#84cdd9e45fd84bc1fac0b394c899ae33aef91afa" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=5b3d383d7a65b0fbe2a771fecf4313f5083be9ae#5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" dependencies = [ "thiserror", "zksync_concurrency", @@ -8459,7 +8508,7 @@ dependencies = [ "futures 0.3.28", "governor", "hex", - "itertools", + "itertools 0.10.5", "jsonrpsee", "lru", "metrics", @@ -8481,26 +8530,31 @@ dependencies = [ "tracing", "vise", "vlog", + "vm_utils", "zksync_circuit_breaker", "zksync_commitment_utils", "zksync_concurrency", "zksync_config", "zksync_consensus_bft", + "zksync_consensus_crypto", "zksync_consensus_executor", "zksync_consensus_roles", "zksync_consensus_storage", + "zksync_consensus_utils", "zksync_contracts", "zksync_dal", + "zksync_env_config", "zksync_eth_client", "zksync_eth_signer", "zksync_health_check", + "zksync_l1_contract_interface", "zksync_mempool", "zksync_merkle_tree", "zksync_mini_merkle_tree", "zksync_object_store", "zksync_protobuf", "zksync_protobuf_build", - "zksync_prover_utils", + "zksync_prover_interface", "zksync_queued_job_processor", "zksync_state", "zksync_storage", @@ -8508,7 +8562,6 @@ dependencies = [ "zksync_test_account", "zksync_types", "zksync_utils", - "zksync_verification_key_generator_and_server", "zksync_web3_decl", ] @@ -8516,7 +8569,6 @@ dependencies = [ name = "zksync_crypto" version = "0.1.0" dependencies = [ - "base64 0.13.1", "blake2 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", "hex", "once_cell", @@ -8535,9 +8587,10 @@ dependencies = [ "assert_matches", "bigdecimal", "bincode", + "chrono", "hex", - "itertools", - "num 0.3.1", + "itertools 0.10.5", + "num 0.4.1", "once_cell", "prost", "rand 0.8.5", @@ -8576,11 +8629,10 @@ dependencies = [ name = "zksync_eth_client" version = "0.1.0" dependencies = [ - "anyhow", "async-trait", - "hex", "jsonrpc-core", "serde", + "static_assertions", "thiserror", "tokio", "tracing", @@ -8601,10 +8653,9 @@ dependencies = [ "futures 0.3.28", "hex", "jsonrpc-core", - "parity-crypto", "reqwest", "rlp", - "secp256k1 0.27.0", + "secp256k1", "serde", "serde_derive", "serde_json", @@ -8631,7 +8682,9 @@ dependencies = [ "vise", "vlog", "zksync_basic_types", + "zksync_concurrency", "zksync_config", + "zksync_consensus_roles", "zksync_contracts", "zksync_core", "zksync_dal", @@ -8656,6 +8709,16 @@ dependencies = [ "tracing", ] +[[package]] +name = "zksync_l1_contract_interface" +version = "0.1.0" +dependencies = [ + "codegen 0.1.0", + "zkevm_test_harness 1.3.3", + "zksync_prover_interface", + "zksync_types", +] + [[package]] name = "zksync_mempool" version = "0.1.0" @@ -8685,6 +8748,7 @@ dependencies = [ "tracing-subscriber", "vise", "zksync_crypto", + "zksync_prover_interface", "zksync_storage", "zksync_system_constants", "zksync_types", @@ -8701,6 +8765,28 @@ dependencies = [ "zksync_crypto", ] +[[package]] +name = "zksync_node" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "futures 0.3.28", + "prometheus_exporter", + "thiserror", + "tokio", + "tracing", + "vlog", + "zksync_config", + "zksync_core", + "zksync_dal", + "zksync_env_config", + "zksync_health_check", + "zksync_object_store", + "zksync_storage", + "zksync_types", +] + [[package]] name = "zksync_object_store" version = "0.1.0" @@ -8726,7 +8812,7 @@ dependencies = [ [[package]] name = "zksync_protobuf" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=84cdd9e45fd84bc1fac0b394c899ae33aef91afa#84cdd9e45fd84bc1fac0b394c899ae33aef91afa" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=5b3d383d7a65b0fbe2a771fecf4313f5083be9ae#5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" dependencies = [ "anyhow", "bit-vec", @@ -8744,7 +8830,7 @@ dependencies = [ [[package]] name = "zksync_protobuf_build" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=84cdd9e45fd84bc1fac0b394c899ae33aef91afa#84cdd9e45fd84bc1fac0b394c899ae33aef91afa" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=5b3d383d7a65b0fbe2a771fecf4313f5083be9ae#5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" dependencies = [ "anyhow", "heck 0.4.1", @@ -8758,22 +8844,34 @@ dependencies = [ ] [[package]] -name = "zksync_prover_utils" +name = "zksync_protobuf_config" version = "0.1.0" dependencies = [ "anyhow", - "async-trait", - "ctrlc", - "futures 0.3.28", - "regex", - "reqwest", - "tokio", - "toml_edit 0.14.4", - "tracing", + "pretty_assertions", + "prost", + "rand 0.8.5", + "serde_json", + "zksync_basic_types", "zksync_config", + "zksync_protobuf", + "zksync_protobuf_build", + "zksync_types", +] + +[[package]] +name = "zksync_prover_interface" +version = "0.1.0" +dependencies = [ + "bincode", + "chrono", + "serde", + "serde_with", + "strum", + "tokio", + "zkevm_test_harness 1.3.3", "zksync_object_store", "zksync_types", - "zksync_utils", ] [[package]] @@ -8795,11 +8893,16 @@ dependencies = [ "anyhow", "clap 4.4.6", "futures 0.3.28", + "serde_json", "tikv-jemallocator", "tokio", "tracing", "vlog", + "zksync_concurrency", "zksync_config", + "zksync_consensus_crypto", + "zksync_consensus_executor", + "zksync_consensus_roles", "zksync_core", "zksync_env_config", "zksync_storage", @@ -8807,15 +8910,34 @@ dependencies = [ "zksync_utils", ] +[[package]] +name = "zksync_snapshots_applier" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "thiserror", + "tokio", + "tracing", + "vise", + "zksync_dal", + "zksync_object_store", + "zksync_types", + "zksync_utils", + "zksync_web3_decl", +] + [[package]] name = "zksync_state" version = "0.1.0" dependencies = [ "anyhow", - "itertools", + "assert_matches", + "itertools 0.10.5", "mini-moka", "rand 0.8.5", "tempfile", + "test-casing", "tokio", "tracing", "vise", @@ -8841,16 +8963,8 @@ dependencies = [ name = "zksync_system_constants" version = "0.1.0" dependencies = [ - "anyhow", - "bigdecimal", - "hex", - "num 0.3.1", "once_cell", - "serde", - "serde_json", - "url", "zksync_basic_types", - "zksync_contracts", "zksync_utils", ] @@ -8874,27 +8988,21 @@ dependencies = [ "anyhow", "blake2 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", "chrono", - "codegen 0.1.0", - "ethereum-types 0.12.1", "hex", - "num 0.3.1", + "num 0.4.1", "num_enum", "once_cell", - "parity-crypto", "prost", "rlp", - "secp256k1 0.27.0", + "secp256k1", "serde", "serde_json", "serde_with", "strum", "thiserror", "tokio", - "zk_evm 1.3.3 (git+https://github.com/matter-labs/era-zk_evm.git?tag=v1.3.3-rc2)", - "zk_evm 1.4.0", - "zkevm_test_harness 1.3.3", "zksync_basic_types", - "zksync_consensus_roles", + "zksync_config", "zksync_contracts", "zksync_mini_merkle_tree", "zksync_protobuf", @@ -8911,9 +9019,9 @@ dependencies = [ "bigdecimal", "futures 0.3.28", "hex", - "itertools", + "itertools 0.10.5", "metrics", - "num 0.3.1", + "num 0.4.1", "reqwest", "serde", "serde_json", @@ -8925,32 +9033,13 @@ dependencies = [ "zksync_basic_types", ] -[[package]] -name = "zksync_verification_key_generator_and_server" -version = "0.1.0" -dependencies = [ - "anyhow", - "bincode", - "circuit_testing", - "ff_ce", - "hex", - "itertools", - "once_cell", - "serde_json", - "structopt", - "tracing", - "vlog", - "zksync_prover_utils", - "zksync_types", -] - [[package]] name = "zksync_web3_decl" version = "0.1.0" dependencies = [ "bigdecimal", "chrono", - "itertools", + "itertools 0.10.5", "jsonrpsee", "rlp", "serde", diff --git a/Cargo.toml b/Cargo.toml index 34115e84bead..8213e01170d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,6 @@ members = [ "core/bin/snapshots_creator", "core/bin/storage_logs_dedup_migration", "core/bin/system-constants-generator", - "core/bin/verification_key_generator_and_server", "core/bin/verified_sources_fetcher", "core/bin/zksync_server", # Libraries @@ -24,24 +23,28 @@ members = [ "core/lib/env_config", "core/lib/eth_client", "core/lib/eth_signer", + "core/lib/l1_contract_interface", "core/lib/mempool", "core/lib/merkle_tree", "core/lib/mini_merkle_tree", + "core/lib/node", "core/lib/object_store", "core/lib/prometheus_exporter", + "core/lib/prover_interface", "core/lib/queued_job_processor", "core/lib/state", "core/lib/storage", "core/lib/types", - "core/lib/prover_utils", + "core/lib/protobuf_config", "core/lib/utils", "core/lib/vlog", "core/lib/multivm", + "core/lib/vm_utils", "core/lib/web3_decl", - "core/lib/test_account", + "core/lib/snapshots_applier", # Test infrastructure - "core/tests/cross_external_nodes_checker", + "core/tests/test_account", "core/tests/loadnext", "core/tests/vm-benchmark", "core/tests/vm-benchmark/harness", diff --git a/README.md b/README.md index b149b5bc5841..c8cd8882de45 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ The following questions will be answered by the following resources: | How can I run the project? | [launch.md](docs/guides/launch.md) | | What is the logical project structure and architecture? | [architecture.md](docs/guides/architecture.md) | | Where can I find protocol specs? | [specs](docs/specs/README.md) | -| Where can I find developer docs? | [docs](https://v2-docs.zksync.io/dev/) | +| Where can I find developer docs? | [docs](https://era.zksync.io/docs/) | ## Policies @@ -30,7 +30,7 @@ The following questions will be answered by the following resources: zkSync Era is distributed under the terms of either - Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) at your option. @@ -40,7 +40,7 @@ at your option. - [GitHub](https://github.com/matter-labs) - [ZK Credo](https://github.com/zksync/credo) - [Twitter](https://twitter.com/zksync) -- [Twitter for Devs](https://twitter.com/zkSyncDevs) +- [Twitter for Developers](https://twitter.com/zkSyncDevs) - [Discord](https://join.zksync.dev/) - [Mirror](https://zksync.mirror.xyz/) - [Youtube](https://www.youtube.com/@zkSync-era) diff --git a/bin/zk b/bin/zk index ca899fd5f465..f22ce90440fc 100755 --- a/bin/zk +++ b/bin/zk @@ -41,7 +41,7 @@ check_subdirectory check_yarn_version if [ -z "$1" ]; then cd $ZKSYNC_HOME - yarn && yarn zk build + yarn install --frozen-lockfile && yarn zk build else # can't start this with yarn since it has quirks with `--` as an argument node -- $ZKSYNC_HOME/infrastructure/zk/build/index.js "$@" diff --git a/checks-config/cspell.json b/checks-config/cspell.json new file mode 100644 index 000000000000..bafb5e036d04 --- /dev/null +++ b/checks-config/cspell.json @@ -0,0 +1,47 @@ +{ + "language": "en", + "ignorePaths": [ + "**/CHANGELOG.md", + "**/node_modules/**", + ".github/**", + ".firebase/**", + ".yarn/**", + "dist/**", + "**/contracts/**", + "**/target/**" + ], + "dictionaries": [ + "typescript", + "cpp", + "npm", + "filetypes", + "cpp", + "en_GB", + "en_US", + "node", + "bash", + "fonts", + "npm", + "cryptocurrencies", + "companies", + "rust", + "html", + "css", + "entities", + "softwareTerms", + "misc", + "fullstack", + "softwareTerms", + "zksync", + "nuxt", + "viem" + ], + "dictionaryDefinitions": [ + { + "name": "zksync", + "addWords": true, + "path": "./era.dic" + } + ], + "allowCompoundWords": true + } \ No newline at end of file diff --git a/spellcheck/era.cfg b/checks-config/era.cfg similarity index 96% rename from spellcheck/era.cfg rename to checks-config/era.cfg index c00c2d7a64ce..c8a6baba820a 100644 --- a/spellcheck/era.cfg +++ b/checks-config/era.cfg @@ -2,7 +2,7 @@ # ${CARGO_MANIFEST_DIR}/.config/spellcheck.toml # Also take into account developer comments -dev_comments = false +dev_comments = true # Skip the README.md file as defined in the cargo manifest skip_readme = false @@ -15,7 +15,7 @@ lang = "en_US" # Windows: [] # macOS [ /home/alice/Libraries/hunspell, /Libraries/hunspell ] -# Additional search paths, which take presedence over the default +# Additional search paths, which take precedence over the default # os specific search dirs, searched in order, defaults last search_dirs = ["."] diff --git a/spellcheck/era.dic b/checks-config/era.dic similarity index 70% rename from spellcheck/era.dic rename to checks-config/era.dic index a054a5930270..66480ebb51fb 100644 --- a/spellcheck/era.dic +++ b/checks-config/era.dic @@ -14,39 +14,69 @@ < > % +^ 0x00 0x01 0x02 +0x20 ~10x u32 u64 +u8 +1B H256 10e18 10^9 +2^32 +2^128 +2^24 +10^32 +10^* +2^16 +2^64 +10^8 U256 +12.5% +5% +10% +20% +*% +90% +f64 k M kb 50M +2M +130µs – 18kb 128kb 10k 100k 120k +800k 24k 500k +50k 120kb +18kb +12GB +20GB 500B 100M ~100us 10ms +1_000ms 1us ~100 +gwei ABI vlog +const L2 +L2s L1 json l1 @@ -57,6 +87,7 @@ ZKSYNC_HOME MultiVMTracer vm_virtual_blocks eth_node +EthCall BaseSystemContracts eth_calls refactor @@ -115,6 +146,7 @@ unfinalizable meterer Timedout bootloader +bootloader's testkit Sepolia Goerli @@ -146,11 +178,6 @@ param HistoryDisabled HistoryEnabled sorted_timestamps -DecommiterOracle -DecommittmentProcessor -encodings -DecommittmentProcessor -decommitment known_bytecodes returndata namespaces @@ -159,6 +186,19 @@ BYTES_PER_ENUMERATION_INDEX derived_key prefill reorg +precompile +Init +init +enqueued +stage2 +testnets +ethCalls +generable +Serde +tokenize +EOAs +zeroized +value // zkSync-related words matterlabs @@ -188,6 +228,7 @@ serializer serializable deserializer Deserializes +deserializes serializing deserializing deserialization @@ -225,7 +266,6 @@ metadata boojum deps Precalculated -decommitted WASM DefaultPrecompilesProcessor LSB @@ -266,6 +306,8 @@ tokenomics validator validator's validator +validators +Validators CHAINID PREVRANDAO ECDSA @@ -279,6 +321,96 @@ blake2 AR16MT Preimages EN's +SystemContext +StorageOracle +intrinsics +chunked +chunking +deadbeef01 +deadbeef0 +deadbeef +unsynced +computable +DevEx +Workspace +NFT +preimage +subcalls +hashmaps +monotonicity +subquery +RPCs +programmatically +stdin +stderr +Linter +SmallRng +ZkPorter +StateDiffs +HashMaps +encodings +CTPOP +decommitter +Decommitter +Decommitments +Decommitment +decommitment +decommitments +Decommit +decommit +decommits +DecommiterOracle +DecommitmentProcessor +decommitted +decommit +decommitting +Demuxer +demultiplex +recid +inversed +plux +Binop +Arithmetization +arithmetization +nocapture +Plonky +permissioned +mathbb +Invb +REDC +iszero +skept +ECADD +ECMUL +preds +inttoptr +syncvm +nasm +rodata +ISZERO +JUMPI +ethir +ptrtoint +lshr +getu +zext +noprofile +umin +cccond +ccret +prodm +prodl +prodeh +prodh +interm +signv +ashr +noalias +immediates +prode +StorageBatchInfo +CommitBatchInfo +IExecutor // Names Vyper @@ -303,6 +435,50 @@ pepe Arweave Streamr dutterbutter +NixOS +CLI +SQLx +Rustup +nextest +NTFS +toolchains +toolchain +IDE +M1 +M2 +MacOS +OpenSSL +Xcode +LLVM +nvm +LTS +logout +WSL +orchestrator +TypeScript +Cryptographical +cryptographical +microservices +Executables +subcomponents +v2 +v1 +rmSync +SSL +setup_2^26 +uncomment +toml +GCP +dev +workspace +subcommand +Kubernetes +Etherscan +cryptographic +hashers +MacBook +DDR5 +~ // Used libraries numberish @@ -340,6 +516,15 @@ porco rosso insize MLOAD +sload +sload +uadd +nocallback +nosync +swrite +Devs +insta +NFTF // ETC gitter @@ -407,6 +592,16 @@ RLP DAL zkSync's l2_to_l1 +PoW +coinbase +FIXME +ASC +DESC +Versioning +initializer +refactoring +prefetch +unformatted // crypto events Edcon @@ -423,12 +618,18 @@ Armeabi scijava gluk @Deniallugo's +emilluta // Programming related words +backfill bytecode bytecodes +impl +subrange timeframe +leaf_count mkdir +librocksdb zksolc zksyncrobot precompiles @@ -445,6 +646,8 @@ Zerion Maverik zk_evm_1_3_3 vk +vks +CORS verifier crypto callee @@ -492,6 +695,7 @@ l2_block submodule enums deserialized +deserialize hashmap vm_m5 SDK @@ -583,20 +787,38 @@ eth_getLogs façade virtual_blocks_per_miniblock virtual_block_interval +max_overhead +total_gas_limit cloneable timestamped healthcheck +Healthcheck +HealthCheck readonly upgrader startup +BFT +PingCAP +witgen +ok +hacky +ceil +Infura +synth +proto AUTOGENERATED x19Ethereum block_timestamp SYSTEM_BLOCK_INFO_BLOCK_NUMBER_MULTIPLIER +MAX_L2_TX_GAS_LIMIT +MAX_TX_ERGS_LIMIT OneTxTracer multicall +Multicall's Multicall3 +proxied +scalers updatable instantiation unexecuted @@ -607,4 +829,70 @@ dal codebase compactions M6 -compiler_common \ No newline at end of file +compiler_common +noop +tokenized +rustc +sqlx +zkevm +Boojum +Sepolia +psql +Cuda +cuda +hdcaa +impls +abda +edaf +unsynchronized +CUDA +gcloud +NVME +OTLP +multiVM +Deduplicator +lobkc +sread +myfunction +merklelization +beaf +subcalls +unallowed +Nuxt +Merklized +satisfiability +demultiplex +precompile +statekeeper +matchers +lifecycle +dedup +deduped +crаsh +protobuf +L1Tx +EIP +DecommittmentProcessor +decommitment +tokenized +Aggregator +DecommittmentProcessor +decommitment +hardcoded +plookup +shivini +EIP4844 +KZG +secp256k1 +vendoring +publickey +keypair +Electrum +healthcheck +healthchecks +after_node_shutdown +runnable +downcasting +parameterized +reimplementation +composability diff --git a/checks-config/links.json b/checks-config/links.json new file mode 100644 index 000000000000..ed336a665905 --- /dev/null +++ b/checks-config/links.json @@ -0,0 +1,29 @@ +{ + "ignorePatterns": [ + { + "pattern": "^https://github\\.com/matter-labs/zksync-2-dev/" + }, + { + "pattern": "^https://www\\.notion\\.so/" + }, + { + "pattern": "^https://github\\.com/matter-labs/zksync-era/compare/" + }, + { + "pattern": "^https://twitter\\.com/zksync" + }, + { + "pattern": "^https://twitter\\.com/zkSyncDevs" + }, + { + "pattern": "^https://github\\.com/matter-labs/zk_evm" + }, + { + "pattern": "^https://sepolia\\.etherscan\\.io/tx/0x18c2a113d18c53237a4056403047ff9fafbf772cb83ccd44bb5b607f8108a64c" + }, + { + "pattern": "^https://github\\.com/matter-labs/zksync-era/commit/" + } + ], + "aliveStatusCodes": [0, 200, 206, 304] +} \ No newline at end of file diff --git a/contracts b/contracts index 87cd8d7b0f8c..2dfbc6bac84e 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 87cd8d7b0f8c02e9672c0603a821641a566b5dd8 +Subproject commit 2dfbc6bac84ecada93cab4a0dea113bc2aceba1c diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 6773f58bbb1f..d994a4a80ff6 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -1,5 +1,181 @@ # Changelog +## [20.5.2](https://github.com/matter-labs/zksync-era/compare/core-v20.5.1...core-v20.5.2) (2024-02-04) + + +### Bug Fixes + +* **db:** miniblocks index ([#1004](https://github.com/matter-labs/zksync-era/issues/1004)) ([b3fd22e](https://github.com/matter-labs/zksync-era/commit/b3fd22e3a730499f37102a1bc00ad1004f192668)) + +## [20.5.1](https://github.com/matter-labs/zksync-era/compare/core-v20.5.0...core-v20.5.1) (2024-02-02) + + +### Bug Fixes + +* **db:** transaction index ([#998](https://github.com/matter-labs/zksync-era/issues/998)) ([2b03736](https://github.com/matter-labs/zksync-era/commit/2b037365543aa39a28601e63b30f9963e7d3e044)) + +## [20.5.0](https://github.com/matter-labs/zksync-era/compare/core-v20.4.0...core-v20.5.0) (2024-02-02) + + +### Features + +* **merkle-tree:** Do not wait for tree initialization when starting node ([#992](https://github.com/matter-labs/zksync-era/issues/992)) ([fdbfcb1](https://github.com/matter-labs/zksync-era/commit/fdbfcb1622ee1eccd380e1930ec5401c52b73567)) + + +### Bug Fixes + +* added consensus column back ([#986](https://github.com/matter-labs/zksync-era/issues/986)) ([b9b48d4](https://github.com/matter-labs/zksync-era/commit/b9b48d45fa5d854b21c3a3b9ff57665a788a53c5)) +* get_block_receipts test ([#989](https://github.com/matter-labs/zksync-era/issues/989)) ([c301359](https://github.com/matter-labs/zksync-era/commit/c30135902afa3c39d1ac0ce2ff3b70f5c1746373)) +* **vm:** Save empty bootloader memory for batches with ancient vms ([#991](https://github.com/matter-labs/zksync-era/issues/991)) ([af7f64f](https://github.com/matter-labs/zksync-era/commit/af7f64f37faa5300ae258874d74cdcfe009dfaae)) + +## [20.4.0](https://github.com/matter-labs/zksync-era/compare/core-v20.3.0...core-v20.4.0) (2024-01-31) + + +### Features + +* **en:** Revert "feat(en): Fix operator address assignment for ENs" ([#977](https://github.com/matter-labs/zksync-era/issues/977)) ([e051f7a](https://github.com/matter-labs/zksync-era/commit/e051f7a80bd1c1c5b76a6e74288fab9f820738b2)) + +## [20.3.0](https://github.com/matter-labs/zksync-era/compare/core-v20.2.0...core-v20.3.0) (2024-01-31) + + +### Features + +* add eth_getBlockReceipts ([#887](https://github.com/matter-labs/zksync-era/issues/887)) ([5dcbcfd](https://github.com/matter-labs/zksync-era/commit/5dcbcfdeb683b02d17b77031b0a2200fa69ac778)) +* **eth-sender:** metrics for finalized and safe L1 block numbers ([#972](https://github.com/matter-labs/zksync-era/issues/972)) ([32c1637](https://github.com/matter-labs/zksync-era/commit/32c163754d5e21b9996267728fe3f527ed8ec4da)) +* Optimized block tip seal criterion ([#968](https://github.com/matter-labs/zksync-era/issues/968)) ([8049eb3](https://github.com/matter-labs/zksync-era/commit/8049eb340eadcb2e9844465d8ea15ae8c08e0ef5)) +* Prover interface and L1 interface crates ([#959](https://github.com/matter-labs/zksync-era/issues/959)) ([4f7e107](https://github.com/matter-labs/zksync-era/commit/4f7e10783afdff67a24246f17f03b536f743352d)) + +## [20.2.0](https://github.com/matter-labs/zksync-era/compare/core-v20.1.0...core-v20.2.0) (2024-01-30) + + +### Features + +* added unauthenticated version of gcs object store ([#916](https://github.com/matter-labs/zksync-era/issues/916)) ([638a813](https://github.com/matter-labs/zksync-era/commit/638a813e1115c36d3d7fbed28f24658769b2b93e)) +* Adding EN snapshots applier ([#882](https://github.com/matter-labs/zksync-era/issues/882)) ([0d2ba09](https://github.com/matter-labs/zksync-era/commit/0d2ba09c5d4b607bd9da31fc4bf0ea8ca2b4d7b8)) +* consensus component config for main node and external node ([#881](https://github.com/matter-labs/zksync-era/issues/881)) ([1aed8de](https://github.com/matter-labs/zksync-era/commit/1aed8de0f1651686bf9e9f8aa7dc9ba15625cc42)) +* **en:** Make ENs detect reorgs earlier ([#964](https://github.com/matter-labs/zksync-era/issues/964)) ([b043cc8](https://github.com/matter-labs/zksync-era/commit/b043cc84cd9f5e9c6e80b810a019c713fb3076d3)) +* **en:** Restore state keeper storage from snapshot ([#885](https://github.com/matter-labs/zksync-era/issues/885)) ([a9553b5](https://github.com/matter-labs/zksync-era/commit/a9553b537a857a6f6a755cd700da4c096c1f80f0)) +* protobuf-generated json configs for the main node (BFT-371) ([#458](https://github.com/matter-labs/zksync-era/issues/458)) ([f938314](https://github.com/matter-labs/zksync-era/commit/f9383143b4f1f0c18af658980bae8ec93b6b588f)) +* Remove zkevm_test_harness public reexport from zksync_types ([#929](https://github.com/matter-labs/zksync-era/issues/929)) ([dd1a35e](https://github.com/matter-labs/zksync-era/commit/dd1a35eec006b40db66da73e6fa3d8963efb7d60)) +* **state-keeper:** track the time that individual transactions spend in mempool ([#941](https://github.com/matter-labs/zksync-era/issues/941)) ([fa45aa9](https://github.com/matter-labs/zksync-era/commit/fa45aa9bd87f284872c9831620b36f2f2339f75b)) +* **vm:** detailed circuit statistic ([#845](https://github.com/matter-labs/zksync-era/issues/845)) ([a20af60](https://github.com/matter-labs/zksync-era/commit/a20af609d6eda25e5530c30b360847f6eadb68d9)) +* **vm:** Support tracers for old vm ([#926](https://github.com/matter-labs/zksync-era/issues/926)) ([9fc2d95](https://github.com/matter-labs/zksync-era/commit/9fc2d95ebaa3670d573a2ed022603132be234a0e)) + + +### Bug Fixes + +* **api:** Order transaction traces in `debug_traceBlock*` methods ([#924](https://github.com/matter-labs/zksync-era/issues/924)) ([5918ef9](https://github.com/matter-labs/zksync-era/commit/5918ef925dae97aee428961c2dc61dd91bf2f07e)) +* **db:** Make `get_expected_l1_batch_timestamp()` more efficient ([#963](https://github.com/matter-labs/zksync-era/issues/963)) ([7334679](https://github.com/matter-labs/zksync-era/commit/73346792952c5538aafc42a2ee778f0069a98607)) +* **db:** Make `snapshot_recovery` migration backward-compatible ([#961](https://github.com/matter-labs/zksync-era/issues/961)) ([e756762](https://github.com/matter-labs/zksync-era/commit/e756762b934f4f2262ee02404b9d18f2f4431842)) +* **zksync_types:** Update SerializationTransactionError::OversizedData description ([#949](https://github.com/matter-labs/zksync-era/issues/949)) ([c95f3ee](https://github.com/matter-labs/zksync-era/commit/c95f3eeb03804ba2739b487288b20f6bf6997e47)) + +## [20.1.0](https://github.com/matter-labs/zksync-era/compare/core-v20.0.0...core-v20.1.0) (2024-01-23) + + +### Features + +* **api:** Get historical fee input ([#919](https://github.com/matter-labs/zksync-era/issues/919)) ([8e1009f](https://github.com/matter-labs/zksync-era/commit/8e1009fc4626465524183ae10a8ff26739fbb647)) +* ZK Stack framework MVP ([#880](https://github.com/matter-labs/zksync-era/issues/880)) ([3e5c528](https://github.com/matter-labs/zksync-era/commit/3e5c528767e907e116e29310460019e2bf9161d1)) + + +### Bug Fixes + +* **test:** Provide higher min allowance in estimation ([#923](https://github.com/matter-labs/zksync-era/issues/923)) ([d379612](https://github.com/matter-labs/zksync-era/commit/d37961296c102555e7128424fb1e9b998579b1de)) + +## [20.0.0](https://github.com/matter-labs/zksync-era/compare/core-v19.2.0...core-v20.0.0) (2024-01-19) + + +### ⚠ BREAKING CHANGES + +* **vm:** fee model updates + 1.4.1 ([#791](https://github.com/matter-labs/zksync-era/issues/791)) + +### Features + +* **api:** Consider State keeper fee model input in the API ([#901](https://github.com/matter-labs/zksync-era/issues/901)) ([3211687](https://github.com/matter-labs/zksync-era/commit/32116878ba0ac68a7b90afa1a7e0fe170bdcd902)) +* **api:** Make Web3 API server work with pruned data ([#838](https://github.com/matter-labs/zksync-era/issues/838)) ([0b7cd0b](https://github.com/matter-labs/zksync-era/commit/0b7cd0b50ead2406915528becad2fac8b7e48f85)) +* **vm:** fee model updates + 1.4.1 ([#791](https://github.com/matter-labs/zksync-era/issues/791)) ([3564aff](https://github.com/matter-labs/zksync-era/commit/3564affbb246c87d668ea2ec74809384bc9d621f)) + + +### Bug Fixes + +* addresses broken links in preparation for ci link check ([#869](https://github.com/matter-labs/zksync-era/issues/869)) ([a78d03c](https://github.com/matter-labs/zksync-era/commit/a78d03cc53d0097f6be892de65a2c35bd7f1baa3)) +* Incorrect exposing of log indexes ([#896](https://github.com/matter-labs/zksync-era/issues/896)) ([12974fc](https://github.com/matter-labs/zksync-era/commit/12974fcba74c5704b89fa63d7f73222d4fa58228)) + +## [19.2.0](https://github.com/matter-labs/zksync-era/compare/core-v19.1.1...core-v19.2.0) (2024-01-17) + + +### Features + +* adds `zk linkcheck` to zk tool and updates zk env for `zk linkcheck` ci usage ([#868](https://github.com/matter-labs/zksync-era/issues/868)) ([d64f584](https://github.com/matter-labs/zksync-era/commit/d64f584f6d505b19cd6424928e9dc68e370e17fd)) +* **contract-verifier:** Support zkVM solc contract verification ([#854](https://github.com/matter-labs/zksync-era/issues/854)) ([1ed5a95](https://github.com/matter-labs/zksync-era/commit/1ed5a95462dbd73151acd8afbc4ab6158a2aecda)) +* **en:** Make batch status updater work with pruned data ([#863](https://github.com/matter-labs/zksync-era/issues/863)) ([3a07890](https://github.com/matter-labs/zksync-era/commit/3a07890dacebf6179636c44d7cce1afd21ab49eb)) +* rewritten gossip sync to be async from block processing ([#711](https://github.com/matter-labs/zksync-era/issues/711)) ([3af4644](https://github.com/matter-labs/zksync-era/commit/3af4644f428af0328cdea0fbae8a8f965489c6c4)) + +## [19.1.1](https://github.com/matter-labs/zksync-era/compare/core-v19.1.0...core-v19.1.1) (2024-01-12) + + +### Bug Fixes + +* **vm:** `inspect_transaction_with_bytecode_compression` for old VMs ([#862](https://github.com/matter-labs/zksync-era/issues/862)) ([077c0c6](https://github.com/matter-labs/zksync-era/commit/077c0c689317fa33c9bf3623942b565e8471f418)) + +## [19.1.0](https://github.com/matter-labs/zksync-era/compare/core-v19.0.0...core-v19.1.0) (2024-01-10) + + +### Features + +* address remaining spelling issues in dev comments and turns on dev_comments in cfg ([#827](https://github.com/matter-labs/zksync-era/issues/827)) ([1fd0afd](https://github.com/matter-labs/zksync-era/commit/1fd0afdcd9b6c344e1f5dac93fda5aa25c106b2f)) +* **core:** removes multiple tokio runtimes and worker number setting. ([#826](https://github.com/matter-labs/zksync-era/issues/826)) ([b8b190f](https://github.com/matter-labs/zksync-era/commit/b8b190f886f1d13602a0b2cc8a2b8525e68b1033)) +* fix spelling in dev comments in `core/lib/*` - continued ([#683](https://github.com/matter-labs/zksync-era/issues/683)) ([0421fe6](https://github.com/matter-labs/zksync-era/commit/0421fe6b3e9629fdad2fb88ad5710200825adc91)) +* fix spelling in dev comments in `core/lib/*` - continued ([#684](https://github.com/matter-labs/zksync-era/issues/684)) ([b46c2e9](https://github.com/matter-labs/zksync-era/commit/b46c2e9cbbcd048647f998810c8d550f8ad0c1f4)) +* fix spelling in dev comments in `core/lib/multivm` - continued ([#682](https://github.com/matter-labs/zksync-era/issues/682)) ([3839d39](https://github.com/matter-labs/zksync-era/commit/3839d39eb6b6d111ec556948c88d1eb9c6ab5e4a)) +* fix spelling in dev comments in `core/lib/zksync_core` - continued ([#685](https://github.com/matter-labs/zksync-era/issues/685)) ([70c3feb](https://github.com/matter-labs/zksync-era/commit/70c3febbf0445d2e0c22a942eaf643828aee045d)) +* **state-keeper:** circuits seal criterion ([#729](https://github.com/matter-labs/zksync-era/issues/729)) ([c4a86bb](https://github.com/matter-labs/zksync-era/commit/c4a86bbbc5697b5391a517299bbd7a5e882a7314)) +* **state-keeper:** Reject transactions that fail to publish bytecodes ([#832](https://github.com/matter-labs/zksync-era/issues/832)) ([0a010f0](https://github.com/matter-labs/zksync-era/commit/0a010f0a6f6682cedc49cb12ab9f9dfcdbccf68e)) +* **vm:** Add batch input abstraction ([#817](https://github.com/matter-labs/zksync-era/issues/817)) ([997db87](https://github.com/matter-labs/zksync-era/commit/997db872455351a484c3161d0a733a4bc59dd684)) + + +### Bug Fixes + +* oldest unpicked batch ([#692](https://github.com/matter-labs/zksync-era/issues/692)) ([a6c869d](https://github.com/matter-labs/zksync-era/commit/a6c869d88c64a986405bbdfb15cab88e910d1e03)) +* **state-keeper:** Updates manager keeps track of fictive block metrics ([#843](https://github.com/matter-labs/zksync-era/issues/843)) ([88fd724](https://github.com/matter-labs/zksync-era/commit/88fd7247c377efce703cd1caeffa4ecd61ed0d7f)) +* **vm:** fix circuit tracer ([#837](https://github.com/matter-labs/zksync-era/issues/837)) ([83fc7be](https://github.com/matter-labs/zksync-era/commit/83fc7be3cb9f4d3082b8b9fa8b8f568330bf744f)) + +## [19.0.0](https://github.com/matter-labs/zksync-era/compare/core-v18.13.0...core-v19.0.0) (2024-01-05) + + +### ⚠ BREAKING CHANGES + +* **vm:** Release v19 - remove allowlist ([#747](https://github.com/matter-labs/zksync-era/issues/747)) + +### Features + +* **en:** Make consistency checker work with pruned data ([#742](https://github.com/matter-labs/zksync-era/issues/742)) ([ae6e18e](https://github.com/matter-labs/zksync-era/commit/ae6e18e5412cadefbc03307a476d6b96c41f04e1)) +* **eth_sender:** Remove generic bounds on L1TxParamsProvider in EthSender ([#799](https://github.com/matter-labs/zksync-era/issues/799)) ([29a4f52](https://github.com/matter-labs/zksync-era/commit/29a4f5299c95e0b338010a6baf83f196ece3a530)) +* **merkle tree:** Finalize metadata calculator snapshot recovery logic ([#798](https://github.com/matter-labs/zksync-era/issues/798)) ([c83db35](https://github.com/matter-labs/zksync-era/commit/c83db35f0929a412bc4d89fbee1448d32c54a83f)) +* **prover:** Remove circuit-synthesizer ([#801](https://github.com/matter-labs/zksync-era/issues/801)) ([1426b1b](https://github.com/matter-labs/zksync-era/commit/1426b1ba3c8b700e0531087b781ced0756c12e3c)) +* **prover:** Remove old prover ([#810](https://github.com/matter-labs/zksync-era/issues/810)) ([8be1925](https://github.com/matter-labs/zksync-era/commit/8be1925b18dcbf268eb03b8ea5f07adfd5330876)) +* **snapshot creator:** Make snapshot creator fault-tolerant ([#691](https://github.com/matter-labs/zksync-era/issues/691)) ([286c7d1](https://github.com/matter-labs/zksync-era/commit/286c7d15a623604e01effa7119de3362f0fb4eb9)) +* **vm:** Add boojum integration folder ([#805](https://github.com/matter-labs/zksync-era/issues/805)) ([4071e90](https://github.com/matter-labs/zksync-era/commit/4071e90578e0fc8c027a4d2a30d09d96db942b4f)) +* **vm:** Make utils version-dependent ([#809](https://github.com/matter-labs/zksync-era/issues/809)) ([e5fbcb5](https://github.com/matter-labs/zksync-era/commit/e5fbcb5dfc2a7d2582f40a481c861fb2f4dd5fb0)) +* **vm:** Release v19 - remove allowlist ([#747](https://github.com/matter-labs/zksync-era/issues/747)) ([0e2bc56](https://github.com/matter-labs/zksync-era/commit/0e2bc561b9642b854718adcc86087a3e9762cf5d)) +* **vm:** Separate boojum integration vm ([#806](https://github.com/matter-labs/zksync-era/issues/806)) ([61712a6](https://github.com/matter-labs/zksync-era/commit/61712a636f69be70d75719c04f364d679ef624e0)) + + +### Bug Fixes + +* **db:** Fix parsing statement timeout from env ([#818](https://github.com/matter-labs/zksync-era/issues/818)) ([3f663ec](https://github.com/matter-labs/zksync-era/commit/3f663eca2f38f4373339ad024e6578099c693af6)) +* **prover:** Remove old prover subsystems tables ([#812](https://github.com/matter-labs/zksync-era/issues/812)) ([9d0aefc](https://github.com/matter-labs/zksync-era/commit/9d0aefc1ef4992e19d7b15ec1ce34697e61a3464)) +* **prover:** Remove prover-utils from core ([#819](https://github.com/matter-labs/zksync-era/issues/819)) ([2ceb911](https://github.com/matter-labs/zksync-era/commit/2ceb9114659f4c4583c87b1bbc8ee230eb1c44db)) + +## [18.13.0](https://github.com/matter-labs/zksync-era/compare/core-v18.12.0...core-v18.13.0) (2024-01-02) + + +### Features + +* **contract-verifier:** add zksolc v1.3.19 ([#797](https://github.com/matter-labs/zksync-era/issues/797)) ([2635570](https://github.com/matter-labs/zksync-era/commit/26355705c8c084344464458f3275c311c392c47f)) +* Remove generic bounds on L1GasPriceProvider ([#792](https://github.com/matter-labs/zksync-era/issues/792)) ([edf071d](https://github.com/matter-labs/zksync-era/commit/edf071d39d4dd8e297fd2fb2244574d5e0537b38)) +* Remove TPS limiter from TX Sender ([#793](https://github.com/matter-labs/zksync-era/issues/793)) ([d0e9296](https://github.com/matter-labs/zksync-era/commit/d0e929652eb431f6b1bc20f83d7c21d2a978293a)) + ## [18.12.0](https://github.com/matter-labs/zksync-era/compare/core-v18.11.0...core-v18.12.0) (2023-12-25) @@ -368,7 +544,7 @@ ### Features * Implement dynamic L2-to-L1 log tree depth ([#126](https://github.com/matter-labs/zksync-era/issues/126)) ([7dfbc5e](https://github.com/matter-labs/zksync-era/commit/7dfbc5eddab94cd24f96912e0d43ba36e1cf363f)) -* **vm:** Introduce new way of returning from the tracer [#2569](https://github.com/matter-labs/zksync-era/issues/2569) ([#116](https://github.com/matter-labs/zksync-era/issues/116)) ([cf44a49](https://github.com/matter-labs/zksync-era/commit/cf44a491a324199b4cf457d28658da44b6dafc61)) +* **vm:** Introduce new way of returning from the tracer [#2569](https://github.com/matter-labs/zksync-2-dev/issues/2569) ([#116](https://github.com/matter-labs/zksync-era/issues/116)) ([cf44a49](https://github.com/matter-labs/zksync-era/commit/cf44a491a324199b4cf457d28658da44b6dafc61)) * **vm:** Restore system-constants-generator ([#115](https://github.com/matter-labs/zksync-era/issues/115)) ([5e61bdc](https://github.com/matter-labs/zksync-era/commit/5e61bdc75b2baa03004d4d3e801170c094766964)) ## [15.0.1](https://github.com/matter-labs/zksync-2-dev/compare/core-v15.0.0...core-v15.0.1) (2023-09-27) diff --git a/core/bin/block_reverter/src/main.rs b/core/bin/block_reverter/src/main.rs index c1b02a1a1201..f7cbc20f554d 100644 --- a/core/bin/block_reverter/src/main.rs +++ b/core/bin/block_reverter/src/main.rs @@ -32,7 +32,7 @@ enum Command { #[arg(long)] l1_batch_number: u32, /// Priority fee used for rollback Ethereum transaction. - // We operate only by priority fee because we want to use base fee from ethereum + // We operate only by priority fee because we want to use base fee from Ethereum // and send transaction as soon as possible without any resend logic #[arg(long)] priority_fee_per_gas: Option, diff --git a/core/bin/contract-verifier/src/main.rs b/core/bin/contract-verifier/src/main.rs index 33090697c510..477b4dc0722d 100644 --- a/core/bin/contract-verifier/src/main.rs +++ b/core/bin/contract-verifier/src/main.rs @@ -178,7 +178,7 @@ async fn main() -> anyhow::Result<()> { let contract_verifier = ContractVerifier::new(verifier_config, pool); let tasks = vec![ - // todo PLA-335: Leftovers after the prover DB split. + // TODO PLA-335: Leftovers after the prover DB split. // The prover connection pool is not used by the contract verifier, but we need to pass it // since `JobProcessor` trait requires it. tokio::spawn(contract_verifier.run(stop_receiver.clone(), opt.jobs_number)), diff --git a/core/bin/contract-verifier/src/verifier.rs b/core/bin/contract-verifier/src/verifier.rs index 63c46ed90f73..4bb2e7745ee2 100644 --- a/core/bin/contract-verifier/src/verifier.rs +++ b/core/bin/contract-verifier/src/verifier.rs @@ -75,6 +75,12 @@ impl ContractVerifier { ); if artifacts.bytecode != deployed_bytecode { + tracing::info!( + "Bytecode mismatch req {}, deployed: 0x{}, compiled 0x{}", + request.id, + hex::encode(deployed_bytecode), + hex::encode(artifacts.bytecode) + ); return Err(ContractVerifierError::BytecodeMismatch); } diff --git a/core/bin/external_node/Cargo.toml b/core/bin/external_node/Cargo.toml index 272bcfc081cb..725ad5a56992 100644 --- a/core/bin/external_node/Cargo.toml +++ b/core/bin/external_node/Cargo.toml @@ -20,6 +20,9 @@ zksync_state = { path = "../../lib/state" } zksync_basic_types = { path = "../../lib/basic_types" } zksync_contracts = { path = "../../lib/contracts" } +zksync_concurrency = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } +zksync_consensus_roles = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } + prometheus_exporter = { path = "../../lib/prometheus_exporter" } zksync_health_check = { path = "../../lib/health_check" } zksync_web3_decl = { path = "../../lib/web3_decl" } diff --git a/core/bin/external_node/src/config/mod.rs b/core/bin/external_node/src/config/mod.rs index b84c6ce59bb6..80caab713a70 100644 --- a/core/bin/external_node/src/config/mod.rs +++ b/core/bin/external_node/src/config/mod.rs @@ -3,15 +3,19 @@ use std::{env, time::Duration}; use anyhow::Context; use serde::Deserialize; use url::Url; -use zksync_basic_types::{Address, L1ChainId, L2ChainId, MiniblockNumber}; -use zksync_core::api_server::{ - tx_sender::TxSenderConfig, - web3::{state::InternalApiConfig, Namespace}, +use zksync_basic_types::{Address, L1ChainId, L2ChainId}; +use zksync_consensus_roles::node; +use zksync_core::{ + api_server::{ + tx_sender::TxSenderConfig, + web3::{state::InternalApiConfig, Namespace}, + }, + consensus, }; use zksync_types::api::BridgeAddresses; use zksync_web3_decl::{ jsonrpsee::http_client::{HttpClient, HttpClientBuilder}, - namespaces::{EnNamespaceClient, EthNamespaceClient, ZksNamespaceClient}, + namespaces::{EthNamespaceClient, ZksNamespaceClient}, }; #[cfg(test)] @@ -30,8 +34,6 @@ pub struct RemoteENConfig { pub l2_testnet_paymaster_addr: Option
, pub l2_chain_id: L2ChainId, pub l1_chain_id: L1ChainId, - - pub fair_l2_gas_price: u64, } impl RemoteENConfig { @@ -63,15 +65,6 @@ impl RemoteENConfig { .context("Failed to fetch L1 chain ID")? .as_u64(), ); - let current_miniblock = client - .get_block_number() - .await - .context("Failed to fetch block number")?; - let block_header = client - .sync_l2_block(MiniblockNumber(current_miniblock.as_u32()), false) - .await - .context("Failed to fetch last miniblock header")? - .expect("Block is known to exist"); Ok(Self { diamond_proxy_addr, @@ -82,11 +75,16 @@ impl RemoteENConfig { l2_weth_bridge_addr: bridges.l2_weth_bridge, l2_chain_id, l1_chain_id, - fair_l2_gas_price: block_header.l2_fair_gas_price, }) } } +#[derive(Debug, Deserialize, Clone, PartialEq)] +pub enum BlockFetcher { + ServerAPI, + Consensus, +} + /// This part of the external node config is completely optional to provide. /// It can tweak limits of the API, delay intervals of certain components, etc. /// If any of the fields are not provided, the default values will be used. @@ -108,7 +106,7 @@ pub struct OptionalENConfig { /// Max number of cache misses during one VM execution. If the number of cache misses exceeds this value, the API server panics. /// This is a temporary solution to mitigate API request resulting in thousands of DB queries. pub vm_execution_cache_misses_limit: Option, - /// Inbound transaction limit used for throttling. + /// Note: Deprecated option, no longer in use. Left to display a warning in case someone used them. pub transactions_per_sec_limit: Option, /// Limit for fee history block range. #[serde(default = "OptionalENConfig::default_fee_history_limit")] @@ -154,6 +152,15 @@ pub struct OptionalENConfig { /// The max possible number of gas that `eth_estimateGas` is allowed to overestimate. #[serde(default = "OptionalENConfig::default_estimate_gas_acceptable_overestimation")] pub estimate_gas_acceptable_overestimation: u32, + /// Whether to use the compatibility mode for gas estimation for L1->L2 transactions. + /// During the migration to the 1.4.1 fee model, there will be a period, when the server + /// will already have the 1.4.1 fee model, while the L1 contracts will still expect the transactions + /// to use the previous fee model with much higher overhead. + /// + /// When set to `true`, the API will ensure to return gasLimit is high enough overhead for both the old + /// and the new fee model when estimating L1->L2 transactions. + #[serde(default = "OptionalENConfig::default_l1_to_l2_transactions_compatibility_mode")] + pub l1_to_l2_transactions_compatibility_mode: bool, /// The multiplier to use when suggesting gas price. Should be higher than one, /// otherwise if the L1 prices soar, the suggested gas price won't be sufficient to be included in block #[serde(default = "OptionalENConfig::default_gas_price_scale_factor")] @@ -226,6 +233,10 @@ impl OptionalENConfig { 1_000 } + const fn default_l1_to_l2_transactions_compatibility_mode() -> bool { + true + } + const fn default_gas_price_scale_factor() -> f64 { 1.2 } @@ -355,8 +366,6 @@ pub struct RequiredENConfig { pub ws_port: u16, /// Port on which the healthcheck REST server is listening. pub healthcheck_port: u16, - /// Number of threads per API server - pub threads_per_server: usize, /// Address of the Ethereum node API. /// Intentionally private: use getter method as it manages the missing port. eth_client_url: String, @@ -407,14 +416,27 @@ impl PostgresConfig { } } +pub(crate) fn read_consensus_config() -> anyhow::Result { + let path = std::env::var("EN_CONSENSUS_CONFIG_PATH") + .context("EN_CONSENSUS_CONFIG_PATH env variable is not set")?; + let cfg = std::fs::read_to_string(&path).context(path)?; + let cfg: consensus::config::Config = + consensus::config::decode_json(&cfg).context("failed decoding JSON")?; + let node_key: node::SecretKey = consensus::config::read_secret("EN_CONSENSUS_NODE_KEY")?; + Ok(consensus::FetcherConfig { + executor: cfg.executor_config(node_key), + }) +} + /// External Node Config contains all the configuration required for the EN operation. /// It is split into three parts: required, optional and remote for easier navigation. -#[derive(Debug, Deserialize, Clone, PartialEq)] +#[derive(Debug, Clone)] pub struct ExternalNodeConfig { pub required: RequiredENConfig, pub postgres: PostgresConfig, pub optional: OptionalENConfig, pub remote: RemoteENConfig, + pub consensus: Option, } impl ExternalNodeConfig { @@ -435,9 +457,8 @@ impl ExternalNodeConfig { let remote = RemoteENConfig::fetch(&client) .await .context("Unable to fetch required config values from the main node")?; - // We can query them from main node, but it's better to set them explicitly - // as well to avoid connecting to wrong envs unintentionally. + // as well to avoid connecting to wrong environment variables unintentionally. let eth_chain_id = HttpClientBuilder::default() .build(required.eth_client_url()?) .expect("Unable to build HTTP client for L1 client") @@ -480,6 +501,7 @@ impl ExternalNodeConfig { postgres, required, optional, + consensus: None, }) } } @@ -529,13 +551,15 @@ impl From for TxSenderConfig { .unwrap(), gas_price_scale_factor: config.optional.gas_price_scale_factor, max_nonce_ahead: config.optional.max_nonce_ahead, - fair_l2_gas_price: config.remote.fair_l2_gas_price, vm_execution_cache_misses_limit: config.optional.vm_execution_cache_misses_limit, // We set these values to the maximum since we don't know the actual values // and they will be enforced by the main node anyway. max_allowed_l2_tx_gas_limit: u32::MAX, validation_computational_gas_limit: u32::MAX, chain_id: config.remote.l2_chain_id, + l1_to_l2_transactions_compatibility_mode: config + .optional + .l1_to_l2_transactions_compatibility_mode, } } } diff --git a/core/bin/external_node/src/main.rs b/core/bin/external_node/src/main.rs index 535eb1c88f7d..8765d656ca59 100644 --- a/core/bin/external_node/src/main.rs +++ b/core/bin/external_node/src/main.rs @@ -7,6 +7,8 @@ use metrics::EN_METRICS; use prometheus_exporter::PrometheusExporterConfig; use tokio::{sync::watch, task, time::sleep}; use zksync_basic_types::{Address, L2ChainId}; +use zksync_concurrency::{ctx, scope}; +use zksync_config::configs::database::MerkleTreeMode; use zksync_core::{ api_server::{ execution_sandbox::VmConcurrencyLimiter, @@ -15,16 +17,15 @@ use zksync_core::{ web3::{ApiBuilder, Namespace}, }, block_reverter::{BlockReverter, BlockReverterFlags, L1ExecutedBatchesRevert}, + consensus, consistency_checker::ConsistencyChecker, - l1_gas_price::MainNodeGasPriceFetcher, - metadata_calculator::{ - MetadataCalculator, MetadataCalculatorConfig, MetadataCalculatorModeConfig, - }, + l1_gas_price::MainNodeFeeParamsFetcher, + metadata_calculator::{MetadataCalculator, MetadataCalculatorConfig}, reorg_detector::ReorgDetector, setup_sigint_handler, state_keeper::{ - L1BatchExecutorBuilder, MainBatchExecutorBuilder, MiniblockSealer, MiniblockSealerHandle, - ZkSyncStateKeeper, + seal_criteria::NoopSealer, L1BatchExecutorBuilder, MainBatchExecutorBuilder, + MiniblockSealer, MiniblockSealerHandle, ZkSyncStateKeeper, }, sync_layer::{ batch_status_updater::BatchStatusUpdater, external_io::ExternalIO, fetcher::FetcherCursor, @@ -75,6 +76,7 @@ async fn build_state_keeper( save_call_traces, false, config.optional.enum_index_migration_chunk_size, + true, )); let main_node_url = config.required.main_node_url().unwrap(); @@ -92,7 +94,12 @@ async fn build_state_keeper( ) .await; - ZkSyncStateKeeper::without_sealer(stop_receiver, Box::new(io), batch_executor_base) + ZkSyncStateKeeper::new( + stop_receiver, + Box::new(io), + batch_executor_base, + Box::new(NoopSealer), + ) } async fn init_tasks( @@ -119,7 +126,7 @@ async fn init_tasks( let (stop_sender, stop_receiver) = watch::channel(false); let mut healthchecks: Vec> = Vec::new(); // Create components. - let gas_adjuster = Arc::new(MainNodeGasPriceFetcher::new(&main_node_url)); + let fee_params_fetcher = Arc::new(MainNodeFeeParamsFetcher::new(&main_node_url)); let sync_state = SyncState::new(); let (action_queue_sender, action_queue) = ActionQueue::new(); @@ -164,36 +171,71 @@ async fn init_tasks( let main_node_client = ::json_rpc(&main_node_url) .context("Failed creating JSON-RPC client for main node")?; let singleton_pool_builder = ConnectionPool::singleton(&config.postgres.database_url); - let fetcher_cursor = { - let pool = singleton_pool_builder - .build() - .await - .context("failed to build a connection pool for `MainNodeFetcher`")?; - let mut storage = pool.access_storage_tagged("sync_layer").await?; - FetcherCursor::new(&mut storage) - .await - .context("failed to load `MainNodeFetcher` cursor from Postgres")? + + let fetcher_handle = match config.consensus.clone() { + None => { + let fetcher_cursor = { + let pool = singleton_pool_builder + .build() + .await + .context("failed to build a connection pool for `MainNodeFetcher`")?; + let mut storage = pool.access_storage_tagged("sync_layer").await?; + FetcherCursor::new(&mut storage) + .await + .context("failed to load `MainNodeFetcher` cursor from Postgres")? + }; + let fetcher = fetcher_cursor.into_fetcher( + Box::new(main_node_client), + action_queue_sender, + sync_state.clone(), + stop_receiver.clone(), + ); + tokio::spawn(fetcher.run()) + } + Some(cfg) => { + let pool = connection_pool.clone(); + let mut stop_receiver = stop_receiver.clone(); + let sync_state = sync_state.clone(); + #[allow(clippy::redundant_locals)] + tokio::spawn(async move { + let sync_state = sync_state; + let main_node_client = main_node_client; + scope::run!(&ctx::root(), |ctx, s| async { + s.spawn_bg(async { + let res = cfg.run(ctx, pool, action_queue_sender).await; + tracing::info!("Consensus actor stopped"); + res + }); + // TODO: information about the head block of the validators + // (currently just the main node) + // should also be provided over the gossip network. + s.spawn_bg(async { + consensus::run_main_node_state_fetcher(ctx, &main_node_client, &sync_state) + .await?; + Ok(()) + }); + ctx.wait(stop_receiver.wait_for(|stop| *stop)).await??; + Ok(()) + }) + .await + .context("consensus actor") + }) + } }; - let fetcher = fetcher_cursor.into_fetcher( - Box::new(main_node_client), - action_queue_sender, - sync_state.clone(), - stop_receiver.clone(), - ); - let metadata_calculator = MetadataCalculator::new(&MetadataCalculatorConfig { - db_path: &config.required.merkle_tree_path, - mode: MetadataCalculatorModeConfig::Full { - store_factory: None, - }, + let metadata_calculator_config = MetadataCalculatorConfig { + db_path: config.required.merkle_tree_path.clone(), + mode: MerkleTreeMode::Full, delay_interval: config.optional.metadata_calculator_delay(), max_l1_batches_per_iter: config.optional.max_l1_batches_per_tree_iter, multi_get_chunk_size: config.optional.merkle_tree_multi_get_chunk_size, block_cache_capacity: config.optional.merkle_tree_block_cache_size(), memtable_capacity: config.optional.merkle_tree_memtable_capacity(), stalled_writes_timeout: config.optional.merkle_tree_stalled_writes_timeout(), - }) - .await; + }; + let metadata_calculator = MetadataCalculator::new(metadata_calculator_config, None) + .await + .context("failed initializing metadata calculator")?; healthchecks.push(Box::new(metadata_calculator.tree_health_check())); let consistency_checker = ConsistencyChecker::new( @@ -215,7 +257,7 @@ async fn init_tasks( .await .context("failed to build a connection pool for BatchStatusUpdater")?, ) - .await; + .context("failed initializing batch status updater")?; // Run the components. let tree_stop_receiver = stop_receiver.clone(); @@ -228,19 +270,20 @@ async fn init_tasks( let consistency_checker_handle = tokio::spawn(consistency_checker.run(stop_receiver.clone())); let updater_handle = task::spawn(batch_status_updater.run(stop_receiver.clone())); + let fee_address_migration_handle = + task::spawn(state_keeper.run_fee_address_migration(connection_pool.clone())); let sk_handle = task::spawn(state_keeper.run()); - let fetcher_handle = tokio::spawn(fetcher.run()); - let gas_adjuster_handle = tokio::spawn(gas_adjuster.clone().run(stop_receiver.clone())); + let fee_params_fetcher_handle = + tokio::spawn(fee_params_fetcher.clone().run(stop_receiver.clone())); let (tx_sender, vm_barrier, cache_update_handle) = { - let mut tx_sender_builder = + let tx_sender_builder = TxSenderBuilder::new(config.clone().into(), connection_pool.clone()) .with_main_connection_pool(connection_pool.clone()) .with_tx_proxy(&main_node_url); - // Add rate limiter if enabled. - if let Some(tps_limit) = config.optional.transactions_per_sec_limit { - tx_sender_builder = tx_sender_builder.with_rate_limiter(tps_limit); + if config.optional.transactions_per_sec_limit.is_some() { + tracing::warn!("`transactions_per_sec_limit` option is deprecated and ignored"); }; let max_concurrency = config.optional.vm_concurrency_limit; @@ -260,7 +303,7 @@ async fn init_tasks( let tx_sender = tx_sender_builder .build( - gas_adjuster, + fee_params_fetcher, Arc::new(vm_concurrency_limiter), ApiContracts::load_from_disk(), // TODO (BFT-138): Allow to dynamically reload API contracts storage_caches, @@ -275,7 +318,6 @@ async fn init_tasks( .with_filter_limit(config.optional.filters_limit) .with_batch_request_size_limit(config.optional.max_batch_request_size) .with_response_body_size_limit(config.optional.max_response_body_size()) - .with_threads(config.required.threads_per_server) .with_tx_sender(tx_sender.clone(), vm_barrier.clone()) .with_sync_state(sync_state.clone()) .enable_api_namespaces(config.optional.api_namespaces()) @@ -291,7 +333,6 @@ async fn init_tasks( .with_batch_request_size_limit(config.optional.max_batch_request_size) .with_response_body_size_limit(config.optional.max_response_body_size()) .with_polling_interval(config.optional.polling_interval()) - .with_threads(config.required.threads_per_server) .with_tx_sender(tx_sender, vm_barrier) .with_sync_state(sync_state) .enable_api_namespaces(config.optional.api_namespaces()) @@ -316,12 +357,13 @@ async fn init_tasks( task_handles.extend(cache_update_handle); task_handles.extend([ sk_handle, + fee_address_migration_handle, fetcher_handle, updater_handle, tree_handle, - gas_adjuster_handle, + consistency_checker_handle, + fee_params_fetcher_handle, ]); - task_handles.push(consistency_checker_handle); Ok((task_handles, stop_sender, healthcheck_handle, stop_receiver)) } @@ -344,6 +386,8 @@ async fn shutdown_components( struct Cli { #[arg(long)] revert_pending_l1_batch: bool, + #[arg(long)] + enable_consensus: bool, } #[tokio::main] @@ -374,9 +418,13 @@ async fn main() -> anyhow::Result<()> { tracing::info!("No sentry URL was provided"); } - let config = ExternalNodeConfig::collect() + let mut config = ExternalNodeConfig::collect() .await .context("Failed to load external node config")?; + if opt.enable_consensus { + config.consensus = + Some(config::read_consensus_config().context("read_consensus_config()")?); + } let main_node_url = config .required .main_node_url() @@ -389,7 +437,6 @@ async fn main() -> anyhow::Result<()> { .build() .await .context("failed to build a connection_pool")?; - if opt.revert_pending_l1_batch { tracing::info!("Rolling pending L1 batch back.."); let reverter = BlockReverter::new( @@ -400,12 +447,15 @@ async fn main() -> anyhow::Result<()> { L1ExecutedBatchesRevert::Allowed, ); - let mut connection = connection_pool.access_storage().await.unwrap(); + let mut connection = connection_pool.access_storage().await?; let sealed_l1_batch_number = connection .blocks_dal() .get_sealed_l1_batch_number() .await - .unwrap(); + .context("Failed getting sealed L1 batch number")? + .context( + "Cannot roll back pending L1 batch since there are no L1 batches in Postgres", + )?; drop(connection); tracing::info!("Rolling back to l1 batch number {sealed_l1_batch_number}"); @@ -419,9 +469,7 @@ async fn main() -> anyhow::Result<()> { } let sigint_receiver = setup_sigint_handler(); - tracing::warn!("The external node is in the alpha phase, and should be used with caution."); - tracing::info!("Started the external node"); tracing::info!("Main node URL is: {}", main_node_url); @@ -470,7 +518,7 @@ async fn main() -> anyhow::Result<()> { let reorg_detector_last_correct_batch = reorg_detector_result.and_then(|result| match result { Ok(Ok(last_correct_batch)) => last_correct_batch, Ok(Err(err)) => { - tracing::error!("Reorg detector failed: {err}"); + tracing::error!("Reorg detector failed: {err:#}"); None } Err(err) => { diff --git a/core/bin/merkle_tree_consistency_checker/src/main.rs b/core/bin/merkle_tree_consistency_checker/src/main.rs index 60a4feb750e9..6d64729f9b6f 100644 --- a/core/bin/merkle_tree_consistency_checker/src/main.rs +++ b/core/bin/merkle_tree_consistency_checker/src/main.rs @@ -27,7 +27,7 @@ impl Cli { let db_path = &config.merkle_tree.path; tracing::info!("Verifying consistency of Merkle tree at {db_path}"); let start = Instant::now(); - let db = RocksDB::new(Path::new(db_path)); + let db = RocksDB::new(Path::new(db_path)).unwrap(); let tree = ZkSyncTree::new_lightweight(db.into()); let l1_batch_number = if let Some(number) = self.l1_batch { diff --git a/core/bin/snapshots_creator/Cargo.toml b/core/bin/snapshots_creator/Cargo.toml index fe18233e7d93..f1882dd2bb7e 100644 --- a/core/bin/snapshots_creator/Cargo.toml +++ b/core/bin/snapshots_creator/Cargo.toml @@ -16,7 +16,6 @@ prometheus_exporter = { path = "../../lib/prometheus_exporter" } zksync_config = { path = "../../lib/config" } zksync_dal = { path = "../../lib/dal" } zksync_env_config = { path = "../../lib/env_config" } -zksync_utils = { path = "../../lib/utils" } zksync_types = { path = "../../lib/types" } zksync_object_store = { path = "../../lib/object_store" } vlog = { path = "../../lib/vlog" } diff --git a/core/bin/snapshots_creator/src/chunking.rs b/core/bin/snapshots_creator/src/chunking.rs deleted file mode 100644 index 11768febd44f..000000000000 --- a/core/bin/snapshots_creator/src/chunking.rs +++ /dev/null @@ -1,69 +0,0 @@ -use std::ops; - -use zksync_types::{H256, U256}; -use zksync_utils::u256_to_h256; - -pub(crate) fn get_chunk_hashed_keys_range( - chunk_id: u64, - chunks_count: u64, -) -> ops::RangeInclusive { - assert!(chunks_count > 0); - let mut stride = U256::MAX / chunks_count; - let stride_minus_one = if stride < U256::MAX { - stride += U256::one(); - stride - 1 - } else { - stride // `stride` is really 1 << 256 == U256::MAX + 1 - }; - - let start = stride * chunk_id; - let (mut end, is_overflow) = stride_minus_one.overflowing_add(start); - if is_overflow { - end = U256::MAX; - } - u256_to_h256(start)..=u256_to_h256(end) -} - -#[cfg(test)] -mod tests { - use zksync_utils::h256_to_u256; - - use super::*; - - #[test] - fn chunking_is_correct() { - for chunks_count in (2..10).chain([42, 256, 500, 1_001, 12_345]) { - println!("Testing chunks_count={chunks_count}"); - let chunked_ranges: Vec<_> = (0..chunks_count) - .map(|chunk_id| get_chunk_hashed_keys_range(chunk_id, chunks_count)) - .collect(); - - assert_eq!(*chunked_ranges[0].start(), H256::zero()); - assert_eq!( - *chunked_ranges.last().unwrap().end(), - H256::repeat_byte(0xff) - ); - for window in chunked_ranges.windows(2) { - let [prev_chunk, next_chunk] = window else { - unreachable!(); - }; - assert_eq!( - h256_to_u256(*prev_chunk.end()) + 1, - h256_to_u256(*next_chunk.start()) - ); - } - - let chunk_sizes: Vec<_> = chunked_ranges - .iter() - .map(|chunk| h256_to_u256(*chunk.end()) - h256_to_u256(*chunk.start()) + 1) - .collect(); - - // Check that chunk sizes are roughly equal. Due to how chunks are constructed, the sizes - // of all chunks except for the last one are the same, and the last chunk size may be slightly smaller; - // the difference in sizes is lesser than the number of chunks. - let min_chunk_size = chunk_sizes.iter().copied().min().unwrap(); - let max_chunk_size = chunk_sizes.iter().copied().max().unwrap(); - assert!(max_chunk_size - min_chunk_size < U256::from(chunks_count)); - } - } -} diff --git a/core/bin/snapshots_creator/src/creator.rs b/core/bin/snapshots_creator/src/creator.rs new file mode 100644 index 000000000000..2d2ce2335b90 --- /dev/null +++ b/core/bin/snapshots_creator/src/creator.rs @@ -0,0 +1,341 @@ +//! [`SnapshotCreator`] and tightly related types. + +use std::sync::Arc; + +use anyhow::Context as _; +use tokio::sync::Semaphore; +use zksync_config::SnapshotsCreatorConfig; +use zksync_dal::{ConnectionPool, StorageProcessor}; +use zksync_object_store::ObjectStore; +use zksync_types::{ + snapshots::{ + uniform_hashed_keys_chunk, SnapshotFactoryDependencies, SnapshotFactoryDependency, + SnapshotMetadata, SnapshotStorageLogsChunk, SnapshotStorageLogsStorageKey, + }, + L1BatchNumber, MiniblockNumber, +}; + +use crate::metrics::{FactoryDepsStage, StorageChunkStage, METRICS}; +#[cfg(test)] +use crate::tests::HandleEvent; + +/// Encapsulates progress of creating a particular storage snapshot. +#[derive(Debug)] +struct SnapshotProgress { + l1_batch_number: L1BatchNumber, + /// `true` if the snapshot is new (i.e., its progress is not recovered from Postgres). + is_new_snapshot: bool, + chunk_count: u64, + remaining_chunk_ids: Vec, +} + +impl SnapshotProgress { + fn new(l1_batch_number: L1BatchNumber, chunk_count: u64) -> Self { + Self { + l1_batch_number, + is_new_snapshot: true, + chunk_count, + remaining_chunk_ids: (0..chunk_count).collect(), + } + } + + fn from_existing_snapshot(snapshot: &SnapshotMetadata) -> Self { + let remaining_chunk_ids = snapshot + .storage_logs_filepaths + .iter() + .enumerate() + .filter_map(|(chunk_id, path)| path.is_none().then_some(chunk_id as u64)) + .collect(); + + Self { + l1_batch_number: snapshot.l1_batch_number, + is_new_snapshot: false, + chunk_count: snapshot.storage_logs_filepaths.len() as u64, + remaining_chunk_ids, + } + } +} + +/// Creator of a single storage snapshot. +#[derive(Debug)] +pub(crate) struct SnapshotCreator { + pub blob_store: Arc, + pub master_pool: ConnectionPool, + pub replica_pool: ConnectionPool, + #[cfg(test)] + pub event_listener: Box, +} + +impl SnapshotCreator { + async fn connect_to_replica(&self) -> anyhow::Result> { + self.replica_pool + .access_storage_tagged("snapshots_creator") + .await + } + + async fn process_storage_logs_single_chunk( + &self, + semaphore: &Semaphore, + miniblock_number: MiniblockNumber, + l1_batch_number: L1BatchNumber, + chunk_id: u64, + chunk_count: u64, + ) -> anyhow::Result<()> { + let _permit = semaphore.acquire().await?; + #[cfg(test)] + if self.event_listener.on_chunk_started().should_exit() { + return Ok(()); + } + + let hashed_keys_range = uniform_hashed_keys_chunk(chunk_id, chunk_count); + let mut conn = self.connect_to_replica().await?; + + let latency = + METRICS.storage_logs_processing_duration[&StorageChunkStage::LoadFromPostgres].start(); + let logs = conn + .snapshots_creator_dal() + .get_storage_logs_chunk(miniblock_number, hashed_keys_range) + .await + .context("Error fetching storage logs count")?; + drop(conn); + let latency = latency.observe(); + tracing::info!( + "Loaded chunk {chunk_id} ({} logs) from Postgres in {latency:?}", + logs.len() + ); + + let latency = + METRICS.storage_logs_processing_duration[&StorageChunkStage::SaveToGcs].start(); + let storage_logs_chunk = SnapshotStorageLogsChunk { storage_logs: logs }; + let key = SnapshotStorageLogsStorageKey { + l1_batch_number, + chunk_id, + }; + let filename = self + .blob_store + .put(key, &storage_logs_chunk) + .await + .context("Error storing storage logs chunk in blob store")?; + let output_filepath_prefix = self + .blob_store + .get_storage_prefix::(); + let output_filepath = format!("{output_filepath_prefix}/{filename}"); + let latency = latency.observe(); + + let mut master_conn = self + .master_pool + .access_storage_tagged("snapshots_creator") + .await?; + master_conn + .snapshots_dal() + .add_storage_logs_filepath_for_snapshot(l1_batch_number, chunk_id, &output_filepath) + .await?; + #[cfg(test)] + self.event_listener.on_chunk_saved(); + + let tasks_left = METRICS.storage_logs_chunks_left_to_process.dec_by(1) - 1; + tracing::info!( + "Saved chunk {chunk_id} (overall progress {}/{chunk_count}) in {latency:?} to location: {output_filepath}", + chunk_count - tasks_left as u64 + ); + Ok(()) + } + + async fn process_factory_deps( + &self, + miniblock_number: MiniblockNumber, + l1_batch_number: L1BatchNumber, + ) -> anyhow::Result { + let mut conn = self.connect_to_replica().await?; + + tracing::info!("Loading factory deps from Postgres..."); + let latency = + METRICS.factory_deps_processing_duration[&FactoryDepsStage::LoadFromPostgres].start(); + let factory_deps = conn + .snapshots_creator_dal() + .get_all_factory_deps(miniblock_number) + .await?; + drop(conn); + let latency = latency.observe(); + tracing::info!("Loaded {} factory deps in {latency:?}", factory_deps.len()); + + tracing::info!("Saving factory deps to GCS..."); + let latency = + METRICS.factory_deps_processing_duration[&FactoryDepsStage::SaveToGcs].start(); + let factory_deps = factory_deps + .into_iter() + .map(|(_, bytecode)| SnapshotFactoryDependency { + bytecode: bytecode.into(), + }) + .collect(); + let factory_deps = SnapshotFactoryDependencies { factory_deps }; + let filename = self + .blob_store + .put(l1_batch_number, &factory_deps) + .await + .context("Error storing factory deps in blob store")?; + let output_filepath_prefix = self + .blob_store + .get_storage_prefix::(); + let output_filepath = format!("{output_filepath_prefix}/{filename}"); + let latency = latency.observe(); + tracing::info!( + "Saved {} factory deps in {latency:?} to location: {output_filepath}", + factory_deps.factory_deps.len() + ); + + Ok(output_filepath) + } + + /// Returns `Ok(None)` if the created snapshot would coincide with `latest_snapshot`. + async fn initialize_snapshot_progress( + config: &SnapshotsCreatorConfig, + min_chunk_count: u64, + latest_snapshot: Option<&SnapshotMetadata>, + conn: &mut StorageProcessor<'_>, + ) -> anyhow::Result> { + // We subtract 1 so that after restore, EN node has at least one L1 batch to fetch + let sealed_l1_batch_number = conn.blocks_dal().get_sealed_l1_batch_number().await?; + let sealed_l1_batch_number = sealed_l1_batch_number.context("No L1 batches in Postgres")?; + anyhow::ensure!( + sealed_l1_batch_number != L1BatchNumber(0), + "Cannot create snapshot when only the genesis L1 batch is present in Postgres" + ); + let l1_batch_number = sealed_l1_batch_number - 1; + + let latest_snapshot_l1_batch_number = + latest_snapshot.map(|snapshot| snapshot.l1_batch_number); + if latest_snapshot_l1_batch_number == Some(l1_batch_number) { + tracing::info!( + "Snapshot at expected L1 batch #{l1_batch_number} is already created; exiting" + ); + return Ok(None); + } + + let distinct_storage_logs_keys_count = conn + .snapshots_creator_dal() + .get_distinct_storage_logs_keys_count(l1_batch_number) + .await?; + let chunk_size = config.storage_logs_chunk_size; + // We force the minimum number of chunks to avoid situations where only one chunk is created in tests. + let chunk_count = distinct_storage_logs_keys_count + .div_ceil(chunk_size) + .max(min_chunk_count); + + tracing::info!( + "Selected storage logs chunking for L1 batch {l1_batch_number}: \ + {chunk_count} chunks of expected size {chunk_size}" + ); + Ok(Some(SnapshotProgress::new(l1_batch_number, chunk_count))) + } + + /// Returns `Ok(None)` if a snapshot should not be created / resumed. + async fn load_or_initialize_snapshot_progress( + &self, + config: &SnapshotsCreatorConfig, + min_chunk_count: u64, + ) -> anyhow::Result> { + let mut master_conn = self + .master_pool + .access_storage_tagged("snapshots_creator") + .await?; + let latest_snapshot = master_conn + .snapshots_dal() + .get_newest_snapshot_metadata() + .await?; + drop(master_conn); + + let pending_snapshot = latest_snapshot + .as_ref() + .filter(|snapshot| !snapshot.is_complete()); + if let Some(snapshot) = pending_snapshot { + Ok(Some(SnapshotProgress::from_existing_snapshot(snapshot))) + } else { + Self::initialize_snapshot_progress( + config, + min_chunk_count, + latest_snapshot.as_ref(), + &mut self.connect_to_replica().await?, + ) + .await + } + } + + pub async fn run( + self, + config: SnapshotsCreatorConfig, + min_chunk_count: u64, + ) -> anyhow::Result<()> { + let latency = METRICS.snapshot_generation_duration.start(); + + let Some(progress) = self + .load_or_initialize_snapshot_progress(&config, min_chunk_count) + .await? + else { + // No snapshot creation is necessary; a snapshot for the current L1 batch is already created + return Ok(()); + }; + + let mut conn = self.connect_to_replica().await?; + let (_, last_miniblock_number_in_batch) = conn + .blocks_dal() + .get_miniblock_range_of_l1_batch(progress.l1_batch_number) + .await? + .context("Error fetching last miniblock number")?; + drop(conn); + + METRICS.storage_logs_chunks_count.set(progress.chunk_count); + tracing::info!( + "Creating snapshot for storage logs up to miniblock {last_miniblock_number_in_batch}, \ + L1 batch {}", + progress.l1_batch_number + ); + + if progress.is_new_snapshot { + let factory_deps_output_file = self + .process_factory_deps(last_miniblock_number_in_batch, progress.l1_batch_number) + .await?; + + let mut master_conn = self + .master_pool + .access_storage_tagged("snapshots_creator") + .await?; + master_conn + .snapshots_dal() + .add_snapshot( + progress.l1_batch_number, + progress.chunk_count, + &factory_deps_output_file, + ) + .await?; + } + + METRICS + .storage_logs_chunks_left_to_process + .set(progress.remaining_chunk_ids.len()); + let semaphore = Semaphore::new(config.concurrent_queries_count as usize); + let tasks = progress.remaining_chunk_ids.into_iter().map(|chunk_id| { + self.process_storage_logs_single_chunk( + &semaphore, + last_miniblock_number_in_batch, + progress.l1_batch_number, + chunk_id, + progress.chunk_count, + ) + }); + futures::future::try_join_all(tasks).await?; + + METRICS + .snapshot_l1_batch + .set(progress.l1_batch_number.0.into()); + + let elapsed = latency.observe(); + tracing::info!("snapshot_generation_duration: {elapsed:?}"); + tracing::info!("snapshot_l1_batch: {}", METRICS.snapshot_l1_batch.get()); + tracing::info!( + "storage_logs_chunks_count: {}", + METRICS.storage_logs_chunks_count.get() + ); + Ok(()) + } +} diff --git a/core/bin/snapshots_creator/src/main.rs b/core/bin/snapshots_creator/src/main.rs index b3c0f0b54ee4..c9a52fe0d746 100644 --- a/core/bin/snapshots_creator/src/main.rs +++ b/core/bin/snapshots_creator/src/main.rs @@ -1,29 +1,25 @@ //! Snapshot creator utility. Intended to run on a schedule, with each run creating a new snapshot. +//! +//! # Assumptions +//! +//! The snapshot creator is fault-tolerant; if it stops in the middle of creating a snapshot, +//! this snapshot will be continued from roughly the same point after the restart. If this is +//! undesired, remove the `snapshots` table record corresponding to the pending snapshot. +//! +//! It is assumed that the snapshot creator is run as a singleton process (no more than 1 instance +//! at a time). use anyhow::Context as _; use prometheus_exporter::PrometheusExporterConfig; -use tokio::{ - sync::{watch, Semaphore}, - task::JoinHandle, -}; +use tokio::{sync::watch, task::JoinHandle}; use zksync_config::{configs::PrometheusConfig, PostgresConfig, SnapshotsCreatorConfig}; use zksync_dal::ConnectionPool; use zksync_env_config::{object_store::SnapshotsObjectStoreConfig, FromEnv}; -use zksync_object_store::{ObjectStore, ObjectStoreFactory}; -use zksync_types::{ - snapshots::{ - SnapshotFactoryDependencies, SnapshotStorageLogsChunk, SnapshotStorageLogsStorageKey, - }, - L1BatchNumber, MiniblockNumber, -}; -use zksync_utils::ceil_div; +use zksync_object_store::ObjectStoreFactory; -use crate::{ - chunking::get_chunk_hashed_keys_range, - metrics::{FactoryDepsStage, StorageChunkStage, METRICS}, -}; +use crate::creator::SnapshotCreator; -mod chunking; +mod creator; mod metrics; #[cfg(test)] mod tests; @@ -47,205 +43,6 @@ async fn maybe_enable_prometheus_metrics( } } -async fn process_storage_logs_single_chunk( - blob_store: &dyn ObjectStore, - pool: &ConnectionPool, - semaphore: &Semaphore, - miniblock_number: MiniblockNumber, - l1_batch_number: L1BatchNumber, - chunk_id: u64, - chunks_count: u64, -) -> anyhow::Result { - let _permit = semaphore.acquire().await?; - let hashed_keys_range = get_chunk_hashed_keys_range(chunk_id, chunks_count); - let mut conn = pool.access_storage_tagged("snapshots_creator").await?; - - let latency = - METRICS.storage_logs_processing_duration[&StorageChunkStage::LoadFromPostgres].start(); - let logs = conn - .snapshots_creator_dal() - .get_storage_logs_chunk(miniblock_number, hashed_keys_range) - .await - .context("Error fetching storage logs count")?; - drop(conn); - let latency = latency.observe(); - tracing::info!( - "Loaded chunk {chunk_id} ({} logs) from Postgres in {latency:?}", - logs.len() - ); - - let latency = METRICS.storage_logs_processing_duration[&StorageChunkStage::SaveToGcs].start(); - let storage_logs_chunk = SnapshotStorageLogsChunk { storage_logs: logs }; - let key = SnapshotStorageLogsStorageKey { - l1_batch_number, - chunk_id, - }; - let filename = blob_store - .put(key, &storage_logs_chunk) - .await - .context("Error storing storage logs chunk in blob store")?; - let output_filepath_prefix = blob_store.get_storage_prefix::(); - let output_filepath = format!("{output_filepath_prefix}/{filename}"); - let latency = latency.observe(); - - let tasks_left = METRICS.storage_logs_chunks_left_to_process.dec_by(1) - 1; - tracing::info!( - "Saved chunk {chunk_id} (overall progress {}/{chunks_count}) in {latency:?} to location: {output_filepath}", - chunks_count - tasks_left - ); - Ok(output_filepath) -} - -async fn process_factory_deps( - blob_store: &dyn ObjectStore, - pool: &ConnectionPool, - miniblock_number: MiniblockNumber, - l1_batch_number: L1BatchNumber, -) -> anyhow::Result { - let mut conn = pool.access_storage_tagged("snapshots_creator").await?; - - tracing::info!("Loading factory deps from Postgres..."); - let latency = - METRICS.factory_deps_processing_duration[&FactoryDepsStage::LoadFromPostgres].start(); - let factory_deps = conn - .snapshots_creator_dal() - .get_all_factory_deps(miniblock_number) - .await?; - drop(conn); - let latency = latency.observe(); - tracing::info!("Loaded {} factory deps in {latency:?}", factory_deps.len()); - - tracing::info!("Saving factory deps to GCS..."); - let latency = METRICS.factory_deps_processing_duration[&FactoryDepsStage::SaveToGcs].start(); - let factory_deps = SnapshotFactoryDependencies { factory_deps }; - let filename = blob_store - .put(l1_batch_number, &factory_deps) - .await - .context("Error storing factory deps in blob store")?; - let output_filepath_prefix = blob_store.get_storage_prefix::(); - let output_filepath = format!("{output_filepath_prefix}/{filename}"); - let latency = latency.observe(); - tracing::info!( - "Saved {} factory deps in {latency:?} to location: {output_filepath}", - factory_deps.factory_deps.len() - ); - - Ok(output_filepath) -} - -async fn run( - blob_store: Box, - replica_pool: ConnectionPool, - master_pool: ConnectionPool, - min_chunk_count: u64, -) -> anyhow::Result<()> { - let latency = METRICS.snapshot_generation_duration.start(); - let config = SnapshotsCreatorConfig::from_env().context("SnapshotsCreatorConfig::from_env")?; - - let mut conn = replica_pool - .access_storage_tagged("snapshots_creator") - .await?; - - // We subtract 1 so that after restore, EN node has at least one L1 batch to fetch - let sealed_l1_batch_number = conn.blocks_dal().get_sealed_l1_batch_number().await?; - assert_ne!( - sealed_l1_batch_number, - L1BatchNumber(0), - "Cannot create snapshot when only the genesis L1 batch is present in Postgres" - ); - let l1_batch_number = sealed_l1_batch_number - 1; - - let mut master_conn = master_pool - .access_storage_tagged("snapshots_creator") - .await?; - if master_conn - .snapshots_dal() - .get_snapshot_metadata(l1_batch_number) - .await? - .is_some() - { - tracing::info!("Snapshot for L1 batch number {l1_batch_number} already exists, exiting"); - return Ok(()); - } - drop(master_conn); - - let (_, last_miniblock_number_in_batch) = conn - .blocks_dal() - .get_miniblock_range_of_l1_batch(l1_batch_number) - .await? - .context("Error fetching last miniblock number")?; - let distinct_storage_logs_keys_count = conn - .snapshots_creator_dal() - .get_distinct_storage_logs_keys_count(l1_batch_number) - .await?; - drop(conn); - - let chunk_size = config.storage_logs_chunk_size; - // We force the minimum number of chunks to avoid situations where only one chunk is created in tests. - let chunks_count = ceil_div(distinct_storage_logs_keys_count, chunk_size).max(min_chunk_count); - - METRICS.storage_logs_chunks_count.set(chunks_count); - - tracing::info!( - "Creating snapshot for storage logs up to miniblock {last_miniblock_number_in_batch}, \ - L1 batch {l1_batch_number}" - ); - tracing::info!("Starting to generate {chunks_count} chunks of expected size {chunk_size}"); - - let factory_deps_output_file = process_factory_deps( - &*blob_store, - &replica_pool, - last_miniblock_number_in_batch, - l1_batch_number, - ) - .await?; - - METRICS - .storage_logs_chunks_left_to_process - .set(chunks_count); - - let semaphore = Semaphore::new(config.concurrent_queries_count as usize); - let tasks = (0..chunks_count).map(|chunk_id| { - process_storage_logs_single_chunk( - &*blob_store, - &replica_pool, - &semaphore, - last_miniblock_number_in_batch, - l1_batch_number, - chunk_id, - chunks_count, - ) - }); - let mut storage_logs_output_files = futures::future::try_join_all(tasks).await?; - // Sanity check: the number of files should equal the number of chunks. - assert_eq!(storage_logs_output_files.len(), chunks_count as usize); - storage_logs_output_files.sort(); - - tracing::info!("Finished generating snapshot, storing progress in Postgres"); - let mut master_conn = master_pool - .access_storage_tagged("snapshots_creator") - .await?; - master_conn - .snapshots_dal() - .add_snapshot( - l1_batch_number, - &storage_logs_output_files, - &factory_deps_output_file, - ) - .await?; - - METRICS.snapshot_l1_batch.set(l1_batch_number.0 as u64); - - let elapsed = latency.observe(); - tracing::info!("snapshot_generation_duration: {elapsed:?}"); - tracing::info!("snapshot_l1_batch: {}", METRICS.snapshot_l1_batch.get()); - tracing::info!( - "storage_logs_chunks_count: {}", - METRICS.storage_logs_chunks_count.get() - ); - Ok(()) -} - /// Minimum number of storage log chunks to produce. const MIN_CHUNK_COUNT: u64 = 10; @@ -292,7 +89,15 @@ async fn main() -> anyhow::Result<()> { .build() .await?; - run(blob_store, replica_pool, master_pool, MIN_CHUNK_COUNT).await?; + let creator = SnapshotCreator { + blob_store, + master_pool, + replica_pool, + #[cfg(test)] + event_listener: Box::new(()), + }; + creator.run(creator_config, MIN_CHUNK_COUNT).await?; + tracing::info!("Finished running snapshot creator!"); stop_sender.send(true).ok(); if let Some(prometheus_exporter_task) = prometheus_exporter_task { diff --git a/core/bin/snapshots_creator/src/metrics.rs b/core/bin/snapshots_creator/src/metrics.rs index 194ed8f1e680..5eb1984712e5 100644 --- a/core/bin/snapshots_creator/src/metrics.rs +++ b/core/bin/snapshots_creator/src/metrics.rs @@ -24,7 +24,7 @@ pub(crate) struct SnapshotsCreatorMetrics { /// Number of chunks in the most recently generated snapshot. Set when a snapshot generation starts. pub storage_logs_chunks_count: Gauge, /// Number of chunks left to process for the snapshot being currently generated. - pub storage_logs_chunks_left_to_process: Gauge, + pub storage_logs_chunks_left_to_process: Gauge, /// Total latency of snapshot generation. #[metrics(buckets = Buckets::LATENCIES, unit = Unit::Seconds)] pub snapshot_generation_duration: Histogram, diff --git a/core/bin/snapshots_creator/src/tests.rs b/core/bin/snapshots_creator/src/tests.rs index 33d7a225b7d6..240857843f59 100644 --- a/core/bin/snapshots_creator/src/tests.rs +++ b/core/bin/snapshots_creator/src/tests.rs @@ -1,17 +1,110 @@ //! Lower-level tests for the snapshot creator component. -use std::collections::{HashMap, HashSet}; +use std::{ + collections::{HashMap, HashSet}, + fmt, + sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, + }, +}; use rand::{thread_rng, Rng}; use zksync_dal::StorageProcessor; +use zksync_object_store::ObjectStore; use zksync_types::{ - block::{BlockGasCount, L1BatchHeader, MiniblockHeader}, - snapshots::{SnapshotFactoryDependency, SnapshotStorageLog}, - AccountTreeId, Address, ProtocolVersion, StorageKey, StorageLog, H256, + block::{L1BatchHeader, MiniblockHeader}, + snapshots::{ + SnapshotFactoryDependencies, SnapshotFactoryDependency, SnapshotStorageLog, + SnapshotStorageLogsChunk, SnapshotStorageLogsStorageKey, + }, + AccountTreeId, Address, L1BatchNumber, MiniblockNumber, ProtocolVersion, StorageKey, + StorageLog, H256, }; use super::*; +const TEST_CONFIG: SnapshotsCreatorConfig = SnapshotsCreatorConfig { + storage_logs_chunk_size: 1_000_000, + concurrent_queries_count: 10, +}; +const SEQUENTIAL_TEST_CONFIG: SnapshotsCreatorConfig = SnapshotsCreatorConfig { + storage_logs_chunk_size: 1_000_000, + concurrent_queries_count: 1, +}; + +#[derive(Debug)] +struct TestEventListener { + stop_after_chunk_count: usize, + processed_chunk_count: AtomicUsize, +} + +impl TestEventListener { + fn new(stop_after_chunk_count: usize) -> Self { + Self { + stop_after_chunk_count, + processed_chunk_count: AtomicUsize::new(0), + } + } +} + +impl HandleEvent for TestEventListener { + fn on_chunk_started(&self) -> TestBehavior { + let should_stop = + self.processed_chunk_count.load(Ordering::SeqCst) >= self.stop_after_chunk_count; + TestBehavior::new(should_stop) + } + + fn on_chunk_saved(&self) { + self.processed_chunk_count.fetch_add(1, Ordering::SeqCst); + } +} + +impl SnapshotCreator { + fn for_tests(blob_store: Arc, pool: ConnectionPool) -> Self { + Self { + blob_store, + master_pool: pool.clone(), + replica_pool: pool, + event_listener: Box::new(()), + } + } + + fn stop_after_chunk_count(self, stop_after_chunk_count: usize) -> Self { + Self { + event_listener: Box::new(TestEventListener::new(stop_after_chunk_count)), + ..self + } + } +} + +#[derive(Debug)] +pub(crate) struct TestBehavior { + should_exit: bool, +} + +impl TestBehavior { + fn new(should_exit: bool) -> Self { + Self { should_exit } + } + + pub fn should_exit(&self) -> bool { + self.should_exit + } +} + +pub(crate) trait HandleEvent: fmt::Debug { + fn on_chunk_started(&self) -> TestBehavior { + TestBehavior::new(false) + } + + fn on_chunk_saved(&self) { + // Do nothing + } +} + +impl HandleEvent for () {} + fn gen_storage_logs(rng: &mut impl Rng, count: usize) -> Vec { (0..count) .map(|_| { @@ -49,9 +142,10 @@ async fn create_miniblock( hash: H256::from_low_u64_be(u64::from(miniblock_number.0)), l1_tx_count: 0, l2_tx_count: 0, + fee_account_address: Address::repeat_byte(1), base_fee_per_gas: 0, - l1_gas_price: 0, - l2_fair_gas_price: 0, + gas_per_pubdata_limit: 0, + batch_fee_input: Default::default(), base_system_contracts_hashes: Default::default(), protocol_version: Some(Default::default()), virtual_blocks: 0, @@ -71,16 +165,9 @@ async fn create_l1_batch( l1_batch_number: L1BatchNumber, logs_for_initial_writes: &[StorageLog], ) { - let mut header = L1BatchHeader::new( - l1_batch_number, - 0, - Address::default(), - Default::default(), - Default::default(), - ); - header.is_finished = true; + let header = L1BatchHeader::new(l1_batch_number, 0, Default::default(), Default::default()); conn.blocks_dal() - .insert_l1_batch(&header, &[], BlockGasCount::default(), &[], &[]) + .insert_mock_l1_batch(&header) .await .unwrap(); conn.blocks_dal() @@ -112,7 +199,8 @@ async fn prepare_postgres( let factory_deps = gen_factory_deps(rng, 10); conn.storage_dal() .insert_factory_deps(MiniblockNumber(block_number), &factory_deps) - .await; + .await + .unwrap(); // Since we generate `logs` randomly, all of them are written the first time. create_l1_batch(conn, L1BatchNumber(block_number), &logs).await; @@ -130,7 +218,8 @@ async fn prepare_postgres( let expected_l1_batches_and_indices = conn .storage_logs_dal() .get_l1_batches_and_indices_for_initial_writes(&hashed_keys) - .await; + .await + .unwrap(); let logs = logs.into_iter().map(|log| { let (l1_batch_number_of_initial_write, enumeration_index) = @@ -159,12 +248,17 @@ async fn persisting_snapshot_metadata() { let mut conn = pool.access_storage().await.unwrap(); prepare_postgres(&mut rng, &mut conn, 10).await; - run(object_store, pool.clone(), pool.clone(), MIN_CHUNK_COUNT) + SnapshotCreator::for_tests(object_store, pool.clone()) + .run(TEST_CONFIG, MIN_CHUNK_COUNT) .await .unwrap(); // Check snapshot metadata in Postgres. - let snapshots = conn.snapshots_dal().get_all_snapshots().await.unwrap(); + let snapshots = conn + .snapshots_dal() + .get_all_complete_snapshots() + .await + .unwrap(); assert_eq!(snapshots.snapshots_l1_batch_numbers.len(), 1); let snapshot_l1_batch_number = snapshots.snapshots_l1_batch_numbers[0]; assert_eq!(snapshot_l1_batch_number, L1BatchNumber(8)); @@ -183,7 +277,11 @@ async fn persisting_snapshot_metadata() { MIN_CHUNK_COUNT as usize ); for path in &snapshot_metadata.storage_logs_filepaths { - let path = path.strip_prefix("storage_logs_snapshots/").unwrap(); + let path = path + .as_ref() + .unwrap() + .strip_prefix("storage_logs_snapshots/") + .unwrap(); assert!(path.ends_with(".proto.gzip")); } } @@ -194,12 +292,11 @@ async fn persisting_snapshot_factory_deps() { let mut rng = thread_rng(); let object_store_factory = ObjectStoreFactory::mock(); let object_store = object_store_factory.create_store().await; - - // Insert some data to Postgres. let mut conn = pool.access_storage().await.unwrap(); let expected_outputs = prepare_postgres(&mut rng, &mut conn, 10).await; - run(object_store, pool.clone(), pool.clone(), MIN_CHUNK_COUNT) + SnapshotCreator::for_tests(object_store, pool.clone()) + .run(TEST_CONFIG, MIN_CHUNK_COUNT) .await .unwrap(); let snapshot_l1_batch_number = L1BatchNumber(8); @@ -217,17 +314,24 @@ async fn persisting_snapshot_logs() { let mut rng = thread_rng(); let object_store_factory = ObjectStoreFactory::mock(); let object_store = object_store_factory.create_store().await; - - // Insert some data to Postgres. let mut conn = pool.access_storage().await.unwrap(); let expected_outputs = prepare_postgres(&mut rng, &mut conn, 10).await; - run(object_store, pool.clone(), pool.clone(), MIN_CHUNK_COUNT) + SnapshotCreator::for_tests(object_store, pool.clone()) + .run(TEST_CONFIG, MIN_CHUNK_COUNT) .await .unwrap(); let snapshot_l1_batch_number = L1BatchNumber(8); let object_store = object_store_factory.create_store().await; + assert_storage_logs(&*object_store, snapshot_l1_batch_number, &expected_outputs).await; +} + +async fn assert_storage_logs( + object_store: &dyn ObjectStore, + snapshot_l1_batch_number: L1BatchNumber, + expected_outputs: &ExpectedOutputs, +) { let mut actual_logs = HashSet::new(); for chunk_id in 0..MIN_CHUNK_COUNT { let key = SnapshotStorageLogsStorageKey { @@ -239,3 +343,114 @@ async fn persisting_snapshot_logs() { } assert_eq!(actual_logs, expected_outputs.storage_logs); } + +#[tokio::test] +async fn recovery_workflow() { + let pool = ConnectionPool::test_pool().await; + let mut rng = thread_rng(); + let object_store_factory = ObjectStoreFactory::mock(); + let object_store = object_store_factory.create_store().await; + let mut conn = pool.access_storage().await.unwrap(); + let expected_outputs = prepare_postgres(&mut rng, &mut conn, 10).await; + + SnapshotCreator::for_tests(object_store, pool.clone()) + .stop_after_chunk_count(0) + .run(SEQUENTIAL_TEST_CONFIG, MIN_CHUNK_COUNT) + .await + .unwrap(); + + let snapshot_l1_batch_number = L1BatchNumber(8); + let snapshot_metadata = conn + .snapshots_dal() + .get_snapshot_metadata(snapshot_l1_batch_number) + .await + .unwrap() + .expect("No snapshot metadata"); + assert!(snapshot_metadata + .storage_logs_filepaths + .iter() + .all(Option::is_none)); + + let object_store = object_store_factory.create_store().await; + let SnapshotFactoryDependencies { factory_deps } = + object_store.get(snapshot_l1_batch_number).await.unwrap(); + let actual_deps: HashSet<_> = factory_deps.into_iter().collect(); + assert_eq!(actual_deps, expected_outputs.deps); + + // Process 2 storage log chunks, then stop. + SnapshotCreator::for_tests(object_store, pool.clone()) + .stop_after_chunk_count(2) + .run(SEQUENTIAL_TEST_CONFIG, MIN_CHUNK_COUNT) + .await + .unwrap(); + + let snapshot_metadata = conn + .snapshots_dal() + .get_snapshot_metadata(snapshot_l1_batch_number) + .await + .unwrap() + .expect("No snapshot metadata"); + assert_eq!( + snapshot_metadata + .storage_logs_filepaths + .iter() + .flatten() + .count(), + 2 + ); + + // Process the remaining chunks. + let object_store = object_store_factory.create_store().await; + SnapshotCreator::for_tests(object_store, pool.clone()) + .run(SEQUENTIAL_TEST_CONFIG, MIN_CHUNK_COUNT) + .await + .unwrap(); + + let object_store = object_store_factory.create_store().await; + assert_storage_logs(&*object_store, snapshot_l1_batch_number, &expected_outputs).await; +} + +#[tokio::test] +async fn recovery_workflow_with_varying_chunk_size() { + let pool = ConnectionPool::test_pool().await; + let mut rng = thread_rng(); + let object_store_factory = ObjectStoreFactory::mock(); + let object_store = object_store_factory.create_store().await; + let mut conn = pool.access_storage().await.unwrap(); + let expected_outputs = prepare_postgres(&mut rng, &mut conn, 10).await; + + SnapshotCreator::for_tests(object_store, pool.clone()) + .stop_after_chunk_count(2) + .run(SEQUENTIAL_TEST_CONFIG, MIN_CHUNK_COUNT) + .await + .unwrap(); + + let snapshot_l1_batch_number = L1BatchNumber(8); + let snapshot_metadata = conn + .snapshots_dal() + .get_snapshot_metadata(snapshot_l1_batch_number) + .await + .unwrap() + .expect("No snapshot metadata"); + assert_eq!( + snapshot_metadata + .storage_logs_filepaths + .iter() + .flatten() + .count(), + 2 + ); + + let config_with_other_size = SnapshotsCreatorConfig { + storage_logs_chunk_size: 1, // << should be ignored + ..SEQUENTIAL_TEST_CONFIG + }; + let object_store = object_store_factory.create_store().await; + SnapshotCreator::for_tests(object_store, pool.clone()) + .run(config_with_other_size, MIN_CHUNK_COUNT) + .await + .unwrap(); + + let object_store = object_store_factory.create_store().await; + assert_storage_logs(&*object_store, snapshot_l1_batch_number, &expected_outputs).await; +} diff --git a/core/bin/storage_logs_dedup_migration/src/main.rs b/core/bin/storage_logs_dedup_migration/src/main.rs index 733976b44e1e..fcaebafc0fe1 100644 --- a/core/bin/storage_logs_dedup_migration/src/main.rs +++ b/core/bin/storage_logs_dedup_migration/src/main.rs @@ -57,7 +57,8 @@ async fn main() { .blocks_dal() .get_sealed_miniblock_number() .await - .unwrap(); + .unwrap() + .expect("Cannot start migration for Postgres recovered from snapshot"); println!( "Migration started for miniblock range {}..={}", opt.start_from_miniblock, sealed_miniblock @@ -107,7 +108,8 @@ async fn main() { let values_for_missing_keys: HashMap<_, _> = connection .storage_logs_dal() .get_storage_values(&missing_keys, miniblock_number - 1) - .await; + .await + .expect("failed getting storage values for missing keys"); in_memory_prev_values_iter .chain( diff --git a/core/bin/system-constants-generator/Cargo.toml b/core/bin/system-constants-generator/Cargo.toml index c80ee49cc215..12795dd32b46 100644 --- a/core/bin/system-constants-generator/Cargo.toml +++ b/core/bin/system-constants-generator/Cargo.toml @@ -16,6 +16,7 @@ zksync_types = { path = "../../lib/types" } zksync_utils = { path = "../../lib/utils" } zksync_contracts = { path = "../../lib/contracts" } multivm = { path = "../../lib/multivm" } +zkevm_test_harness_1_3_3 = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.3.3", package = "zkevm_test_harness" } codegen = "0.2.0" diff --git a/core/bin/system-constants-generator/src/intrinsic_costs.rs b/core/bin/system-constants-generator/src/intrinsic_costs.rs index d09da8c5b252..4f5e988e7b1a 100644 --- a/core/bin/system-constants-generator/src/intrinsic_costs.rs +++ b/core/bin/system-constants-generator/src/intrinsic_costs.rs @@ -4,8 +4,8 @@ //! as well as contracts/SystemConfig.json //! -use multivm::vm_latest::constants::BOOTLOADER_TX_ENCODING_SPACE; -use zksync_types::{ethabi::Address, IntrinsicSystemGasConstants, U256}; +use multivm::utils::get_bootloader_encoding_space; +use zksync_types::{ethabi::Address, IntrinsicSystemGasConstants, ProtocolVersionId, U256}; use crate::utils::{ execute_internal_transfer_test, execute_user_txs_in_test_gas_vm, get_l1_tx, get_l1_txs, @@ -81,7 +81,7 @@ pub(crate) fn l2_gas_constants() -> IntrinsicSystemGasConstants { true, ); - // This price does not include the overhead for the transaction itself, but rather auxilary parts + // This price does not include the overhead for the transaction itself, but rather auxiliary parts // that must be done by the transaction and it can not be enforced by the operator to not to accept // the transaction if it does not cover the minimal costs. let min_l1_tx_price = empty_l1_tx_result.gas_consumed - bootloader_intrinsic_gas; @@ -107,7 +107,7 @@ pub(crate) fn l2_gas_constants() -> IntrinsicSystemGasConstants { let delta_from_544_bytes = lengthier_tx_result.gas_consumed - empty_l1_tx_result.gas_consumed; - // The number of public data per factory dep should not depend on the size/structure of the factory + // The number of public data per factory dependencies should not depend on the size/structure of the factory // dependency, since the dependency has already been published on L1. let tx_with_more_factory_deps_result = execute_user_txs_in_test_gas_vm( vec![get_l1_tx( @@ -129,7 +129,8 @@ pub(crate) fn l2_gas_constants() -> IntrinsicSystemGasConstants { tx_with_more_factory_deps_result.pubdata_published - empty_l1_tx_result.pubdata_published; // The number of the bootloader memory that can be filled up with transactions. - let bootloader_tx_memory_size_slots = BOOTLOADER_TX_ENCODING_SPACE; + let bootloader_tx_memory_size_slots = + get_bootloader_encoding_space(ProtocolVersionId::latest().into()); IntrinsicSystemGasConstants { l2_tx_intrinsic_gas, @@ -179,7 +180,7 @@ fn get_intrinsic_overheads_for_tx_type(tx_generator: &TransactionGenerator) -> I let bootloader_intrinsic_pubdata = result_0.pubdata_published; // For various small reasons the overhead for the first transaction and for all the subsequent ones - // might differ a bit, so we will calculate both and will use the maximum one as the result for l2 txs. + // might differ a bit, so we will calculate both and will use the maximum one as the result for L2 txs. let (tx1_intrinsic_gas, tx1_intrinsic_pubdata) = get_intrinsic_price(result_0, result_1); let (tx2_intrinsic_gas, tx2_intrinsic_pubdata) = get_intrinsic_price(result_1, result_2); diff --git a/core/bin/system-constants-generator/src/main.rs b/core/bin/system-constants-generator/src/main.rs index e6009a7a393d..db42d91fbb55 100644 --- a/core/bin/system-constants-generator/src/main.rs +++ b/core/bin/system-constants-generator/src/main.rs @@ -1,22 +1,26 @@ use std::fs; use codegen::{Block, Scope}; -use multivm::vm_latest::constants::{ - BLOCK_OVERHEAD_GAS, BLOCK_OVERHEAD_L1_GAS, BOOTLOADER_TX_ENCODING_SPACE, MAX_PUBDATA_PER_BLOCK, +use multivm::{ + utils::{get_bootloader_encoding_space, get_bootloader_max_txs_in_batch}, + vm_latest::constants::MAX_PUBDATA_PER_BLOCK, }; use serde::{Deserialize, Serialize}; -use zksync_types::{ - zkevm_test_harness::zk_evm::zkevm_opcode_defs::{ - circuit_prices::{ - ECRECOVER_CIRCUIT_COST_IN_ERGS, KECCAK256_CIRCUIT_COST_IN_ERGS, - SHA256_CIRCUIT_COST_IN_ERGS, - }, - system_params::MAX_TX_ERGS_LIMIT, +use zkevm_test_harness_1_3_3::zk_evm::zkevm_opcode_defs::{ + circuit_prices::{ + ECRECOVER_CIRCUIT_COST_IN_ERGS, KECCAK256_CIRCUIT_COST_IN_ERGS, SHA256_CIRCUIT_COST_IN_ERGS, }, - IntrinsicSystemGasConstants, GUARANTEED_PUBDATA_IN_TX, L1_GAS_PER_PUBDATA_BYTE, - MAX_GAS_PER_PUBDATA_BYTE, MAX_NEW_FACTORY_DEPS, MAX_TXS_IN_BLOCK, + system_params::MAX_TX_ERGS_LIMIT, +}; +use zksync_types::{ + IntrinsicSystemGasConstants, ProtocolVersionId, GUARANTEED_PUBDATA_IN_TX, + L1_GAS_PER_PUBDATA_BYTE, MAX_NEW_FACTORY_DEPS, REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE, }; +// For configs we will use the default value of `800_000` to represent the rough amount of L1 gas +// needed to cover the batch expenses. +const BLOCK_OVERHEAD_L1_GAS: u32 = 800_000; + mod intrinsic_costs; mod utils; @@ -29,7 +33,6 @@ struct L1SystemConfig { priority_tx_max_pubdata: u32, fair_l2_gas_price: u64, l1_gas_per_pubdata_byte: u32, - block_overhead_l2_gas: u32, block_overhead_l1_gas: u32, max_transactions_in_block: u32, bootloader_tx_encoding_space: u32, @@ -55,11 +58,13 @@ pub fn generate_l1_contracts_system_config(gas_constants: &IntrinsicSystemGasCon priority_tx_max_pubdata: (L1_TX_DECREASE * (MAX_PUBDATA_PER_BLOCK as f64)) as u32, fair_l2_gas_price: FAIR_L2_GAS_PRICE_ON_L1_CONTRACT, l1_gas_per_pubdata_byte: L1_GAS_PER_PUBDATA_BYTE, - block_overhead_l2_gas: BLOCK_OVERHEAD_GAS, block_overhead_l1_gas: BLOCK_OVERHEAD_L1_GAS, - max_transactions_in_block: MAX_TXS_IN_BLOCK as u32, - bootloader_tx_encoding_space: BOOTLOADER_TX_ENCODING_SPACE, - + max_transactions_in_block: get_bootloader_max_txs_in_batch( + ProtocolVersionId::latest().into(), + ) as u32, + bootloader_tx_encoding_space: get_bootloader_encoding_space( + ProtocolVersionId::latest().into(), + ), l1_tx_intrinsic_l2_gas: gas_constants.l1_tx_intrinsic_gas, l1_tx_intrinsic_pubdata: gas_constants.l1_tx_intrinsic_pubdata, l1_tx_min_l2_gas_base: gas_constants.l1_tx_min_gas_base, @@ -67,7 +72,7 @@ pub fn generate_l1_contracts_system_config(gas_constants: &IntrinsicSystemGasCon l1_tx_delta_factory_deps_l2_gas: gas_constants.l1_tx_delta_factory_dep_gas, l1_tx_delta_factory_deps_pubdata: gas_constants.l1_tx_delta_factory_dep_pubdata, max_new_factory_deps: MAX_NEW_FACTORY_DEPS as u32, - required_l2_gas_price_per_pubdata: MAX_GAS_PER_PUBDATA_BYTE, + required_l2_gas_price_per_pubdata: REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE, }; serde_json::to_string_pretty(&l1_contracts_config).unwrap() @@ -80,7 +85,6 @@ struct L2SystemConfig { guaranteed_pubdata_bytes: u32, max_pubdata_per_block: u32, max_transactions_in_block: u32, - block_overhead_l2_gas: u32, block_overhead_l1_gas: u32, l2_tx_intrinsic_gas: u32, l2_tx_intrinsic_pubdata: u32, @@ -98,15 +102,18 @@ pub fn generate_l2_contracts_system_config(gas_constants: &IntrinsicSystemGasCon let l2_contracts_config = L2SystemConfig { guaranteed_pubdata_bytes: GUARANTEED_PUBDATA_IN_TX, max_pubdata_per_block: MAX_PUBDATA_PER_BLOCK, - max_transactions_in_block: MAX_TXS_IN_BLOCK as u32, - block_overhead_l2_gas: BLOCK_OVERHEAD_GAS, + max_transactions_in_block: get_bootloader_max_txs_in_batch( + ProtocolVersionId::latest().into(), + ) as u32, block_overhead_l1_gas: BLOCK_OVERHEAD_L1_GAS, l2_tx_intrinsic_gas: gas_constants.l2_tx_intrinsic_gas, l2_tx_intrinsic_pubdata: gas_constants.l2_tx_intrinsic_pubdata, l1_tx_intrinsic_l2_gas: gas_constants.l1_tx_intrinsic_gas, l1_tx_intrinsic_pubdata: gas_constants.l1_tx_intrinsic_pubdata, max_gas_per_transaction: MAX_TX_ERGS_LIMIT, - bootloader_memory_for_txs: BOOTLOADER_TX_ENCODING_SPACE, + bootloader_memory_for_txs: get_bootloader_encoding_space( + ProtocolVersionId::latest().into(), + ), refund_gas: gas_constants.l2_tx_gas_for_refund_transfer, keccak_round_cost_gas: KECCAK256_CIRCUIT_COST_IN_ERGS, sha256_round_cost_gas: SHA256_CIRCUIT_COST_IN_ERGS, diff --git a/core/bin/system-constants-generator/src/utils.rs b/core/bin/system-constants-generator/src/utils.rs index fbf69a43306b..75b47b6aa054 100644 --- a/core/bin/system-constants-generator/src/utils.rs +++ b/core/bin/system-constants-generator/src/utils.rs @@ -2,7 +2,7 @@ use std::{cell::RefCell, rc::Rc}; use multivm::{ interface::{ - dyn_tracers::vm_1_4_0::DynTracer, tracer::VmExecutionStopReason, L1BatchEnv, L2BlockEnv, + dyn_tracers::vm_1_4_1::DynTracer, tracer::VmExecutionStopReason, L1BatchEnv, L2BlockEnv, SystemEnv, TxExecutionMode, VmExecutionMode, VmInterface, }, vm_latest::{ @@ -10,6 +10,7 @@ use multivm::{ BootloaderState, HistoryEnabled, HistoryMode, SimpleMemory, ToTracerPointer, Vm, VmTracer, ZkSyncVmState, }, + zk_evm_latest::aux_structures::Timestamp, }; use once_cell::sync::Lazy; use zksync_contracts::{ @@ -18,12 +19,11 @@ use zksync_contracts::{ }; use zksync_state::{InMemoryStorage, StorageView, WriteStorage}; use zksync_types::{ - block::MiniblockHasher, ethabi::Token, fee::Fee, l1::L1Tx, l2::L2Tx, + block::MiniblockHasher, ethabi::Token, fee::Fee, fee_model::BatchFeeInput, l1::L1Tx, l2::L2Tx, utils::storage_key_for_eth_balance, AccountTreeId, Address, Execute, L1BatchNumber, - L1TxCommonData, L2ChainId, MiniblockNumber, Nonce, ProtocolVersionId, StorageKey, Timestamp, - Transaction, BOOTLOADER_ADDRESS, H256, SYSTEM_CONTEXT_ADDRESS, - SYSTEM_CONTEXT_GAS_PRICE_POSITION, SYSTEM_CONTEXT_TX_ORIGIN_POSITION, U256, - ZKPORTER_IS_AVAILABLE, + L1TxCommonData, L2ChainId, MiniblockNumber, Nonce, ProtocolVersionId, StorageKey, Transaction, + BOOTLOADER_ADDRESS, H256, SYSTEM_CONTEXT_ADDRESS, SYSTEM_CONTEXT_GAS_PRICE_POSITION, + SYSTEM_CONTEXT_TX_ORIGIN_POSITION, U256, ZKPORTER_IS_AVAILABLE, }; use zksync_utils::{bytecode::hash_bytecode, bytes_to_be_words, u256_to_h256}; @@ -164,8 +164,8 @@ pub(super) fn get_l1_txs(number_of_txs: usize) -> (Vec, Vec Vec { read_zbin_bytecode(format!( - "contracts/system-contracts/bootloader/tests/artifacts/{}.yul/{}.yul.zbin", - test, test + "contracts/system-contracts/bootloader/tests/artifacts/{}.yul.zbin", + test )) } @@ -174,8 +174,10 @@ fn default_l1_batch() -> L1BatchEnv { previous_batch_hash: None, number: L1BatchNumber(1), timestamp: 100, - l1_gas_price: 50_000_000_000, // 50 gwei - fair_l2_gas_price: 250_000_000, // 0.25 gwei + fee_input: BatchFeeInput::l1_pegged( + 50_000_000_000, // 50 gwei + 250_000_000, // 0.25 gwei + ), fee_account: Address::random(), enforced_base_fee: None, first_l2_block: L2BlockEnv { diff --git a/core/bin/verification_key_generator_and_server/Cargo.toml b/core/bin/verification_key_generator_and_server/Cargo.toml deleted file mode 100644 index b49683424a40..000000000000 --- a/core/bin/verification_key_generator_and_server/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[package] -name = "zksync_verification_key_generator_and_server" -version = "0.1.0" -edition = "2018" -license = "MIT OR Apache-2.0" - -[lib] -name = "zksync_verification_key_server" -path = "src/lib.rs" - -[[bin]] -name = "zksync_verification_key_generator" -path = "src/main.rs" - -[[bin]] -name = "zksync_json_to_binary_vk_converter" -path = "src/json_to_binary_vk_converter.rs" - -[[bin]] -name = "zksync_commitment_generator" -path = "src/commitment_generator.rs" - -[dependencies] -zksync_types = { path = "../../lib/types" } -zksync_prover_utils = { path = "../../lib/prover_utils" } -vlog = { path = "../../lib/vlog" } -circuit_testing = { git = "https://github.com/matter-labs/era-circuit_testing.git", branch = "main" } -itertools = "0.10.5" -bincode = "1.3.3" - -anyhow = "1.0" -serde_json = "1.0.85" -hex = "0.4.3" -structopt = "0.3.26" -ff = { package = "ff_ce", version = "0.14.1" } -once_cell = "1.8.0" -tracing = "0.1" diff --git a/core/bin/verification_key_generator_and_server/README.md b/core/bin/verification_key_generator_and_server/README.md deleted file mode 100644 index efe7d3f99a4e..000000000000 --- a/core/bin/verification_key_generator_and_server/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# Verification keys - -We currently have around 20 different circuits like: Scheduler, Leaf, KeccakPrecompile etc (for the full list - look at -CircuitType enum in sync_vm repo). - -Each such circuit requires a separate verification key. - -This crate fulfills 2 roles: - -- it has the binaries that can generate the updated versions of the keys (for example if VM code changes) -- it provides the libraries that can be used by other components that need to use these keys (for example provers) - - behaving like a key server. - -Moreover, all these keys are submitted as code within the repo in `verification_XX_key.json` files. - -## zksync_verification_key_server - -This is the library that can be used by other components to fetch the verification key for a given circuit (using -`get_vk_for_circuit_type` function). - -## zksync_verification_key_generator - -The main binary that generates verification key for given circuits. Most of the heavy lifting is done by the -`create_vk_for_padding_size_log_2` method from circuit_testing repo. - -The results are written to the `verification_XX_key.json` files in the current repository. - -## zksync_json_to_binary_vk_converter - -Converts the local json verification keys into the binary format (and stores them in the output directory). - -## zksync_commitment_generator - -This tool takes the 3 commitments (one for all the basic circuits, one for node and one for leaf), computed based on the -current verification keys - and updates the contract.toml config file (which is located in etc/env/base/contracts.toml). - -These commitments are later used in one of the circuit breakers - to compare their values to the commitments that L1 -contract holds (so that we can 'panic' properly - if we notice that our server's commitments differ from the L1 -contracts - which would result in failed L1 transactions). diff --git a/core/bin/verification_key_generator_and_server/data/verification_0_key.json b/core/bin/verification_key_generator_and_server/data/verification_0_key.json deleted file mode 100644 index c3262193a4fd..000000000000 --- a/core/bin/verification_key_generator_and_server/data/verification_0_key.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "n": 67108863, - "num_inputs": 1, - "state_width": 4, - "num_witness_polys": 0, - "gate_setup_commitments": [ - { - "x": [ - 14745348174000482855, - 2839037062185937123, - 3369862715588854899, - 1495909583940713128 - ], - "y": [ - 6859454683840363585, - 11340551061368171664, - 9528805406487149561, - 3414144677220223705 - ], - "infinity": false - }, - { - "x": [ - 9215749870136224396, - 18418669114332753377, - 13140219601461030180, - 2381098845928447331 - ], - "y": [ - 8834765081837029169, - 4424842234296363904, - 13294547557836067005, - 414624398145171890 - ], - "infinity": false - }, - { - "x": [ - 2148575411987453084, - 16730180692461995258, - 12423475767707134837, - 3014264170083149730 - ], - "y": [ - 10870860158804422503, - 14060279526953529989, - 2266257082861680293, - 22356173050560284 - ], - "infinity": false - }, - { - "x": [ - 17803008042411335770, - 5713064950476621403, - 17979342410816871746, - 491265656076548841 - ], - "y": [ - 9823492080506672630, - 3637386621225409615, - 8776978043600973097, - 2514196809208915768 - ], - "infinity": false - }, - { - "x": [ - 3768479078383323179, - 16153057542709544671, - 10578964798085613273, - 2831188075764800753 - ], - "y": [ - 2387514805820590694, - 15085489652142686165, - 8141513931186597223, - 1582376980242699819 - ], - "infinity": false - }, - { - "x": [ - 5395455814671474247, - 5013790368139874617, - 8671649443504728767, - 839142828943885970 - ], - "y": [ - 11231626069154926735, - 5078347962234771017, - 17373886182204596447, - 513647957075879347 - ], - "infinity": false - }, - { - "x": [ - 8940485327950054531, - 9156997542069636576, - 14316753178152000598, - 3357551869664255582 - ], - "y": [ - 14102490706504125272, - 4494991810930729808, - 15532318871086968466, - 1537365238286274178 - ], - "infinity": false - }, - { - "x": [ - 13914906478277300859, - 6213896071228541481, - 4364409818367302306, - 659097390118096039 - ], - "y": [ - 7328372274594390887, - 2650332638498669615, - 15455628473476960005, - 3119379427019958230 - ], - "infinity": false - } - ], - "gate_selectors_commitments": [ - { - "x": [ - 9438200511694036157, - 11094162170960057340, - 9123678872696723713, - 2950597355117190054 - ], - "y": [ - 6153972960518016517, - 8045683598100955864, - 13410633858416643489, - 988361678931464913 - ], - "infinity": false - }, - { - "x": [ - 805964423710846142, - 13603470797942296854, - 11292123377140077447, - 1455913517812009773 - ], - "y": [ - 4541622738043214385, - 8186357170000535775, - 4765839113294831637, - 3026863977499737494 - ], - "infinity": false - } - ], - "permutation_commitments": [ - { - "x": [ - 1851039213129741497, - 11907960788190413713, - 2882727828085561070, - 1451278944954982956 - ], - "y": [ - 15245785050592773860, - 1774295027236395480, - 3373069120056880915, - 1080245109458702174 - ], - "infinity": false - }, - { - "x": [ - 9366052859968548005, - 12275028918364559591, - 2472023927159177225, - 1052535074027277666 - ], - "y": [ - 2428574557555628629, - 15067392861858369528, - 16949255188095910778, - 2297925771936569168 - ], - "infinity": false - }, - { - "x": [ - 17016009610362956206, - 4047659663396753591, - 1832464593155416403, - 2725142957049914767 - ], - "y": [ - 12447928856414787240, - 3072280375285720285, - 12294239288643819494, - 613511140380288958 - ], - "infinity": false - }, - { - "x": [ - 6312774245791141720, - 496150993329472460, - 12773767122915456934, - 3404402910494500531 - ], - "y": [ - 13852578578747731084, - 9030931732410275304, - 17159996848865265705, - 1696956882146098553 - ], - "infinity": false - } - ], - "total_lookup_entries_length": 1073530, - "lookup_selector_commitment": { - "x": [ - 4441974708940861232, - 11325614820129407652, - 7273013871150456559, - 2270181644629652201 - ], - "y": [ - 3070631142979677922, - 15247189094202672776, - 12651459662740804392, - 1832216259472686694 - ], - "infinity": false - }, - "lookup_tables_commitments": [ - { - "x": [ - 631990924006796604, - 16139625628991115157, - 13331739325995827711, - 1062301837743594995 - ], - "y": [ - 15303054606290800139, - 15906872095881647437, - 7093896572295020249, - 1342952934989901142 - ], - "infinity": false - }, - { - "x": [ - 7983921919542246393, - 13296544189644416678, - 17081022784392007697, - 1980832835348244027 - ], - "y": [ - 10874958134865200330, - 7702740658637630534, - 14052057929798961943, - 3193353539419869016 - ], - "infinity": false - }, - { - "x": [ - 1114587284824996932, - 4636906500482867924, - 15328247172597030456, - 87946895873973686 - ], - "y": [ - 15573033830207915877, - 5194694185599035278, - 2562407345425607214, - 2782078999306862675 - ], - "infinity": false - }, - { - "x": [ - 18225112781127431982, - 18048613958187123807, - 7325490730844456621, - 1953409020724855888 - ], - "y": [ - 7577000130125917198, - 6193701449695751861, - 4102082927677054717, - 395350071385269650 - ], - "infinity": false - } - ], - "lookup_table_type_commitment": { - "x": [ - 7312875299592476003, - 313526216906044060, - 13914875394436353152, - 3424388477700656316 - ], - "y": [ - 2572062173996296044, - 5984767625164919974, - 12005537293370417131, - 616463121946800406 - ], - "infinity": false - }, - "non_residues": [ - [ - 5, - 0, - 0, - 0 - ], - [ - 7, - 0, - 0, - 0 - ], - [ - 10, - 0, - 0, - 0 - ] - ], - "g2_elements": [ - { - "x": { - "c0": [ - 5106727233969649389, - 7440829307424791261, - 4785637993704342649, - 1729627375292849782 - ], - "c1": [ - 10945020018377822914, - 17413811393473931026, - 8241798111626485029, - 1841571559660931130 - ] - }, - "y": { - "c0": [ - 5541340697920699818, - 16416156555105522555, - 5380518976772849807, - 1353435754470862315 - ], - "c1": [ - 6173549831154472795, - 13567992399387660019, - 17050234209342075797, - 650358724130500725 - ] - }, - "infinity": false - }, - { - "x": { - "c0": [ - 9089143573911733168, - 11482283522806384523, - 13585589533905622862, - 79029415676722370 - ], - "c1": [ - 5692040832573735873, - 16884514497384809355, - 16717166481813659368, - 2742131088506155463 - ] - }, - "y": { - "c0": [ - 9604638503594647125, - 1289961608472612514, - 6217038149984805214, - 2521661352385209130 - ], - "c1": [ - 17168069778630926308, - 11309277837895768996, - 15154989611154567813, - 359271377050603491 - ] - }, - "infinity": false - } - ] -} \ No newline at end of file diff --git a/core/bin/verification_key_generator_and_server/data/verification_10_key.json b/core/bin/verification_key_generator_and_server/data/verification_10_key.json deleted file mode 100644 index ec9d3727bff9..000000000000 --- a/core/bin/verification_key_generator_and_server/data/verification_10_key.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "n": 67108863, - "num_inputs": 1, - "state_width": 4, - "num_witness_polys": 0, - "gate_setup_commitments": [ - { - "x": [ - 4364720487844379181, - 17010766725144227333, - 1022678199111276314, - 1146578362772127376 - ], - "y": [ - 10340654727439455072, - 12691578856596245032, - 837883495763401146, - 2135776887902289239 - ], - "infinity": false - }, - { - "x": [ - 14564870240038241482, - 16001391704613609683, - 16397364612792898214, - 1316914335235774452 - ], - "y": [ - 2386942353392090183, - 4642131766714508143, - 16789479723446408276, - 2261353401184907401 - ], - "infinity": false - }, - { - "x": [ - 6081056006818109026, - 14051483412950926523, - 8605392534710099348, - 1527183574619010123 - ], - "y": [ - 3896696527234063839, - 12862398541231039501, - 1005646628007936886, - 3479645512156004366 - ], - "infinity": false - }, - { - "x": [ - 11266242489999219523, - 8100856016495224488, - 6788749864393617587, - 482299081118345826 - ], - "y": [ - 225211373180020785, - 6498635074385582091, - 4274055525472487569, - 2578651815252093838 - ], - "infinity": false - }, - { - "x": [ - 10378455392293934375, - 13391940670290769236, - 10463014668466536299, - 472544008986099462 - ], - "y": [ - 1502016714118108544, - 14252801754530793876, - 2203844491975584716, - 1116114255465135672 - ], - "infinity": false - }, - { - "x": [ - 9703616742074407567, - 9691703077434834222, - 7366620887865105973, - 36165572355418066 - ], - "y": [ - 7430304832706471782, - 5173267152399523091, - 14416699599905226230, - 2681204653630184824 - ], - "infinity": false - }, - { - "x": [ - 9347312215430913530, - 13606433894103359668, - 14013475178334262360, - 2947181048682744075 - ], - "y": [ - 4001199390012145932, - 4622813642635649819, - 16433672063298879053, - 1247842462976799965 - ], - "infinity": false - }, - { - "x": [ - 1639425503718708209, - 8242804754724970899, - 11043260258533730377, - 2245145560504199089 - ], - "y": [ - 14202551139064230506, - 4307109380979442947, - 13141687433511141087, - 1913204959448290015 - ], - "infinity": false - } - ], - "gate_selectors_commitments": [ - { - "x": [ - 17540836040216578409, - 14577118461028955096, - 2300935836423716880, - 427649651480863044 - ], - "y": [ - 13066723755606073272, - 17324941433857131282, - 1679499122173566851, - 3298750515604566671 - ], - "infinity": false - }, - { - "x": [ - 14709152157752642079, - 13510549649315108277, - 3019440420162710858, - 627188607991231846 - ], - "y": [ - 16615706301470133997, - 915024441316023047, - 13798541787831785917, - 3340602253234308653 - ], - "infinity": false - } - ], - "permutation_commitments": [ - { - "x": [ - 12626704863583094704, - 3308474372162220296, - 16088806788444947642, - 636430705662147361 - ], - "y": [ - 17052785040105865748, - 11203395113497209978, - 2939609765212411460, - 3167290643533167611 - ], - "infinity": false - }, - { - "x": [ - 3075146465184418179, - 11559452521956513155, - 1656597085428845901, - 1618447062156730856 - ], - "y": [ - 2010693621773175313, - 2977509893150409878, - 9431891659616951962, - 1776222288355278384 - ], - "infinity": false - }, - { - "x": [ - 6408318860212838666, - 9847136022608767026, - 18080834927350013528, - 3306285138140631107 - ], - "y": [ - 16064928058583899597, - 461689523483649779, - 13572099112445223829, - 1563453638232968523 - ], - "infinity": false - }, - { - "x": [ - 327171445663828020, - 12706053900720413614, - 9237483585964880752, - 1960293149538216528 - ], - "y": [ - 11030775691809003651, - 11089052388657955457, - 3209890793790993499, - 1198867574642866523 - ], - "infinity": false - } - ], - "total_lookup_entries_length": 5202052, - "lookup_selector_commitment": { - "x": [ - 781239045644769777, - 14316527640474633593, - 2443643435827373112, - 3049372365263474427 - ], - "y": [ - 4073012743593667819, - 16009537994875540924, - 11173412503242869179, - 1513208421597995174 - ], - "infinity": false - }, - "lookup_tables_commitments": [ - { - "x": [ - 697552212563769686, - 7709943502535418760, - 15019345407325619175, - 3433081085078580257 - ], - "y": [ - 8668947019840357731, - 14698901351824712883, - 15088598879190660424, - 2873081208166433946 - ], - "infinity": false - }, - { - "x": [ - 7893133928909060673, - 7064922516930129957, - 3592836702741304814, - 2239702595710114437 - ], - "y": [ - 7691360541875191519, - 11379321785127235277, - 6653616064071569031, - 2555434628517540774 - ], - "infinity": false - }, - { - "x": [ - 6243944238013052821, - 7908243182210136125, - 17178099109525791299, - 2553622184721264566 - ], - "y": [ - 736121280088239428, - 6158073429758170526, - 11217302997977204117, - 2594798912020899417 - ], - "infinity": false - }, - { - "x": [ - 2064240298596094591, - 16917726764104887991, - 11042784977532408536, - 3377647228930170830 - ], - "y": [ - 10635525052494768819, - 387400048616497096, - 9379200582543310995, - 1571766153703296253 - ], - "infinity": false - } - ], - "lookup_table_type_commitment": { - "x": [ - 7603211811706190713, - 2486982239745271096, - 11528266448545919500, - 3080741880407152411 - ], - "y": [ - 7967754771633653173, - 6016822892450616749, - 9688696792558711613, - 2682562048141398047 - ], - "infinity": false - }, - "non_residues": [ - [ - 5, - 0, - 0, - 0 - ], - [ - 7, - 0, - 0, - 0 - ], - [ - 10, - 0, - 0, - 0 - ] - ], - "g2_elements": [ - { - "x": { - "c0": [ - 5106727233969649389, - 7440829307424791261, - 4785637993704342649, - 1729627375292849782 - ], - "c1": [ - 10945020018377822914, - 17413811393473931026, - 8241798111626485029, - 1841571559660931130 - ] - }, - "y": { - "c0": [ - 5541340697920699818, - 16416156555105522555, - 5380518976772849807, - 1353435754470862315 - ], - "c1": [ - 6173549831154472795, - 13567992399387660019, - 17050234209342075797, - 650358724130500725 - ] - }, - "infinity": false - }, - { - "x": { - "c0": [ - 9089143573911733168, - 11482283522806384523, - 13585589533905622862, - 79029415676722370 - ], - "c1": [ - 5692040832573735873, - 16884514497384809355, - 16717166481813659368, - 2742131088506155463 - ] - }, - "y": { - "c0": [ - 9604638503594647125, - 1289961608472612514, - 6217038149984805214, - 2521661352385209130 - ], - "c1": [ - 17168069778630926308, - 11309277837895768996, - 15154989611154567813, - 359271377050603491 - ] - }, - "infinity": false - } - ] -} \ No newline at end of file diff --git a/core/bin/verification_key_generator_and_server/data/verification_11_key.json b/core/bin/verification_key_generator_and_server/data/verification_11_key.json deleted file mode 100644 index ec60b1b5c70c..000000000000 --- a/core/bin/verification_key_generator_and_server/data/verification_11_key.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "n": 67108863, - "num_inputs": 1, - "state_width": 4, - "num_witness_polys": 0, - "gate_setup_commitments": [ - { - "x": [ - 6404793958941109752, - 600086648940026770, - 17621036346050218167, - 648286585825030202 - ], - "y": [ - 15536368541166505022, - 13874331483468128999, - 15299774519724050181, - 694528839710637549 - ], - "infinity": false - }, - { - "x": [ - 8437895530551083583, - 9515418928119648176, - 13043255827139294721, - 2995712510038409810 - ], - "y": [ - 2599666661350767554, - 5213004864468121936, - 3448071048439343925, - 3372727479169634860 - ], - "infinity": false - }, - { - "x": [ - 4949545806128010634, - 7991544258837652527, - 13984289231122041826, - 435264553263929947 - ], - "y": [ - 5315155210033461895, - 5269954775753247626, - 8365554241810378947, - 3038338810517586456 - ], - "infinity": false - }, - { - "x": [ - 10765735847634894938, - 996016141851615448, - 17905928073714218280, - 1382306444325686451 - ], - "y": [ - 2138154197587423296, - 10332772886666867909, - 18365120064743353477, - 3036329558617382049 - ], - "infinity": false - }, - { - "x": [ - 10826908009799408310, - 17008417534705779156, - 6763973494549063072, - 2085829964414931488 - ], - "y": [ - 8778528796073273991, - 3575354418973385595, - 7700555759899743641, - 2991788183234680231 - ], - "infinity": false - }, - { - "x": [ - 4838537981048085423, - 17733460364049897496, - 2406410363431464143, - 317979983533551325 - ], - "y": [ - 1063783130085451648, - 17468950496650586998, - 1638492556781126884, - 2655791721465286744 - ], - "infinity": false - }, - { - "x": [ - 9900079822056413611, - 2971494295919434281, - 3851188096409515874, - 1674965457600938162 - ], - "y": [ - 278026997091552202, - 4169606578927284200, - 4285297176993939496, - 1835673146863992148 - ], - "infinity": false - }, - { - "x": [ - 14972922803706426724, - 1950002897609593521, - 14885502244328862256, - 2711533695106895845 - ], - "y": [ - 6445273103061253271, - 13093783937225622775, - 16913300898726970338, - 3338984185497324237 - ], - "infinity": false - } - ], - "gate_selectors_commitments": [ - { - "x": [ - 7023363902839996761, - 10470701207992157969, - 15655647820064667897, - 1574806151825297776 - ], - "y": [ - 5374465760860613169, - 17808737811039085287, - 9497881147171478776, - 2496973717640690197 - ], - "infinity": false - }, - { - "x": [ - 11667333913021610767, - 981513539224109240, - 906325130343873228, - 2938085706999497365 - ], - "y": [ - 12114685726509803851, - 8176447551157079615, - 4677211732718215770, - 612959750791398009 - ], - "infinity": false - } - ], - "permutation_commitments": [ - { - "x": [ - 5178916486603003859, - 12440762249350081718, - 17531240512375127539, - 562979322442547791 - ], - "y": [ - 13269831614205338393, - 14075713698585784838, - 5009519510530479124, - 346033861980045408 - ], - "infinity": false - }, - { - "x": [ - 9815443577325313677, - 10727907015331332054, - 7582395371050260833, - 1746872659838481572 - ], - "y": [ - 3973552805135639320, - 14426732004648741961, - 8133164322153358522, - 2668541869556858228 - ], - "infinity": false - }, - { - "x": [ - 4868257934818957423, - 11529848268525929099, - 7089666284160764141, - 796901367628793969 - ], - "y": [ - 991195814042705325, - 1559922382138761102, - 15616159453482282503, - 1031107741111093289 - ], - "infinity": false - }, - { - "x": [ - 17936772813090339705, - 10208762457499980701, - 14796710996322725970, - 638550977107438851 - ], - "y": [ - 5073905611192321777, - 2956648407808816974, - 7778989780119416172, - 2955106321082932072 - ], - "infinity": false - } - ], - "total_lookup_entries_length": 7960377, - "lookup_selector_commitment": { - "x": [ - 1083743271968869166, - 3134203175755215736, - 5835502497758804469, - 3010956977291777466 - ], - "y": [ - 3645612220088813035, - 32844736552579976, - 5426466326302260857, - 1489565191618899261 - ], - "infinity": false - }, - "lookup_tables_commitments": [ - { - "x": [ - 5825422128268478267, - 9219263846299851036, - 3879231702557190566, - 1702488722758880769 - ], - "y": [ - 18311881100262470992, - 5742998199368802392, - 18106865487471159417, - 502191980176920012 - ], - "infinity": false - }, - { - "x": [ - 17195892082859417081, - 7890531942603584793, - 2381805632820057528, - 3173232410464566465 - ], - "y": [ - 16359614627947132075, - 3459600273035137079, - 4550762061432972122, - 3394559699318358224 - ], - "infinity": false - }, - { - "x": [ - 1716103379277390185, - 18097936269579187542, - 16357329729761063450, - 1508640059338197502 - ], - "y": [ - 11014806739603983364, - 4396503314588777389, - 9397245609635151055, - 1703957955248411380 - ], - "infinity": false - }, - { - "x": [ - 4770171350693477354, - 17110558673192292253, - 9799800677557311408, - 761984875463445481 - ], - "y": [ - 1560561403388310063, - 31331275310848146, - 287152055803835484, - 457826332542037277 - ], - "infinity": false - } - ], - "lookup_table_type_commitment": { - "x": [ - 11327495732840772606, - 7407664417001729515, - 9486600059857658309, - 3060296564241189838 - ], - "y": [ - 7624492872489320847, - 18248981556039704277, - 3877205757853252152, - 939885486002612376 - ], - "infinity": false - }, - "non_residues": [ - [ - 5, - 0, - 0, - 0 - ], - [ - 7, - 0, - 0, - 0 - ], - [ - 10, - 0, - 0, - 0 - ] - ], - "g2_elements": [ - { - "x": { - "c0": [ - 5106727233969649389, - 7440829307424791261, - 4785637993704342649, - 1729627375292849782 - ], - "c1": [ - 10945020018377822914, - 17413811393473931026, - 8241798111626485029, - 1841571559660931130 - ] - }, - "y": { - "c0": [ - 5541340697920699818, - 16416156555105522555, - 5380518976772849807, - 1353435754470862315 - ], - "c1": [ - 6173549831154472795, - 13567992399387660019, - 17050234209342075797, - 650358724130500725 - ] - }, - "infinity": false - }, - { - "x": { - "c0": [ - 9089143573911733168, - 11482283522806384523, - 13585589533905622862, - 79029415676722370 - ], - "c1": [ - 5692040832573735873, - 16884514497384809355, - 16717166481813659368, - 2742131088506155463 - ] - }, - "y": { - "c0": [ - 9604638503594647125, - 1289961608472612514, - 6217038149984805214, - 2521661352385209130 - ], - "c1": [ - 17168069778630926308, - 11309277837895768996, - 15154989611154567813, - 359271377050603491 - ] - }, - "infinity": false - } - ] -} \ No newline at end of file diff --git a/core/bin/verification_key_generator_and_server/data/verification_12_key.json b/core/bin/verification_key_generator_and_server/data/verification_12_key.json deleted file mode 100644 index fec076f39eda..000000000000 --- a/core/bin/verification_key_generator_and_server/data/verification_12_key.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "n": 67108863, - "num_inputs": 1, - "state_width": 4, - "num_witness_polys": 0, - "gate_setup_commitments": [ - { - "x": [ - 456514006020943025, - 9595480195714948127, - 12254096252487404245, - 1742692690750856358 - ], - "y": [ - 16294223586064957217, - 3958270970168887906, - 11264067544872898258, - 1692817687935973108 - ], - "infinity": false - }, - { - "x": [ - 1359655052308122459, - 13840124148496555776, - 1774237333490664500, - 2964872651584750318 - ], - "y": [ - 11907598503482948769, - 8700506041798646988, - 15081040576888859990, - 3096802642049924528 - ], - "infinity": false - }, - { - "x": [ - 2884314851670818573, - 13442465544210396156, - 5937955495868181363, - 2486997439179977778 - ], - "y": [ - 9309776793338098458, - 14492906371677122697, - 8837309186596588911, - 1081143755093508499 - ], - "infinity": false - }, - { - "x": [ - 2655654413304275855, - 4244723109566147837, - 12150359360501203194, - 3338981627918702615 - ], - "y": [ - 2522870072161287404, - 17341373219317210182, - 13058930363994599297, - 210373422168410518 - ], - "infinity": false - }, - { - "x": [ - 16728834675380740056, - 2139390496020366235, - 9480389182940223467, - 2279560291896695719 - ], - "y": [ - 12461418813218976432, - 357566005384566098, - 5295578385080568808, - 1801243085576438875 - ], - "infinity": false - }, - { - "x": [ - 8716201428771436123, - 3392394702404760386, - 9990956922582058945, - 1388317411153212399 - ], - "y": [ - 11666415392681680155, - 10553517485129490455, - 16061047708722635939, - 2386622646140901822 - ], - "infinity": false - }, - { - "x": [ - 16162432560623854812, - 15537581062716888632, - 12927223782958923606, - 2800634589869451227 - ], - "y": [ - 5345141365329635916, - 2224393250977631865, - 396527108738048188, - 2298318725146167177 - ], - "infinity": false - }, - { - "x": [ - 18372685954785469756, - 10436523365152935441, - 15509622927999798123, - 2050428620045833325 - ], - "y": [ - 4996265985148335658, - 6073112270434155721, - 4873288683270752338, - 503179567393027927 - ], - "infinity": false - } - ], - "gate_selectors_commitments": [ - { - "x": [ - 4986139828502830074, - 8644425445976253042, - 4851433922656693398, - 1419574698085640872 - ], - "y": [ - 16192186537521161947, - 16183885683582261905, - 1655718756619164666, - 3420236094426390604 - ], - "infinity": false - }, - { - "x": [ - 10727231722644915889, - 13777116005624794169, - 1422623412369619026, - 1701279717637612575 - ], - "y": [ - 6503647097427010249, - 6381043883853023011, - 15391366286376907281, - 1261207976874708261 - ], - "infinity": false - } - ], - "permutation_commitments": [ - { - "x": [ - 11852073725466955067, - 179170887563176222, - 17529899074897279348, - 2496783194148289461 - ], - "y": [ - 15490041181991978284, - 6745436372504113852, - 7017978386715410058, - 3482556315200370895 - ], - "infinity": false - }, - { - "x": [ - 1330152738947291505, - 1668990644246591877, - 6805443255260621096, - 1309987766073890626 - ], - "y": [ - 18322300356676620444, - 8225233874302527542, - 5744327785164342590, - 410571567010522636 - ], - "infinity": false - }, - { - "x": [ - 13968210937929584911, - 17067601391996082961, - 4861463652254416951, - 2147834012714370408 - ], - "y": [ - 9012483356698219484, - 8660929519763525826, - 17744882010750642463, - 331423342438323189 - ], - "infinity": false - }, - { - "x": [ - 1352282553299127274, - 8587971715415488300, - 2471024479841756772, - 1239586065229072559 - ], - "y": [ - 1597792022909153930, - 5020991346876715357, - 5622801511814109910, - 1916460940163680567 - ], - "infinity": false - } - ], - "total_lookup_entries_length": 46287674, - "lookup_selector_commitment": { - "x": [ - 11573469000684493293, - 15304040816406013002, - 9206902553183544808, - 2597693769113957036 - ], - "y": [ - 10538181061926273477, - 5239567589495426242, - 3627181047901924882, - 302644994241575377 - ], - "infinity": false - }, - "lookup_tables_commitments": [ - { - "x": [ - 5134795695995115566, - 12287750992060803275, - 3112021177339560487, - 2737779104829043419 - ], - "y": [ - 12960786984497012138, - 17246059378047870426, - 11486754204718893642, - 46104506716724806 - ], - "infinity": false - }, - { - "x": [ - 148472607159578301, - 1393814398025790148, - 13651878286378332448, - 3460878321325997474 - ], - "y": [ - 10791022888598424744, - 1931353219232076143, - 12342018346439101174, - 23632989633122111 - ], - "infinity": false - }, - { - "x": [ - 1355031833403957875, - 10754997913401276231, - 8672292473740482178, - 3014145653612856517 - ], - "y": [ - 3728402825933673134, - 16492594359417243041, - 14619929139939206930, - 2894280666048705144 - ], - "infinity": false - }, - { - "x": [ - 11362104917939269301, - 3050269804312222606, - 17884269955997757593, - 2804911625130359365 - ], - "y": [ - 9563576475625880180, - 9736108320914226650, - 11545696954602328389, - 1108440262014676246 - ], - "infinity": false - } - ], - "lookup_table_type_commitment": { - "x": [ - 5367643753678334453, - 18149093736372716410, - 1335188566370936146, - 668596617655217713 - ], - "y": [ - 9984652217894703540, - 16253861114794085212, - 2139268495406835151, - 710303505771002735 - ], - "infinity": false - }, - "non_residues": [ - [ - 5, - 0, - 0, - 0 - ], - [ - 7, - 0, - 0, - 0 - ], - [ - 10, - 0, - 0, - 0 - ] - ], - "g2_elements": [ - { - "x": { - "c0": [ - 5106727233969649389, - 7440829307424791261, - 4785637993704342649, - 1729627375292849782 - ], - "c1": [ - 10945020018377822914, - 17413811393473931026, - 8241798111626485029, - 1841571559660931130 - ] - }, - "y": { - "c0": [ - 5541340697920699818, - 16416156555105522555, - 5380518976772849807, - 1353435754470862315 - ], - "c1": [ - 6173549831154472795, - 13567992399387660019, - 17050234209342075797, - 650358724130500725 - ] - }, - "infinity": false - }, - { - "x": { - "c0": [ - 9089143573911733168, - 11482283522806384523, - 13585589533905622862, - 79029415676722370 - ], - "c1": [ - 5692040832573735873, - 16884514497384809355, - 16717166481813659368, - 2742131088506155463 - ] - }, - "y": { - "c0": [ - 9604638503594647125, - 1289961608472612514, - 6217038149984805214, - 2521661352385209130 - ], - "c1": [ - 17168069778630926308, - 11309277837895768996, - 15154989611154567813, - 359271377050603491 - ] - }, - "infinity": false - } - ] -} \ No newline at end of file diff --git a/core/bin/verification_key_generator_and_server/data/verification_13_key.json b/core/bin/verification_key_generator_and_server/data/verification_13_key.json deleted file mode 100644 index 73ffbd212002..000000000000 --- a/core/bin/verification_key_generator_and_server/data/verification_13_key.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "n": 67108863, - "num_inputs": 1, - "state_width": 4, - "num_witness_polys": 0, - "gate_setup_commitments": [ - { - "x": [ - 17551054392858982554, - 6093238351564742844, - 9461983640740135929, - 665917981733823732 - ], - "y": [ - 5039211542045701927, - 14102316155129161178, - 7599318237652648682, - 1484263542771007309 - ], - "infinity": false - }, - { - "x": [ - 14015566113565304739, - 12895182424777444911, - 5150482782915031712, - 3280776276671330755 - ], - "y": [ - 5503211683737487414, - 5857977821275887356, - 1294122171191120577, - 2917900236095606783 - ], - "infinity": false - }, - { - "x": [ - 11180353512945796758, - 5467792637578213396, - 14862660111090994534, - 1678570344676416345 - ], - "y": [ - 16496106534540891926, - 4355829424666415263, - 8379906815867503783, - 2141225531456729878 - ], - "infinity": false - }, - { - "x": [ - 10512618919562577175, - 8909238001556772501, - 8669074760108324520, - 3259590816167766101 - ], - "y": [ - 15477336671232249792, - 10209451912771766896, - 13672268903388741173, - 682487251336397201 - ], - "infinity": false - }, - { - "x": [ - 14233534177298597555, - 14428793231398751908, - 18070433438826750034, - 1176819688107481869 - ], - "y": [ - 9251234182098356520, - 17131606126090989402, - 17185633762130361526, - 70013401388751862 - ], - "infinity": false - }, - { - "x": [ - 14148566925658671094, - 812517577375883951, - 5030512299767107864, - 44275794325016754 - ], - "y": [ - 3275438385460491589, - 12366768737850140720, - 10754478223029148744, - 64366431004577735 - ], - "infinity": false - }, - { - "x": [ - 5646513434714516506, - 12578668031398681290, - 6956692825033783810, - 536471110695536326 - ], - "y": [ - 876079378616587621, - 9787032999740439668, - 14965634813605966164, - 367083452910738472 - ], - "infinity": false - }, - { - "x": [ - 10902302115259229513, - 14044271471332330954, - 14571826360674828773, - 733766328575554031 - ], - "y": [ - 8186695183963076514, - 621472878958955881, - 14756382569165412398, - 3165780226323675661 - ], - "infinity": false - } - ], - "gate_selectors_commitments": [ - { - "x": [ - 17780673306296332984, - 10355922416617009060, - 5077451999006954761, - 2644291606399153501 - ], - "y": [ - 884498752701137122, - 731399349168706916, - 4286165746592754883, - 3279732117855760703 - ], - "infinity": false - }, - { - "x": [ - 11012802284910829398, - 7859388231941271159, - 17586341808458361180, - 1386364899721133297 - ], - "y": [ - 15634369655108108777, - 3858480397682251762, - 17706291110507066608, - 1663421415693803071 - ], - "infinity": false - } - ], - "permutation_commitments": [ - { - "x": [ - 18134041530736321349, - 4345724579806003155, - 2324407857452293002, - 2319164124977213120 - ], - "y": [ - 14302129084811449335, - 8588677756442252515, - 3323846949783670865, - 2109729211841784387 - ], - "infinity": false - }, - { - "x": [ - 14486843004985564085, - 10799247040254992370, - 7658639806933647132, - 2215292564171027727 - ], - "y": [ - 14258341133968554193, - 11685656973533320944, - 14111972937744219524, - 1172604679688980794 - ], - "infinity": false - }, - { - "x": [ - 12872375111956991701, - 14049784009914403066, - 15325016171856456312, - 2811875539960405333 - ], - "y": [ - 5711194902040443430, - 13827091592207472460, - 17950028361571343192, - 1672758585097311581 - ], - "infinity": false - }, - { - "x": [ - 11717525586585736911, - 730672019767199816, - 3010255132348992613, - 2780587454575324896 - ], - "y": [ - 1473124157542628664, - 1573646910034288561, - 10026766074599473146, - 563223750818543582 - ], - "infinity": false - } - ], - "total_lookup_entries_length": 42547753, - "lookup_selector_commitment": { - "x": [ - 4539928924349895484, - 2792770915461027618, - 11611697420465472575, - 1384307956752801018 - ], - "y": [ - 8840366360901511807, - 8892919985613263102, - 11941090149541110830, - 1930352681887390920 - ], - "infinity": false - }, - "lookup_tables_commitments": [ - { - "x": [ - 631990924006796604, - 16139625628991115157, - 13331739325995827711, - 1062301837743594995 - ], - "y": [ - 15303054606290800139, - 15906872095881647437, - 7093896572295020249, - 1342952934989901142 - ], - "infinity": false - }, - { - "x": [ - 7983921919542246393, - 13296544189644416678, - 17081022784392007697, - 1980832835348244027 - ], - "y": [ - 10874958134865200330, - 7702740658637630534, - 14052057929798961943, - 3193353539419869016 - ], - "infinity": false - }, - { - "x": [ - 1114587284824996932, - 4636906500482867924, - 15328247172597030456, - 87946895873973686 - ], - "y": [ - 15573033830207915877, - 5194694185599035278, - 2562407345425607214, - 2782078999306862675 - ], - "infinity": false - }, - { - "x": [ - 18225112781127431982, - 18048613958187123807, - 7325490730844456621, - 1953409020724855888 - ], - "y": [ - 7577000130125917198, - 6193701449695751861, - 4102082927677054717, - 395350071385269650 - ], - "infinity": false - } - ], - "lookup_table_type_commitment": { - "x": [ - 4121704254446914578, - 13863658665929861884, - 15362282368839162345, - 2762703036966024619 - ], - "y": [ - 102846692212239082, - 14904466746900448136, - 16872429770359000841, - 1687152581020907098 - ], - "infinity": false - }, - "non_residues": [ - [ - 5, - 0, - 0, - 0 - ], - [ - 7, - 0, - 0, - 0 - ], - [ - 10, - 0, - 0, - 0 - ] - ], - "g2_elements": [ - { - "x": { - "c0": [ - 5106727233969649389, - 7440829307424791261, - 4785637993704342649, - 1729627375292849782 - ], - "c1": [ - 10945020018377822914, - 17413811393473931026, - 8241798111626485029, - 1841571559660931130 - ] - }, - "y": { - "c0": [ - 5541340697920699818, - 16416156555105522555, - 5380518976772849807, - 1353435754470862315 - ], - "c1": [ - 6173549831154472795, - 13567992399387660019, - 17050234209342075797, - 650358724130500725 - ] - }, - "infinity": false - }, - { - "x": { - "c0": [ - 9089143573911733168, - 11482283522806384523, - 13585589533905622862, - 79029415676722370 - ], - "c1": [ - 5692040832573735873, - 16884514497384809355, - 16717166481813659368, - 2742131088506155463 - ] - }, - "y": { - "c0": [ - 9604638503594647125, - 1289961608472612514, - 6217038149984805214, - 2521661352385209130 - ], - "c1": [ - 17168069778630926308, - 11309277837895768996, - 15154989611154567813, - 359271377050603491 - ] - }, - "infinity": false - } - ] -} \ No newline at end of file diff --git a/core/bin/verification_key_generator_and_server/data/verification_14_key.json b/core/bin/verification_key_generator_and_server/data/verification_14_key.json deleted file mode 100644 index e8c42d407e35..000000000000 --- a/core/bin/verification_key_generator_and_server/data/verification_14_key.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "n": 67108863, - "num_inputs": 1, - "state_width": 4, - "num_witness_polys": 0, - "gate_setup_commitments": [ - { - "x": [ - 6916434521451934576, - 614815553772638285, - 3742595993843812033, - 2823214088432624432 - ], - "y": [ - 11642815096362884283, - 18063950820723921281, - 6353943092001719992, - 3201898419478369298 - ], - "infinity": false - }, - { - "x": [ - 10647237757917239762, - 1269177049592707998, - 2650053775033150725, - 582198744757304104 - ], - "y": [ - 9804667267596536998, - 493663115027956828, - 13953159385227792767, - 1568248765042207679 - ], - "infinity": false - }, - { - "x": [ - 7910659438561833906, - 12456422925439856914, - 10869604528749370003, - 1213616301038416610 - ], - "y": [ - 2606202790862698157, - 6809934263763206210, - 17472080335242458272, - 2884639755368519501 - ], - "infinity": false - }, - { - "x": [ - 14211325859682683183, - 11018598407116786751, - 10064425366978091674, - 2748595948091261209 - ], - "y": [ - 13960202853590116423, - 1211975538022172568, - 16303435518817750320, - 1634234707214097860 - ], - "infinity": false - }, - { - "x": [ - 4528591178982443847, - 16310104707629911601, - 5532120103079323919, - 1347877820087040669 - ], - "y": [ - 17983603511717948746, - 9529659424488112452, - 7820918413906679254, - 1819855238351369466 - ], - "infinity": false - }, - { - "x": [ - 14415562798118912210, - 6550719056383417327, - 424281724891761932, - 1264340531903932141 - ], - "y": [ - 7768057951329404686, - 15024442753889769568, - 9676935351692818899, - 1492251668690310932 - ], - "infinity": false - }, - { - "x": [ - 2619366878850208112, - 12150914745315976156, - 8375197026043390274, - 1935272977563031501 - ], - "y": [ - 5381369692389055354, - 17978011500330472972, - 17420193441326928998, - 479187691463910357 - ], - "infinity": false - }, - { - "x": [ - 8720830951139717797, - 15985700059986022675, - 11876530273787337931, - 421322430672290976 - ], - "y": [ - 9700690437922183179, - 1976785701667862157, - 16634886936358874061, - 3002178567925406588 - ], - "infinity": false - } - ], - "gate_selectors_commitments": [ - { - "x": [ - 8284083154661042764, - 11776500066398184343, - 868620904897679124, - 2988582549909766892 - ], - "y": [ - 10794129605563176627, - 15487634480061313925, - 17194646451372113884, - 2087686927573540537 - ], - "infinity": false - }, - { - "x": [ - 7916190330285050096, - 11731220788334102406, - 6221883233572429550, - 2552280229203107267 - ], - "y": [ - 10510502959728300366, - 14682539966609739595, - 8275243146917870162, - 164811532254637923 - ], - "infinity": false - } - ], - "permutation_commitments": [ - { - "x": [ - 195850038587200624, - 10136289160450054078, - 4386512701252721226, - 219366815902177323 - ], - "y": [ - 12042545079209848932, - 599057886584676736, - 14545610403811537682, - 498958995843318019 - ], - "infinity": false - }, - { - "x": [ - 4721932753701441297, - 1676671918244393403, - 6943597542294442696, - 50994782040503038 - ], - "y": [ - 8321420884695240511, - 10606883887907326697, - 11471075822795411018, - 1311422627151559437 - ], - "infinity": false - }, - { - "x": [ - 85448132386017640, - 13016912343020112485, - 11647418800345296605, - 1741562939125330787 - ], - "y": [ - 10753835454658443286, - 8646325836340244979, - 7348777908140142985, - 2196062626460604424 - ], - "infinity": false - }, - { - "x": [ - 2125624295892265840, - 12754141819506101591, - 8789168208880604752, - 947087620272222934 - ], - "y": [ - 12566258871261234263, - 12307504590191426495, - 6700589767183706452, - 1828704371386663334 - ], - "infinity": false - } - ], - "total_lookup_entries_length": 42212029, - "lookup_selector_commitment": { - "x": [ - 7709849601046260359, - 6836713108454667472, - 17360769186231334246, - 2348971634881039863 - ], - "y": [ - 13380830060569421804, - 15446653016734774164, - 17884501636917484387, - 1386904567459265970 - ], - "infinity": false - }, - "lookup_tables_commitments": [ - { - "x": [ - 631990924006796604, - 16139625628991115157, - 13331739325995827711, - 1062301837743594995 - ], - "y": [ - 15303054606290800139, - 15906872095881647437, - 7093896572295020249, - 1342952934989901142 - ], - "infinity": false - }, - { - "x": [ - 7983921919542246393, - 13296544189644416678, - 17081022784392007697, - 1980832835348244027 - ], - "y": [ - 10874958134865200330, - 7702740658637630534, - 14052057929798961943, - 3193353539419869016 - ], - "infinity": false - }, - { - "x": [ - 1114587284824996932, - 4636906500482867924, - 15328247172597030456, - 87946895873973686 - ], - "y": [ - 15573033830207915877, - 5194694185599035278, - 2562407345425607214, - 2782078999306862675 - ], - "infinity": false - }, - { - "x": [ - 18225112781127431982, - 18048613958187123807, - 7325490730844456621, - 1953409020724855888 - ], - "y": [ - 7577000130125917198, - 6193701449695751861, - 4102082927677054717, - 395350071385269650 - ], - "infinity": false - } - ], - "lookup_table_type_commitment": { - "x": [ - 6960699536013090594, - 2075384204892265266, - 12053931571725248687, - 1371193846897305849 - ], - "y": [ - 8904850119058507432, - 10465598889525773001, - 16159541505228012497, - 1982452464017823539 - ], - "infinity": false - }, - "non_residues": [ - [ - 5, - 0, - 0, - 0 - ], - [ - 7, - 0, - 0, - 0 - ], - [ - 10, - 0, - 0, - 0 - ] - ], - "g2_elements": [ - { - "x": { - "c0": [ - 5106727233969649389, - 7440829307424791261, - 4785637993704342649, - 1729627375292849782 - ], - "c1": [ - 10945020018377822914, - 17413811393473931026, - 8241798111626485029, - 1841571559660931130 - ] - }, - "y": { - "c0": [ - 5541340697920699818, - 16416156555105522555, - 5380518976772849807, - 1353435754470862315 - ], - "c1": [ - 6173549831154472795, - 13567992399387660019, - 17050234209342075797, - 650358724130500725 - ] - }, - "infinity": false - }, - { - "x": { - "c0": [ - 9089143573911733168, - 11482283522806384523, - 13585589533905622862, - 79029415676722370 - ], - "c1": [ - 5692040832573735873, - 16884514497384809355, - 16717166481813659368, - 2742131088506155463 - ] - }, - "y": { - "c0": [ - 9604638503594647125, - 1289961608472612514, - 6217038149984805214, - 2521661352385209130 - ], - "c1": [ - 17168069778630926308, - 11309277837895768996, - 15154989611154567813, - 359271377050603491 - ] - }, - "infinity": false - } - ] -} \ No newline at end of file diff --git a/core/bin/verification_key_generator_and_server/data/verification_15_key.json b/core/bin/verification_key_generator_and_server/data/verification_15_key.json deleted file mode 100644 index 356dbb3c531a..000000000000 --- a/core/bin/verification_key_generator_and_server/data/verification_15_key.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "n": 67108863, - "num_inputs": 1, - "state_width": 4, - "num_witness_polys": 0, - "gate_setup_commitments": [ - { - "x": [ - 3227382513538635502, - 10189582412003011525, - 1928710987967879299, - 1641062823248805930 - ], - "y": [ - 3271795224553087841, - 14036363906521936156, - 10253705337161624780, - 3091191233208402889 - ], - "infinity": false - }, - { - "x": [ - 3541471743181642086, - 8117051273006688414, - 685909872467163024, - 2614724468827209722 - ], - "y": [ - 1096952120887201428, - 8197980407203032569, - 3949713006885563085, - 2838982585728277197 - ], - "infinity": false - }, - { - "x": [ - 12432945880074879560, - 13444859845042471186, - 16599097070979057001, - 3064039790213026567 - ], - "y": [ - 3745088406100356357, - 11715355314289478148, - 2282946417129489745, - 1619614407449915711 - ], - "infinity": false - }, - { - "x": [ - 6864310053920223866, - 11095455024311706186, - 12229748247000682102, - 2475016349586561501 - ], - "y": [ - 2946781066962542712, - 14275500021265062654, - 7624481756022778467, - 1439658776940615826 - ], - "infinity": false - }, - { - "x": [ - 13589273139905087785, - 10411035015021574213, - 7322465558208873130, - 1805943743448229826 - ], - "y": [ - 13035238946064559886, - 8309482746549063820, - 14229757515324464781, - 1676135665275665956 - ], - "infinity": false - }, - { - "x": [ - 84006308859404982, - 13783127238980064918, - 14101945786439708601, - 3343881426944938693 - ], - "y": [ - 11959320721291234482, - 7288504259378326725, - 9638777183731403514, - 1648453409181088010 - ], - "infinity": false - }, - { - "x": [ - 10987163680360734145, - 3374907765066907489, - 14421201974855570464, - 3148542489906320493 - ], - "y": [ - 17180031485000081847, - 1609372527008367113, - 6050341427989573858, - 477684541505306009 - ], - "infinity": false - }, - { - "x": [ - 2257028353691713628, - 6330174784373016532, - 1686021628649718039, - 2159927805963705967 - ], - "y": [ - 10814125155819336479, - 9673780307204445954, - 7995606758095566598, - 2252251279727988680 - ], - "infinity": false - } - ], - "gate_selectors_commitments": [ - { - "x": [ - 12209724104183572477, - 11631007075974892904, - 18407423517909669447, - 1123848354500646471 - ], - "y": [ - 4749227851055533192, - 16918951234067984229, - 5345146076707243019, - 2836719468222132526 - ], - "infinity": false - }, - { - "x": [ - 7250866110466496804, - 16022969863388101391, - 16334300930347324147, - 2232272485807431638 - ], - "y": [ - 257675104580526310, - 8044331403028603186, - 2070174268860891010, - 412313474208091695 - ], - "infinity": false - } - ], - "permutation_commitments": [ - { - "x": [ - 6736882681315025594, - 13400430183084617843, - 17182588928882896917, - 413858188107207402 - ], - "y": [ - 11944170108613027081, - 10598841640624895850, - 9086311820289524704, - 994240611047161478 - ], - "infinity": false - }, - { - "x": [ - 9500318283622871785, - 5480449932874899465, - 13224510306395939252, - 1891329668301281157 - ], - "y": [ - 7314078756040350933, - 1023294602177498218, - 16475078688698425911, - 1793945182112302214 - ], - "infinity": false - }, - { - "x": [ - 17207548058425781429, - 2519222249126358251, - 16087595361924038018, - 3470846273906312296 - ], - "y": [ - 7578361094884620755, - 7082109151721400218, - 13675372677342046523, - 3204472226310685459 - ], - "infinity": false - }, - { - "x": [ - 7036282717341939568, - 3035419720331773758, - 6765191455902729185, - 1301973211946290083 - ], - "y": [ - 697377419426635450, - 14612037890797520515, - 11746079616766057625, - 1031190413179598818 - ], - "infinity": false - } - ], - "total_lookup_entries_length": 6391155, - "lookup_selector_commitment": { - "x": [ - 17111915492430945419, - 17971275185478677346, - 14211391044159602918, - 2381455978713737016 - ], - "y": [ - 13971515893527127207, - 7078722574057096191, - 6337080743811431820, - 757015217034494132 - ], - "infinity": false - }, - "lookup_tables_commitments": [ - { - "x": [ - 5825422128268478267, - 9219263846299851036, - 3879231702557190566, - 1702488722758880769 - ], - "y": [ - 18311881100262470992, - 5742998199368802392, - 18106865487471159417, - 502191980176920012 - ], - "infinity": false - }, - { - "x": [ - 17195892082859417081, - 7890531942603584793, - 2381805632820057528, - 3173232410464566465 - ], - "y": [ - 16359614627947132075, - 3459600273035137079, - 4550762061432972122, - 3394559699318358224 - ], - "infinity": false - }, - { - "x": [ - 1716103379277390185, - 18097936269579187542, - 16357329729761063450, - 1508640059338197502 - ], - "y": [ - 11014806739603983364, - 4396503314588777389, - 9397245609635151055, - 1703957955248411380 - ], - "infinity": false - }, - { - "x": [ - 4770171350693477354, - 17110558673192292253, - 9799800677557311408, - 761984875463445481 - ], - "y": [ - 1560561403388310063, - 31331275310848146, - 287152055803835484, - 457826332542037277 - ], - "infinity": false - } - ], - "lookup_table_type_commitment": { - "x": [ - 12452920133699897102, - 6896642231513345496, - 4655495116895575043, - 1453525729114564853 - ], - "y": [ - 3574087764464303986, - 10141819911397868785, - 2342639320036978232, - 556196027732983028 - ], - "infinity": false - }, - "non_residues": [ - [ - 5, - 0, - 0, - 0 - ], - [ - 7, - 0, - 0, - 0 - ], - [ - 10, - 0, - 0, - 0 - ] - ], - "g2_elements": [ - { - "x": { - "c0": [ - 5106727233969649389, - 7440829307424791261, - 4785637993704342649, - 1729627375292849782 - ], - "c1": [ - 10945020018377822914, - 17413811393473931026, - 8241798111626485029, - 1841571559660931130 - ] - }, - "y": { - "c0": [ - 5541340697920699818, - 16416156555105522555, - 5380518976772849807, - 1353435754470862315 - ], - "c1": [ - 6173549831154472795, - 13567992399387660019, - 17050234209342075797, - 650358724130500725 - ] - }, - "infinity": false - }, - { - "x": { - "c0": [ - 9089143573911733168, - 11482283522806384523, - 13585589533905622862, - 79029415676722370 - ], - "c1": [ - 5692040832573735873, - 16884514497384809355, - 16717166481813659368, - 2742131088506155463 - ] - }, - "y": { - "c0": [ - 9604638503594647125, - 1289961608472612514, - 6217038149984805214, - 2521661352385209130 - ], - "c1": [ - 17168069778630926308, - 11309277837895768996, - 15154989611154567813, - 359271377050603491 - ] - }, - "infinity": false - } - ] -} \ No newline at end of file diff --git a/core/bin/verification_key_generator_and_server/data/verification_16_key.json b/core/bin/verification_key_generator_and_server/data/verification_16_key.json deleted file mode 100644 index 356dbb3c531a..000000000000 --- a/core/bin/verification_key_generator_and_server/data/verification_16_key.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "n": 67108863, - "num_inputs": 1, - "state_width": 4, - "num_witness_polys": 0, - "gate_setup_commitments": [ - { - "x": [ - 3227382513538635502, - 10189582412003011525, - 1928710987967879299, - 1641062823248805930 - ], - "y": [ - 3271795224553087841, - 14036363906521936156, - 10253705337161624780, - 3091191233208402889 - ], - "infinity": false - }, - { - "x": [ - 3541471743181642086, - 8117051273006688414, - 685909872467163024, - 2614724468827209722 - ], - "y": [ - 1096952120887201428, - 8197980407203032569, - 3949713006885563085, - 2838982585728277197 - ], - "infinity": false - }, - { - "x": [ - 12432945880074879560, - 13444859845042471186, - 16599097070979057001, - 3064039790213026567 - ], - "y": [ - 3745088406100356357, - 11715355314289478148, - 2282946417129489745, - 1619614407449915711 - ], - "infinity": false - }, - { - "x": [ - 6864310053920223866, - 11095455024311706186, - 12229748247000682102, - 2475016349586561501 - ], - "y": [ - 2946781066962542712, - 14275500021265062654, - 7624481756022778467, - 1439658776940615826 - ], - "infinity": false - }, - { - "x": [ - 13589273139905087785, - 10411035015021574213, - 7322465558208873130, - 1805943743448229826 - ], - "y": [ - 13035238946064559886, - 8309482746549063820, - 14229757515324464781, - 1676135665275665956 - ], - "infinity": false - }, - { - "x": [ - 84006308859404982, - 13783127238980064918, - 14101945786439708601, - 3343881426944938693 - ], - "y": [ - 11959320721291234482, - 7288504259378326725, - 9638777183731403514, - 1648453409181088010 - ], - "infinity": false - }, - { - "x": [ - 10987163680360734145, - 3374907765066907489, - 14421201974855570464, - 3148542489906320493 - ], - "y": [ - 17180031485000081847, - 1609372527008367113, - 6050341427989573858, - 477684541505306009 - ], - "infinity": false - }, - { - "x": [ - 2257028353691713628, - 6330174784373016532, - 1686021628649718039, - 2159927805963705967 - ], - "y": [ - 10814125155819336479, - 9673780307204445954, - 7995606758095566598, - 2252251279727988680 - ], - "infinity": false - } - ], - "gate_selectors_commitments": [ - { - "x": [ - 12209724104183572477, - 11631007075974892904, - 18407423517909669447, - 1123848354500646471 - ], - "y": [ - 4749227851055533192, - 16918951234067984229, - 5345146076707243019, - 2836719468222132526 - ], - "infinity": false - }, - { - "x": [ - 7250866110466496804, - 16022969863388101391, - 16334300930347324147, - 2232272485807431638 - ], - "y": [ - 257675104580526310, - 8044331403028603186, - 2070174268860891010, - 412313474208091695 - ], - "infinity": false - } - ], - "permutation_commitments": [ - { - "x": [ - 6736882681315025594, - 13400430183084617843, - 17182588928882896917, - 413858188107207402 - ], - "y": [ - 11944170108613027081, - 10598841640624895850, - 9086311820289524704, - 994240611047161478 - ], - "infinity": false - }, - { - "x": [ - 9500318283622871785, - 5480449932874899465, - 13224510306395939252, - 1891329668301281157 - ], - "y": [ - 7314078756040350933, - 1023294602177498218, - 16475078688698425911, - 1793945182112302214 - ], - "infinity": false - }, - { - "x": [ - 17207548058425781429, - 2519222249126358251, - 16087595361924038018, - 3470846273906312296 - ], - "y": [ - 7578361094884620755, - 7082109151721400218, - 13675372677342046523, - 3204472226310685459 - ], - "infinity": false - }, - { - "x": [ - 7036282717341939568, - 3035419720331773758, - 6765191455902729185, - 1301973211946290083 - ], - "y": [ - 697377419426635450, - 14612037890797520515, - 11746079616766057625, - 1031190413179598818 - ], - "infinity": false - } - ], - "total_lookup_entries_length": 6391155, - "lookup_selector_commitment": { - "x": [ - 17111915492430945419, - 17971275185478677346, - 14211391044159602918, - 2381455978713737016 - ], - "y": [ - 13971515893527127207, - 7078722574057096191, - 6337080743811431820, - 757015217034494132 - ], - "infinity": false - }, - "lookup_tables_commitments": [ - { - "x": [ - 5825422128268478267, - 9219263846299851036, - 3879231702557190566, - 1702488722758880769 - ], - "y": [ - 18311881100262470992, - 5742998199368802392, - 18106865487471159417, - 502191980176920012 - ], - "infinity": false - }, - { - "x": [ - 17195892082859417081, - 7890531942603584793, - 2381805632820057528, - 3173232410464566465 - ], - "y": [ - 16359614627947132075, - 3459600273035137079, - 4550762061432972122, - 3394559699318358224 - ], - "infinity": false - }, - { - "x": [ - 1716103379277390185, - 18097936269579187542, - 16357329729761063450, - 1508640059338197502 - ], - "y": [ - 11014806739603983364, - 4396503314588777389, - 9397245609635151055, - 1703957955248411380 - ], - "infinity": false - }, - { - "x": [ - 4770171350693477354, - 17110558673192292253, - 9799800677557311408, - 761984875463445481 - ], - "y": [ - 1560561403388310063, - 31331275310848146, - 287152055803835484, - 457826332542037277 - ], - "infinity": false - } - ], - "lookup_table_type_commitment": { - "x": [ - 12452920133699897102, - 6896642231513345496, - 4655495116895575043, - 1453525729114564853 - ], - "y": [ - 3574087764464303986, - 10141819911397868785, - 2342639320036978232, - 556196027732983028 - ], - "infinity": false - }, - "non_residues": [ - [ - 5, - 0, - 0, - 0 - ], - [ - 7, - 0, - 0, - 0 - ], - [ - 10, - 0, - 0, - 0 - ] - ], - "g2_elements": [ - { - "x": { - "c0": [ - 5106727233969649389, - 7440829307424791261, - 4785637993704342649, - 1729627375292849782 - ], - "c1": [ - 10945020018377822914, - 17413811393473931026, - 8241798111626485029, - 1841571559660931130 - ] - }, - "y": { - "c0": [ - 5541340697920699818, - 16416156555105522555, - 5380518976772849807, - 1353435754470862315 - ], - "c1": [ - 6173549831154472795, - 13567992399387660019, - 17050234209342075797, - 650358724130500725 - ] - }, - "infinity": false - }, - { - "x": { - "c0": [ - 9089143573911733168, - 11482283522806384523, - 13585589533905622862, - 79029415676722370 - ], - "c1": [ - 5692040832573735873, - 16884514497384809355, - 16717166481813659368, - 2742131088506155463 - ] - }, - "y": { - "c0": [ - 9604638503594647125, - 1289961608472612514, - 6217038149984805214, - 2521661352385209130 - ], - "c1": [ - 17168069778630926308, - 11309277837895768996, - 15154989611154567813, - 359271377050603491 - ] - }, - "infinity": false - } - ] -} \ No newline at end of file diff --git a/core/bin/verification_key_generator_and_server/data/verification_17_key.json b/core/bin/verification_key_generator_and_server/data/verification_17_key.json deleted file mode 100644 index 4886f501712e..000000000000 --- a/core/bin/verification_key_generator_and_server/data/verification_17_key.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "n": 67108863, - "num_inputs": 1, - "state_width": 4, - "num_witness_polys": 0, - "gate_setup_commitments": [ - { - "x": [ - 17914331890341023175, - 5200903915088916638, - 7417971632353510341, - 989671567770015891 - ], - "y": [ - 2927207345798721401, - 12686845373576710402, - 977520799157489114, - 1882223742569339495 - ], - "infinity": false - }, - { - "x": [ - 17162848902278956536, - 16169550484471334725, - 10830640611178609260, - 1347016616567630867 - ], - "y": [ - 6224316231648682710, - 10518372790293065661, - 4887066336660303630, - 703109868065750569 - ], - "infinity": false - }, - { - "x": [ - 15783141083967762454, - 16153855592853073081, - 5667838393811413602, - 1552498518850981979 - ], - "y": [ - 4220445586486275972, - 13196202402039716924, - 17506868028821343237, - 2718319833724164541 - ], - "infinity": false - }, - { - "x": [ - 4896615254637588846, - 5804270398165250639, - 10274952983674590649, - 1937027782721476561 - ], - "y": [ - 14180244016629518742, - 1376497406583367686, - 11268467489552574214, - 2331396669725958189 - ], - "infinity": false - }, - { - "x": [ - 191294939748295885, - 2804205121966814820, - 3897841028303648224, - 3406986167359695085 - ], - "y": [ - 6000542982074572633, - 1697448874567677325, - 10313504031977824294, - 320347014349001728 - ], - "infinity": false - }, - { - "x": [ - 6817435454105168413, - 15823888625999007373, - 9766931118761036330, - 3392959293697897728 - ], - "y": [ - 3549039265311512008, - 4758653036115592629, - 219467419355603781, - 83059544477934848 - ], - "infinity": false - }, - { - "x": [ - 5038171725639341807, - 6859992384823395611, - 15284967171349293554, - 16807092603996758 - ], - "y": [ - 16504201956683368367, - 12931995037356002803, - 16812826192957092842, - 3169839139097845275 - ], - "infinity": false - }, - { - "x": [ - 7140480682142203727, - 9518528852331365100, - 6189914959408603471, - 535939568308325781 - ], - "y": [ - 5944679084532939174, - 17280810090456322382, - 3743919877743496107, - 1235924204609568068 - ], - "infinity": false - } - ], - "gate_selectors_commitments": [ - { - "x": [ - 1929812895882850703, - 10386198218814398503, - 17007521659662498274, - 1093092717342753672 - ], - "y": [ - 14834187133095267171, - 15506032964234961178, - 7626816120460943443, - 871778379365004315 - ], - "infinity": false - }, - { - "x": [ - 15660406110329165813, - 8146521122567923995, - 2421739551937359002, - 3037598346026174089 - ], - "y": [ - 526124545966722472, - 1168331442853419483, - 4128095883471549051, - 2951909971734725955 - ], - "infinity": false - } - ], - "permutation_commitments": [ - { - "x": [ - 6206240620508019400, - 3690935139087147193, - 15230272164329216928, - 2140680869789406894 - ], - "y": [ - 14967331981004447304, - 1624146052760537503, - 8986435052862626311, - 334011853307313390 - ], - "infinity": false - }, - { - "x": [ - 4342223064246074020, - 2037946044543710684, - 9057698479075332373, - 1955362957846693345 - ], - "y": [ - 13253375713250043938, - 6754658208742468331, - 9339617748652368850, - 3066524060291544175 - ], - "infinity": false - }, - { - "x": [ - 17765629723696241082, - 14243015821582305127, - 922013493526048847, - 186830516636733479 - ], - "y": [ - 14465184942185208224, - 11235596895177038197, - 5490682932088517686, - 1253279069662324930 - ], - "infinity": false - }, - { - "x": [ - 9369367805867402420, - 12663806522952881709, - 10184609326459106945, - 1664572000409921348 - ], - "y": [ - 4383960972942823390, - 6526609131568596717, - 1343118583674917141, - 113408414321095416 - ], - "infinity": false - } - ], - "total_lookup_entries_length": 6306340, - "lookup_selector_commitment": { - "x": [ - 8662938005624859815, - 9126108646717466191, - 14321121874090966307, - 2777446762308933634 - ], - "y": [ - 12555265159079607081, - 9054928862248682392, - 2784170007581120117, - 1769718192676345815 - ], - "infinity": false - }, - "lookup_tables_commitments": [ - { - "x": [ - 631990924006796604, - 16139625628991115157, - 13331739325995827711, - 1062301837743594995 - ], - "y": [ - 15303054606290800139, - 15906872095881647437, - 7093896572295020249, - 1342952934989901142 - ], - "infinity": false - }, - { - "x": [ - 7983921919542246393, - 13296544189644416678, - 17081022784392007697, - 1980832835348244027 - ], - "y": [ - 10874958134865200330, - 7702740658637630534, - 14052057929798961943, - 3193353539419869016 - ], - "infinity": false - }, - { - "x": [ - 1114587284824996932, - 4636906500482867924, - 15328247172597030456, - 87946895873973686 - ], - "y": [ - 15573033830207915877, - 5194694185599035278, - 2562407345425607214, - 2782078999306862675 - ], - "infinity": false - }, - { - "x": [ - 18225112781127431982, - 18048613958187123807, - 7325490730844456621, - 1953409020724855888 - ], - "y": [ - 7577000130125917198, - 6193701449695751861, - 4102082927677054717, - 395350071385269650 - ], - "infinity": false - } - ], - "lookup_table_type_commitment": { - "x": [ - 12644448349947379666, - 16345179309557779118, - 10854030671875297787, - 1358228639202695992 - ], - "y": [ - 2673142241557152443, - 11674634738064487673, - 12992693662201776412, - 1888958170754620568 - ], - "infinity": false - }, - "non_residues": [ - [ - 5, - 0, - 0, - 0 - ], - [ - 7, - 0, - 0, - 0 - ], - [ - 10, - 0, - 0, - 0 - ] - ], - "g2_elements": [ - { - "x": { - "c0": [ - 5106727233969649389, - 7440829307424791261, - 4785637993704342649, - 1729627375292849782 - ], - "c1": [ - 10945020018377822914, - 17413811393473931026, - 8241798111626485029, - 1841571559660931130 - ] - }, - "y": { - "c0": [ - 5541340697920699818, - 16416156555105522555, - 5380518976772849807, - 1353435754470862315 - ], - "c1": [ - 6173549831154472795, - 13567992399387660019, - 17050234209342075797, - 650358724130500725 - ] - }, - "infinity": false - }, - { - "x": { - "c0": [ - 9089143573911733168, - 11482283522806384523, - 13585589533905622862, - 79029415676722370 - ], - "c1": [ - 5692040832573735873, - 16884514497384809355, - 16717166481813659368, - 2742131088506155463 - ] - }, - "y": { - "c0": [ - 9604638503594647125, - 1289961608472612514, - 6217038149984805214, - 2521661352385209130 - ], - "c1": [ - 17168069778630926308, - 11309277837895768996, - 15154989611154567813, - 359271377050603491 - ] - }, - "infinity": false - } - ] -} \ No newline at end of file diff --git a/core/bin/verification_key_generator_and_server/data/verification_18_key.json b/core/bin/verification_key_generator_and_server/data/verification_18_key.json deleted file mode 100644 index 0987039dd1fa..000000000000 --- a/core/bin/verification_key_generator_and_server/data/verification_18_key.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "n": 67108863, - "num_inputs": 1, - "state_width": 4, - "num_witness_polys": 0, - "gate_setup_commitments": [ - { - "x": [ - 8828437332483635107, - 13777915698231175292, - 11504510351588004199, - 2516385517175522236 - ], - "y": [ - 1530453459325046685, - 2126477283125660971, - 6874073688275717548, - 2971751478402184988 - ], - "infinity": false - }, - { - "x": [ - 3490885152333630169, - 4123320877294819459, - 5138828731030738163, - 3039569146695764058 - ], - "y": [ - 10725322881860790776, - 1512262420257872325, - 10563843054743673205, - 447776577449487981 - ], - "infinity": false - }, - { - "x": [ - 14957646468235752771, - 6216555943494703122, - 7827110015048654177, - 2702223139144227095 - ], - "y": [ - 505353369980003046, - 9687811614109626117, - 5346740791392836415, - 1340467989233731971 - ], - "infinity": false - }, - { - "x": [ - 3201028595190213325, - 9659059230246338206, - 901122635500995415, - 765851963674764103 - ], - "y": [ - 10609226610841230792, - 8145519080052709505, - 17851750066177581293, - 362176586681460505 - ], - "infinity": false - }, - { - "x": [ - 13374935211181268625, - 1347742735582506393, - 4588995338963087243, - 94453217016201562 - ], - "y": [ - 4077548225372117006, - 11859845367084549583, - 2736752177668563039, - 1134818940315684409 - ], - "infinity": false - }, - { - "x": [ - 9467178015658262369, - 10545965721679492606, - 5726831550010619228, - 2051827871593168334 - ], - "y": [ - 6169140154733194545, - 5574043976386236933, - 12140759986363309479, - 1521273866181786590 - ], - "infinity": false - }, - { - "x": [ - 9642818207174528085, - 15617465062711953088, - 11263174413902929450, - 639683138088730423 - ], - "y": [ - 15150652293369779803, - 11338278639695990684, - 12204993260723588081, - 2039902155290309382 - ], - "infinity": false - }, - { - "x": [ - 7292405600450693833, - 573142590034645775, - 1583019100043676600, - 1978695840953226358 - ], - "y": [ - 5154489367309996043, - 8763740977657654022, - 9821219773990064941, - 2636875463267519559 - ], - "infinity": false - } - ], - "gate_selectors_commitments": [ - { - "x": [ - 2075450237700219880, - 2920304484074114568, - 8294843245052708759, - 555293007149161182 - ], - "y": [ - 6360019558055677441, - 7673047654179899818, - 10263007591992092214, - 2148859098846651643 - ], - "infinity": false - }, - { - "x": [ - 3970783323754285443, - 13019363829879217592, - 18197490676081603277, - 630296172623407012 - ], - "y": [ - 7987745494904024640, - 9631048689610078757, - 1592818072678520163, - 2678374240960081558 - ], - "infinity": false - } - ], - "permutation_commitments": [ - { - "x": [ - 3055966415338102721, - 18231075292903695376, - 9187400351012014001, - 2311743062653684305 - ], - "y": [ - 2553578246375478674, - 930511927228692161, - 2271826946385879571, - 3124263363559878329 - ], - "infinity": false - }, - { - "x": [ - 6936812562216228782, - 15195638439305648290, - 17827467578192758430, - 2674740411261002393 - ], - "y": [ - 9738743088557108685, - 17225541903460577384, - 16627013813461429872, - 494410407050490065 - ], - "infinity": false - }, - { - "x": [ - 10570962909758341245, - 18167360144953681397, - 2744925075742623060, - 736412139310579435 - ], - "y": [ - 13849279071386536985, - 10093748777935480433, - 904764951143479286, - 138814932031469939 - ], - "infinity": false - }, - { - "x": [ - 4533871929444677010, - 10106157783629999301, - 4178648893377901718, - 3164693318611048089 - ], - "y": [ - 12699039702383686311, - 4388078229442418460, - 8961813905523894854, - 570254591975307765 - ], - "infinity": false - } - ], - "total_lookup_entries_length": 18884644, - "lookup_selector_commitment": { - "x": [ - 15022814412717317376, - 17444332185630324119, - 14685665421775887958, - 906494215348891007 - ], - "y": [ - 9833778905776399360, - 1648124311168457783, - 3500435402371619753, - 2370413643071351216 - ], - "infinity": false - }, - "lookup_tables_commitments": [ - { - "x": [ - 631990924006796604, - 16139625628991115157, - 13331739325995827711, - 1062301837743594995 - ], - "y": [ - 15303054606290800139, - 15906872095881647437, - 7093896572295020249, - 1342952934989901142 - ], - "infinity": false - }, - { - "x": [ - 7983921919542246393, - 13296544189644416678, - 17081022784392007697, - 1980832835348244027 - ], - "y": [ - 10874958134865200330, - 7702740658637630534, - 14052057929798961943, - 3193353539419869016 - ], - "infinity": false - }, - { - "x": [ - 1114587284824996932, - 4636906500482867924, - 15328247172597030456, - 87946895873973686 - ], - "y": [ - 15573033830207915877, - 5194694185599035278, - 2562407345425607214, - 2782078999306862675 - ], - "infinity": false - }, - { - "x": [ - 18225112781127431982, - 18048613958187123807, - 7325490730844456621, - 1953409020724855888 - ], - "y": [ - 7577000130125917198, - 6193701449695751861, - 4102082927677054717, - 395350071385269650 - ], - "infinity": false - } - ], - "lookup_table_type_commitment": { - "x": [ - 8321950609730151216, - 18010887235457883784, - 17038267498493175776, - 1380842840607309871 - ], - "y": [ - 3264160671000273944, - 16611917363401804468, - 8505391859632632917, - 2149881676646664319 - ], - "infinity": false - }, - "non_residues": [ - [ - 5, - 0, - 0, - 0 - ], - [ - 7, - 0, - 0, - 0 - ], - [ - 10, - 0, - 0, - 0 - ] - ], - "g2_elements": [ - { - "x": { - "c0": [ - 5106727233969649389, - 7440829307424791261, - 4785637993704342649, - 1729627375292849782 - ], - "c1": [ - 10945020018377822914, - 17413811393473931026, - 8241798111626485029, - 1841571559660931130 - ] - }, - "y": { - "c0": [ - 5541340697920699818, - 16416156555105522555, - 5380518976772849807, - 1353435754470862315 - ], - "c1": [ - 6173549831154472795, - 13567992399387660019, - 17050234209342075797, - 650358724130500725 - ] - }, - "infinity": false - }, - { - "x": { - "c0": [ - 9089143573911733168, - 11482283522806384523, - 13585589533905622862, - 79029415676722370 - ], - "c1": [ - 5692040832573735873, - 16884514497384809355, - 16717166481813659368, - 2742131088506155463 - ] - }, - "y": { - "c0": [ - 9604638503594647125, - 1289961608472612514, - 6217038149984805214, - 2521661352385209130 - ], - "c1": [ - 17168069778630926308, - 11309277837895768996, - 15154989611154567813, - 359271377050603491 - ] - }, - "infinity": false - } - ] -} \ No newline at end of file diff --git a/core/bin/verification_key_generator_and_server/data/verification_1_key.json b/core/bin/verification_key_generator_and_server/data/verification_1_key.json deleted file mode 100644 index 0310303d2a53..000000000000 --- a/core/bin/verification_key_generator_and_server/data/verification_1_key.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "n": 67108863, - "num_inputs": 1, - "state_width": 4, - "num_witness_polys": 0, - "gate_setup_commitments": [ - { - "x": [ - 7601801432079276288, - 15201863322122857773, - 8806193975262404580, - 2590787273683229105 - ], - "y": [ - 16702527967956763728, - 6181870639994435984, - 1867123357108619315, - 2767403024411663364 - ], - "infinity": false - }, - { - "x": [ - 2455316591212726341, - 2027771240685247927, - 10685588854446154162, - 3030775657966372875 - ], - "y": [ - 18300009037843703356, - 1612973442135305251, - 10693350009422283513, - 1442590213691840716 - ], - "infinity": false - }, - { - "x": [ - 12311884457715965312, - 10390638194798557018, - 11306832124741148566, - 300716765354847473 - ], - "y": [ - 9707964220031061231, - 14753080439380196493, - 5717535245627190368, - 702219636062983319 - ], - "infinity": false - }, - { - "x": [ - 7758453297146426337, - 1673770484163252092, - 14607544807007157753, - 857313958429629763 - ], - "y": [ - 14921629410308576937, - 15298335487420996140, - 2704982045392946878, - 2611590721009022852 - ], - "infinity": false - }, - { - "x": [ - 14311011031579784592, - 15625526098906078640, - 1319146597092063841, - 774276845418764858 - ], - "y": [ - 3893523842912943845, - 18146056093503974553, - 11030513442747849089, - 389965813625175232 - ], - "infinity": false - }, - { - "x": [ - 7007915445081129178, - 2401922490835966325, - 418720827124106725, - 2770268368066902308 - ], - "y": [ - 12116308634970006696, - 14528630571959109449, - 9950799281726780069, - 724152027617190422 - ], - "infinity": false - }, - { - "x": [ - 2442021019274420960, - 16295185893380203674, - 2439146651414642189, - 2243335375830582173 - ], - "y": [ - 3782090054162740071, - 4704457281172608987, - 4410900061257118309, - 764611777065564766 - ], - "infinity": false - }, - { - "x": [ - 17964884224938230037, - 7876675311267561320, - 16762398450655445790, - 1210707988542142007 - ], - "y": [ - 10470358785861361347, - 9485656365593190672, - 6046378362748740079, - 2457285875935475197 - ], - "infinity": false - } - ], - "gate_selectors_commitments": [ - { - "x": [ - 17157526827088368172, - 11284084393440625999, - 9351565798611728109, - 3234841809825307363 - ], - "y": [ - 8319704714678793930, - 4159327153032521498, - 15356346081767327573, - 3239913585027348493 - ], - "infinity": false - }, - { - "x": [ - 15456321646261647359, - 15891438700803416959, - 3317730603133051465, - 2641175705943818316 - ], - "y": [ - 1411951218052246200, - 1661720531643832913, - 13537400120511760371, - 2292851110898807736 - ], - "infinity": false - } - ], - "permutation_commitments": [ - { - "x": [ - 10328956753700766823, - 2827084848292920926, - 6753362467616392790, - 3266354497443915853 - ], - "y": [ - 4786671171082888838, - 11071539213550223285, - 3886224490311829958, - 1435384580945051012 - ], - "infinity": false - }, - { - "x": [ - 6970901872301032061, - 11845499850875638451, - 12523013241874863158, - 564589203700245768 - ], - "y": [ - 9149991346853645253, - 10833082414663634622, - 10032445307744641248, - 3184550747076826571 - ], - "infinity": false - }, - { - "x": [ - 2899501934612768796, - 7289832407727333580, - 15398305180487198919, - 2955735241334744486 - ], - "y": [ - 4963499698281910643, - 5723522390488208800, - 3637467607919864741, - 339118267031086794 - ], - "infinity": false - }, - { - "x": [ - 16561673014946600686, - 6893642268089467710, - 11554023210615815565, - 122477375056362239 - ], - "y": [ - 15978560303000591303, - 6087766803442805629, - 6114779478264008006, - 2753348573959524636 - ], - "infinity": false - } - ], - "total_lookup_entries_length": 30899639, - "lookup_selector_commitment": { - "x": [ - 4819118611809066421, - 16205075690681881406, - 8088108199972047891, - 2462381205202312681 - ], - "y": [ - 9403235417076804812, - 11746452954984920263, - 5479393366572364588, - 2168476120537571525 - ], - "infinity": false - }, - "lookup_tables_commitments": [ - { - "x": [ - 1589280911861251894, - 2000192568988587993, - 18399902493387281635, - 1843483375839232315 - ], - "y": [ - 14712825033319581746, - 11500494123399487569, - 4370642671010258701, - 567620704393396341 - ], - "infinity": false - }, - { - "x": [ - 0, - 0, - 0, - 0 - ], - "y": [ - 1, - 0, - 0, - 0 - ], - "infinity": true - }, - { - "x": [ - 0, - 0, - 0, - 0 - ], - "y": [ - 1, - 0, - 0, - 0 - ], - "infinity": true - }, - { - "x": [ - 5989740765536181742, - 7510673671757970234, - 7988398980529338112, - 2047433943537325290 - ], - "y": [ - 14952889876146512965, - 17141012675484923048, - 328206788961236528, - 866564802795139 - ], - "infinity": false - } - ], - "lookup_table_type_commitment": { - "x": [ - 4824978155651454377, - 12191454623887257586, - 12973919510878979890, - 52932438992466171 - ], - "y": [ - 17857145998747603901, - 2092039184434926372, - 11018504664231591204, - 1321736242331612854 - ], - "infinity": false - }, - "non_residues": [ - [ - 5, - 0, - 0, - 0 - ], - [ - 7, - 0, - 0, - 0 - ], - [ - 10, - 0, - 0, - 0 - ] - ], - "g2_elements": [ - { - "x": { - "c0": [ - 5106727233969649389, - 7440829307424791261, - 4785637993704342649, - 1729627375292849782 - ], - "c1": [ - 10945020018377822914, - 17413811393473931026, - 8241798111626485029, - 1841571559660931130 - ] - }, - "y": { - "c0": [ - 5541340697920699818, - 16416156555105522555, - 5380518976772849807, - 1353435754470862315 - ], - "c1": [ - 6173549831154472795, - 13567992399387660019, - 17050234209342075797, - 650358724130500725 - ] - }, - "infinity": false - }, - { - "x": { - "c0": [ - 9089143573911733168, - 11482283522806384523, - 13585589533905622862, - 79029415676722370 - ], - "c1": [ - 5692040832573735873, - 16884514497384809355, - 16717166481813659368, - 2742131088506155463 - ] - }, - "y": { - "c0": [ - 9604638503594647125, - 1289961608472612514, - 6217038149984805214, - 2521661352385209130 - ], - "c1": [ - 17168069778630926308, - 11309277837895768996, - 15154989611154567813, - 359271377050603491 - ] - }, - "infinity": false - } - ] -} \ No newline at end of file diff --git a/core/bin/verification_key_generator_and_server/data/verification_2_key.json b/core/bin/verification_key_generator_and_server/data/verification_2_key.json deleted file mode 100644 index 79b16257213f..000000000000 --- a/core/bin/verification_key_generator_and_server/data/verification_2_key.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "n": 67108863, - "num_inputs": 1, - "state_width": 4, - "num_witness_polys": 0, - "gate_setup_commitments": [ - { - "x": [ - 5518783475412319303, - 13900056820557691891, - 3293972357974626054, - 2215936931279678502 - ], - "y": [ - 7955917949806788616, - 13341003959544330056, - 2090626280536970058, - 340565138339520735 - ], - "infinity": false - }, - { - "x": [ - 14185170917510557830, - 8046892618400404954, - 16599645397148333553, - 2994187418830549588 - ], - "y": [ - 7234254448777026502, - 8445782435526889669, - 14116370103157060862, - 2248206929083565209 - ], - "infinity": false - }, - { - "x": [ - 11154659552703848544, - 12941656139895069323, - 17062140236305086427, - 722110816848028084 - ], - "y": [ - 5009717036998782771, - 827592822749515890, - 15966856850732642654, - 618036931564479654 - ], - "infinity": false - }, - { - "x": [ - 5157594213696692987, - 15014090155482426422, - 706425002062263449, - 3203486979181293219 - ], - "y": [ - 14363949081622225749, - 9001876918808042476, - 1615414451418136701, - 444697301726425121 - ], - "infinity": false - }, - { - "x": [ - 9176460251336839321, - 17295305184785757140, - 7831134341003191604, - 2666806971657364559 - ], - "y": [ - 2598277252699259004, - 11916936738177575234, - 2912317122505195338, - 2404138220482962548 - ], - "infinity": false - }, - { - "x": [ - 11575910134534349159, - 14192914809594698195, - 18267718409201448839, - 142641722814285206 - ], - "y": [ - 5883506329268908990, - 2832339585209792351, - 14642260147093833347, - 392817691249359885 - ], - "infinity": false - }, - { - "x": [ - 12908012748245269010, - 6525727331816152736, - 16979431824428028279, - 2845131870310951239 - ], - "y": [ - 1571963770034876851, - 17602700402136611105, - 13310928253737079884, - 3347891464097055062 - ], - "infinity": false - }, - { - "x": [ - 832167803175150309, - 11457734167413059640, - 13250442890410377059, - 2814079984479722654 - ], - "y": [ - 1463471541691279258, - 1744973157713476297, - 1204969522442685286, - 1269233371856967282 - ], - "infinity": false - } - ], - "gate_selectors_commitments": [ - { - "x": [ - 10352656458395970023, - 3995520406692994966, - 13084432248093257522, - 2302839365715839904 - ], - "y": [ - 8225034751786073151, - 16771047952615636124, - 616708265068224682, - 186403683175385821 - ], - "infinity": false - }, - { - "x": [ - 4270731028924703792, - 3128341040439802084, - 15083522049785140229, - 2261189689222904761 - ], - "y": [ - 8781157350107493893, - 14766318733918494793, - 9428422381369337621, - 419743052593117743 - ], - "infinity": false - } - ], - "permutation_commitments": [ - { - "x": [ - 11112968480130414212, - 11913364106966677596, - 36671493864905181, - 496058283903160224 - ], - "y": [ - 9691136012048916590, - 12909186572206021308, - 1700657689434945171, - 3072265811815532764 - ], - "infinity": false - }, - { - "x": [ - 11360744654540534278, - 9830357778413675465, - 5192069313646589173, - 113131628631742646 - ], - "y": [ - 5515513518975242303, - 323890392099446701, - 2255482865429449468, - 2322464724330067577 - ], - "infinity": false - }, - { - "x": [ - 3414259545645111239, - 5416149397109634837, - 12993204506510556426, - 2894091844446687144 - ], - "y": [ - 4731949297479191167, - 1043460441127916951, - 16890401788673829290, - 1356564712828723527 - ], - "infinity": false - }, - { - "x": [ - 8993182433738017869, - 11441314659459910136, - 8181494681500166120, - 1591321336872387140 - ], - "y": [ - 5278254820002084488, - 17932571960593236295, - 7626453034762681225, - 3463596506399756742 - ], - "infinity": false - } - ], - "total_lookup_entries_length": 30783671, - "lookup_selector_commitment": { - "x": [ - 1336161834228740427, - 15823221750660268452, - 13689567356831376139, - 1839611883700311389 - ], - "y": [ - 14875759795137726191, - 20318096045504920, - 8816565555629805366, - 75556627728969178 - ], - "infinity": false - }, - "lookup_tables_commitments": [ - { - "x": [ - 1589280911861251894, - 2000192568988587993, - 18399902493387281635, - 1843483375839232315 - ], - "y": [ - 14712825033319581746, - 11500494123399487569, - 4370642671010258701, - 567620704393396341 - ], - "infinity": false - }, - { - "x": [ - 0, - 0, - 0, - 0 - ], - "y": [ - 1, - 0, - 0, - 0 - ], - "infinity": true - }, - { - "x": [ - 0, - 0, - 0, - 0 - ], - "y": [ - 1, - 0, - 0, - 0 - ], - "infinity": true - }, - { - "x": [ - 5989740765536181742, - 7510673671757970234, - 7988398980529338112, - 2047433943537325290 - ], - "y": [ - 14952889876146512965, - 17141012675484923048, - 328206788961236528, - 866564802795139 - ], - "infinity": false - } - ], - "lookup_table_type_commitment": { - "x": [ - 3408213281770836085, - 15382444791373914560, - 16110552627056571461, - 1161688479331593061 - ], - "y": [ - 13379188756114722390, - 12926267823879081751, - 14282599792449107495, - 3244837013658545871 - ], - "infinity": false - }, - "non_residues": [ - [ - 5, - 0, - 0, - 0 - ], - [ - 7, - 0, - 0, - 0 - ], - [ - 10, - 0, - 0, - 0 - ] - ], - "g2_elements": [ - { - "x": { - "c0": [ - 5106727233969649389, - 7440829307424791261, - 4785637993704342649, - 1729627375292849782 - ], - "c1": [ - 10945020018377822914, - 17413811393473931026, - 8241798111626485029, - 1841571559660931130 - ] - }, - "y": { - "c0": [ - 5541340697920699818, - 16416156555105522555, - 5380518976772849807, - 1353435754470862315 - ], - "c1": [ - 6173549831154472795, - 13567992399387660019, - 17050234209342075797, - 650358724130500725 - ] - }, - "infinity": false - }, - { - "x": { - "c0": [ - 9089143573911733168, - 11482283522806384523, - 13585589533905622862, - 79029415676722370 - ], - "c1": [ - 5692040832573735873, - 16884514497384809355, - 16717166481813659368, - 2742131088506155463 - ] - }, - "y": { - "c0": [ - 9604638503594647125, - 1289961608472612514, - 6217038149984805214, - 2521661352385209130 - ], - "c1": [ - 17168069778630926308, - 11309277837895768996, - 15154989611154567813, - 359271377050603491 - ] - }, - "infinity": false - } - ] -} \ No newline at end of file diff --git a/core/bin/verification_key_generator_and_server/data/verification_3_key.json b/core/bin/verification_key_generator_and_server/data/verification_3_key.json deleted file mode 100644 index 613c65dec32a..000000000000 --- a/core/bin/verification_key_generator_and_server/data/verification_3_key.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "n": 67108863, - "num_inputs": 1, - "state_width": 4, - "num_witness_polys": 0, - "gate_setup_commitments": [ - { - "x": [ - 4247884029119603815, - 14048318895702359089, - 1617022869923646571, - 1004300266779052296 - ], - "y": [ - 17868528514201987465, - 4244261302597587354, - 10221573892940475912, - 2482382880446840010 - ], - "infinity": false - }, - { - "x": [ - 6238506840459074871, - 18254983327500098151, - 12976360180164130634, - 1219856697105853614 - ], - "y": [ - 1359994609126438238, - 17827470346804056210, - 16773833510918183872, - 2604619773311417557 - ], - "infinity": false - }, - { - "x": [ - 5480908979724966765, - 3393255975447524652, - 10371160681199271551, - 3483125449532424455 - ], - "y": [ - 6910224697959110691, - 8190986918875328214, - 18233342390114194740, - 371038657258361111 - ], - "infinity": false - }, - { - "x": [ - 1589636458242554884, - 17321835409586313003, - 13993520794641679178, - 1266542986497561712 - ], - "y": [ - 5397891169353072140, - 5878548729835574296, - 15706893227817678651, - 1769961527856953483 - ], - "infinity": false - }, - { - "x": [ - 17541435070606794744, - 2655627213950653916, - 11216216944579921605, - 1313780180047509779 - ], - "y": [ - 16950319453735037870, - 1632204383055288188, - 15201163922365522932, - 2864472556240937346 - ], - "infinity": false - }, - { - "x": [ - 11997977223945303553, - 14325590013978700522, - 15557533141347230729, - 3289139360100222484 - ], - "y": [ - 2276406350677881932, - 12276125258173429823, - 6135372778488654786, - 2960027660870022236 - ], - "infinity": false - }, - { - "x": [ - 8889079782908651911, - 9444258938063781000, - 6152157289837951831, - 2046144251434758098 - ], - "y": [ - 3506685845878604982, - 480610274681523215, - 17898829927408725055, - 478373452366390807 - ], - "infinity": false - }, - { - "x": [ - 9543795530837745598, - 5641706788025454992, - 2058665597673045347, - 3199980849578540913 - ], - "y": [ - 2134420461745303677, - 11079036403297001210, - 13973590059437528369, - 2236186172656440899 - ], - "infinity": false - } - ], - "gate_selectors_commitments": [ - { - "x": [ - 17082763384512425754, - 5415974525679408765, - 2982831717715582652, - 2185533346241584143 - ], - "y": [ - 889517497459248510, - 11305258809453581163, - 14785916458686019285, - 712045239932611417 - ], - "infinity": false - }, - { - "x": [ - 1486326951928055275, - 17648143945822975405, - 8789056175543467342, - 1582641302957127155 - ], - "y": [ - 16130216435506275947, - 186882025793811656, - 5333388052689527168, - 2555185016165074595 - ], - "infinity": false - } - ], - "permutation_commitments": [ - { - "x": [ - 6775436174991417687, - 1962133343483010121, - 3639644700285584252, - 2751431324201714590 - ], - "y": [ - 16721581791017871189, - 2572212631009994187, - 12263629829130796245, - 1194783809693078725 - ], - "infinity": false - }, - { - "x": [ - 9781583375044732502, - 17099127122236789849, - 15683598159868779227, - 2137916464125382410 - ], - "y": [ - 11971077938028623721, - 14460546631248863771, - 3674726360546135290, - 2587006282919627488 - ], - "infinity": false - }, - { - "x": [ - 2258960665841769264, - 11476106728738999555, - 2154715457718708453, - 1652460267728538717 - ], - "y": [ - 591013691648424928, - 2747643213972148016, - 4382285331965077793, - 700518369290275435 - ], - "infinity": false - }, - { - "x": [ - 17029386353507514799, - 12736838109975824615, - 17948233540620781856, - 1661567367117856229 - ], - "y": [ - 5088293739561490025, - 257269786506894093, - 7029871828271960168, - 2982592857123453815 - ], - "infinity": false - } - ], - "total_lookup_entries_length": 15390957, - "lookup_selector_commitment": { - "x": [ - 3143229288506876352, - 14398478555351850494, - 17971061391349533728, - 2397240458539623423 - ], - "y": [ - 2507720097747632492, - 4897824016944146490, - 8535810669426357324, - 2617442440174156771 - ], - "infinity": false - }, - "lookup_tables_commitments": [ - { - "x": [ - 12925597216490182210, - 13030942092034120135, - 17733316148446765999, - 112547709703624791 - ], - "y": [ - 13293415162200038331, - 13010565234555563811, - 15476251035925496743, - 2588541998389664114 - ], - "infinity": false - }, - { - "x": [ - 11118240121224901946, - 9394562257959111170, - 9026436993514314918, - 1751747619588842429 - ], - "y": [ - 6039590802345873394, - 17531716309156986038, - 1711770599161550805, - 1941094644175870288 - ], - "infinity": false - }, - { - "x": [ - 17999903301086933877, - 10468070608989378923, - 3479353092436121335, - 607756992244480908 - ], - "y": [ - 10863079642303790364, - 4737012301447477097, - 4605789209164294308, - 1430572887755557386 - ], - "infinity": false - }, - { - "x": [ - 4609762018249049814, - 4113097757442144437, - 4725434011535510809, - 2977599521231955696 - ], - "y": [ - 14636094180551257630, - 8819447661702130886, - 1091706295519429215, - 56675985696303183 - ], - "infinity": false - } - ], - "lookup_table_type_commitment": { - "x": [ - 7406705046881629689, - 13550366909312172285, - 11707241152492715411, - 1951231993396003315 - ], - "y": [ - 649840467305243342, - 10916062129580101841, - 7643158916474300887, - 1216418901317802861 - ], - "infinity": false - }, - "non_residues": [ - [ - 5, - 0, - 0, - 0 - ], - [ - 7, - 0, - 0, - 0 - ], - [ - 10, - 0, - 0, - 0 - ] - ], - "g2_elements": [ - { - "x": { - "c0": [ - 5106727233969649389, - 7440829307424791261, - 4785637993704342649, - 1729627375292849782 - ], - "c1": [ - 10945020018377822914, - 17413811393473931026, - 8241798111626485029, - 1841571559660931130 - ] - }, - "y": { - "c0": [ - 5541340697920699818, - 16416156555105522555, - 5380518976772849807, - 1353435754470862315 - ], - "c1": [ - 6173549831154472795, - 13567992399387660019, - 17050234209342075797, - 650358724130500725 - ] - }, - "infinity": false - }, - { - "x": { - "c0": [ - 9089143573911733168, - 11482283522806384523, - 13585589533905622862, - 79029415676722370 - ], - "c1": [ - 5692040832573735873, - 16884514497384809355, - 16717166481813659368, - 2742131088506155463 - ] - }, - "y": { - "c0": [ - 9604638503594647125, - 1289961608472612514, - 6217038149984805214, - 2521661352385209130 - ], - "c1": [ - 17168069778630926308, - 11309277837895768996, - 15154989611154567813, - 359271377050603491 - ] - }, - "infinity": false - } - ] -} \ No newline at end of file diff --git a/core/bin/verification_key_generator_and_server/data/verification_4_key.json b/core/bin/verification_key_generator_and_server/data/verification_4_key.json deleted file mode 100644 index 8d42dcd66a75..000000000000 --- a/core/bin/verification_key_generator_and_server/data/verification_4_key.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "n": 67108863, - "num_inputs": 1, - "state_width": 4, - "num_witness_polys": 0, - "gate_setup_commitments": [ - { - "x": [ - 15923176050075197, - 8963905519117333456, - 5333091548039957996, - 1660697180439834807 - ], - "y": [ - 13105864494044341635, - 10079874572012628853, - 4164109084931753781, - 1860950003357484648 - ], - "infinity": false - }, - { - "x": [ - 8216018177730810417, - 13660800917029254431, - 2933384097067755755, - 2823425599268575868 - ], - "y": [ - 8768863192718196559, - 10146282684570870426, - 8275806247588563419, - 605489936306033583 - ], - "infinity": false - }, - { - "x": [ - 4277344855257545209, - 11172040917478096607, - 4489086903928758598, - 289283798032159440 - ], - "y": [ - 10444137083253378550, - 12133212848977612596, - 6748791972701343485, - 286274227999569844 - ], - "infinity": false - }, - { - "x": [ - 8861797510071553254, - 12734094237204882518, - 13692967202881086499, - 641906135411222522 - ], - "y": [ - 6831762763487302461, - 11965405347371646114, - 6218256502970252800, - 3201462388136754725 - ], - "infinity": false - }, - { - "x": [ - 12385743015818134054, - 16282219738575446638, - 3256359841301423419, - 505673042938576760 - ], - "y": [ - 6744956686738207932, - 8994291190634790001, - 16789606231722015883, - 2027930268272962928 - ], - "infinity": false - }, - { - "x": [ - 13671822069226357541, - 818021157447551159, - 10542481209144358852, - 2459295197762128786 - ], - "y": [ - 1072649761929447549, - 6089126583512618706, - 1178131210084507361, - 1066836948212725576 - ], - "infinity": false - }, - { - "x": [ - 16878956366815094090, - 364977461173568122, - 5439594588743996145, - 1265442855735725449 - ], - "y": [ - 11461704536083653156, - 660278441271820299, - 4314245569905306892, - 1438663846765259508 - ], - "infinity": false - }, - { - "x": [ - 9038539654045396650, - 539827912679485452, - 15399544523862100757, - 1256406598444490417 - ], - "y": [ - 5422113905848106255, - 4943961807853536385, - 10022409325033689104, - 3200702511424842211 - ], - "infinity": false - } - ], - "gate_selectors_commitments": [ - { - "x": [ - 7750990741566547331, - 12040155777441846781, - 3000981333322867315, - 2393292192734976436 - ], - "y": [ - 3394853839941291504, - 944019051205640111, - 1104911864338577098, - 2127308956089601096 - ], - "infinity": false - }, - { - "x": [ - 4735140124663926465, - 16935779121597983173, - 17111626619540374574, - 2327973550601526140 - ], - "y": [ - 8990848735371189388, - 4589751206662798166, - 7575424772436241307, - 2798852347400154642 - ], - "infinity": false - } - ], - "permutation_commitments": [ - { - "x": [ - 4765077060699177749, - 15235935045874519477, - 2022237788491579392, - 354385727984957703 - ], - "y": [ - 11620113321350620961, - 2521830680983779826, - 14047226057605943635, - 2718701882953208503 - ], - "infinity": false - }, - { - "x": [ - 12967015398643083015, - 1100660813730542482, - 7835181433213557652, - 803165211156388599 - ], - "y": [ - 8557385569712401227, - 535900682745452035, - 16083571717847325979, - 396765644246918860 - ], - "infinity": false - }, - { - "x": [ - 6868107733370365435, - 17106601841261210672, - 12219407605084986215, - 2345246684976405066 - ], - "y": [ - 17532412968783851743, - 9996315626158111485, - 17970945522106166231, - 1003764081419207606 - ], - "infinity": false - }, - { - "x": [ - 7011201477832405407, - 8818123127103997131, - 2979445003396953339, - 318603240233076406 - ], - "y": [ - 11712108043964996282, - 3474989587891133574, - 3983451673298542860, - 1181581919257021598 - ], - "infinity": false - } - ], - "total_lookup_entries_length": 8484642, - "lookup_selector_commitment": { - "x": [ - 27459247093738343, - 1785927757103538268, - 14972116880195568621, - 1034224917068963325 - ], - "y": [ - 17453858127001596558, - 6200103235089742197, - 16245568162666829501, - 651193715230511441 - ], - "infinity": false - }, - "lookup_tables_commitments": [ - { - "x": [ - 697552212563769686, - 7709943502535418760, - 15019345407325619175, - 3433081085078580257 - ], - "y": [ - 8668947019840357731, - 14698901351824712883, - 15088598879190660424, - 2873081208166433946 - ], - "infinity": false - }, - { - "x": [ - 7893133928909060673, - 7064922516930129957, - 3592836702741304814, - 2239702595710114437 - ], - "y": [ - 7691360541875191519, - 11379321785127235277, - 6653616064071569031, - 2555434628517540774 - ], - "infinity": false - }, - { - "x": [ - 6243944238013052821, - 7908243182210136125, - 17178099109525791299, - 2553622184721264566 - ], - "y": [ - 736121280088239428, - 6158073429758170526, - 11217302997977204117, - 2594798912020899417 - ], - "infinity": false - }, - { - "x": [ - 2064240298596094591, - 16917726764104887991, - 11042784977532408536, - 3377647228930170830 - ], - "y": [ - 10635525052494768819, - 387400048616497096, - 9379200582543310995, - 1571766153703296253 - ], - "infinity": false - } - ], - "lookup_table_type_commitment": { - "x": [ - 14868101692362122308, - 8135288013508071846, - 9460482611527381887, - 512823635961282598 - ], - "y": [ - 8358211286664762188, - 3532634521932288534, - 5862145521507736138, - 1807935137626658536 - ], - "infinity": false - }, - "non_residues": [ - [ - 5, - 0, - 0, - 0 - ], - [ - 7, - 0, - 0, - 0 - ], - [ - 10, - 0, - 0, - 0 - ] - ], - "g2_elements": [ - { - "x": { - "c0": [ - 5106727233969649389, - 7440829307424791261, - 4785637993704342649, - 1729627375292849782 - ], - "c1": [ - 10945020018377822914, - 17413811393473931026, - 8241798111626485029, - 1841571559660931130 - ] - }, - "y": { - "c0": [ - 5541340697920699818, - 16416156555105522555, - 5380518976772849807, - 1353435754470862315 - ], - "c1": [ - 6173549831154472795, - 13567992399387660019, - 17050234209342075797, - 650358724130500725 - ] - }, - "infinity": false - }, - { - "x": { - "c0": [ - 9089143573911733168, - 11482283522806384523, - 13585589533905622862, - 79029415676722370 - ], - "c1": [ - 5692040832573735873, - 16884514497384809355, - 16717166481813659368, - 2742131088506155463 - ] - }, - "y": { - "c0": [ - 9604638503594647125, - 1289961608472612514, - 6217038149984805214, - 2521661352385209130 - ], - "c1": [ - 17168069778630926308, - 11309277837895768996, - 15154989611154567813, - 359271377050603491 - ] - }, - "infinity": false - } - ] -} \ No newline at end of file diff --git a/core/bin/verification_key_generator_and_server/data/verification_5_key.json b/core/bin/verification_key_generator_and_server/data/verification_5_key.json deleted file mode 100644 index b9a31b919f1c..000000000000 --- a/core/bin/verification_key_generator_and_server/data/verification_5_key.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "n": 67108863, - "num_inputs": 1, - "state_width": 4, - "num_witness_polys": 0, - "gate_setup_commitments": [ - { - "x": [ - 12322129650547620518, - 4320033807979823995, - 4503809593276792861, - 630958448551597950 - ], - "y": [ - 4947307957322067889, - 1897773243457379956, - 1563584362302565484, - 802109862761172056 - ], - "infinity": false - }, - { - "x": [ - 5860641327684713918, - 16885915425353665713, - 7037370194263044401, - 1837438863045303696 - ], - "y": [ - 13386292219804271609, - 4960073609197619993, - 7328379249582994262, - 191728769121948464 - ], - "infinity": false - }, - { - "x": [ - 9390502900121613993, - 17218409610830310329, - 4830832371938391322, - 1805131323553685028 - ], - "y": [ - 15707040961083920686, - 16216062707384374953, - 16957058843586642758, - 1341814870249072628 - ], - "infinity": false - }, - { - "x": [ - 969252611989285232, - 181405773082212747, - 11110666465356509832, - 1888802363524687207 - ], - "y": [ - 5293477339288357424, - 12076391347720360980, - 11422893229655154394, - 3165450734777404812 - ], - "infinity": false - }, - { - "x": [ - 642192487369089358, - 9585449571929647331, - 3847960352134961209, - 984199510163128792 - ], - "y": [ - 13950390676065893881, - 975256099594703300, - 253120832016214204, - 1860679841584192219 - ], - "infinity": false - }, - { - "x": [ - 3564548447861991296, - 6278944799487206913, - 1163701992635366786, - 3214877162977671335 - ], - "y": [ - 13131873482361140204, - 14012120801722220187, - 13254371011592477950, - 1082108070640175604 - ], - "infinity": false - }, - { - "x": [ - 14190764189814537607, - 18412181832598818289, - 17213387738194113336, - 1662783623959823461 - ], - "y": [ - 7987199081435644988, - 17119136750046780209, - 8770669323846078492, - 3183489396270587333 - ], - "infinity": false - }, - { - "x": [ - 14638218826597535389, - 16409988612234258347, - 5025411344133541245, - 603088654230685360 - ], - "y": [ - 12538363432956258836, - 6558875956959901550, - 2415879426147965883, - 750702584304895055 - ], - "infinity": false - } - ], - "gate_selectors_commitments": [ - { - "x": [ - 2599908293582905760, - 13534206398743622493, - 15926090086034346074, - 467418127379229858 - ], - "y": [ - 9529512934078774185, - 1459270552041127965, - 13418846370362665102, - 2270996612016337371 - ], - "infinity": false - }, - { - "x": [ - 7264275706530137047, - 5590205367072257545, - 17891440127697345143, - 360638857846382524 - ], - "y": [ - 17983779934218975397, - 1625779403076670241, - 1474025795387210129, - 1716171421120825643 - ], - "infinity": false - } - ], - "permutation_commitments": [ - { - "x": [ - 9354841115000244260, - 12887310615208346489, - 1120617137774653400, - 424227936372254439 - ], - "y": [ - 3626714025954019309, - 4480975902927818206, - 10093567956580931634, - 2779897825000836477 - ], - "infinity": false - }, - { - "x": [ - 1864884782104066211, - 1247154271168453374, - 9982166936353409582, - 1177339527115773898 - ], - "y": [ - 9932597332303163060, - 1888682277213109000, - 11684220277443154622, - 3062389133489783806 - ], - "infinity": false - }, - { - "x": [ - 9943021177878836437, - 9004866876172522532, - 14085451328492136137, - 1567186274425392936 - ], - "y": [ - 7148906168793986389, - 4780330524752436486, - 10067456648871712650, - 179752856567560382 - ], - "infinity": false - }, - { - "x": [ - 14745822832390509907, - 13862030626549782961, - 10000268356302875837, - 705042314567833799 - ], - "y": [ - 11091254259539384938, - 11733968109785394056, - 11099103738494585500, - 1527456782567955191 - ], - "infinity": false - } - ], - "total_lookup_entries_length": 35330543, - "lookup_selector_commitment": { - "x": [ - 12333191731462980214, - 17841370099698959347, - 12878670991018181621, - 2894319630687016858 - ], - "y": [ - 76816727314643395, - 3214684791046221459, - 878301108738499830, - 126016925902987736 - ], - "infinity": false - }, - "lookup_tables_commitments": [ - { - "x": [ - 911668445361375614, - 12752365066512000136, - 11550232015863976467, - 2053619216798992367 - ], - "y": [ - 4194339833917391280, - 1643071887467668153, - 3377480965202592691, - 1664272901450533719 - ], - "infinity": false - }, - { - "x": [ - 2999316735203966181, - 5189676006781764591, - 14324679313847304783, - 1264086978509739587 - ], - "y": [ - 8714172036038650967, - 10907167170124829028, - 8950970593162102458, - 1596853051185997037 - ], - "infinity": false - }, - { - "x": [ - 1146500486770850326, - 13562754408872334896, - 14063471769392190265, - 3387351506820193517 - ], - "y": [ - 6677788829230735422, - 15425668102208730571, - 5341291772716012975, - 539156410041791428 - ], - "infinity": false - }, - { - "x": [ - 18159886519320172405, - 4286826840324377773, - 16364826089434525345, - 228697666397725767 - ], - "y": [ - 4850633487261444791, - 6327421534074497160, - 12883776034588695446, - 1510314148471267214 - ], - "infinity": false - } - ], - "lookup_table_type_commitment": { - "x": [ - 18245233954308230592, - 8193493714287610439, - 6521078295132558240, - 861511081336275611 - ], - "y": [ - 4275834222266292944, - 13179071278128968874, - 5943013356852335765, - 2456639561657053045 - ], - "infinity": false - }, - "non_residues": [ - [ - 5, - 0, - 0, - 0 - ], - [ - 7, - 0, - 0, - 0 - ], - [ - 10, - 0, - 0, - 0 - ] - ], - "g2_elements": [ - { - "x": { - "c0": [ - 5106727233969649389, - 7440829307424791261, - 4785637993704342649, - 1729627375292849782 - ], - "c1": [ - 10945020018377822914, - 17413811393473931026, - 8241798111626485029, - 1841571559660931130 - ] - }, - "y": { - "c0": [ - 5541340697920699818, - 16416156555105522555, - 5380518976772849807, - 1353435754470862315 - ], - "c1": [ - 6173549831154472795, - 13567992399387660019, - 17050234209342075797, - 650358724130500725 - ] - }, - "infinity": false - }, - { - "x": { - "c0": [ - 9089143573911733168, - 11482283522806384523, - 13585589533905622862, - 79029415676722370 - ], - "c1": [ - 5692040832573735873, - 16884514497384809355, - 16717166481813659368, - 2742131088506155463 - ] - }, - "y": { - "c0": [ - 9604638503594647125, - 1289961608472612514, - 6217038149984805214, - 2521661352385209130 - ], - "c1": [ - 17168069778630926308, - 11309277837895768996, - 15154989611154567813, - 359271377050603491 - ] - }, - "infinity": false - } - ] -} \ No newline at end of file diff --git a/core/bin/verification_key_generator_and_server/data/verification_6_key.json b/core/bin/verification_key_generator_and_server/data/verification_6_key.json deleted file mode 100644 index 34419df17702..000000000000 --- a/core/bin/verification_key_generator_and_server/data/verification_6_key.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "n": 67108863, - "num_inputs": 1, - "state_width": 4, - "num_witness_polys": 0, - "gate_setup_commitments": [ - { - "x": [ - 11033020679838791108, - 14920056278440370765, - 8156477685651219112, - 2935096142913695825 - ], - "y": [ - 12780055516709256833, - 966513406268819160, - 9584266886886532866, - 892347068344972829 - ], - "infinity": false - }, - { - "x": [ - 4044870432040348042, - 10630300946926732771, - 3143480015080245177, - 323917785885883620 - ], - "y": [ - 2297905282612888789, - 8206728682979815807, - 10628767928228215441, - 3062326525278498604 - ], - "infinity": false - }, - { - "x": [ - 14760731158538087565, - 9176522400170689419, - 9855180338242634009, - 2456568616568530201 - ], - "y": [ - 5168103953295979961, - 397013651969935557, - 13864468728668213717, - 2925074735515169158 - ], - "infinity": false - }, - { - "x": [ - 13613691592548742743, - 11339389230513898784, - 4864282628000142183, - 2568915564796772962 - ], - "y": [ - 13074021698952750513, - 14891339562597317806, - 6145754680491802845, - 913243322463864468 - ], - "infinity": false - }, - { - "x": [ - 9607983563343027008, - 1604609357347728263, - 6735137627175405143, - 91305611485454778 - ], - "y": [ - 2068449139446365265, - 6171753015906067998, - 16290186276604645197, - 420889087081901603 - ], - "infinity": false - }, - { - "x": [ - 15994614598808477960, - 5137738490508028659, - 6599503545391493738, - 3293094250487745346 - ], - "y": [ - 3246688300070721763, - 8836841286539929132, - 1231014124908407748, - 3042941126579517307 - ], - "infinity": false - }, - { - "x": [ - 12550390789117808745, - 14001030013656521177, - 16383284077678821701, - 1815317458772356897 - ], - "y": [ - 10125044837604978181, - 7468984969058409331, - 592554137766258541, - 2877688586321491725 - ], - "infinity": false - }, - { - "x": [ - 12238091769471133989, - 184716847866634800, - 5888077423956723698, - 609118759536864800 - ], - "y": [ - 7725369615076384544, - 7561073323636510559, - 10473734750023783127, - 861766554781597742 - ], - "infinity": false - } - ], - "gate_selectors_commitments": [ - { - "x": [ - 1206127807467530207, - 3510053718168412786, - 7933459343694333819, - 3179950874373950282 - ], - "y": [ - 5784856107466398982, - 395767970566909293, - 11244200096534021583, - 2068407511544404377 - ], - "infinity": false - }, - { - "x": [ - 4044617248058764838, - 11957266999135308674, - 17621747993137866783, - 990156155955733134 - ], - "y": [ - 17234504892477991728, - 17558826298225495489, - 9349531438753716103, - 2656409262947709594 - ], - "infinity": false - } - ], - "permutation_commitments": [ - { - "x": [ - 4308597000331285311, - 12130199317436319902, - 3842336010209461436, - 191866453597778475 - ], - "y": [ - 2144400171783010971, - 13016087318985913183, - 7166370365336301922, - 2216888390030560212 - ], - "infinity": false - }, - { - "x": [ - 4661184458541745063, - 12423889401726065791, - 11959346001895915074, - 779668716585305501 - ], - "y": [ - 16401363790535442499, - 7367694133722005848, - 8015837005184593399, - 454166987511489961 - ], - "infinity": false - }, - { - "x": [ - 858215262803403659, - 1405268530667707386, - 7763962169005921611, - 2845435536097215865 - ], - "y": [ - 10639490331338262540, - 6397733211512468794, - 968161689973799899, - 2054756257253905633 - ], - "infinity": false - }, - { - "x": [ - 17338818659525246480, - 13318488425310212471, - 10548319374858973842, - 87084958643052105 - ], - "y": [ - 2279840344577984658, - 15197280761751903251, - 16019225334594459873, - 149925650787595538 - ], - "infinity": false - } - ], - "total_lookup_entries_length": 3054916, - "lookup_selector_commitment": { - "x": [ - 4844230422625825285, - 956290027823441223, - 763010695794739308, - 2426170829255106638 - ], - "y": [ - 13850520521470006763, - 9003994589054655373, - 10310690204425503422, - 3012516431885755457 - ], - "infinity": false - }, - "lookup_tables_commitments": [ - { - "x": [ - 5825422128268478267, - 9219263846299851036, - 3879231702557190566, - 1702488722758880769 - ], - "y": [ - 18311881100262470992, - 5742998199368802392, - 18106865487471159417, - 502191980176920012 - ], - "infinity": false - }, - { - "x": [ - 17195892082859417081, - 7890531942603584793, - 2381805632820057528, - 3173232410464566465 - ], - "y": [ - 16359614627947132075, - 3459600273035137079, - 4550762061432972122, - 3394559699318358224 - ], - "infinity": false - }, - { - "x": [ - 1716103379277390185, - 18097936269579187542, - 16357329729761063450, - 1508640059338197502 - ], - "y": [ - 11014806739603983364, - 4396503314588777389, - 9397245609635151055, - 1703957955248411380 - ], - "infinity": false - }, - { - "x": [ - 4770171350693477354, - 17110558673192292253, - 9799800677557311408, - 761984875463445481 - ], - "y": [ - 1560561403388310063, - 31331275310848146, - 287152055803835484, - 457826332542037277 - ], - "infinity": false - } - ], - "lookup_table_type_commitment": { - "x": [ - 16775586915653722908, - 9787338077086882544, - 8381721730521821042, - 2974660093975661578 - ], - "y": [ - 3011389235487891234, - 15409507493813096391, - 17416460976276029026, - 324418288749844627 - ], - "infinity": false - }, - "non_residues": [ - [ - 5, - 0, - 0, - 0 - ], - [ - 7, - 0, - 0, - 0 - ], - [ - 10, - 0, - 0, - 0 - ] - ], - "g2_elements": [ - { - "x": { - "c0": [ - 5106727233969649389, - 7440829307424791261, - 4785637993704342649, - 1729627375292849782 - ], - "c1": [ - 10945020018377822914, - 17413811393473931026, - 8241798111626485029, - 1841571559660931130 - ] - }, - "y": { - "c0": [ - 5541340697920699818, - 16416156555105522555, - 5380518976772849807, - 1353435754470862315 - ], - "c1": [ - 6173549831154472795, - 13567992399387660019, - 17050234209342075797, - 650358724130500725 - ] - }, - "infinity": false - }, - { - "x": { - "c0": [ - 9089143573911733168, - 11482283522806384523, - 13585589533905622862, - 79029415676722370 - ], - "c1": [ - 5692040832573735873, - 16884514497384809355, - 16717166481813659368, - 2742131088506155463 - ] - }, - "y": { - "c0": [ - 9604638503594647125, - 1289961608472612514, - 6217038149984805214, - 2521661352385209130 - ], - "c1": [ - 17168069778630926308, - 11309277837895768996, - 15154989611154567813, - 359271377050603491 - ] - }, - "infinity": false - } - ] -} \ No newline at end of file diff --git a/core/bin/verification_key_generator_and_server/data/verification_7_key.json b/core/bin/verification_key_generator_and_server/data/verification_7_key.json deleted file mode 100644 index 406afcf4f0fe..000000000000 --- a/core/bin/verification_key_generator_and_server/data/verification_7_key.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "n": 67108863, - "num_inputs": 1, - "state_width": 4, - "num_witness_polys": 0, - "gate_setup_commitments": [ - { - "x": [ - 14104278525941001335, - 6652111379088654370, - 12369045377338511525, - 969809670184836151 - ], - "y": [ - 10111598525423302991, - 15018239425425696172, - 3683372413830991953, - 1023765059890131543 - ], - "infinity": false - }, - { - "x": [ - 11576486884237685781, - 16315823052257401029, - 9860864515877414033, - 3179959598270002012 - ], - "y": [ - 487035971539979311, - 5573003039451484772, - 15711637819381564577, - 1904127920269177012 - ], - "infinity": false - }, - { - "x": [ - 18299921128106602792, - 211731469708793711, - 17645028854462121436, - 675870769139913517 - ], - "y": [ - 15146647508675165454, - 18353083579110652488, - 12704645658780892142, - 2929235299763077823 - ], - "infinity": false - }, - { - "x": [ - 11570586127780196277, - 2363872676317471379, - 7386811009552915084, - 959006902628416514 - ], - "y": [ - 17455735716787098890, - 14879699386306994564, - 5628100821420984321, - 2862659911936763739 - ], - "infinity": false - }, - { - "x": [ - 8746328571248006135, - 17089435014355939378, - 8764506524471462449, - 1810135458362589443 - ], - "y": [ - 14070512019208911265, - 8756287737315170424, - 14821473955626613, - 1559545289765661890 - ], - "infinity": false - }, - { - "x": [ - 2113591086436573082, - 12629483649401688389, - 11845953673798951216, - 3081238281103628853 - ], - "y": [ - 727696133406005469, - 14413827745813557208, - 6425035421156126073, - 291513487083052109 - ], - "infinity": false - }, - { - "x": [ - 15346257923988607256, - 10403316660718504706, - 7158515894996917286, - 2702098910103276762 - ], - "y": [ - 16559143492878738107, - 12716298061927369795, - 12296985344891017351, - 2814996798832983835 - ], - "infinity": false - }, - { - "x": [ - 2213195001372039295, - 8878300942582564036, - 10524986226191936528, - 1815326540993196034 - ], - "y": [ - 11397120982692424098, - 4455537142488107627, - 14205354993332845055, - 2313809587433567240 - ], - "infinity": false - } - ], - "gate_selectors_commitments": [ - { - "x": [ - 14849046431510808003, - 11699893139960418168, - 6000246307731364190, - 3362832011707902866 - ], - "y": [ - 3242560497217933852, - 11672398501106836413, - 987926723326096281, - 2451226739475091625 - ], - "infinity": false - }, - { - "x": [ - 9272095445402359796, - 1201046264826394411, - 7424934554242366462, - 1125893484262333608 - ], - "y": [ - 15903920299684884420, - 17703294385387204708, - 2256937129195345942, - 1905295733884217610 - ], - "infinity": false - } - ], - "permutation_commitments": [ - { - "x": [ - 7591926766688292250, - 10457199375342460747, - 3214976192729961314, - 1412860682249358355 - ], - "y": [ - 16894260140402496006, - 3666374878391815131, - 15124268261678582348, - 1340579262756129480 - ], - "infinity": false - }, - { - "x": [ - 2963934507934439034, - 17415763666461861018, - 6331792462137338053, - 3122358526111186727 - ], - "y": [ - 15040784043381591388, - 7188410244350767315, - 14077554108063383431, - 1704329843327300001 - ], - "infinity": false - }, - { - "x": [ - 7967507884960122293, - 13509230570773443525, - 11125712791473385552, - 2241808950326876268 - ], - "y": [ - 10594180941877323940, - 17179032413109513856, - 17941607623778808075, - 646138820984886096 - ], - "infinity": false - }, - { - "x": [ - 4729534828155895283, - 15489050734511381239, - 4847364931161261393, - 2461584260035042491 - ], - "y": [ - 15255817542606978857, - 6517429187947361297, - 17127878630247240853, - 3389541567226838859 - ], - "infinity": false - } - ], - "total_lookup_entries_length": 40724289, - "lookup_selector_commitment": { - "x": [ - 5449769839889646584, - 2072406321611922291, - 9391796773218391195, - 2377769168011090955 - ], - "y": [ - 1789189431152658324, - 2639430755172378798, - 136577695530283091, - 3045539535973502646 - ], - "infinity": false - }, - "lookup_tables_commitments": [ - { - "x": [ - 631990924006796604, - 16139625628991115157, - 13331739325995827711, - 1062301837743594995 - ], - "y": [ - 15303054606290800139, - 15906872095881647437, - 7093896572295020249, - 1342952934989901142 - ], - "infinity": false - }, - { - "x": [ - 7983921919542246393, - 13296544189644416678, - 17081022784392007697, - 1980832835348244027 - ], - "y": [ - 10874958134865200330, - 7702740658637630534, - 14052057929798961943, - 3193353539419869016 - ], - "infinity": false - }, - { - "x": [ - 1114587284824996932, - 4636906500482867924, - 15328247172597030456, - 87946895873973686 - ], - "y": [ - 15573033830207915877, - 5194694185599035278, - 2562407345425607214, - 2782078999306862675 - ], - "infinity": false - }, - { - "x": [ - 18225112781127431982, - 18048613958187123807, - 7325490730844456621, - 1953409020724855888 - ], - "y": [ - 7577000130125917198, - 6193701449695751861, - 4102082927677054717, - 395350071385269650 - ], - "infinity": false - } - ], - "lookup_table_type_commitment": { - "x": [ - 12639039925867405095, - 9606685454938605275, - 7802675863289639223, - 1948831418843225802 - ], - "y": [ - 11059150608777595761, - 10458812733010634961, - 16772660325487078311, - 340608886692078192 - ], - "infinity": false - }, - "non_residues": [ - [ - 5, - 0, - 0, - 0 - ], - [ - 7, - 0, - 0, - 0 - ], - [ - 10, - 0, - 0, - 0 - ] - ], - "g2_elements": [ - { - "x": { - "c0": [ - 5106727233969649389, - 7440829307424791261, - 4785637993704342649, - 1729627375292849782 - ], - "c1": [ - 10945020018377822914, - 17413811393473931026, - 8241798111626485029, - 1841571559660931130 - ] - }, - "y": { - "c0": [ - 5541340697920699818, - 16416156555105522555, - 5380518976772849807, - 1353435754470862315 - ], - "c1": [ - 6173549831154472795, - 13567992399387660019, - 17050234209342075797, - 650358724130500725 - ] - }, - "infinity": false - }, - { - "x": { - "c0": [ - 9089143573911733168, - 11482283522806384523, - 13585589533905622862, - 79029415676722370 - ], - "c1": [ - 5692040832573735873, - 16884514497384809355, - 16717166481813659368, - 2742131088506155463 - ] - }, - "y": { - "c0": [ - 9604638503594647125, - 1289961608472612514, - 6217038149984805214, - 2521661352385209130 - ], - "c1": [ - 17168069778630926308, - 11309277837895768996, - 15154989611154567813, - 359271377050603491 - ] - }, - "infinity": false - } - ] -} \ No newline at end of file diff --git a/core/bin/verification_key_generator_and_server/data/verification_8_key.json b/core/bin/verification_key_generator_and_server/data/verification_8_key.json deleted file mode 100644 index b8511e17b755..000000000000 --- a/core/bin/verification_key_generator_and_server/data/verification_8_key.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "n": 67108863, - "num_inputs": 1, - "state_width": 4, - "num_witness_polys": 0, - "gate_setup_commitments": [ - { - "x": [ - 1834112096176967541, - 5137529514715617427, - 6540843391881340212, - 3033401888759110412 - ], - "y": [ - 8910602970094475216, - 13169513767982514776, - 5761530093694221441, - 2733318557350866268 - ], - "infinity": false - }, - { - "x": [ - 4701064149158432365, - 5425087325981406309, - 7911131985858828309, - 1683257627049186617 - ], - "y": [ - 13565328904521460918, - 17013189171844282257, - 4897087111183007258, - 2345861178674095559 - ], - "infinity": false - }, - { - "x": [ - 17285353863442654170, - 17787410547699779811, - 4803131526909484890, - 1607731426619418092 - ], - "y": [ - 3219378920021652314, - 11046862703797106703, - 10595836629242151972, - 2970963661532337787 - ], - "infinity": false - }, - { - "x": [ - 6619857367954187649, - 8023974497004524989, - 10088058961892288757, - 938018804109053807 - ], - "y": [ - 15549411064757453720, - 1776820811429478220, - 8222111141823917842, - 290593315633281086 - ], - "infinity": false - }, - { - "x": [ - 3338931670632164423, - 11330459786926502111, - 13560408114559586439, - 233279858410037466 - ], - "y": [ - 9757980615881472290, - 6475296714459436577, - 15954545788543926629, - 2522580407814024231 - ], - "infinity": false - }, - { - "x": [ - 2168501453409628158, - 16417992951888116942, - 1994813140597965849, - 1938552030580060698 - ], - "y": [ - 2393885012813093493, - 5109365147685051030, - 4449898145078443978, - 996506294158321126 - ], - "infinity": false - }, - { - "x": [ - 8163446935422765754, - 17127634458571165785, - 18101155318188210010, - 1502677094108070955 - ], - "y": [ - 4184320355428455210, - 15479528531137595907, - 8455846016430686855, - 2570922865513301289 - ], - "infinity": false - }, - { - "x": [ - 407579941387952352, - 17088458915370169940, - 16892753644011369852, - 2421666516533613805 - ], - "y": [ - 597435837737447683, - 18122233368438707442, - 4844832744563923839, - 396103093107107006 - ], - "infinity": false - } - ], - "gate_selectors_commitments": [ - { - "x": [ - 16242434178832819081, - 2218928756172422054, - 5871927983870638422, - 810020555846721779 - ], - "y": [ - 9387856576677982883, - 5119490172321159350, - 14295435318421985120, - 1325809191818871673 - ], - "infinity": false - }, - { - "x": [ - 5933965238687071287, - 10681704800081225943, - 14555731010498897395, - 959799154476325145 - ], - "y": [ - 1501632601560034962, - 9401704677918783964, - 12292111854761501889, - 858616662661742045 - ], - "infinity": false - } - ], - "permutation_commitments": [ - { - "x": [ - 12841507457971520539, - 6525486152471484441, - 3744486588589217686, - 2769451038405535407 - ], - "y": [ - 14145668232228974364, - 9864097401535863500, - 12665512227995054273, - 1710776254334161256 - ], - "infinity": false - }, - { - "x": [ - 12108157388466567796, - 12008825937320240484, - 11228446795405478904, - 1520424921904150640 - ], - "y": [ - 18157047055378899649, - 10836823561088895074, - 583613418617515639, - 2570085764232471205 - ], - "infinity": false - }, - { - "x": [ - 3117226099128838157, - 10181632193024509490, - 1215328570209780930, - 1536961491401844084 - ], - "y": [ - 11646905141441654681, - 6168936708987385450, - 14459621573162108487, - 2047975568887748173 - ], - "infinity": false - }, - { - "x": [ - 12034664246790330785, - 12032082546920592595, - 12002839514296456095, - 3009479689157977152 - ], - "y": [ - 180421277197569955, - 5815678523367268562, - 11718416396488597085, - 408186057258055191 - ], - "infinity": false - } - ], - "total_lookup_entries_length": 34384753, - "lookup_selector_commitment": { - "x": [ - 3872970821419373956, - 13556503327407661223, - 12832313376327677595, - 211677646774476601 - ], - "y": [ - 17281673428499585093, - 235933066531227024, - 17890327653152417391, - 2551853991532334733 - ], - "infinity": false - }, - "lookup_tables_commitments": [ - { - "x": [ - 14943975734974680929, - 9516136771242606543, - 6695719565456036638, - 3449077049666620393 - ], - "y": [ - 11678209093898264827, - 4499447145490933412, - 6317798459829178953, - 1439219764789809864 - ], - "infinity": false - }, - { - "x": [ - 13501290183905491407, - 17914451638435951710, - 5188762915201956497, - 1220375585898114161 - ], - "y": [ - 14519533874806433487, - 409100046306023, - 2203176115240501563, - 3105700623762337563 - ], - "infinity": false - }, - { - "x": [ - 13968159480895722732, - 6973568812120893251, - 6250254745096478587, - 2299355969860561070 - ], - "y": [ - 7695944005480078577, - 12009671787784557856, - 13727042561077817002, - 219052945806305675 - ], - "infinity": false - }, - { - "x": [ - 4871629130106420314, - 4091595855728790015, - 1851744390500340594, - 3123168382710331270 - ], - "y": [ - 9703969956757970162, - 1215036492891076659, - 11876727836856213678, - 2640893636590396388 - ], - "infinity": false - } - ], - "lookup_table_type_commitment": { - "x": [ - 10299044894603982393, - 4664166516779563250, - 13124827128688646542, - 3361599897730972314 - ], - "y": [ - 18259946931458798404, - 10145479316480429602, - 15446978899103328376, - 265382288883021070 - ], - "infinity": false - }, - "non_residues": [ - [ - 5, - 0, - 0, - 0 - ], - [ - 7, - 0, - 0, - 0 - ], - [ - 10, - 0, - 0, - 0 - ] - ], - "g2_elements": [ - { - "x": { - "c0": [ - 5106727233969649389, - 7440829307424791261, - 4785637993704342649, - 1729627375292849782 - ], - "c1": [ - 10945020018377822914, - 17413811393473931026, - 8241798111626485029, - 1841571559660931130 - ] - }, - "y": { - "c0": [ - 5541340697920699818, - 16416156555105522555, - 5380518976772849807, - 1353435754470862315 - ], - "c1": [ - 6173549831154472795, - 13567992399387660019, - 17050234209342075797, - 650358724130500725 - ] - }, - "infinity": false - }, - { - "x": { - "c0": [ - 9089143573911733168, - 11482283522806384523, - 13585589533905622862, - 79029415676722370 - ], - "c1": [ - 5692040832573735873, - 16884514497384809355, - 16717166481813659368, - 2742131088506155463 - ] - }, - "y": { - "c0": [ - 9604638503594647125, - 1289961608472612514, - 6217038149984805214, - 2521661352385209130 - ], - "c1": [ - 17168069778630926308, - 11309277837895768996, - 15154989611154567813, - 359271377050603491 - ] - }, - "infinity": false - } - ] -} \ No newline at end of file diff --git a/core/bin/verification_key_generator_and_server/data/verification_9_key.json b/core/bin/verification_key_generator_and_server/data/verification_9_key.json deleted file mode 100644 index 75de5f75c78d..000000000000 --- a/core/bin/verification_key_generator_and_server/data/verification_9_key.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "n": 67108863, - "num_inputs": 1, - "state_width": 4, - "num_witness_polys": 0, - "gate_setup_commitments": [ - { - "x": [ - 15041888416700822899, - 15908701850433687369, - 6928173929840686173, - 501601364708497325 - ], - "y": [ - 9443860646360881208, - 15174745959183347299, - 3341918218952258763, - 1470216750942469587 - ], - "infinity": false - }, - { - "x": [ - 1713492202424532619, - 5921868784153327820, - 3919870428680620477, - 2459274846398943915 - ], - "y": [ - 8012717129874416534, - 13032363221581987781, - 9462161206147300944, - 1151760065513271967 - ], - "infinity": false - }, - { - "x": [ - 6636128327108235840, - 9362733145474272574, - 7779132015244601843, - 474802631021936400 - ], - "y": [ - 3900992471196218787, - 113851245079995197, - 7493904056590361535, - 3140468871801097229 - ], - "infinity": false - }, - { - "x": [ - 4340102674797800902, - 8715432707094353745, - 4331145745081713603, - 45456583984841487 - ], - "y": [ - 18326546742044058782, - 15443239165658185296, - 9765917874876721196, - 687859761729374839 - ], - "infinity": false - }, - { - "x": [ - 10804694580890857975, - 10550068287306981825, - 14956274043654722561, - 3060589920124935341 - ], - "y": [ - 17010223672048359580, - 263749806111642373, - 8349695975133446526, - 2826070525773268002 - ], - "infinity": false - }, - { - "x": [ - 16133249269780245267, - 4275571784340824698, - 6262619645627758753, - 3231281899173719188 - ], - "y": [ - 11839616617849449709, - 7142633755989890055, - 10840735473548209733, - 2847350786075278882 - ], - "infinity": false - }, - { - "x": [ - 16258572583186965203, - 1354691125575792689, - 17235265854934968790, - 1252220109588505888 - ], - "y": [ - 9336541637487074271, - 18402912967310224930, - 13223187653117829136, - 2979297976786733465 - ], - "infinity": false - }, - { - "x": [ - 8525686695522099028, - 4103157564078645049, - 18392570749492199187, - 2911539491816599180 - ], - "y": [ - 114653447583918953, - 10470307038453386601, - 11189850644566793538, - 1298227034210846592 - ], - "infinity": false - } - ], - "gate_selectors_commitments": [ - { - "x": [ - 2069700145549311928, - 4250782333685017927, - 14207216715687122978, - 1145927286048477791 - ], - "y": [ - 9341202692364554712, - 12346939747104737180, - 2826478533799125818, - 2279570556437452275 - ], - "infinity": false - }, - { - "x": [ - 12388902775325386546, - 1277383964095999647, - 10535796018183893831, - 3359866702323175506 - ], - "y": [ - 16500893366957272235, - 2806147688388338314, - 8233156072220488773, - 2867848844627212711 - ], - "infinity": false - } - ], - "permutation_commitments": [ - { - "x": [ - 17521183961631816299, - 18327810537117645266, - 16586212795163003556, - 3052771534158410452 - ], - "y": [ - 8441310283734453731, - 14146088755801181801, - 17480253356603213989, - 3217948944323396651 - ], - "infinity": false - }, - { - "x": [ - 16076801532842923524, - 7514743296775639295, - 2571323986448120255, - 184367540214459973 - ], - "y": [ - 13389643967183613114, - 17108261756464256828, - 11145735340309739417, - 2142196980030893874 - ], - "infinity": false - }, - { - "x": [ - 8034683328666433725, - 5436036566901194392, - 18053257213361014053, - 2821377847227509494 - ], - "y": [ - 14471305228212723444, - 8894846184648865892, - 7047725473055235530, - 2413388400332075493 - ], - "infinity": false - }, - { - "x": [ - 14026981588443304814, - 14671946927765496183, - 13387079215022495926, - 2554705188091675830 - ], - "y": [ - 440116222237740520, - 1630168477189852269, - 17833425794232523381, - 908824471705597078 - ], - "infinity": false - } - ], - "total_lookup_entries_length": 41494904, - "lookup_selector_commitment": { - "x": [ - 13889323383351416990, - 17887386740570674124, - 5463612855590268091, - 2434255340534820869 - ], - "y": [ - 2436699678434218349, - 11251365794004058995, - 11023509005141034197, - 2867854671852170604 - ], - "infinity": false - }, - "lookup_tables_commitments": [ - { - "x": [ - 631990924006796604, - 16139625628991115157, - 13331739325995827711, - 1062301837743594995 - ], - "y": [ - 15303054606290800139, - 15906872095881647437, - 7093896572295020249, - 1342952934989901142 - ], - "infinity": false - }, - { - "x": [ - 7983921919542246393, - 13296544189644416678, - 17081022784392007697, - 1980832835348244027 - ], - "y": [ - 10874958134865200330, - 7702740658637630534, - 14052057929798961943, - 3193353539419869016 - ], - "infinity": false - }, - { - "x": [ - 1114587284824996932, - 4636906500482867924, - 15328247172597030456, - 87946895873973686 - ], - "y": [ - 15573033830207915877, - 5194694185599035278, - 2562407345425607214, - 2782078999306862675 - ], - "infinity": false - }, - { - "x": [ - 18225112781127431982, - 18048613958187123807, - 7325490730844456621, - 1953409020724855888 - ], - "y": [ - 7577000130125917198, - 6193701449695751861, - 4102082927677054717, - 395350071385269650 - ], - "infinity": false - } - ], - "lookup_table_type_commitment": { - "x": [ - 3832160677272803715, - 2122279734318217808, - 811690144328522684, - 1416829483108546006 - ], - "y": [ - 10041279311991435550, - 14702496983143623186, - 4419862575487552747, - 1429817244630465543 - ], - "infinity": false - }, - "non_residues": [ - [ - 5, - 0, - 0, - 0 - ], - [ - 7, - 0, - 0, - 0 - ], - [ - 10, - 0, - 0, - 0 - ] - ], - "g2_elements": [ - { - "x": { - "c0": [ - 5106727233969649389, - 7440829307424791261, - 4785637993704342649, - 1729627375292849782 - ], - "c1": [ - 10945020018377822914, - 17413811393473931026, - 8241798111626485029, - 1841571559660931130 - ] - }, - "y": { - "c0": [ - 5541340697920699818, - 16416156555105522555, - 5380518976772849807, - 1353435754470862315 - ], - "c1": [ - 6173549831154472795, - 13567992399387660019, - 17050234209342075797, - 650358724130500725 - ] - }, - "infinity": false - }, - { - "x": { - "c0": [ - 9089143573911733168, - 11482283522806384523, - 13585589533905622862, - 79029415676722370 - ], - "c1": [ - 5692040832573735873, - 16884514497384809355, - 16717166481813659368, - 2742131088506155463 - ] - }, - "y": { - "c0": [ - 9604638503594647125, - 1289961608472612514, - 6217038149984805214, - 2521661352385209130 - ], - "c1": [ - 17168069778630926308, - 11309277837895768996, - 15154989611154567813, - 359271377050603491 - ] - }, - "infinity": false - } - ] -} \ No newline at end of file diff --git a/core/bin/verification_key_generator_and_server/src/commitment_generator.rs b/core/bin/verification_key_generator_and_server/src/commitment_generator.rs deleted file mode 100644 index ed859bcb4366..000000000000 --- a/core/bin/verification_key_generator_and_server/src/commitment_generator.rs +++ /dev/null @@ -1,37 +0,0 @@ -use anyhow::Context as _; -use zksync_prover_utils::vk_commitment_helper::{ - get_toml_formatted_value, read_contract_toml, write_contract_toml, -}; -use zksync_verification_key_server::generate_commitments; - -fn main() -> anyhow::Result<()> { - tracing::info!("Starting commitment generation!"); - read_and_update_contract_toml() -} - -fn read_and_update_contract_toml() -> anyhow::Result<()> { - let mut contract_doc = read_contract_toml().context("read_contract_toml()")?; - let ( - basic_circuit_commitment_hex, - leaf_aggregation_commitment_hex, - node_aggregation_commitment_hex, - ) = generate_commitments(); - contract_doc["contracts"]["RECURSION_CIRCUITS_SET_VKS_HASH"] = - get_toml_formatted_value(basic_circuit_commitment_hex); - contract_doc["contracts"]["RECURSION_LEAF_LEVEL_VK_HASH"] = - get_toml_formatted_value(leaf_aggregation_commitment_hex); - contract_doc["contracts"]["RECURSION_NODE_LEVEL_VK_HASH"] = - get_toml_formatted_value(node_aggregation_commitment_hex); - tracing::info!("Updated toml content: {:?}", contract_doc.to_string()); - write_contract_toml(contract_doc).context("write_contract_toml") -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_read_and_update_contract_toml() { - read_and_update_contract_toml().unwrap(); - } -} diff --git a/core/bin/verification_key_generator_and_server/src/json_to_binary_vk_converter.rs b/core/bin/verification_key_generator_and_server/src/json_to_binary_vk_converter.rs deleted file mode 100644 index c04a67128334..000000000000 --- a/core/bin/verification_key_generator_and_server/src/json_to_binary_vk_converter.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::{fs::File, io::BufWriter}; - -use bincode::serialize_into; -use structopt::StructOpt; -use zksync_verification_key_server::get_vk_for_circuit_type; - -#[derive(Debug, StructOpt)] -#[structopt( - name = "json existing json VK's to binary vk", - about = "converter tool" -)] -struct Opt { - /// Binary output path of verification keys. - #[structopt(short)] - output_bin_path: String, -} - -fn main() { - let opt = Opt::from_args(); - println!("Converting existing json keys to binary"); - generate_bin_vks(opt.output_bin_path); -} - -fn generate_bin_vks(output_path: String) { - for circuit_type in 1..=18 { - let filename = format!("{}/verification_{}.key", output_path, circuit_type); - let vk = get_vk_for_circuit_type(circuit_type); - let mut f = BufWriter::new(File::create(filename).unwrap()); - serialize_into(&mut f, &vk).unwrap(); - } -} diff --git a/core/bin/verification_key_generator_and_server/src/lib.rs b/core/bin/verification_key_generator_and_server/src/lib.rs deleted file mode 100644 index 20260a30b20b..000000000000 --- a/core/bin/verification_key_generator_and_server/src/lib.rs +++ /dev/null @@ -1,188 +0,0 @@ -use std::{collections::HashMap, path::Path, str::FromStr}; - -use ff::to_hex; -use itertools::Itertools; -use once_cell::sync::Lazy; -use structopt::lazy_static::lazy_static; -use zksync_types::{ - circuit::{ - GEOMETRY_CONFIG, LEAF_CIRCUIT_INDEX, LEAF_SPLITTING_FACTOR, NODE_CIRCUIT_INDEX, - NODE_SPLITTING_FACTOR, SCHEDULER_CIRCUIT_INDEX, SCHEDULER_UPPER_BOUND, - }, - protocol_version::{L1VerifierConfig, VerifierParams}, - vk_transform::generate_vk_commitment, - zkevm_test_harness::{ - abstract_zksync_circuit::concrete_circuits::ZkSyncCircuit, - bellman::{bn256::Bn256, plonk::better_better_cs::setup::VerificationKey}, - witness, - witness::{ - full_block_artifact::BlockBasicCircuits, - oracle::VmWitnessOracle, - recursive_aggregation::{erase_vk_type, padding_aggregations}, - vk_set_generator::circuits_for_vk_generation, - }, - }, - H256, -}; - -#[cfg(test)] -mod tests; - -lazy_static! { - static ref COMMITMENTS: Lazy = Lazy::new(|| { circuit_commitments() }); -} - -pub fn get_vks_for_basic_circuits( -) -> HashMap>>> { - // 3-17 are the ids of basic circuits - (3..=18) - .map(|circuit_type| (circuit_type, get_vk_for_circuit_type(circuit_type))) - .collect() -} - -pub fn get_vk_for_circuit_type( - circuit_type: u8, -) -> VerificationKey>> { - let filepath = get_file_path(circuit_type); - tracing::info!("Fetching verification key from path: {}", filepath); - let text = std::fs::read_to_string(&filepath) - .unwrap_or_else(|_| panic!("Failed reading verification key from path: {}", filepath)); - serde_json::from_str::>>>( - &text, - ) - .unwrap_or_else(|_| { - panic!( - "Failed deserializing verification key from path: {}", - filepath - ) - }) -} - -pub fn save_vk_for_circuit_type( - circuit_type: u8, - vk: VerificationKey>>, -) { - let filepath = get_file_path(circuit_type); - tracing::info!("saving verification key to: {}", filepath); - std::fs::write(filepath, serde_json::to_string_pretty(&vk).unwrap()).unwrap(); -} - -pub fn get_ordered_vks_for_basic_circuits( - circuits: &BlockBasicCircuits, - verification_keys: &HashMap< - u8, - VerificationKey>>, - >, -) -> Vec>>> { - circuits - .clone() - .into_flattened_set() - .iter() - .map(|circuit| { - let circuit_id = circuit.numeric_circuit_type(); - verification_keys - .get(&circuit_id) - .unwrap_or_else(|| { - panic!("no VK for circuit number {:?}", circuit.short_description()) - }) - .clone() - }) - .collect() -} - -pub fn get_vks_for_commitment( - verification_keys: HashMap< - u8, - VerificationKey>>, - >, -) -> Vec>>> { - // We need all the vks sorted by their respective circuit ids - verification_keys - .into_iter() - .sorted_by_key(|(id, _)| *id) - .map(|(_, val)| val) - .collect() -} - -pub fn get_circuits_for_vk() -> Vec>> { - ensure_setup_key_exist(); - let padding_aggregations = padding_aggregations(NODE_SPLITTING_FACTOR); - circuits_for_vk_generation( - GEOMETRY_CONFIG, - LEAF_SPLITTING_FACTOR, - NODE_SPLITTING_FACTOR, - SCHEDULER_UPPER_BOUND, - padding_aggregations, - ) -} - -fn ensure_setup_key_exist() { - if !Path::new("setup_2^26.key").exists() { - panic!("File setup_2^26.key is required to be present in current directory for verification keys generation. \ndownload from https://storage.googleapis.com/matterlabs-setup-keys-us/setup-keys/setup_2^26.key"); - } -} -fn get_file_path(circuit_type: u8) -> String { - let zksync_home = std::env::var("ZKSYNC_HOME").unwrap_or_else(|_| "/".into()); - format!( - "{}/core/bin/verification_key_generator_and_server/data/verification_{}_key.json", - zksync_home, circuit_type - ) -} - -pub fn generate_commitments() -> (String, String, String) { - let (_, basic_circuit_commitment, _) = - witness::recursive_aggregation::form_base_circuits_committment(get_vks_for_commitment( - get_vks_for_basic_circuits(), - )); - - let leaf_aggregation_vk = get_vk_for_circuit_type(LEAF_CIRCUIT_INDEX); - let node_aggregation_vk = get_vk_for_circuit_type(NODE_CIRCUIT_INDEX); - - let (_, leaf_aggregation_vk_commitment) = - witness::recursive_aggregation::compute_vk_encoding_and_committment(erase_vk_type( - leaf_aggregation_vk, - )); - - let (_, node_aggregation_vk_commitment) = - witness::recursive_aggregation::compute_vk_encoding_and_committment(erase_vk_type( - node_aggregation_vk, - )); - let basic_circuit_commitment_hex = format!("0x{}", to_hex(&basic_circuit_commitment)); - let leaf_aggregation_commitment_hex = format!("0x{}", to_hex(&leaf_aggregation_vk_commitment)); - let node_aggregation_commitment_hex = format!("0x{}", to_hex(&node_aggregation_vk_commitment)); - tracing::info!( - "basic circuit commitment {:?}", - basic_circuit_commitment_hex - ); - tracing::info!( - "leaf aggregation commitment {:?}", - leaf_aggregation_commitment_hex - ); - tracing::info!( - "node aggregation commitment {:?}", - node_aggregation_commitment_hex - ); - ( - basic_circuit_commitment_hex, - leaf_aggregation_commitment_hex, - node_aggregation_commitment_hex, - ) -} - -fn circuit_commitments() -> L1VerifierConfig { - let (basic, leaf, node) = generate_commitments(); - let scheduler = generate_vk_commitment(get_vk_for_circuit_type(SCHEDULER_CIRCUIT_INDEX)); - L1VerifierConfig { - params: VerifierParams { - recursion_node_level_vk_hash: H256::from_str(&node).expect("invalid node commitment"), - recursion_leaf_level_vk_hash: H256::from_str(&leaf).expect("invalid leaf commitment"), - recursion_circuits_set_vks_hash: H256::from_str(&basic) - .expect("invalid basic commitment"), - }, - recursion_scheduler_level_vk_hash: scheduler, - } -} - -pub fn get_cached_commitments() -> L1VerifierConfig { - **COMMITMENTS -} diff --git a/core/bin/verification_key_generator_and_server/src/main.rs b/core/bin/verification_key_generator_and_server/src/main.rs deleted file mode 100644 index b64e5757fceb..000000000000 --- a/core/bin/verification_key_generator_and_server/src/main.rs +++ /dev/null @@ -1,48 +0,0 @@ -use std::{collections::HashSet, env}; - -use zksync_types::zkevm_test_harness::{ - abstract_zksync_circuit::concrete_circuits::ZkSyncCircuit, - bellman::{ - bn256::Bn256, plonk::better_better_cs::cs::PlonkCsWidth4WithNextStepAndCustomGatesParams, - }, - witness::oracle::VmWitnessOracle, -}; -use zksync_verification_key_server::{get_circuits_for_vk, save_vk_for_circuit_type}; - -/// Creates verification keys for the given circuit. -fn main() { - let args: Vec = env::args().collect(); - - let circuit_types: HashSet = if args.len() > 1 { - [get_and_ensure_valid_circuit_type(args[1].clone())].into() - } else { - (3..17).collect() - }; - tracing::info!("Starting verification key generation!"); - get_circuits_for_vk() - .into_iter() - .filter(|c| circuit_types.contains(&c.numeric_circuit_type())) - .for_each(generate_verification_key); -} - -fn get_and_ensure_valid_circuit_type(circuit_type: String) -> u8 { - tracing::info!("Received circuit_type: {:?}", circuit_type); - circuit_type - .parse::() - .expect("Please specify a circuit type in range [1, 17]") -} - -fn generate_verification_key(circuit: ZkSyncCircuit>) { - let res = circuit_testing::create_vk_for_padding_size_log_2::< - Bn256, - _, - PlonkCsWidth4WithNextStepAndCustomGatesParams, - >(circuit.clone(), 26) - .unwrap(); - save_vk_for_circuit_type(circuit.numeric_circuit_type(), res); - tracing::info!( - "Finished VK generation for circuit {:?} (id {:?})", - circuit.short_description(), - circuit.numeric_circuit_type() - ); -} diff --git a/core/bin/verification_key_generator_and_server/src/tests.rs b/core/bin/verification_key_generator_and_server/src/tests.rs deleted file mode 100644 index f0fea866de6d..000000000000 --- a/core/bin/verification_key_generator_and_server/src/tests.rs +++ /dev/null @@ -1,68 +0,0 @@ -use std::collections::HashMap; - -use itertools::Itertools; -use serde_json::Value; -use zksync_types::zkevm_test_harness::{ - abstract_zksync_circuit::concrete_circuits::ZkSyncCircuit, - bellman::{bn256::Bn256, plonk::better_better_cs::setup::VerificationKey}, - witness::oracle::VmWitnessOracle, -}; - -use crate::{get_vk_for_circuit_type, get_vks_for_basic_circuits, get_vks_for_commitment}; - -#[test] -fn test_get_vk_for_circuit_type() { - for circuit_type in 1..=18 { - get_vk_for_circuit_type(circuit_type); - } -} - -#[test] -fn test_get_vks_for_basic_circuits() { - let circuit_type_to_vk = get_vks_for_basic_circuits(); - let circuit_types: Vec = circuit_type_to_vk.into_keys().sorted().collect::>(); - let expected: Vec = (3..=18).collect(); - assert_eq!( - expected, circuit_types, - "circuit types must be in the range [3, 17]" - ); -} - -#[test] -fn test_get_vks_for_commitment() { - let vk_5 = get_vk_for_circuit_type(5); - let vk_2 = get_vk_for_circuit_type(2); - let vk_3 = get_vk_for_circuit_type(3); - let map = HashMap::from([ - (5u8, vk_5.clone()), - (2u8, vk_2.clone()), - (3u8, vk_3.clone()), - ]); - let vks = get_vks_for_commitment(map); - let expected = vec![vk_2, vk_3, vk_5]; - compare_vks( - expected, - vks, - "expected verification key to be in order 2, 3, 5", - ); -} - -fn get_vk_json(vk: &VerificationKey>>) -> Value { - serde_json::to_value(vk).unwrap() -} - -fn get_vk_jsons( - vks: Vec>>>, -) -> Vec { - vks.into_iter().map(|vk| get_vk_json(&vk)).collect() -} - -fn compare_vks( - first: Vec>>>, - second: Vec>>>, - error_message: &str, -) { - let first_json = get_vk_jsons(first); - let second_json = get_vk_jsons(second); - assert_eq!(first_json, second_json, "{:?}", error_message); -} diff --git a/core/bin/zksync_server/Cargo.toml b/core/bin/zksync_server/Cargo.toml index a1de2ef057ad..33835ba09523 100644 --- a/core/bin/zksync_server/Cargo.toml +++ b/core/bin/zksync_server/Cargo.toml @@ -17,10 +17,18 @@ zksync_storage = { path = "../../lib/storage" } zksync_utils = { path = "../../lib/utils" } zksync_types = { path = "../../lib/types" } zksync_core = { path = "../../lib/zksync_core" } + +# Consensus dependenices +zksync_consensus_crypto = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } +zksync_consensus_roles = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } +zksync_consensus_executor = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } +zksync_concurrency = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } + vlog = { path = "../../lib/vlog" } anyhow = "1.0" clap = { version = "4.2.4", features = ["derive"] } +serde_json = "1.0" tokio = { version = "1", features = ["full"] } tracing = "0.1" futures = "0.3" diff --git a/core/bin/zksync_server/src/config.rs b/core/bin/zksync_server/src/config.rs new file mode 100644 index 000000000000..bdd06a80eef9 --- /dev/null +++ b/core/bin/zksync_server/src/config.rs @@ -0,0 +1,17 @@ +use anyhow::Context as _; +use zksync_consensus_roles::{node, validator}; +use zksync_core::consensus; + +pub(crate) fn read_consensus_config() -> anyhow::Result { + let path = std::env::var("CONSENSUS_CONFIG_PATH").context("CONSENSUS_CONFIG_PATH")?; + let cfg = std::fs::read_to_string(&path).context(path)?; + let cfg: consensus::config::Config = + consensus::config::decode_json(&cfg).context("failed decoding JSON")?; + let validator_key: validator::SecretKey = + consensus::config::read_secret("CONSENSUS_VALIDATOR_KEY")?; + let node_key: node::SecretKey = consensus::config::read_secret("CONSENSUS_NODE_KEY")?; + Ok(consensus::MainNodeConfig { + executor: cfg.executor_config(node_key), + validator: cfg.validator_config(validator_key), + }) +} diff --git a/core/bin/zksync_server/src/main.rs b/core/bin/zksync_server/src/main.rs index a7825da919a2..f9f18a11c05c 100644 --- a/core/bin/zksync_server/src/main.rs +++ b/core/bin/zksync_server/src/main.rs @@ -12,10 +12,10 @@ use zksync_config::{ fri_prover_group::FriProverGroupConfig, house_keeper::HouseKeeperConfig, FriProofCompressorConfig, FriProverConfig, FriWitnessGeneratorConfig, PrometheusConfig, - ProofDataHandlerConfig, ProverGroupConfig, WitnessGeneratorConfig, + ProofDataHandlerConfig, WitnessGeneratorConfig, }, ApiConfig, ContractsConfig, DBConfig, ETHClientConfig, ETHSenderConfig, ETHWatchConfig, - GasAdjusterConfig, ObjectStoreConfig, PostgresConfig, ProverConfigs, + GasAdjusterConfig, ObjectStoreConfig, PostgresConfig, }; use zksync_core::{ genesis_init, initialize_components, is_genesis_needed, setup_sigint_handler, @@ -25,6 +25,8 @@ use zksync_env_config::FromEnv; use zksync_storage::RocksDB; use zksync_utils::wait_for_tasks::wait_for_tasks; +mod config; + #[cfg(not(target_env = "msvc"))] #[global_allocator] static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; @@ -93,7 +95,7 @@ async fn main() -> anyhow::Result<()> { // Right now, we are trying to deserialize all the configs that may be needed by `zksync_core`. // "May" is the key word here, since some configs are only used by certain component configuration, // hence we are using `Option`s. - let configs: TempConfigStore = TempConfigStore { + let mut configs: TempConfigStore = TempConfigStore { postgres_config: PostgresConfig::from_env().ok(), health_check_config: HealthCheckConfig::from_env().ok(), merkle_tree_api_config: MerkleTreeApiConfig::from_env().ok(), @@ -105,12 +107,11 @@ async fn main() -> anyhow::Result<()> { state_keeper_config: StateKeeperConfig::from_env().ok(), house_keeper_config: HouseKeeperConfig::from_env().ok(), fri_proof_compressor_config: FriProofCompressorConfig::from_env().ok(), - fri_prover_config: FriProverConfig::from_env().ok(), + fri_prover_config: Some(FriProverConfig::from_env().context("fri_prover_config")?), fri_prover_group_config: FriProverGroupConfig::from_env().ok(), fri_witness_generator_config: FriWitnessGeneratorConfig::from_env().ok(), prometheus_config: PrometheusConfig::from_env().ok(), proof_data_handler_config: ProofDataHandlerConfig::from_env().ok(), - prover_group_config: ProverGroupConfig::from_env().ok(), witness_generator_config: WitnessGeneratorConfig::from_env().ok(), api_config: ApiConfig::from_env().ok(), contracts_config: ContractsConfig::from_env().ok(), @@ -119,10 +120,15 @@ async fn main() -> anyhow::Result<()> { eth_sender_config: ETHSenderConfig::from_env().ok(), eth_watch_config: ETHWatchConfig::from_env().ok(), gas_adjuster_config: GasAdjusterConfig::from_env().ok(), - prover_configs: ProverConfigs::from_env().ok(), object_store_config: ObjectStoreConfig::from_env().ok(), + consensus_config: None, }; + if opt.components.0.contains(&Component::Consensus) { + configs.consensus_config = + Some(config::read_consensus_config().context("read_consensus_config()")?); + } + let postgres_config = configs.postgres_config.clone().context("PostgresConfig")?; if opt.genesis || is_genesis_needed(&postgres_config).await { diff --git a/core/lib/basic_types/src/basic_fri_types.rs b/core/lib/basic_types/src/basic_fri_types.rs index 47444c6675f9..5aaba2ece6ee 100644 --- a/core/lib/basic_types/src/basic_fri_types.rs +++ b/core/lib/basic_types/src/basic_fri_types.rs @@ -1,8 +1,12 @@ //! Basic types for FRI prover. +// TODO (PLA-773): Should be moved to the prover workspace. + +use std::{convert::TryFrom, str::FromStr}; + use serde::{Deserialize, Serialize}; -#[derive(Debug, Deserialize, Serialize, Clone, Eq, Hash, PartialEq)] +#[derive(Debug, Deserialize, Serialize, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)] pub struct CircuitIdRoundTuple { pub circuit_id: u8, pub aggregation_round: u8, @@ -16,3 +20,82 @@ impl CircuitIdRoundTuple { } } } + +/// Represents the sequential number of the proof aggregation round. +/// Mostly used to be stored in `aggregation_round` column in `prover_jobs` table +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] +pub enum AggregationRound { + BasicCircuits = 0, + LeafAggregation = 1, + NodeAggregation = 2, + Scheduler = 3, +} + +impl From for AggregationRound { + fn from(item: u8) -> Self { + match item { + 0 => AggregationRound::BasicCircuits, + 1 => AggregationRound::LeafAggregation, + 2 => AggregationRound::NodeAggregation, + 3 => AggregationRound::Scheduler, + _ => panic!("Invalid round"), + } + } +} + +impl AggregationRound { + pub fn next(&self) -> Option { + match self { + AggregationRound::BasicCircuits => Some(AggregationRound::LeafAggregation), + AggregationRound::LeafAggregation => Some(AggregationRound::NodeAggregation), + AggregationRound::NodeAggregation => Some(AggregationRound::Scheduler), + AggregationRound::Scheduler => None, + } + } +} + +impl std::fmt::Display for AggregationRound { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str(match self { + Self::BasicCircuits => "basic_circuits", + Self::LeafAggregation => "leaf_aggregation", + Self::NodeAggregation => "node_aggregation", + Self::Scheduler => "scheduler", + }) + } +} + +impl FromStr for AggregationRound { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "basic_circuits" => Ok(AggregationRound::BasicCircuits), + "leaf_aggregation" => Ok(AggregationRound::LeafAggregation), + "node_aggregation" => Ok(AggregationRound::NodeAggregation), + "scheduler" => Ok(AggregationRound::Scheduler), + other => Err(format!( + "{} is not a valid round name for witness generation", + other + )), + } + } +} + +impl TryFrom for AggregationRound { + type Error = (); + + fn try_from(v: i32) -> Result { + match v { + x if x == AggregationRound::BasicCircuits as i32 => Ok(AggregationRound::BasicCircuits), + x if x == AggregationRound::LeafAggregation as i32 => { + Ok(AggregationRound::LeafAggregation) + } + x if x == AggregationRound::NodeAggregation as i32 => { + Ok(AggregationRound::NodeAggregation) + } + x if x == AggregationRound::Scheduler as i32 => Ok(AggregationRound::Scheduler), + _ => Err(()), + } + } +} diff --git a/core/lib/basic_types/src/lib.rs b/core/lib/basic_types/src/lib.rs index aa9bf615c915..5c8b4e6ee69a 100644 --- a/core/lib/basic_types/src/lib.rs +++ b/core/lib/basic_types/src/lib.rs @@ -115,9 +115,9 @@ impl FromStr for L2ChainId { impl L2ChainId { /// The maximum value of the L2 chain ID. - // 2^53 - 1 is a max safe integer in JS. In ethereum JS libs chain ID should be the safe integer. + // `2^53 - 1` is a max safe integer in JS. In Ethereum JS libraries chain ID should be the safe integer. // Next arithmetic operation: subtract 36 and divide by 2 comes from `v` calculation: - // v = 2*chainId + 36, that should be save integer as well. + // `v = 2*chainId + 36`, that should be save integer as well. const MAX: u64 = ((1 << 53) - 1 - 36) / 2; pub fn max() -> Self { diff --git a/core/lib/circuit_breaker/Cargo.toml b/core/lib/circuit_breaker/Cargo.toml index 41aa978829ef..a76e933b4b6c 100644 --- a/core/lib/circuit_breaker/Cargo.toml +++ b/core/lib/circuit_breaker/Cargo.toml @@ -14,7 +14,6 @@ zksync_types = { path = "../types" } zksync_config = { path = "../config" } zksync_contracts = { path = "../contracts" } zksync_dal = { path = "../dal" } -zksync_eth_client = { path = "../eth_client" } thiserror = "1.0" serde_json = "1.0" futures = { version = "0.3", features = ["compat"] } @@ -22,8 +21,6 @@ tokio = { version = "1", features = ["time"] } anyhow = "1.0" async-trait = "0.1" hex = "0.4" -convert_case = "0.6.0" -backon = "0.4.0" metrics = "0.21" tracing = "0.1.26" diff --git a/core/lib/circuit_breaker/src/lib.rs b/core/lib/circuit_breaker/src/lib.rs index 4c84f857a295..db602ca9656d 100644 --- a/core/lib/circuit_breaker/src/lib.rs +++ b/core/lib/circuit_breaker/src/lib.rs @@ -62,7 +62,7 @@ impl CircuitBreakerChecker { return circuit_breaker_sender .send(error) .ok() - .context("failed to send circuit breaker messsage"); + .context("failed to send circuit breaker message"); } tokio::time::sleep(self.sync_interval).await; } diff --git a/core/lib/commitment_utils/Cargo.toml b/core/lib/commitment_utils/Cargo.toml index 801f90ea0f23..d74ff3c9572e 100644 --- a/core/lib/commitment_utils/Cargo.toml +++ b/core/lib/commitment_utils/Cargo.toml @@ -12,4 +12,8 @@ categories = ["cryptography"] [dependencies] zksync_types = { path = "../../lib/types" } zksync_utils = { path = "../../lib/utils" } -zkevm_test_harness = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.0" } +zkevm_test_harness_1_4_0 = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.0", package = "zkevm_test_harness" } +zkevm_test_harness_1_4_1 = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.1", package = "zkevm_test_harness" } +zk_evm_1_4_1 = { package = "zk_evm", git = "https://github.com/matter-labs/era-zk_evm.git", branch = "v1.4.1" } +zk_evm_1_3_3 = { package = "zk_evm", git = "https://github.com/matter-labs/era-zk_evm.git", tag = "v1.3.3-rc2" } +multivm = { path = "../../lib/multivm" } diff --git a/core/lib/commitment_utils/src/lib.rs b/core/lib/commitment_utils/src/lib.rs index ac6dc8ff9178..cfdfa23e81d5 100644 --- a/core/lib/commitment_utils/src/lib.rs +++ b/core/lib/commitment_utils/src/lib.rs @@ -1,23 +1,97 @@ //! Utils for commitment calculation. -use zkevm_test_harness::witness::utils::{ - events_queue_commitment_fixed, initial_heap_content_commitment_fixed, +use multivm::utils::get_used_bootloader_memory_bytes; +use zk_evm_1_3_3::{ + aux_structures::Timestamp as Timestamp_1_3_3, + zk_evm_abstractions::queries::LogQuery as LogQuery_1_3_3, }; -use zksync_types::{LogQuery, H256, U256, USED_BOOTLOADER_MEMORY_BYTES}; +use zk_evm_1_4_1::{ + aux_structures::Timestamp as Timestamp_1_4_1, + zk_evm_abstractions::queries::LogQuery as LogQuery_1_4_1, +}; +use zksync_types::{zk_evm_types::LogQuery, ProtocolVersionId, VmVersion, H256, U256}; use zksync_utils::expand_memory_contents; -pub fn events_queue_commitment(events_queue: &Vec, is_pre_boojum: bool) -> Option { - (!is_pre_boojum).then(|| H256(events_queue_commitment_fixed(events_queue))) +pub fn events_queue_commitment( + events_queue: &[LogQuery], + protocol_version: ProtocolVersionId, +) -> Option { + match VmVersion::from(protocol_version) { + VmVersion::VmBoojumIntegration => Some(H256( + zkevm_test_harness_1_4_0::witness::utils::events_queue_commitment_fixed( + &events_queue + .iter() + .map(|x| to_log_query_1_3_3(*x)) + .collect(), + ), + )), + VmVersion::Vm1_4_1 => Some(H256( + zkevm_test_harness_1_4_1::witness::utils::events_queue_commitment_fixed( + &events_queue + .iter() + .map(|x| to_log_query_1_4_1(*x)) + .collect(), + ), + )), + _ => None, + } } pub fn bootloader_initial_content_commitment( initial_bootloader_contents: &[(usize, U256)], - is_pre_boojum: bool, + protocol_version: ProtocolVersionId, ) -> Option { - (!is_pre_boojum).then(|| { - let full_bootloader_memory = - expand_memory_contents(initial_bootloader_contents, USED_BOOTLOADER_MEMORY_BYTES); - H256(initial_heap_content_commitment_fixed( - &full_bootloader_memory, - )) - }) + let expanded_memory_size = if protocol_version.is_pre_boojum() { + return None; + } else { + get_used_bootloader_memory_bytes(protocol_version.into()) + }; + + let full_bootloader_memory = + expand_memory_contents(initial_bootloader_contents, expanded_memory_size); + + match VmVersion::from(protocol_version) { + VmVersion::VmBoojumIntegration => Some(H256( + zkevm_test_harness_1_4_0::witness::utils::initial_heap_content_commitment_fixed( + &full_bootloader_memory, + ), + )), + VmVersion::Vm1_4_1 => Some(H256( + zkevm_test_harness_1_4_1::witness::utils::initial_heap_content_commitment_fixed( + &full_bootloader_memory, + ), + )), + _ => unreachable!(), + } +} + +fn to_log_query_1_3_3(log_query: LogQuery) -> LogQuery_1_3_3 { + LogQuery_1_3_3 { + timestamp: Timestamp_1_3_3(log_query.timestamp.0), + tx_number_in_block: log_query.tx_number_in_block, + aux_byte: log_query.aux_byte, + shard_id: log_query.shard_id, + address: log_query.address, + key: log_query.key, + read_value: log_query.read_value, + written_value: log_query.written_value, + rw_flag: log_query.rw_flag, + rollback: log_query.rollback, + is_service: log_query.is_service, + } +} + +fn to_log_query_1_4_1(log_query: LogQuery) -> LogQuery_1_4_1 { + LogQuery_1_4_1 { + timestamp: Timestamp_1_4_1(log_query.timestamp.0), + tx_number_in_block: log_query.tx_number_in_block, + aux_byte: log_query.aux_byte, + shard_id: log_query.shard_id, + address: log_query.address, + key: log_query.key, + read_value: log_query.read_value, + written_value: log_query.written_value, + rw_flag: log_query.rw_flag, + rollback: log_query.rollback, + is_service: log_query.is_service, + } } diff --git a/core/lib/config/Cargo.toml b/core/lib/config/Cargo.toml index 2532e474ca29..ecbc781df655 100644 --- a/core/lib/config/Cargo.toml +++ b/core/lib/config/Cargo.toml @@ -13,4 +13,5 @@ categories = ["cryptography"] zksync_basic_types = { path = "../../lib/basic_types" } anyhow = "1.0" +rand = "0.8" serde = { version = "1.0", features = ["derive"] } diff --git a/core/lib/config/src/configs/api.rs b/core/lib/config/src/configs/api.rs index ad48743664f3..a06b9fa53dfe 100644 --- a/core/lib/config/src/configs/api.rs +++ b/core/lib/config/src/configs/api.rs @@ -38,15 +38,11 @@ pub struct Web3JsonRpcConfig { pub subscriptions_limit: Option, /// Interval between polling db for pubsub (in ms). pub pubsub_polling_interval: Option, - /// number of threads per server - pub threads_per_server: u32, /// Tx nonce: how far ahead from the committed nonce can it be. pub max_nonce_ahead: u32, /// The multiplier to use when suggesting gas price. Should be higher than one, /// otherwise if the L1 prices soar, the suggested gas price won't be sufficient to be included in block pub gas_price_scale_factor: f64, - /// Inbound transaction limit used for throttling - pub transactions_per_sec_limit: Option, /// Timeout for requests (in s) pub request_timeout: Option, /// Private keys for accounts managed by node @@ -55,6 +51,14 @@ pub struct Web3JsonRpcConfig { pub estimate_gas_scale_factor: f64, /// The max possible number of gas that `eth_estimateGas` is allowed to overestimate. pub estimate_gas_acceptable_overestimation: u32, + /// Whether to use the compatibility mode for gas estimation for L1->L2 transactions. + /// During the migration to the 1.4.1 fee model, there will be a period, when the server + /// will already have the 1.4.1 fee model, while the L1 contracts will still expect the transactions + /// to use the previous fee model with much higher overhead. + /// + /// When set to `true`, the API will ensure to return gasLimit is high enough overhead for both the old + /// and the new fee model when estimating L1->L2 transactions. + pub l1_to_l2_transactions_compatibility_mode: bool, /// Max possible size of an ABI encoded tx (in bytes). pub max_tx_size: usize, /// Max number of cache misses during one VM execution. If the number of cache misses exceeds this value, the API server panics. @@ -71,12 +75,6 @@ pub struct Web3JsonRpcConfig { /// Latest values cache size in MiBs. The default value is 128 MiB. If set to 0, the latest /// values cache will be disabled. pub latest_values_cache_size_mb: Option, - /// Override value for the amount of threads used for HTTP RPC server. - /// If not set, the value from `threads_per_server` is used. - pub http_threads: Option, - /// Override value for the amount of threads used for WebSocket RPC server. - /// If not set, the value from `threads_per_server` is used. - pub ws_threads: Option, /// Limit for fee history block range. pub fee_history_limit: Option, /// Maximum number of requests in a single batch JSON RPC request. Default is 500. @@ -105,22 +103,19 @@ impl Web3JsonRpcConfig { filters_limit: Some(10000), subscriptions_limit: Some(10000), pubsub_polling_interval: Some(200), - threads_per_server: 1, max_nonce_ahead: 50, gas_price_scale_factor: 1.2, - transactions_per_sec_limit: Default::default(), request_timeout: Default::default(), account_pks: Default::default(), estimate_gas_scale_factor: 1.2, estimate_gas_acceptable_overestimation: 1000, + l1_to_l2_transactions_compatibility_mode: true, max_tx_size: 1000000, vm_execution_cache_misses_limit: Default::default(), vm_concurrency_limit: Default::default(), factory_deps_cache_size_mb: Default::default(), initial_writes_cache_size_mb: Default::default(), latest_values_cache_size_mb: Default::default(), - http_threads: Default::default(), - ws_threads: Default::default(), fee_history_limit: Default::default(), max_batch_request_size: Default::default(), max_response_body_size_mb: Default::default(), @@ -183,14 +178,6 @@ impl Web3JsonRpcConfig { self.latest_values_cache_size_mb.unwrap_or(128) * super::BYTES_IN_MEGABYTE } - pub fn http_server_threads(&self) -> usize { - self.http_threads.unwrap_or(self.threads_per_server) as usize - } - - pub fn ws_server_threads(&self) -> usize { - self.ws_threads.unwrap_or(self.threads_per_server) as usize - } - pub fn fee_history_limit(&self) -> u64 { self.fee_history_limit.unwrap_or(1024) } @@ -233,8 +220,6 @@ pub struct ContractVerificationApiConfig { pub port: u16, /// URL to access REST server. pub url: String, - /// number of threads per server - pub threads_per_server: u32, } impl ContractVerificationApiConfig { diff --git a/core/lib/config/src/configs/chain.rs b/core/lib/config/src/configs/chain.rs index eb77467183fe..d35c6ed52b55 100644 --- a/core/lib/config/src/configs/chain.rs +++ b/core/lib/config/src/configs/chain.rs @@ -3,20 +3,6 @@ use std::{str::FromStr, time::Duration}; use serde::Deserialize; use zksync_basic_types::{network::Network, Address, L2ChainId}; -#[derive(Debug, Deserialize, Clone, PartialEq)] -pub struct ChainConfig { - /// L1 parameters configuration. - pub network: NetworkConfig, - /// State keeper / block generating configuration. - pub state_keeper: StateKeeperConfig, - /// Operations manager / Metadata calculator. - pub operations_manager: OperationsManagerConfig, - /// mempool configuration - pub mempool: MempoolConfig, - /// circuit breaker configuration - pub circuit_breaker: CircuitBreakerConfig, -} - #[derive(Debug, Deserialize, Clone, PartialEq)] pub struct NetworkConfig { /// Name of the used Ethereum network, e.g. `localhost` or `rinkeby`. @@ -40,6 +26,25 @@ impl NetworkConfig { } } +/// An enum that represents the version of the fee model to use. +/// - `V1`, the first model that was used in zkSync Era. In this fee model, the pubdata price must be pegged to the L1 gas price. +/// Also, the fair L2 gas price is expected to only include the proving/computation price for the operator and not the costs that come from +/// processing the batch on L1. +/// - `V2`, the second model that was used in zkSync Era. There the pubdata price might be independent from the L1 gas price. Also, +/// The fair L2 gas price is expected to both the proving/computation price for the operator and the costs that come from +/// processing the batch on L1. +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)] +pub enum FeeModelVersion { + V1, + V2, +} + +impl Default for FeeModelVersion { + fn default() -> Self { + Self::V1 + } +} + #[derive(Debug, Deserialize, Clone, PartialEq, Default)] pub struct StateKeeperConfig { /// The max number of slots for txs in a block before it should be sealed by the slots sealer. @@ -77,8 +82,26 @@ pub struct StateKeeperConfig { pub fee_account_addr: Address, - /// The price the operator spends on 1 gas of computation in wei. - pub fair_l2_gas_price: u64, + /// The minimal acceptable L2 gas price, i.e. the price that should include the cost of computation/proving as well + /// as potentially premium for congestion. + pub minimal_l2_gas_price: u64, + /// The constant that represents the possibility that a batch can be sealed because of overuse of computation resources. + /// It has range from 0 to 1. If it is 0, the compute will not depend on the cost for closing the batch. + /// If it is 1, the gas limit per batch will have to cover the entire cost of closing the batch. + pub compute_overhead_part: f64, + /// The constant that represents the possibility that a batch can be sealed because of overuse of pubdata. + /// It has range from 0 to 1. If it is 0, the pubdata will not depend on the cost for closing the batch. + /// If it is 1, the pubdata limit per batch will have to cover the entire cost of closing the batch. + pub pubdata_overhead_part: f64, + /// The constant amount of L1 gas that is used as the overhead for the batch. It includes the price for batch verification, etc. + pub batch_overhead_l1_gas: u64, + /// The maximum amount of gas that can be used by the batch. This value is derived from the circuits limitation per batch. + pub max_gas_per_batch: u64, + /// The maximum amount of pubdata that can be used by the batch. Note that if the calldata is used as pubdata, this variable should not exceed 128kb. + pub max_pubdata_per_batch: u64, + + /// The version of the fee model to use. + pub fee_model_version: FeeModelVersion, /// Max number of computational gas that validation step is allowed to take. pub validation_computational_gas_limit: u32, @@ -114,7 +137,13 @@ impl StateKeeperConfig { close_block_at_gas_percentage: 0.95, fee_account_addr: Address::from_str("0xde03a0B5963f75f1C8485B355fF6D30f3093BDE7") .unwrap(), - fair_l2_gas_price: 250000000, + compute_overhead_part: 0.0, + pubdata_overhead_part: 1.0, + batch_overhead_l1_gas: 800_000, + max_gas_per_batch: 200_000_000, + max_pubdata_per_batch: 100_000, + minimal_l2_gas_price: 100000000, + fee_model_version: FeeModelVersion::V2, validation_computational_gas_limit: 300000, save_call_traces: true, virtual_blocks_interval: 1, diff --git a/core/lib/config/src/configs/circuit_synthesizer.rs b/core/lib/config/src/configs/circuit_synthesizer.rs deleted file mode 100644 index 8df0f4bbd1a1..000000000000 --- a/core/lib/config/src/configs/circuit_synthesizer.rs +++ /dev/null @@ -1,42 +0,0 @@ -use std::time::Duration; - -use serde::Deserialize; - -/// Configuration for the witness generation -#[derive(Debug, Deserialize, Clone, PartialEq)] -pub struct CircuitSynthesizerConfig { - /// Max time for circuit to be synthesized - pub generation_timeout_in_secs: u16, - /// Max attempts for synthesizing circuit - pub max_attempts: u32, - /// Max time before an `reserved` prover instance in considered as `available` - pub gpu_prover_queue_timeout_in_secs: u16, - /// Max time to wait to get a free prover instance - pub prover_instance_wait_timeout_in_secs: u16, - // Time to wait between 2 consecutive poll to get new prover instance. - pub prover_instance_poll_time_in_milli_secs: u16, - /// Configurations for prometheus - pub prometheus_listener_port: u16, - pub prometheus_pushgateway_url: String, - pub prometheus_push_interval_ms: Option, - // Group id for this synthesizer, synthesizer running the same circuit types shall have same group id. - pub prover_group_id: u8, -} - -impl CircuitSynthesizerConfig { - pub fn generation_timeout(&self) -> Duration { - Duration::from_secs(self.generation_timeout_in_secs as u64) - } - - pub fn prover_instance_wait_timeout(&self) -> Duration { - Duration::from_secs(self.prover_instance_wait_timeout_in_secs as u64) - } - - pub fn gpu_prover_queue_timeout(&self) -> Duration { - Duration::from_secs(self.gpu_prover_queue_timeout_in_secs as u64) - } - - pub fn prover_instance_poll_time(&self) -> Duration { - Duration::from_millis(self.prover_instance_poll_time_in_milli_secs as u64) - } -} diff --git a/core/lib/config/src/configs/database.rs b/core/lib/config/src/configs/database.rs index 578cd6be46a6..acca253d4024 100644 --- a/core/lib/config/src/configs/database.rs +++ b/core/lib/config/src/configs/database.rs @@ -123,7 +123,7 @@ impl DBConfig { /// Collection of different database URLs and general PostgreSQL options. /// All the entries are optional, since some components may only require a subset of them, /// and any component may have overrides. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct PostgresConfig { /// URL for the main (sequencer) database. pub master_url: Option, diff --git a/core/lib/config/src/configs/fri_prover.rs b/core/lib/config/src/configs/fri_prover.rs index 44521ee36576..a5e99a407374 100644 --- a/core/lib/config/src/configs/fri_prover.rs +++ b/core/lib/config/src/configs/fri_prover.rs @@ -22,6 +22,7 @@ pub struct FriProverConfig { pub witness_vector_generator_thread_count: Option, pub queue_capacity: usize, pub witness_vector_receiver_port: u16, + pub zone_read_url: String, // whether to write to public GCS bucket for https://github.com/matter-labs/era-boojum-validator-cli pub shall_save_to_public_bucket: bool, diff --git a/core/lib/config/src/configs/mod.rs b/core/lib/config/src/configs/mod.rs index 87fbad72a016..fc0e7eb6d4d2 100644 --- a/core/lib/config/src/configs/mod.rs +++ b/core/lib/config/src/configs/mod.rs @@ -2,8 +2,6 @@ pub use self::{ alerts::AlertsConfig, api::ApiConfig, - chain::ChainConfig, - circuit_synthesizer::CircuitSynthesizerConfig, contract_verifier::ContractVerifierConfig, contracts::ContractsConfig, database::{DBConfig, PostgresConfig}, @@ -17,8 +15,6 @@ pub use self::{ fri_witness_vector_generator::FriWitnessVectorGeneratorConfig, object_store::ObjectStoreConfig, proof_data_handler::ProofDataHandlerConfig, - prover::{ProverConfig, ProverConfigs}, - prover_group::ProverGroupConfig, snapshots_creator::SnapshotsCreatorConfig, utils::PrometheusConfig, witness_generator::WitnessGeneratorConfig, @@ -27,7 +23,6 @@ pub use self::{ pub mod alerts; pub mod api; pub mod chain; -pub mod circuit_synthesizer; pub mod contract_verifier; pub mod contracts; pub mod database; @@ -43,8 +38,6 @@ pub mod fri_witness_vector_generator; pub mod house_keeper; pub mod object_store; pub mod proof_data_handler; -pub mod prover; -pub mod prover_group; pub mod snapshots_creator; pub mod utils; pub mod witness_generator; diff --git a/core/lib/config/src/configs/object_store.rs b/core/lib/config/src/configs/object_store.rs index 5524b6ade253..4cf5553d639e 100644 --- a/core/lib/config/src/configs/object_store.rs +++ b/core/lib/config/src/configs/object_store.rs @@ -5,6 +5,7 @@ pub enum ObjectStoreMode { GCS, GCSWithCredentialFile, FileBacked, + GCSAnonymousReadOnly, } /// Configuration for the object store diff --git a/core/lib/config/src/configs/proof_data_handler.rs b/core/lib/config/src/configs/proof_data_handler.rs index b773efbd7df2..e81e55b8a530 100644 --- a/core/lib/config/src/configs/proof_data_handler.rs +++ b/core/lib/config/src/configs/proof_data_handler.rs @@ -15,6 +15,7 @@ pub struct ProofDataHandlerConfig { pub protocol_version_loading_mode: ProtocolVersionLoadingMode, pub fri_protocol_version_id: u16, } + impl ProofDataHandlerConfig { pub fn proof_generation_timeout(&self) -> Duration { Duration::from_secs(self.proof_generation_timeout_in_secs as u64) diff --git a/core/lib/config/src/configs/prover.rs b/core/lib/config/src/configs/prover.rs deleted file mode 100644 index 45ed7100f9f4..000000000000 --- a/core/lib/config/src/configs/prover.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::time::Duration; - -use serde::Deserialize; - -/// Configuration for the prover application -#[derive(Debug, Deserialize, Clone, PartialEq)] -pub struct ProverConfig { - /// Port to which the Prometheus exporter server is listening. - pub prometheus_port: u16, - /// Currently only a single (largest) key is supported. We'll support different ones in the future - pub initial_setup_key_path: String, - /// https://storage.googleapis.com/matterlabs-setup-keys-us/setup-keys/setup_2\^26.key - pub key_download_url: String, - /// Max time for proof to be generated - pub generation_timeout_in_secs: u16, - /// Number of threads to be used concurrent proof generation. - pub number_of_threads: u16, - /// Max attempts for generating proof - pub max_attempts: u32, - // Polling time in mill-seconds. - pub polling_duration_in_millis: u64, - // Path to setup keys for individual circuit. - pub setup_keys_path: String, - // Group id for this prover, provers running the same circuit types shall have same group id. - pub specialized_prover_group_id: u8, - // Number of setup-keys kept in memory without swapping - // number_of_setup_slots = (R-C*A-4)/S - // R is available ram - // C is the number of parallel synth - // A is the size of Assembly that is 12gb - // S is the size of the Setup that is 20gb - // constant 4 is for the data copy with gpu - pub number_of_setup_slots: u8, - /// Port at which server would be listening to receive incoming assembly - pub assembly_receiver_port: u16, - /// Socket polling time for receiving incoming assembly - pub assembly_receiver_poll_time_in_millis: u64, - /// maximum number of assemblies that are kept in memory, - pub assembly_queue_capacity: usize, -} - -/// Prover configs for different machine types that are currently supported. -#[derive(Debug, Deserialize, Clone, PartialEq)] -pub struct ProverConfigs { - // used by witness-generator - pub non_gpu: ProverConfig, - // https://gcloud-compute.com/a2-highgpu-2g.html - pub two_gpu_forty_gb_mem: ProverConfig, - // https://gcloud-compute.com/a2-ultragpu-1g.html - pub one_gpu_eighty_gb_mem: ProverConfig, - // https://gcloud-compute.com/a2-ultragpu-2g.html - pub two_gpu_eighty_gb_mem: ProverConfig, - // https://gcloud-compute.com/a2-ultragpu-4g.html - pub four_gpu_eighty_gb_mem: ProverConfig, -} - -impl ProverConfig { - pub fn proof_generation_timeout(&self) -> Duration { - Duration::from_secs(self.generation_timeout_in_secs as u64) - } -} diff --git a/core/lib/config/src/configs/prover_group.rs b/core/lib/config/src/configs/prover_group.rs deleted file mode 100644 index 2d40d47ba8c1..000000000000 --- a/core/lib/config/src/configs/prover_group.rs +++ /dev/null @@ -1,66 +0,0 @@ -use serde::Deserialize; - -/// Configuration for the grouping of specialized provers. -/// This config would be used by circuit-synthesizer and provers. -#[derive(Debug, Deserialize, Clone, PartialEq)] -pub struct ProverGroupConfig { - pub group_0_circuit_ids: Vec, - pub group_1_circuit_ids: Vec, - pub group_2_circuit_ids: Vec, - pub group_3_circuit_ids: Vec, - pub group_4_circuit_ids: Vec, - pub group_5_circuit_ids: Vec, - pub group_6_circuit_ids: Vec, - pub group_7_circuit_ids: Vec, - pub group_8_circuit_ids: Vec, - pub group_9_circuit_ids: Vec, - pub region_read_url: String, - // This is used while running the provers/synthesizer in non-gcp cloud env. - pub region_override: Option, - pub zone_read_url: String, - // This is used while running the provers/synthesizer in non-gcp cloud env. - pub zone_override: Option, - pub synthesizer_per_gpu: u16, -} - -impl ProverGroupConfig { - pub fn get_circuit_ids_for_group_id(&self, group_id: u8) -> Option> { - match group_id { - 0 => Some(self.group_0_circuit_ids.clone()), - 1 => Some(self.group_1_circuit_ids.clone()), - 2 => Some(self.group_2_circuit_ids.clone()), - 3 => Some(self.group_3_circuit_ids.clone()), - 4 => Some(self.group_4_circuit_ids.clone()), - 5 => Some(self.group_5_circuit_ids.clone()), - 6 => Some(self.group_6_circuit_ids.clone()), - 7 => Some(self.group_7_circuit_ids.clone()), - 8 => Some(self.group_8_circuit_ids.clone()), - 9 => Some(self.group_9_circuit_ids.clone()), - _ => None, - } - } - - pub fn is_specialized_group_id(&self, group_id: u8) -> bool { - group_id <= 9 - } - - pub fn get_group_id_for_circuit_id(&self, circuit_id: u8) -> Option { - let configs = [ - &self.group_0_circuit_ids, - &self.group_1_circuit_ids, - &self.group_2_circuit_ids, - &self.group_3_circuit_ids, - &self.group_4_circuit_ids, - &self.group_5_circuit_ids, - &self.group_6_circuit_ids, - &self.group_7_circuit_ids, - &self.group_8_circuit_ids, - &self.group_9_circuit_ids, - ]; - configs - .iter() - .enumerate() - .find(|(_, group)| group.contains(&circuit_id)) - .map(|(group_id, _)| group_id as u8) - } -} diff --git a/core/lib/config/src/lib.rs b/core/lib/config/src/lib.rs index edb596be4984..cde1582a1a28 100644 --- a/core/lib/config/src/lib.rs +++ b/core/lib/config/src/lib.rs @@ -1,9 +1,9 @@ #![allow(clippy::upper_case_acronyms, clippy::derive_partial_eq_without_eq)] pub use crate::configs::{ - ApiConfig, ChainConfig, ContractVerifierConfig, ContractsConfig, DBConfig, ETHClientConfig, - ETHSenderConfig, ETHWatchConfig, GasAdjusterConfig, ObjectStoreConfig, PostgresConfig, - ProverConfig, ProverConfigs, SnapshotsCreatorConfig, + ApiConfig, ContractVerifierConfig, ContractsConfig, DBConfig, ETHClientConfig, ETHSenderConfig, + ETHWatchConfig, GasAdjusterConfig, ObjectStoreConfig, PostgresConfig, SnapshotsCreatorConfig, }; pub mod configs; +pub mod testonly; diff --git a/core/lib/config/src/testonly.rs b/core/lib/config/src/testonly.rs new file mode 100644 index 000000000000..64a38ff51ae2 --- /dev/null +++ b/core/lib/config/src/testonly.rs @@ -0,0 +1,708 @@ +use std::collections::HashSet; + +use rand::{distributions::Alphanumeric, Rng}; +use zksync_basic_types::{ + basic_fri_types::CircuitIdRoundTuple, network::Network, Address, L2ChainId, H256, +}; + +use crate::configs; + +/// Generator of random configs. +pub struct Gen<'a, R: Rng> { + /// Underlying RNG. + pub rng: &'a mut R, + /// Generate configs with only required fields. + pub required_only: bool, + /// Generate decimal fractions for f64 + /// to avoid rounding errors of decimal encodings. + pub decimal_fractions: bool, +} + +impl<'a, R: Rng> Gen<'a, R> { + pub fn gen(&mut self) -> C { + C::sample(self) + } +} + +pub trait RandomConfig { + fn sample(g: &mut Gen) -> Self; +} + +impl RandomConfig for String { + fn sample(g: &mut Gen) -> Self { + let n = g.rng.gen_range(5..10); + g.rng + .sample_iter(&Alphanumeric) + .take(n) + .map(char::from) + .collect() + } +} + +impl RandomConfig for Option { + fn sample(g: &mut Gen) -> Self { + if g.required_only { + return None; + } + Some(g.gen()) + } +} + +impl RandomConfig for Vec { + fn sample(g: &mut Gen) -> Self { + if g.required_only { + return vec![]; + } + (0..g.rng.gen_range(5..10)).map(|_| g.gen()).collect() + } +} + +impl RandomConfig for HashSet { + fn sample(g: &mut Gen) -> Self { + if g.required_only { + return HashSet::new(); + } + (0..g.rng.gen_range(5..10)).map(|_| g.gen()).collect() + } +} + +impl RandomConfig for bool { + fn sample(g: &mut Gen) -> Self { + g.rng.gen() + } +} + +impl RandomConfig for u8 { + fn sample(g: &mut Gen) -> Self { + g.rng.gen() + } +} + +impl RandomConfig for u16 { + fn sample(g: &mut Gen) -> Self { + g.rng.gen() + } +} + +impl RandomConfig for u32 { + fn sample(g: &mut Gen) -> Self { + g.rng.gen() + } +} + +impl RandomConfig for u64 { + fn sample(g: &mut Gen) -> Self { + g.rng.gen() + } +} + +impl RandomConfig for f64 { + fn sample(g: &mut Gen) -> Self { + if g.decimal_fractions { + const PRECISION: usize = 1000000; + return g.rng.gen_range(0..PRECISION) as f64 / PRECISION as f64; + } + g.rng.gen() + } +} + +impl RandomConfig for usize { + fn sample(g: &mut Gen) -> Self { + g.rng.gen() + } +} + +impl RandomConfig for std::num::NonZeroU32 { + fn sample(g: &mut Gen) -> Self { + g.rng.gen() + } +} + +impl RandomConfig for Address { + fn sample(g: &mut Gen) -> Self { + g.rng.gen() + } +} + +impl RandomConfig for H256 { + fn sample(g: &mut Gen) -> Self { + g.rng.gen() + } +} + +impl RandomConfig for Network { + fn sample(g: &mut Gen) -> Self { + match g.rng.gen_range(0..8) { + 0 => Self::Mainnet, + 1 => Self::Rinkeby, + 2 => Self::Ropsten, + 3 => Self::Goerli, + 4 => Self::Sepolia, + 5 => Self::Localhost, + 6 => Self::Unknown, + _ => Self::Test, + } + } +} + +impl RandomConfig for configs::chain::FeeModelVersion { + fn sample(g: &mut Gen) -> Self { + match g.rng.gen_range(0..2) { + 0 => Self::V1, + _ => Self::V2, + } + } +} + +impl RandomConfig for configs::AlertsConfig { + fn sample(g: &mut Gen) -> Self { + Self { + sporadic_crypto_errors_substrs: g.gen(), + } + } +} + +impl RandomConfig for configs::ApiConfig { + fn sample(g: &mut Gen) -> Self { + Self { + web3_json_rpc: g.gen(), + contract_verification: g.gen(), + prometheus: g.gen(), + healthcheck: g.gen(), + merkle_tree: g.gen(), + } + } +} + +impl RandomConfig for configs::api::Web3JsonRpcConfig { + fn sample(g: &mut Gen) -> Self { + Self { + http_port: g.gen(), + http_url: g.gen(), + ws_port: g.gen(), + ws_url: g.gen(), + req_entities_limit: g.gen(), + filters_limit: g.gen(), + subscriptions_limit: g.gen(), + pubsub_polling_interval: g.gen(), + max_nonce_ahead: g.gen(), + gas_price_scale_factor: g.gen(), + request_timeout: g.gen(), + account_pks: g.gen(), + estimate_gas_scale_factor: g.gen(), + estimate_gas_acceptable_overestimation: g.gen(), + l1_to_l2_transactions_compatibility_mode: g.gen(), + max_tx_size: g.gen(), + vm_execution_cache_misses_limit: g.gen(), + vm_concurrency_limit: g.gen(), + factory_deps_cache_size_mb: g.gen(), + initial_writes_cache_size_mb: g.gen(), + latest_values_cache_size_mb: g.gen(), + fee_history_limit: g.gen(), + max_batch_request_size: g.gen(), + max_response_body_size_mb: g.gen(), + websocket_requests_per_minute_limit: g.gen(), + tree_api_url: g.gen(), + } + } +} + +impl RandomConfig for configs::api::HealthCheckConfig { + fn sample(g: &mut Gen) -> Self { + Self { port: g.gen() } + } +} + +impl RandomConfig for configs::api::ContractVerificationApiConfig { + fn sample(g: &mut Gen) -> Self { + Self { + port: g.gen(), + url: g.gen(), + } + } +} + +impl RandomConfig for configs::api::MerkleTreeApiConfig { + fn sample(g: &mut Gen) -> Self { + Self { port: g.gen() } + } +} + +impl RandomConfig for configs::PrometheusConfig { + fn sample(g: &mut Gen) -> Self { + Self { + listener_port: g.gen(), + pushgateway_url: g.gen(), + push_interval_ms: g.gen(), + } + } +} + +impl RandomConfig for configs::chain::NetworkConfig { + fn sample(g: &mut Gen) -> Self { + Self { + network: g.gen(), + zksync_network: g.gen(), + zksync_network_id: L2ChainId::max(), + } + } +} + +impl RandomConfig for configs::chain::StateKeeperConfig { + fn sample(g: &mut Gen) -> Self { + Self { + transaction_slots: g.gen(), + block_commit_deadline_ms: g.gen(), + miniblock_commit_deadline_ms: g.gen(), + miniblock_seal_queue_capacity: g.gen(), + max_single_tx_gas: g.gen(), + max_allowed_l2_tx_gas_limit: g.gen(), + reject_tx_at_geometry_percentage: g.gen(), + reject_tx_at_eth_params_percentage: g.gen(), + reject_tx_at_gas_percentage: g.gen(), + close_block_at_geometry_percentage: g.gen(), + close_block_at_eth_params_percentage: g.gen(), + close_block_at_gas_percentage: g.gen(), + fee_account_addr: g.gen(), + minimal_l2_gas_price: g.gen(), + compute_overhead_part: g.gen(), + pubdata_overhead_part: g.gen(), + batch_overhead_l1_gas: g.gen(), + max_gas_per_batch: g.gen(), + max_pubdata_per_batch: g.gen(), + fee_model_version: g.gen(), + validation_computational_gas_limit: g.gen(), + save_call_traces: g.gen(), + virtual_blocks_interval: g.gen(), + virtual_blocks_per_miniblock: g.gen(), + upload_witness_inputs_to_gcs: g.gen(), + enum_index_migration_chunk_size: g.gen(), + } + } +} + +impl RandomConfig for configs::chain::OperationsManagerConfig { + fn sample(g: &mut Gen) -> Self { + Self { + delay_interval: g.gen(), + } + } +} + +impl RandomConfig for configs::chain::CircuitBreakerConfig { + fn sample(g: &mut Gen) -> Self { + Self { + sync_interval_ms: g.gen(), + http_req_max_retry_number: g.gen(), + http_req_retry_interval_sec: g.gen(), + replication_lag_limit_sec: g.gen(), + } + } +} + +impl RandomConfig for configs::chain::MempoolConfig { + fn sample(g: &mut Gen) -> Self { + Self { + sync_interval_ms: g.gen(), + sync_batch_size: g.gen(), + capacity: g.gen(), + stuck_tx_timeout: g.gen(), + remove_stuck_txs: g.gen(), + delay_interval: g.gen(), + } + } +} + +impl RandomConfig for configs::ContractVerifierConfig { + fn sample(g: &mut Gen) -> Self { + Self { + compilation_timeout: g.gen(), + polling_interval: g.gen(), + prometheus_port: g.gen(), + } + } +} + +impl RandomConfig for configs::contracts::ProverAtGenesis { + fn sample(g: &mut Gen) -> Self { + match g.rng.gen_range(0..2) { + 0 => Self::Fri, + _ => Self::Old, + } + } +} + +impl RandomConfig for configs::ContractsConfig { + fn sample(g: &mut Gen) -> Self { + Self { + governance_addr: g.gen(), + mailbox_facet_addr: g.gen(), + executor_facet_addr: g.gen(), + admin_facet_addr: g.gen(), + getters_facet_addr: g.gen(), + verifier_addr: g.gen(), + diamond_init_addr: g.gen(), + diamond_upgrade_init_addr: g.gen(), + diamond_proxy_addr: g.gen(), + validator_timelock_addr: g.gen(), + genesis_tx_hash: g.gen(), + l1_erc20_bridge_proxy_addr: g.gen(), + l1_erc20_bridge_impl_addr: g.gen(), + l2_erc20_bridge_addr: g.gen(), + l1_weth_bridge_proxy_addr: g.gen(), + l2_weth_bridge_addr: g.gen(), + l1_allow_list_addr: g.gen(), + l2_testnet_paymaster_addr: g.gen(), + recursion_scheduler_level_vk_hash: g.gen(), + recursion_node_level_vk_hash: g.gen(), + recursion_leaf_level_vk_hash: g.gen(), + recursion_circuits_set_vks_hash: g.gen(), + l1_multicall3_addr: g.gen(), + fri_recursion_scheduler_level_vk_hash: g.gen(), + fri_recursion_node_level_vk_hash: g.gen(), + fri_recursion_leaf_level_vk_hash: g.gen(), + prover_at_genesis: g.gen(), + snark_wrapper_vk_hash: g.gen(), + } + } +} + +impl RandomConfig for configs::database::MerkleTreeMode { + fn sample(g: &mut Gen) -> Self { + match g.rng.gen_range(0..2) { + 0 => Self::Full, + _ => Self::Lightweight, + } + } +} + +impl RandomConfig for configs::database::MerkleTreeConfig { + fn sample(g: &mut Gen) -> Self { + Self { + path: g.gen(), + mode: g.gen(), + multi_get_chunk_size: g.gen(), + block_cache_size_mb: g.gen(), + memtable_capacity_mb: g.gen(), + stalled_writes_timeout_sec: g.gen(), + max_l1_batches_per_iter: g.gen(), + } + } +} + +impl RandomConfig for configs::database::DBConfig { + fn sample(g: &mut Gen) -> Self { + Self { + state_keeper_db_path: g.gen(), + merkle_tree: g.gen(), + } + } +} + +impl RandomConfig for configs::database::PostgresConfig { + fn sample(g: &mut Gen) -> Self { + Self { + master_url: g.gen(), + replica_url: g.gen(), + prover_url: g.gen(), + max_connections: g.gen(), + statement_timeout_sec: g.gen(), + } + } +} + +impl RandomConfig for configs::ETHClientConfig { + fn sample(g: &mut Gen) -> Self { + Self { + chain_id: g.gen(), + web3_url: g.gen(), + } + } +} + +impl RandomConfig for configs::ETHSenderConfig { + fn sample(g: &mut Gen) -> Self { + Self { + sender: g.gen(), + gas_adjuster: g.gen(), + } + } +} + +impl RandomConfig for configs::eth_sender::ProofSendingMode { + fn sample(g: &mut Gen) -> Self { + match g.rng.gen_range(0..3) { + 0 => Self::OnlyRealProofs, + 1 => Self::OnlySampledProofs, + _ => Self::SkipEveryProof, + } + } +} + +impl RandomConfig for configs::eth_sender::ProofLoadingMode { + fn sample(g: &mut Gen) -> Self { + match g.rng.gen_range(0..2) { + 0 => Self::OldProofFromDb, + _ => Self::FriProofFromGcs, + } + } +} + +impl RandomConfig for configs::eth_sender::SenderConfig { + fn sample(g: &mut Gen) -> Self { + Self { + aggregated_proof_sizes: g.gen(), + wait_confirmations: g.gen(), + tx_poll_period: g.gen(), + aggregate_tx_poll_period: g.gen(), + max_txs_in_flight: g.gen(), + proof_sending_mode: g.gen(), + max_aggregated_tx_gas: g.gen(), + max_eth_tx_data_size: g.gen(), + max_aggregated_blocks_to_commit: g.gen(), + max_aggregated_blocks_to_execute: g.gen(), + aggregated_block_commit_deadline: g.gen(), + aggregated_block_prove_deadline: g.gen(), + aggregated_block_execute_deadline: g.gen(), + timestamp_criteria_max_allowed_lag: g.gen(), + l1_batch_min_age_before_execute_seconds: g.gen(), + max_acceptable_priority_fee_in_gwei: g.gen(), + proof_loading_mode: g.gen(), + } + } +} + +impl RandomConfig for configs::eth_sender::GasAdjusterConfig { + fn sample(g: &mut Gen) -> Self { + Self { + default_priority_fee_per_gas: g.gen(), + max_base_fee_samples: g.gen(), + pricing_formula_parameter_a: g.gen(), + pricing_formula_parameter_b: g.gen(), + internal_l1_pricing_multiplier: g.gen(), + internal_enforced_l1_gas_price: g.gen(), + poll_period: g.gen(), + max_l1_gas_price: g.gen(), + } + } +} + +impl RandomConfig for configs::ETHWatchConfig { + fn sample(g: &mut Gen) -> Self { + Self { + confirmations_for_eth_event: g.gen(), + eth_node_poll_interval: g.gen(), + } + } +} + +impl RandomConfig for configs::FriProofCompressorConfig { + fn sample(g: &mut Gen) -> Self { + Self { + compression_mode: g.gen(), + prometheus_listener_port: g.gen(), + prometheus_pushgateway_url: g.gen(), + prometheus_push_interval_ms: g.gen(), + generation_timeout_in_secs: g.gen(), + max_attempts: g.gen(), + universal_setup_path: g.gen(), + universal_setup_download_url: g.gen(), + verify_wrapper_proof: g.gen(), + } + } +} + +impl RandomConfig for configs::fri_prover::SetupLoadMode { + fn sample(g: &mut Gen) -> Self { + match g.rng.gen_range(0..2) { + 0 => Self::FromDisk, + _ => Self::FromMemory, + } + } +} + +impl RandomConfig for configs::FriProverConfig { + fn sample(g: &mut Gen) -> Self { + Self { + setup_data_path: g.gen(), + prometheus_port: g.gen(), + max_attempts: g.gen(), + generation_timeout_in_secs: g.gen(), + base_layer_circuit_ids_to_be_verified: g.gen(), + recursive_layer_circuit_ids_to_be_verified: g.gen(), + setup_load_mode: g.gen(), + specialized_group_id: g.gen(), + witness_vector_generator_thread_count: g.gen(), + queue_capacity: g.gen(), + witness_vector_receiver_port: g.gen(), + zone_read_url: g.gen(), + shall_save_to_public_bucket: g.gen(), + } + } +} + +impl RandomConfig for configs::FriProverGatewayConfig { + fn sample(g: &mut Gen) -> Self { + Self { + api_url: g.gen(), + api_poll_duration_secs: g.gen(), + prometheus_listener_port: g.gen(), + prometheus_pushgateway_url: g.gen(), + prometheus_push_interval_ms: g.gen(), + } + } +} + +impl RandomConfig for CircuitIdRoundTuple { + fn sample(g: &mut Gen) -> Self { + Self { + circuit_id: g.gen(), + aggregation_round: g.gen(), + } + } +} + +impl RandomConfig for configs::fri_prover_group::FriProverGroupConfig { + fn sample(g: &mut Gen) -> Self { + Self { + group_0: g.gen(), + group_1: g.gen(), + group_2: g.gen(), + group_3: g.gen(), + group_4: g.gen(), + group_5: g.gen(), + group_6: g.gen(), + group_7: g.gen(), + group_8: g.gen(), + group_9: g.gen(), + group_10: g.gen(), + group_11: g.gen(), + group_12: g.gen(), + } + } +} + +impl RandomConfig for configs::FriWitnessGeneratorConfig { + fn sample(g: &mut Gen) -> Self { + Self { + generation_timeout_in_secs: g.gen(), + max_attempts: g.gen(), + blocks_proving_percentage: g.gen(), + dump_arguments_for_blocks: g.gen(), + last_l1_batch_to_process: g.gen(), + force_process_block: g.gen(), + shall_save_to_public_bucket: g.gen(), + } + } +} + +impl RandomConfig for configs::FriWitnessVectorGeneratorConfig { + fn sample(g: &mut Gen) -> Self { + Self { + max_prover_reservation_duration_in_secs: g.gen(), + prover_instance_wait_timeout_in_secs: g.gen(), + prover_instance_poll_time_in_milli_secs: g.gen(), + prometheus_listener_port: g.gen(), + prometheus_pushgateway_url: g.gen(), + prometheus_push_interval_ms: g.gen(), + specialized_group_id: g.gen(), + } + } +} + +impl RandomConfig for configs::house_keeper::HouseKeeperConfig { + fn sample(g: &mut Gen) -> Self { + Self { + l1_batch_metrics_reporting_interval_ms: g.gen(), + gpu_prover_queue_reporting_interval_ms: g.gen(), + prover_job_retrying_interval_ms: g.gen(), + prover_stats_reporting_interval_ms: g.gen(), + witness_job_moving_interval_ms: g.gen(), + witness_generator_stats_reporting_interval_ms: g.gen(), + fri_witness_job_moving_interval_ms: g.gen(), + fri_prover_job_retrying_interval_ms: g.gen(), + fri_witness_generator_job_retrying_interval_ms: g.gen(), + prover_db_pool_size: g.gen(), + fri_prover_stats_reporting_interval_ms: g.gen(), + fri_proof_compressor_job_retrying_interval_ms: g.gen(), + fri_proof_compressor_stats_reporting_interval_ms: g.gen(), + } + } +} + +impl RandomConfig for configs::object_store::ObjectStoreMode { + fn sample(g: &mut Gen) -> Self { + match g.rng.gen_range(0..4) { + 0 => Self::GCS, + 1 => Self::GCSWithCredentialFile, + 2 => Self::FileBacked, + _ => Self::GCSAnonymousReadOnly, + } + } +} + +impl RandomConfig for configs::ObjectStoreConfig { + fn sample(g: &mut Gen) -> Self { + Self { + bucket_base_url: g.gen(), + mode: g.gen(), + file_backed_base_path: g.gen(), + gcs_credential_file_path: g.gen(), + max_retries: g.gen(), + } + } +} + +impl RandomConfig for configs::proof_data_handler::ProtocolVersionLoadingMode { + fn sample(g: &mut Gen) -> Self { + match g.rng.gen_range(0..2) { + 0 => Self::FromDb, + _ => Self::FromEnvVar, + } + } +} + +impl RandomConfig for configs::ProofDataHandlerConfig { + fn sample(g: &mut Gen) -> Self { + Self { + http_port: g.gen(), + proof_generation_timeout_in_secs: g.gen(), + protocol_version_loading_mode: g.gen(), + fri_protocol_version_id: g.gen(), + } + } +} + +impl RandomConfig for configs::SnapshotsCreatorConfig { + fn sample(g: &mut Gen) -> Self { + Self { + storage_logs_chunk_size: g.gen(), + concurrent_queries_count: g.gen(), + } + } +} + +impl RandomConfig for configs::witness_generator::BasicWitnessGeneratorDataSource { + fn sample(g: &mut Gen) -> Self { + match g.rng.gen_range(0..2) { + 0 => Self::FromPostgres, + 1 => Self::FromPostgresShadowBlob, + _ => Self::FromBlob, + } + } +} + +impl RandomConfig for configs::WitnessGeneratorConfig { + fn sample(g: &mut Gen) -> Self { + Self { + generation_timeout_in_secs: g.gen(), + initial_setup_key_path: g.gen(), + key_download_url: g.gen(), + max_attempts: g.gen(), + blocks_proving_percentage: g.gen(), + dump_arguments_for_blocks: g.gen(), + last_l1_batch_to_process: g.gen(), + data_source: g.gen(), + } + } +} diff --git a/core/lib/constants/Cargo.toml b/core/lib/constants/Cargo.toml index e7e12206da2c..36483d95bee2 100644 --- a/core/lib/constants/Cargo.toml +++ b/core/lib/constants/Cargo.toml @@ -12,13 +12,5 @@ categories = ["cryptography"] [dependencies] zksync_basic_types = { path = "../../lib/basic_types" } zksync_utils = { path = "../../lib/utils" } -zksync_contracts = { path = "../../lib/contracts" } -anyhow = "1.0" -url = "2.1" -num = "0.3.1" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" once_cell = "1.13.0" -bigdecimal = "0.2.2" -hex = "0.4" diff --git a/core/lib/constants/src/blocks.rs b/core/lib/constants/src/blocks.rs index 7579b408f0c0..5f7f83c2de2c 100644 --- a/core/lib/constants/src/blocks.rs +++ b/core/lib/constants/src/blocks.rs @@ -1,7 +1,7 @@ use zksync_basic_types::H256; -// By design we don't have a term: uncle blocks. Hence we have to use rlp hash -// from empty list for ethereum compatibility. +// By design we don't have a term: uncle blocks. Hence we have to use RLP hash +// from empty list for Ethereum compatibility. pub const EMPTY_UNCLES_HASH: H256 = H256([ 0x1d, 0xcc, 0x4d, 0xe8, 0xde, 0xc7, 0x5d, 0x7a, 0xab, 0x85, 0xb5, 0x67, 0xb6, 0xcc, 0xd4, 0x1a, 0xd3, 0x12, 0x45, 0x1b, 0x94, 0x8a, 0x74, 0x13, 0xf0, 0xa1, 0x42, 0xfd, 0x40, 0xd4, 0x93, 0x47, diff --git a/core/lib/constants/src/contracts.rs b/core/lib/constants/src/contracts.rs index 5e49f83e5e1d..9d167f7346a3 100644 --- a/core/lib/constants/src/contracts.rs +++ b/core/lib/constants/src/contracts.rs @@ -113,5 +113,5 @@ pub const ERC20_TRANSFER_TOPIC: H256 = H256([ // TODO (SMA-240): Research whether using zero address is ok pub const MINT_AND_BURN_ADDRESS: H160 = H160::zero(); -// The storage_log.value database value for a contract that was deployed in a failed transaction. +// The `storage_log.value` database value for a contract that was deployed in a failed transaction. pub const FAILED_CONTRACT_DEPLOYMENT_BYTECODE_HASH: H256 = H256::zero(); diff --git a/core/lib/constants/src/crypto.rs b/core/lib/constants/src/crypto.rs index 53a5bb98b796..ead2cc318370 100644 --- a/core/lib/constants/src/crypto.rs +++ b/core/lib/constants/src/crypto.rs @@ -1,32 +1,10 @@ -use num::BigUint; -use once_cell::sync::Lazy; - pub const ZKPORTER_IS_AVAILABLE: bool = false; /// Depth of the account tree. pub const ROOT_TREE_DEPTH: usize = 256; -/// Cost of 1 byte of calldata in bytes. -// TODO (SMA-1609): Double check this value. -// TODO: possibly remove this value. -pub const GAS_PER_PUBDATA_BYTE: u32 = 16; - -/// Maximum amount of bytes in one packed write storage slot. -/// Calculated as `(len(hash) + 1) + len(u256)` -// TODO (SMA-1609): Double check this value. -pub const MAX_BYTES_PER_PACKED_SLOT: u64 = 65; - -/// Amount of gas required to publish one slot in pubdata. -pub static GAS_PER_SLOT: Lazy = - Lazy::new(|| BigUint::from(MAX_BYTES_PER_PACKED_SLOT) * BigUint::from(GAS_PER_PUBDATA_BYTE)); - -pub const MAX_TXS_IN_BLOCK: usize = 1024; pub const MAX_NEW_FACTORY_DEPS: usize = 32; -pub const PAD_MSG_BEFORE_HASH_BITS_LEN: usize = 736; - -/// The size of the bootloader memory in bytes which is used by the protocol. -/// While the maximal possible size is a lot higher, we restrict ourselves to a certain limit to reduce -/// the requirements on RAM. -pub const USED_BOOTLOADER_MEMORY_BYTES: usize = 1 << 24; -pub const USED_BOOTLOADER_MEMORY_WORDS: usize = USED_BOOTLOADER_MEMORY_BYTES / 32; +/// To avoid DDoS we limit the size of the transactions size. +/// TODO(X): remove this as a constant and introduce a config. +pub const MAX_ENCODED_TX_SIZE: usize = 1 << 24; diff --git a/core/lib/constants/src/ethereum.rs b/core/lib/constants/src/ethereum.rs index 299b08e3d0d2..cd44b0486c56 100644 --- a/core/lib/constants/src/ethereum.rs +++ b/core/lib/constants/src/ethereum.rs @@ -3,25 +3,20 @@ use zksync_basic_types::Address; /// Priority op should be executed for this number of eth blocks. pub const PRIORITY_EXPIRATION: u64 = 50000; pub const MAX_L1_TRANSACTION_GAS_LIMIT: u64 = 300000; -pub static ETHEREUM_ADDRESS: Address = Address::zero(); - -/// This the number of pubdata such that it should be always possible to publish -/// from a single transaction. Note, that these pubdata bytes include only bytes that are -/// to be published inside the body of transaction (i.e. excluding of factory deps). -pub const GUARANTEED_PUBDATA_PER_L1_BATCH: u64 = 4000; +pub const ETHEREUM_ADDRESS: Address = Address::zero(); /// The maximum number of pubdata per L1 batch. This limit is due to the fact that the Ethereum /// nodes do not accept transactions that have more than 128kb of pubdata. /// The 18kb margin is left in case of any impreciseness of the pubdata calculation. pub const MAX_PUBDATA_PER_L1_BATCH: u64 = 110000; -// TODO: import from zkevm_opcode_defs once VM1.3 is supported +// TODO: import from `zkevm_opcode_defs` once `VM1.3` is supported pub const MAX_L2_TX_GAS_LIMIT: u64 = 80000000; -// The users should always be able to provide `MAX_GAS_PER_PUBDATA_BYTE` gas per pubdata in their -// transactions so that they are able to send at least GUARANTEED_PUBDATA_PER_L1_BATCH bytes per -// transaction. -pub const MAX_GAS_PER_PUBDATA_BYTE: u64 = MAX_L2_TX_GAS_LIMIT / GUARANTEED_PUBDATA_PER_L1_BATCH; - // The L1->L2 are required to have the following gas per pubdata byte. pub const REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE: u64 = 800; + +// The default gas per pubdata byte for L2 transactions, that is used, for instance, when we need to +// insert some default value for type 2 transactions. +// It is a realistic value, but it is large enough to fill into any batch regardless of the pubdata price. +pub const DEFAULT_L2_TX_GAS_PER_PUBDATA_BYTE: u64 = 50_000; diff --git a/core/lib/constants/src/system_context.rs b/core/lib/constants/src/system_context.rs index 6fa2def5f315..6a90469fb1f2 100644 --- a/core/lib/constants/src/system_context.rs +++ b/core/lib/constants/src/system_context.rs @@ -35,7 +35,7 @@ pub const SYSTEM_CONTEXT_DIFFICULTY_POSITION: H256 = H256([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ]); -// 2500000000000000. THe number is chosen for compatibility with other L2s. +// 2500000000000000. The number is chosen for compatibility with other L2s. pub const SYSTEM_CONTEXT_DIFFICULTY: H256 = H256([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xE1, 0xBC, 0x9B, 0xF0, 0x40, 0x00, @@ -48,7 +48,7 @@ pub const SYSTEM_CONTEXT_BASE_FEE_POSITION: H256 = H256([ // Tenth of a gwei in wei. 1 gwei is 10^9 wei, so 0.1 gwei is 10^8 wei. const TENTH_OF_GWEI: u64 = 10u64.pow(8); -// The base fee in wei. u64 as u32 would limit this price to be ~4.3 gwei. +// The base fee in wei. u64 as u32 would limit this price to be approximately 4.3 gwei. pub const SYSTEM_CONTEXT_MINIMAL_BASE_FEE: u64 = TENTH_OF_GWEI; pub const SYSTEM_CONTEXT_BLOCK_INFO_POSITION: H256 = H256([ @@ -78,12 +78,12 @@ pub const SYSTEM_CONTEXT_CURRENT_L2_BLOCK_HASHES_POSITION: H256 = H256([ pub const SYSTEM_CONTEXT_STORED_L2_BLOCK_HASHES: u32 = 257; -// It is equal to SYSTEM_CONTEXT_CURRENT_L2_BLOCK_HASHES_POSITION + SYSTEM_CONTEXT_STORED_L2_BLOCK_HASHES +// It is equal to `SYSTEM_CONTEXT_CURRENT_L2_BLOCK_HASHES_POSITION + SYSTEM_CONTEXT_STORED_L2_BLOCK_HASHES` pub const CURRENT_VIRTUAL_BLOCK_INFO_POSITION: H256 = H256([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0c, ]); -/// Block info is stored compactly as SYSTEM_BLOCK_INFO_BLOCK_NUMBER_MULTIPLIER * block_number + block_timestamp. -/// This number is equal to 2**128 +/// Block info is stored compactly as `SYSTEM_BLOCK_INFO_BLOCK_NUMBER_MULTIPLIER * block_number + block_timestamp`. +/// This number is equal to `2**128` pub const SYSTEM_BLOCK_INFO_BLOCK_NUMBER_MULTIPLIER: U256 = U256([0, 0, 1, 0]); diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs index 5b6e29129519..f6bfd9c1e4a3 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -33,12 +33,8 @@ const MULTICALL3_CONTRACT_FILE: &str = "contracts/l1-contracts/artifacts/cache/solpp-generated-contracts/dev-contracts/Multicall3.sol/Multicall3.json"; const VERIFIER_CONTRACT_FILE: &str = "contracts/l1-contracts/artifacts/cache/solpp-generated-contracts/zksync/Verifier.sol/Verifier.json"; -const IERC20_CONTRACT_FILE: &str = - "contracts/l1-contracts/artifacts/cache/solpp-generated-contracts/common/interfaces/IERC20.sol/IERC20.json"; -const FAIL_ON_RECEIVE_CONTRACT_FILE: &str = - "contracts/l1-contracts/artifacts/cache/solpp-generated-contracts/zksync/dev-contracts/FailOnReceive.sol/FailOnReceive.json"; const L2_BRIDGE_CONTRACT_FILE: &str = - "contracts/l2-contracts/artifacts-zk/cache-zk/solpp-generated-contracts/bridge/interfaces/IL2Bridge.sol/IL2Bridge.json"; + "contracts/l2-contracts/artifacts-zk/contracts-preprocessed/bridge/interfaces/IL2Bridge.sol/IL2Bridge.json"; const LOADNEXT_CONTRACT_FILE: &str = "etc/contracts-test-data/artifacts-zk/contracts/loadnext/loadnext_contract.sol/LoadnextContract.json"; const LOADNEXT_SIMPLE_CONTRACT_FILE: &str = @@ -53,7 +49,7 @@ fn read_file_to_json_value(path: impl AsRef) -> serde_json::Value { .unwrap_or_else(|e| panic!("Failed to parse file {:?}: {}", path, e)) } -pub fn load_contract_if_present + std::fmt::Debug>(path: P) -> Option { +fn load_contract_if_present + std::fmt::Debug>(path: P) -> Option { let zksync_home = std::env::var("ZKSYNC_HOME").unwrap_or_else(|_| ".".into()); let path = Path::new(&zksync_home).join(path); path.exists().then(|| { @@ -70,18 +66,11 @@ pub fn load_contract + std::fmt::Debug>(path: P) -> Contract { pub fn load_sys_contract(contract_name: &str) -> Contract { load_contract(format!( - "contracts/system-contracts/artifacts-zk/cache-zk/solpp-generated-contracts/{0}.sol/{0}.json", + "contracts/system-contracts/artifacts-zk/contracts-preprocessed/{0}.sol/{0}.json", contract_name )) } -pub fn read_contract_abi(path: impl AsRef) -> String { - read_file_to_json_value(path)["abi"] - .as_str() - .expect("Failed to parse abi") - .to_string() -} - pub fn governance_contract() -> Contract { load_contract_if_present(GOVERNANCE_CONTRACT_FILE).expect("Governance contract not found") } @@ -94,10 +83,6 @@ pub fn multicall_contract() -> Contract { load_contract(MULTICALL3_CONTRACT_FILE) } -pub fn erc20_contract() -> Contract { - load_contract(IERC20_CONTRACT_FILE) -} - pub fn l2_bridge_contract() -> Contract { load_contract(L2_BRIDGE_CONTRACT_FILE) } @@ -129,30 +114,16 @@ pub fn get_loadnext_contract() -> TestContract { } // Returns loadnext contract and its factory dependencies -pub fn loadnext_contract() -> Contract { +fn loadnext_contract() -> Contract { load_contract("etc/contracts-test-data/artifacts-zk/contracts/loadnext/loadnext_contract.sol/LoadnextContract.json") } -pub fn loadnext_simple_contract() -> Contract { - load_contract( - "etc/contracts-test-data/artifacts-zk/contracts/loadnext/loadnext_contract.sol/Foo.json", - ) -} - -pub fn fail_on_receive_contract() -> Contract { - load_contract(FAIL_ON_RECEIVE_CONTRACT_FILE) -} - pub fn deployer_contract() -> Contract { load_sys_contract("ContractDeployer") } -pub fn eth_contract() -> Contract { - load_sys_contract("L2EthToken") -} - -pub fn known_codes_contract() -> Contract { - load_sys_contract("KnownCodesStorage") +pub fn l1_messenger_contract() -> Contract { + load_sys_contract("L1Messenger") } /// Reads bytecode from the path RELATIVE to the ZKSYNC_HOME environment variable. @@ -161,8 +132,9 @@ pub fn read_bytecode(relative_path: impl AsRef) -> Vec { let artifact_path = Path::new(&zksync_home).join(relative_path); read_bytecode_from_path(artifact_path) } + /// Reads bytecode from a given path. -pub fn read_bytecode_from_path(artifact_path: PathBuf) -> Vec { +fn read_bytecode_from_path(artifact_path: PathBuf) -> Vec { let artifact = read_file_to_json_value(artifact_path.clone()); let bytecode = artifact["bytecode"] @@ -175,22 +147,18 @@ pub fn read_bytecode_from_path(artifact_path: PathBuf) -> Vec { .unwrap_or_else(|err| panic!("Can't decode bytecode in {:?}: {}", artifact_path, err)) } -pub fn default_erc20_bytecode() -> Vec { - read_bytecode("etc/ERC20/artifacts-zk/contracts/ZkSyncERC20.sol/ZkSyncERC20.json") -} - pub fn read_sys_contract_bytecode(directory: &str, name: &str, lang: ContractLanguage) -> Vec { DEFAULT_SYSTEM_CONTRACTS_REPO.read_sys_contract_bytecode(directory, name, lang) } -pub static DEFAULT_SYSTEM_CONTRACTS_REPO: Lazy = +static DEFAULT_SYSTEM_CONTRACTS_REPO: Lazy = Lazy::new(SystemContractsRepo::from_env); /// Structure representing a system contract repository - that allows /// fetching contracts that are located there. /// As most of the static methods in this file, is loading data based on ZKSYNC_HOME environment variable. pub struct SystemContractsRepo { - // Path to the root of the system contracts repo. + // Path to the root of the system contracts repository. pub root: PathBuf, } @@ -203,6 +171,7 @@ impl SystemContractsRepo { root: zksync_home.join("contracts/system-contracts"), } } + pub fn read_sys_contract_bytecode( &self, directory: &str, @@ -211,11 +180,11 @@ impl SystemContractsRepo { ) -> Vec { match lang { ContractLanguage::Sol => read_bytecode_from_path(self.root.join(format!( - "artifacts-zk/cache-zk/solpp-generated-contracts/{0}{1}.sol/{1}.json", + "artifacts-zk/contracts-preprocessed/{0}{1}.sol/{1}.json", directory, name ))), ContractLanguage::Yul => read_zbin_bytecode_from_path(self.root.join(format!( - "contracts/{0}artifacts/{1}.yul/{1}.yul.zbin", + "contracts-preprocessed/{0}artifacts/{1}.yul.zbin", directory, name ))), } @@ -224,33 +193,19 @@ impl SystemContractsRepo { pub fn read_bootloader_code(bootloader_type: &str) -> Vec { read_zbin_bytecode(format!( - "contracts/system-contracts/bootloader/build/artifacts/{}.yul/{}.yul.zbin", - bootloader_type, bootloader_type + "contracts/system-contracts/bootloader/build/artifacts/{}.yul.zbin", + bootloader_type )) } -pub fn read_proved_batch_bootloader_bytecode() -> Vec { +fn read_proved_batch_bootloader_bytecode() -> Vec { read_bootloader_code("proved_batch") } -pub fn read_playground_batch_bootloader_bytecode() -> Vec { +fn read_playground_batch_bootloader_bytecode() -> Vec { read_bootloader_code("playground_batch") } -pub fn get_loadnext_test_contract_path(file_name: &str, contract_name: &str) -> String { - format!( - "core/tests/loadnext/test-contracts/loadnext_contract/artifacts/loadnext_contract.sol/{}.sol:{}.abi", - file_name, contract_name - ) -} - -pub fn get_loadnext_test_contract_bytecode(file_name: &str, contract_name: &str) -> String { - format!( - "core/tests/loadnext/test-contracts/loadnext_contract/artifacts/loadnext_contract.sol/{}.sol:{}.zbin", - file_name, contract_name - ) -} - /// Reads zbin bytecode from a given path, relative to ZKSYNC_HOME. pub fn read_zbin_bytecode(relative_zbin_path: impl AsRef) -> Vec { let zksync_home = std::env::var("ZKSYNC_HOME").unwrap_or_else(|_| ".".into()); @@ -259,7 +214,7 @@ pub fn read_zbin_bytecode(relative_zbin_path: impl AsRef) -> Vec { } /// Reads zbin bytecode from a given path. -pub fn read_zbin_bytecode_from_path(bytecode_path: PathBuf) -> Vec { +fn read_zbin_bytecode_from_path(bytecode_path: PathBuf) -> Vec { fs::read(&bytecode_path) .unwrap_or_else(|err| panic!("Can't read .zbin bytecode at {:?}: {}", bytecode_path, err)) } @@ -289,26 +244,6 @@ impl PartialEq for BaseSystemContracts { } } -pub static PLAYGROUND_BLOCK_BOOTLOADER_CODE: Lazy = Lazy::new(|| { - let bytecode = read_playground_batch_bootloader_bytecode(); - let hash = hash_bytecode(&bytecode); - - SystemContractCode { - code: bytes_to_be_words(bytecode), - hash, - } -}); - -pub static ESTIMATE_FEE_BLOCK_CODE: Lazy = Lazy::new(|| { - let bytecode = read_bootloader_code("fee_estimate"); - let hash = hash_bytecode(&bytecode); - - SystemContractCode { - code: bytes_to_be_words(bytecode), - hash, - } -}); - impl BaseSystemContracts { fn load_with_bootloader(bootloader_bytecode: Vec) -> Self { let hash = hash_bytecode(&bootloader_bytecode); @@ -365,9 +300,15 @@ impl BaseSystemContracts { BaseSystemContracts::load_with_bootloader(bootloader_bytecode) } - /// BaseSystemContracts with playground bootloader - used for handling eth_calls. - pub fn estimate_gas() -> Self { - let bootloader_bytecode = read_bootloader_code("fee_estimate"); + pub fn playground_post_allowlist_removal() -> Self { + let bootloader_bytecode = read_zbin_bytecode("etc/multivm_bootloaders/vm_remove_allowlist/playground_batch.yul/playground_batch.yul.zbin"); + BaseSystemContracts::load_with_bootloader(bootloader_bytecode) + } + + pub fn playground_post_1_4_1() -> Self { + let bootloader_bytecode = read_zbin_bytecode( + "etc/multivm_bootloaders/vm_1_4_1/playground_batch.yul/playground_batch.yul.zbin", + ); BaseSystemContracts::load_with_bootloader(bootloader_bytecode) } @@ -399,6 +340,20 @@ impl BaseSystemContracts { BaseSystemContracts::load_with_bootloader(bootloader_bytecode) } + pub fn estimate_gas_post_allowlist_removal() -> Self { + let bootloader_bytecode = read_zbin_bytecode( + "etc/multivm_bootloaders/vm_remove_allowlist/fee_estimate.yul/fee_estimate.yul.zbin", + ); + BaseSystemContracts::load_with_bootloader(bootloader_bytecode) + } + + pub fn estimate_gas_post_1_4_1() -> Self { + let bootloader_bytecode = read_zbin_bytecode( + "etc/multivm_bootloaders/vm_1_4_1/fee_estimate.yul/fee_estimate.yul.zbin", + ); + BaseSystemContracts::load_with_bootloader(bootloader_bytecode) + } + pub fn hashes(&self) -> BaseSystemContractsHashes { BaseSystemContractsHashes { bootloader: self.bootloader.hash, diff --git a/core/lib/crypto/Cargo.toml b/core/lib/crypto/Cargo.toml index 56ee24ddfe9a..8c9dfb7be49e 100644 --- a/core/lib/crypto/Cargo.toml +++ b/core/lib/crypto/Cargo.toml @@ -16,7 +16,6 @@ serde = "1.0" thiserror = "1.0" once_cell = "1.7" hex = "0.4" -base64 = "0.13" sha2 = "0.9" blake2 = "0.10" diff --git a/core/lib/crypto/README.md b/core/lib/crypto/README.md index 2a4f3d4b9c5c..e224b2732d34 100644 --- a/core/lib/crypto/README.md +++ b/core/lib/crypto/README.md @@ -7,4 +7,4 @@ `zksync_crypto` is a part of zkSync stack, which is distributed under the terms of both the MIT license and the Apache License (Version 2.0). -See [LICENSE-APACHE](../../LICENSE-APACHE), [LICENSE-MIT](../../LICENSE-MIT) for details. +See [LICENSE-APACHE](../../../LICENSE-APACHE), [LICENSE-MIT](../../../LICENSE-MIT) for details. diff --git a/core/lib/dal/.sqlx/query-0034bc1041d9ba7d3c681be6dfc4e7dfacfcf625e057b99924c245de03c2888c.json b/core/lib/dal/.sqlx/query-0034bc1041d9ba7d3c681be6dfc4e7dfacfcf625e057b99924c245de03c2888c.json new file mode 100644 index 000000000000..cf78a74dfb3c --- /dev/null +++ b/core/lib/dal/.sqlx/query-0034bc1041d9ba7d3c681be6dfc4e7dfacfcf625e057b99924c245de03c2888c.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE l1_batches\n SET\n fee_account_address = $1::bytea\n WHERE\n number = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "0034bc1041d9ba7d3c681be6dfc4e7dfacfcf625e057b99924c245de03c2888c" +} diff --git a/core/lib/dal/.sqlx/query-00b88ec7fcf40bb18e0018b7c76f6e1df560ab1e8935564355236e90b6147d2f.json b/core/lib/dal/.sqlx/query-00b88ec7fcf40bb18e0018b7c76f6e1df560ab1e8935564355236e90b6147d2f.json new file mode 100644 index 000000000000..49a533897ce3 --- /dev/null +++ b/core/lib/dal/.sqlx/query-00b88ec7fcf40bb18e0018b7c76f6e1df560ab1e8935564355236e90b6147d2f.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE scheduler_witness_jobs_fri\n SET\n status = 'successful',\n updated_at = NOW(),\n time_taken = $1\n WHERE\n l1_batch_number = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Time", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "00b88ec7fcf40bb18e0018b7c76f6e1df560ab1e8935564355236e90b6147d2f" +} diff --git a/core/lib/dal/.sqlx/query-012bed5d34240ed28c331c8515c381d82925556a4801f678b8786235d525d784.json b/core/lib/dal/.sqlx/query-012bed5d34240ed28c331c8515c381d82925556a4801f678b8786235d525d784.json new file mode 100644 index 000000000000..fbeefdfbf956 --- /dev/null +++ b/core/lib/dal/.sqlx/query-012bed5d34240ed28c331c8515c381d82925556a4801f678b8786235d525d784.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE l1_batches\n SET\n eth_commit_tx_id = $1,\n updated_at = NOW()\n WHERE\n number BETWEEN $2 AND $3\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4", + "Int8", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "012bed5d34240ed28c331c8515c381d82925556a4801f678b8786235d525d784" +} diff --git a/core/lib/dal/.sqlx/query-015350f8d729ef490553550a68f07703b2581dda4fe3c00be6c5422c78980c4b.json b/core/lib/dal/.sqlx/query-015350f8d729ef490553550a68f07703b2581dda4fe3c00be6c5422c78980c4b.json new file mode 100644 index 000000000000..d8495583ba97 --- /dev/null +++ b/core/lib/dal/.sqlx/query-015350f8d729ef490553550a68f07703b2581dda4fe3c00be6c5422c78980c4b.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n MAX(id) AS \"max?\"\n FROM\n protocol_versions\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "max?", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "015350f8d729ef490553550a68f07703b2581dda4fe3c00be6c5422c78980c4b" +} diff --git a/core/lib/dal/.sqlx/query-01ac5343beb09ec5bd45b39d560e57a83f37da8999849377dfad60b44989be39.json b/core/lib/dal/.sqlx/query-01ac5343beb09ec5bd45b39d560e57a83f37da8999849377dfad60b44989be39.json new file mode 100644 index 000000000000..8ca4bb693c23 --- /dev/null +++ b/core/lib/dal/.sqlx/query-01ac5343beb09ec5bd45b39d560e57a83f37da8999849377dfad60b44989be39.json @@ -0,0 +1,107 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE node_aggregation_witness_jobs_fri\n SET\n status = 'in_progress',\n attempts = attempts + 1,\n updated_at = NOW(),\n processing_started_at = NOW(),\n picked_by = $2\n WHERE\n id = (\n SELECT\n id\n FROM\n node_aggregation_witness_jobs_fri\n WHERE\n status = 'queued'\n AND protocol_version = ANY ($1)\n ORDER BY\n l1_batch_number ASC,\n depth ASC,\n id ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n node_aggregation_witness_jobs_fri.*\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "circuit_id", + "type_info": "Int2" + }, + { + "ordinal": 3, + "name": "depth", + "type_info": "Int4" + }, + { + "ordinal": 4, + "name": "status", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "attempts", + "type_info": "Int2" + }, + { + "ordinal": 6, + "name": "aggregations_url", + "type_info": "Text" + }, + { + "ordinal": 7, + "name": "processing_started_at", + "type_info": "Timestamp" + }, + { + "ordinal": 8, + "name": "time_taken", + "type_info": "Time" + }, + { + "ordinal": 9, + "name": "error", + "type_info": "Text" + }, + { + "ordinal": 10, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 11, + "name": "updated_at", + "type_info": "Timestamp" + }, + { + "ordinal": 12, + "name": "number_of_dependent_jobs", + "type_info": "Int4" + }, + { + "ordinal": 13, + "name": "protocol_version", + "type_info": "Int4" + }, + { + "ordinal": 14, + "name": "picked_by", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Int4Array", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + true, + true, + true + ] + }, + "hash": "01ac5343beb09ec5bd45b39d560e57a83f37da8999849377dfad60b44989be39" +} diff --git a/core/lib/dal/.sqlx/query-01e4cde73867da612084c3f6fe882d56bbace9013f1d95ea0926eef1fb48039b.json b/core/lib/dal/.sqlx/query-01e4cde73867da612084c3f6fe882d56bbace9013f1d95ea0926eef1fb48039b.json new file mode 100644 index 000000000000..4a229dbe78d6 --- /dev/null +++ b/core/lib/dal/.sqlx/query-01e4cde73867da612084c3f6fe882d56bbace9013f1d95ea0926eef1fb48039b.json @@ -0,0 +1,34 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_number,\n factory_deps_filepath,\n storage_logs_filepaths\n FROM\n snapshots\n WHERE\n l1_batch_number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "factory_deps_filepath", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "storage_logs_filepaths", + "type_info": "TextArray" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "01e4cde73867da612084c3f6fe882d56bbace9013f1d95ea0926eef1fb48039b" +} diff --git a/core/lib/dal/.sqlx/query-01f72dfc1eee6360a8ef7809874a1b4ba7fe355ebc02ea49a054aa073ce324ba.json b/core/lib/dal/.sqlx/query-01f72dfc1eee6360a8ef7809874a1b4ba7fe355ebc02ea49a054aa073ce324ba.json new file mode 100644 index 000000000000..e28c68abc281 --- /dev/null +++ b/core/lib/dal/.sqlx/query-01f72dfc1eee6360a8ef7809874a1b4ba7fe355ebc02ea49a054aa073ce324ba.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE storage\n SET\n value = u.value\n FROM\n UNNEST($1::bytea[], $2::bytea[]) AS u (key, value)\n WHERE\n u.key = hashed_key\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "ByteaArray", + "ByteaArray" + ] + }, + "nullable": [] + }, + "hash": "01f72dfc1eee6360a8ef7809874a1b4ba7fe355ebc02ea49a054aa073ce324ba" +} diff --git a/core/lib/dal/.sqlx/query-026ab7dd7407f10074a2966b5eac2563a3e061bcc6505d8c295b1b2517f85f1b.json b/core/lib/dal/.sqlx/query-026ab7dd7407f10074a2966b5eac2563a3e061bcc6505d8c295b1b2517f85f1b.json new file mode 100644 index 000000000000..d98798241f7e --- /dev/null +++ b/core/lib/dal/.sqlx/query-026ab7dd7407f10074a2966b5eac2563a3e061bcc6505d8c295b1b2517f85f1b.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n number\n FROM\n l1_batches\n LEFT JOIN eth_txs_history AS prove_tx ON (l1_batches.eth_prove_tx_id = prove_tx.eth_tx_id)\n WHERE\n prove_tx.confirmed_at IS NOT NULL\n ORDER BY\n number DESC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "026ab7dd7407f10074a2966b5eac2563a3e061bcc6505d8c295b1b2517f85f1b" +} diff --git a/core/lib/dal/.sqlx/query-03c585c7e9f918e608757496088c7e3b6bdb2a08149d5f443310607d3c78988c.json b/core/lib/dal/.sqlx/query-03c585c7e9f918e608757496088c7e3b6bdb2a08149d5f443310607d3c78988c.json new file mode 100644 index 000000000000..9c811e9f87cc --- /dev/null +++ b/core/lib/dal/.sqlx/query-03c585c7e9f918e608757496088c7e3b6bdb2a08149d5f443310607d3c78988c.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n storage_refunds\n FROM\n l1_batches\n WHERE\n number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "storage_refunds", + "type_info": "Int8Array" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + true + ] + }, + "hash": "03c585c7e9f918e608757496088c7e3b6bdb2a08149d5f443310607d3c78988c" +} diff --git a/core/lib/dal/.sqlx/query-040eaa878c3473f5edc73b77e572b5ea100f59295cd693d14ee0d5ee089c7981.json b/core/lib/dal/.sqlx/query-040eaa878c3473f5edc73b77e572b5ea100f59295cd693d14ee0d5ee089c7981.json new file mode 100644 index 000000000000..c0e0c777cc52 --- /dev/null +++ b/core/lib/dal/.sqlx/query-040eaa878c3473f5edc73b77e572b5ea100f59295cd693d14ee0d5ee089c7981.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_number\n FROM\n snapshots\n WHERE\n NOT (''::TEXT = ANY (storage_logs_filepaths))\n ORDER BY\n l1_batch_number DESC\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "040eaa878c3473f5edc73b77e572b5ea100f59295cd693d14ee0d5ee089c7981" +} diff --git a/core/lib/dal/.sqlx/query-04e407cc7675c0787847209d378242a0eb9cad22a120a957a699c8752933b8a7.json b/core/lib/dal/.sqlx/query-04e407cc7675c0787847209d378242a0eb9cad22a120a957a699c8752933b8a7.json new file mode 100644 index 000000000000..8720a96ca132 --- /dev/null +++ b/core/lib/dal/.sqlx/query-04e407cc7675c0787847209d378242a0eb9cad22a120a957a699c8752933b8a7.json @@ -0,0 +1,226 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n parent_hash,\n commitment,\n compressed_write_logs,\n compressed_contracts,\n eth_prove_tx_id,\n eth_commit_tx_id,\n eth_execute_tx_id,\n merkle_root_hash,\n l2_to_l1_logs,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_compressed_messages,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n WHERE\n eth_commit_tx_id IS NOT NULL\n AND eth_prove_tx_id IS NULL\n ORDER BY\n number\n LIMIT\n $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "l1_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 3, + "name": "l2_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 4, + "name": "bloom", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "priority_ops_onchain_data", + "type_info": "ByteaArray" + }, + { + "ordinal": 6, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "parent_hash", + "type_info": "Bytea" + }, + { + "ordinal": 8, + "name": "commitment", + "type_info": "Bytea" + }, + { + "ordinal": 9, + "name": "compressed_write_logs", + "type_info": "Bytea" + }, + { + "ordinal": 10, + "name": "compressed_contracts", + "type_info": "Bytea" + }, + { + "ordinal": 11, + "name": "eth_prove_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 12, + "name": "eth_commit_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 13, + "name": "eth_execute_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 14, + "name": "merkle_root_hash", + "type_info": "Bytea" + }, + { + "ordinal": 15, + "name": "l2_to_l1_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 16, + "name": "l2_to_l1_messages", + "type_info": "ByteaArray" + }, + { + "ordinal": 17, + "name": "used_contract_hashes", + "type_info": "Jsonb" + }, + { + "ordinal": 18, + "name": "compressed_initial_writes", + "type_info": "Bytea" + }, + { + "ordinal": 19, + "name": "compressed_repeated_writes", + "type_info": "Bytea" + }, + { + "ordinal": 20, + "name": "l2_l1_compressed_messages", + "type_info": "Bytea" + }, + { + "ordinal": 21, + "name": "l2_l1_merkle_root", + "type_info": "Bytea" + }, + { + "ordinal": 22, + "name": "rollup_last_leaf_index", + "type_info": "Int8" + }, + { + "ordinal": 23, + "name": "zkporter_is_available", + "type_info": "Bool" + }, + { + "ordinal": 24, + "name": "bootloader_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 25, + "name": "default_aa_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 26, + "name": "aux_data_hash", + "type_info": "Bytea" + }, + { + "ordinal": 27, + "name": "pass_through_data_hash", + "type_info": "Bytea" + }, + { + "ordinal": 28, + "name": "meta_parameters_hash", + "type_info": "Bytea" + }, + { + "ordinal": 29, + "name": "protocol_version", + "type_info": "Int4" + }, + { + "ordinal": 30, + "name": "compressed_state_diffs", + "type_info": "Bytea" + }, + { + "ordinal": 31, + "name": "system_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 32, + "name": "events_queue_commitment", + "type_info": "Bytea" + }, + { + "ordinal": 33, + "name": "bootloader_initial_content_commitment", + "type_info": "Bytea" + }, + { + "ordinal": 34, + "name": "pubdata_input", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + true, + true + ] + }, + "hash": "04e407cc7675c0787847209d378242a0eb9cad22a120a957a699c8752933b8a7" +} diff --git a/core/lib/dal/.sqlx/query-04fbbd198108d2614a3b29fa795994723ebe57b3ed209069bd3db906921ef1a3.json b/core/lib/dal/.sqlx/query-04fbbd198108d2614a3b29fa795994723ebe57b3ed209069bd3db906921ef1a3.json new file mode 100644 index 000000000000..00f94f7c864e --- /dev/null +++ b/core/lib/dal/.sqlx/query-04fbbd198108d2614a3b29fa795994723ebe57b3ed209069bd3db906921ef1a3.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n MIN(miniblocks.number) AS \"min?\",\n MAX(miniblocks.number) AS \"max?\"\n FROM\n miniblocks\n WHERE\n l1_batch_number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "min?", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "max?", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + null, + null + ] + }, + "hash": "04fbbd198108d2614a3b29fa795994723ebe57b3ed209069bd3db906921ef1a3" +} diff --git a/core/lib/dal/.sqlx/query-0535c87d0ae694d5f10e529742ba2803cd147dec7450d1f81a41aea8dcf3be93.json b/core/lib/dal/.sqlx/query-0535c87d0ae694d5f10e529742ba2803cd147dec7450d1f81a41aea8dcf3be93.json new file mode 100644 index 000000000000..8c16bcb25c8a --- /dev/null +++ b/core/lib/dal/.sqlx/query-0535c87d0ae694d5f10e529742ba2803cd147dec7450d1f81a41aea8dcf3be93.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n fee_account_address\n FROM\n miniblocks\n WHERE\n number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "fee_account_address", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "0535c87d0ae694d5f10e529742ba2803cd147dec7450d1f81a41aea8dcf3be93" +} diff --git a/core/lib/dal/.sqlx/query-07310d96fc7e258154ad510684e33d196907ebd599e926d305e5ef9f26afa2fa.json b/core/lib/dal/.sqlx/query-07310d96fc7e258154ad510684e33d196907ebd599e926d305e5ef9f26afa2fa.json new file mode 100644 index 000000000000..a293d217645c --- /dev/null +++ b/core/lib/dal/.sqlx/query-07310d96fc7e258154ad510684e33d196907ebd599e926d305e5ef9f26afa2fa.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO eth_txs_history (eth_tx_id, base_fee_per_gas, priority_fee_per_gas, tx_hash, signed_raw_tx, created_at, updated_at, confirmed_at) VALUES ($1, 0, 0, $2, '\\x00', now(), now(), $3) RETURNING id", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int4", + "Text", + "Timestamp" + ] + }, + "nullable": [ + false + ] + }, + "hash": "07310d96fc7e258154ad510684e33d196907ebd599e926d305e5ef9f26afa2fa" +} diff --git a/core/lib/dal/.sqlx/query-083991abb3f1c2183d1bd1fb2ad4710daa723e2d9a23317c347f6081465c3643.json b/core/lib/dal/.sqlx/query-083991abb3f1c2183d1bd1fb2ad4710daa723e2d9a23317c347f6081465c3643.json new file mode 100644 index 000000000000..e2c3a7105562 --- /dev/null +++ b/core/lib/dal/.sqlx/query-083991abb3f1c2183d1bd1fb2ad4710daa723e2d9a23317c347f6081465c3643.json @@ -0,0 +1,52 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE basic_witness_input_producer_jobs\n SET\n status = $1,\n updated_at = NOW(),\n time_taken = $3,\n error = $4\n WHERE\n l1_batch_number = $2\n AND status != $5\n RETURNING\n basic_witness_input_producer_jobs.attempts\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "attempts", + "type_info": "Int2" + } + ], + "parameters": { + "Left": [ + { + "Custom": { + "name": "basic_witness_input_producer_job_status", + "kind": { + "Enum": [ + "Queued", + "ManuallySkipped", + "InProgress", + "Successful", + "Failed" + ] + } + } + }, + "Int8", + "Time", + "Text", + { + "Custom": { + "name": "basic_witness_input_producer_job_status", + "kind": { + "Enum": [ + "Queued", + "ManuallySkipped", + "InProgress", + "Successful", + "Failed" + ] + } + } + } + ] + }, + "nullable": [ + false + ] + }, + "hash": "083991abb3f1c2183d1bd1fb2ad4710daa723e2d9a23317c347f6081465c3643" +} diff --git a/core/lib/dal/.sqlx/query-08737d11b3e5067a2468013ec6e5d95fc47eb6bedc32f4d824aac9b2b6f96faf.json b/core/lib/dal/.sqlx/query-08737d11b3e5067a2468013ec6e5d95fc47eb6bedc32f4d824aac9b2b6f96faf.json new file mode 100644 index 000000000000..2e83c0036b95 --- /dev/null +++ b/core/lib/dal/.sqlx/query-08737d11b3e5067a2468013ec6e5d95fc47eb6bedc32f4d824aac9b2b6f96faf.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE miniblocks\n SET\n fee_account_address = l1_batches.fee_account_address\n FROM\n l1_batches\n WHERE\n l1_batches.number = miniblocks.l1_batch_number\n AND miniblocks.number BETWEEN $1 AND $2\n AND miniblocks.fee_account_address = '\\x0000000000000000000000000000000000000000'::bytea\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "08737d11b3e5067a2468013ec6e5d95fc47eb6bedc32f4d824aac9b2b6f96faf" +} diff --git a/core/lib/dal/.sqlx/query-08e59ed8e2fd1a74e19d8bf0d131e4ee6682a89fb86f3b715a240805d44e6d87.json b/core/lib/dal/.sqlx/query-08e59ed8e2fd1a74e19d8bf0d131e4ee6682a89fb86f3b715a240805d44e6d87.json new file mode 100644 index 000000000000..0c3ca92c10c5 --- /dev/null +++ b/core/lib/dal/.sqlx/query-08e59ed8e2fd1a74e19d8bf0d131e4ee6682a89fb86f3b715a240805d44e6d87.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n proof_generation_details (l1_batch_number, status, proof_gen_data_blob_url, created_at, updated_at)\n VALUES\n ($1, 'ready_to_be_proven', $2, NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Text" + ] + }, + "nullable": [] + }, + "hash": "08e59ed8e2fd1a74e19d8bf0d131e4ee6682a89fb86f3b715a240805d44e6d87" +} diff --git a/core/lib/dal/.sqlx/query-0914f0ad03d6a8c55d287f94917c6f03469d78bf4f45f5fd1eaf37171db2f04a.json b/core/lib/dal/.sqlx/query-0914f0ad03d6a8c55d287f94917c6f03469d78bf4f45f5fd1eaf37171db2f04a.json new file mode 100644 index 000000000000..b8e36d109065 --- /dev/null +++ b/core/lib/dal/.sqlx/query-0914f0ad03d6a8c55d287f94917c6f03469d78bf4f45f5fd1eaf37171db2f04a.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_number\n FROM\n proof_generation_details\n WHERE\n status NOT IN ('generated', 'skipped')\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "0914f0ad03d6a8c55d287f94917c6f03469d78bf4f45f5fd1eaf37171db2f04a" +} diff --git a/core/lib/dal/.sqlx/query-0a3c928a616b5ebc0b977bd773edcde721ca1c652ae2f8db41fb75cecdecb674.json b/core/lib/dal/.sqlx/query-0a3c928a616b5ebc0b977bd773edcde721ca1c652ae2f8db41fb75cecdecb674.json new file mode 100644 index 000000000000..f0e439d0e0b8 --- /dev/null +++ b/core/lib/dal/.sqlx/query-0a3c928a616b5ebc0b977bd773edcde721ca1c652ae2f8db41fb75cecdecb674.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT COUNT(*) FROM storage_logs WHERE miniblock_number = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + null + ] + }, + "hash": "0a3c928a616b5ebc0b977bd773edcde721ca1c652ae2f8db41fb75cecdecb674" +} diff --git a/core/lib/dal/.sqlx/query-0a3cb11f5bdcb8da31dbd4e3016fced141fb29dd8b6c32dd2dc3452dc294fe1f.json b/core/lib/dal/.sqlx/query-0a3cb11f5bdcb8da31dbd4e3016fced141fb29dd8b6c32dd2dc3452dc294fe1f.json new file mode 100644 index 000000000000..854e34b4f184 --- /dev/null +++ b/core/lib/dal/.sqlx/query-0a3cb11f5bdcb8da31dbd4e3016fced141fb29dd8b6c32dd2dc3452dc294fe1f.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n protocol_versions (\n id,\n timestamp,\n recursion_scheduler_level_vk_hash,\n recursion_node_level_vk_hash,\n recursion_leaf_level_vk_hash,\n recursion_circuits_set_vks_hash,\n bootloader_code_hash,\n default_account_code_hash,\n verifier_address,\n upgrade_tx_hash,\n created_at\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, NOW())\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4", + "Int8", + "Bytea", + "Bytea", + "Bytea", + "Bytea", + "Bytea", + "Bytea", + "Bytea", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "0a3cb11f5bdcb8da31dbd4e3016fced141fb29dd8b6c32dd2dc3452dc294fe1f" +} diff --git a/core/lib/dal/.sqlx/query-0a53fc3c90a14038c9f3f32c3e2e5f7edcafa4fc6757264a96a46dbf7dd1f9cc.json b/core/lib/dal/.sqlx/query-0a53fc3c90a14038c9f3f32c3e2e5f7edcafa4fc6757264a96a46dbf7dd1f9cc.json new file mode 100644 index 000000000000..00379abe6df7 --- /dev/null +++ b/core/lib/dal/.sqlx/query-0a53fc3c90a14038c9f3f32c3e2e5f7edcafa4fc6757264a96a46dbf7dd1f9cc.json @@ -0,0 +1,31 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n transactions (\n hash,\n is_priority,\n initiator_address,\n gas_limit,\n max_fee_per_gas,\n gas_per_pubdata_limit,\n data,\n priority_op_id,\n full_fee,\n layer_2_tip_fee,\n contract_address,\n l1_block_number,\n value,\n paymaster,\n paymaster_input,\n tx_format,\n l1_tx_mint,\n l1_tx_refund_recipient,\n received_at,\n created_at,\n updated_at\n )\n VALUES\n (\n $1,\n TRUE,\n $2,\n $3,\n $4,\n $5,\n $6,\n $7,\n $8,\n $9,\n $10,\n $11,\n $12,\n $13,\n $14,\n $15,\n $16,\n $17,\n $18,\n NOW(),\n NOW()\n )\n ON CONFLICT (hash) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Bytea", + "Numeric", + "Numeric", + "Numeric", + "Jsonb", + "Int8", + "Numeric", + "Numeric", + "Bytea", + "Int4", + "Numeric", + "Bytea", + "Bytea", + "Int4", + "Numeric", + "Bytea", + "Timestamp" + ] + }, + "nullable": [] + }, + "hash": "0a53fc3c90a14038c9f3f32c3e2e5f7edcafa4fc6757264a96a46dbf7dd1f9cc" +} diff --git a/core/lib/dal/.sqlx/query-0bdcf87f6910c7222b621f76f71bc6e326e15dca141050bc9d7dacae98a430e8.json b/core/lib/dal/.sqlx/query-0bdcf87f6910c7222b621f76f71bc6e326e15dca141050bc9d7dacae98a430e8.json new file mode 100644 index 000000000000..e5ed48130726 --- /dev/null +++ b/core/lib/dal/.sqlx/query-0bdcf87f6910c7222b621f76f71bc6e326e15dca141050bc9d7dacae98a430e8.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n hash\n FROM\n l1_batches\n WHERE\n number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hash", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + true + ] + }, + "hash": "0bdcf87f6910c7222b621f76f71bc6e326e15dca141050bc9d7dacae98a430e8" +} diff --git a/core/lib/dal/.sqlx/query-0c899c68886f76a232ffac0454cdfbf962636347864fc365fafa46c7a2da5f30.json b/core/lib/dal/.sqlx/query-0c899c68886f76a232ffac0454cdfbf962636347864fc365fafa46c7a2da5f30.json new file mode 100644 index 000000000000..35c1633fc557 --- /dev/null +++ b/core/lib/dal/.sqlx/query-0c899c68886f76a232ffac0454cdfbf962636347864fc365fafa46c7a2da5f30.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n virtual_blocks\n FROM\n miniblocks\n WHERE\n number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "virtual_blocks", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "0c899c68886f76a232ffac0454cdfbf962636347864fc365fafa46c7a2da5f30" +} diff --git a/core/lib/dal/.sqlx/query-0c95fbfb3a816bd49fd06e3a4f0a52daa202279bf612a9278f663deb78bc6e41.json b/core/lib/dal/.sqlx/query-0c95fbfb3a816bd49fd06e3a4f0a52daa202279bf612a9278f663deb78bc6e41.json new file mode 100644 index 000000000000..100761f54b41 --- /dev/null +++ b/core/lib/dal/.sqlx/query-0c95fbfb3a816bd49fd06e3a4f0a52daa202279bf612a9278f663deb78bc6e41.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n protocol_version\n FROM\n l1_batches\n WHERE\n number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "protocol_version", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + true + ] + }, + "hash": "0c95fbfb3a816bd49fd06e3a4f0a52daa202279bf612a9278f663deb78bc6e41" +} diff --git a/core/lib/dal/.sqlx/query-0d13b8947b1bafa9e5bc6fdc70a986511265c541d81b1d21f0a751ae1399c626.json b/core/lib/dal/.sqlx/query-0d13b8947b1bafa9e5bc6fdc70a986511265c541d81b1d21f0a751ae1399c626.json new file mode 100644 index 000000000000..8b5605f078a5 --- /dev/null +++ b/core/lib/dal/.sqlx/query-0d13b8947b1bafa9e5bc6fdc70a986511265c541d81b1d21f0a751ae1399c626.json @@ -0,0 +1,72 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE gpu_prover_queue_fri\n SET\n instance_status = 'reserved',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n id IN (\n SELECT\n id\n FROM\n gpu_prover_queue_fri\n WHERE\n specialized_prover_group_id = $2\n AND zone = $3\n AND (\n instance_status = 'available'\n OR (\n instance_status = 'reserved'\n AND processing_started_at < NOW() - $1::INTERVAL\n )\n )\n ORDER BY\n updated_at ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n gpu_prover_queue_fri.*\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "instance_host", + "type_info": "Inet" + }, + { + "ordinal": 2, + "name": "instance_port", + "type_info": "Int4" + }, + { + "ordinal": 3, + "name": "instance_status", + "type_info": "Text" + }, + { + "ordinal": 4, + "name": "specialized_prover_group_id", + "type_info": "Int2" + }, + { + "ordinal": 5, + "name": "zone", + "type_info": "Text" + }, + { + "ordinal": 6, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 7, + "name": "updated_at", + "type_info": "Timestamp" + }, + { + "ordinal": 8, + "name": "processing_started_at", + "type_info": "Timestamp" + } + ], + "parameters": { + "Left": [ + "Interval", + "Int2", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + true, + false, + false, + true + ] + }, + "hash": "0d13b8947b1bafa9e5bc6fdc70a986511265c541d81b1d21f0a751ae1399c626" +} diff --git a/core/lib/dal/.sqlx/query-10959c91f01ce0da196f4c6eaf0661a097308d9f81024fdfef24a14418202730.json b/core/lib/dal/.sqlx/query-10959c91f01ce0da196f4c6eaf0661a097308d9f81024fdfef24a14418202730.json new file mode 100644 index 000000000000..8f929a7a7336 --- /dev/null +++ b/core/lib/dal/.sqlx/query-10959c91f01ce0da196f4c6eaf0661a097308d9f81024fdfef24a14418202730.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n verification_info\n FROM\n contracts_verification_info\n WHERE\n address = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "verification_info", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [ + true + ] + }, + "hash": "10959c91f01ce0da196f4c6eaf0661a097308d9f81024fdfef24a14418202730" +} diff --git a/core/lib/dal/.sqlx/query-11af69fc254e54449b64c086667700a95e4c37a7a18531b3cdf120394cb055b9.json b/core/lib/dal/.sqlx/query-11af69fc254e54449b64c086667700a95e4c37a7a18531b3cdf120394cb055b9.json new file mode 100644 index 000000000000..ed211d7dc9d8 --- /dev/null +++ b/core/lib/dal/.sqlx/query-11af69fc254e54449b64c086667700a95e4c37a7a18531b3cdf120394cb055b9.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE proof_generation_details\n SET\n status = 'picked_by_prover',\n updated_at = NOW(),\n prover_taken_at = NOW()\n WHERE\n l1_batch_number = (\n SELECT\n l1_batch_number\n FROM\n proof_generation_details\n WHERE\n status = 'ready_to_be_proven'\n OR (\n status = 'picked_by_prover'\n AND prover_taken_at < NOW() - $1::INTERVAL\n )\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n proof_generation_details.l1_batch_number\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Interval" + ] + }, + "nullable": [ + false + ] + }, + "hash": "11af69fc254e54449b64c086667700a95e4c37a7a18531b3cdf120394cb055b9" +} diff --git a/core/lib/dal/.sqlx/query-12ab208f416e2875f89e558f0d4aff3a06b7a9c1866132d62e4449fa9436c7c4.json b/core/lib/dal/.sqlx/query-12ab208f416e2875f89e558f0d4aff3a06b7a9c1866132d62e4449fa9436c7c4.json new file mode 100644 index 000000000000..5441bce3e016 --- /dev/null +++ b/core/lib/dal/.sqlx/query-12ab208f416e2875f89e558f0d4aff3a06b7a9c1866132d62e4449fa9436c7c4.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE node_aggregation_witness_jobs_fri\n SET\n status = 'failed',\n error = $1,\n updated_at = NOW()\n WHERE\n id = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "12ab208f416e2875f89e558f0d4aff3a06b7a9c1866132d62e4449fa9436c7c4" +} diff --git a/core/lib/dal/.sqlx/query-12ab8ba692a42f528450f2adf8d263298abc0521734f807fbf45484158b167b2.json b/core/lib/dal/.sqlx/query-12ab8ba692a42f528450f2adf8d263298abc0521734f807fbf45484158b167b2.json new file mode 100644 index 000000000000..556867a21ff4 --- /dev/null +++ b/core/lib/dal/.sqlx/query-12ab8ba692a42f528450f2adf8d263298abc0521734f807fbf45484158b167b2.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_address\n FROM\n tokens\n WHERE\n well_known = FALSE\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_address", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "12ab8ba692a42f528450f2adf8d263298abc0521734f807fbf45484158b167b2" +} diff --git a/core/lib/dal/.sqlx/query-136569d7eb4037fd77e0fac2246c68e8e15a831f1a45dc3b2240d5c6809d5ef2.json b/core/lib/dal/.sqlx/query-136569d7eb4037fd77e0fac2246c68e8e15a831f1a45dc3b2240d5c6809d5ef2.json new file mode 100644 index 000000000000..fc33c9693033 --- /dev/null +++ b/core/lib/dal/.sqlx/query-136569d7eb4037fd77e0fac2246c68e8e15a831f1a45dc3b2240d5c6809d5ef2.json @@ -0,0 +1,82 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n *\n FROM\n protocol_versions\n WHERE\n id = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "recursion_scheduler_level_vk_hash", + "type_info": "Bytea" + }, + { + "ordinal": 3, + "name": "recursion_node_level_vk_hash", + "type_info": "Bytea" + }, + { + "ordinal": 4, + "name": "recursion_leaf_level_vk_hash", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "recursion_circuits_set_vks_hash", + "type_info": "Bytea" + }, + { + "ordinal": 6, + "name": "bootloader_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "default_account_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 8, + "name": "verifier_address", + "type_info": "Bytea" + }, + { + "ordinal": 9, + "name": "upgrade_tx_hash", + "type_info": "Bytea" + }, + { + "ordinal": 10, + "name": "created_at", + "type_info": "Timestamp" + } + ], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + false + ] + }, + "hash": "136569d7eb4037fd77e0fac2246c68e8e15a831f1a45dc3b2240d5c6809d5ef2" +} diff --git a/core/lib/dal/.sqlx/query-15858168fea6808c6d59d0e6d8f28a20420763a3a22899ad0e5f4b953b615a9e.json b/core/lib/dal/.sqlx/query-15858168fea6808c6d59d0e6d8f28a20420763a3a22899ad0e5f4b953b615a9e.json new file mode 100644 index 000000000000..ac0e433a9195 --- /dev/null +++ b/core/lib/dal/.sqlx/query-15858168fea6808c6d59d0e6d8f28a20420763a3a22899ad0e5f4b953b615a9e.json @@ -0,0 +1,25 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n id\n FROM\n prover_fri_protocol_versions\n WHERE\n recursion_circuits_set_vks_hash = $1\n AND recursion_leaf_level_vk_hash = $2\n AND recursion_node_level_vk_hash = $3\n AND recursion_scheduler_level_vk_hash = $4\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Bytea", + "Bytea", + "Bytea", + "Bytea" + ] + }, + "nullable": [ + false + ] + }, + "hash": "15858168fea6808c6d59d0e6d8f28a20420763a3a22899ad0e5f4b953b615a9e" +} diff --git a/core/lib/dal/.sqlx/query-1689c212d411ebd99a22210519ea2d505a1aabf52ff4136d2ed1b39c70dd1632.json b/core/lib/dal/.sqlx/query-1689c212d411ebd99a22210519ea2d505a1aabf52ff4136d2ed1b39c70dd1632.json new file mode 100644 index 000000000000..7b939d137db9 --- /dev/null +++ b/core/lib/dal/.sqlx/query-1689c212d411ebd99a22210519ea2d505a1aabf52ff4136d2ed1b39c70dd1632.json @@ -0,0 +1,230 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n *\n FROM\n transactions\n WHERE\n miniblock_number IS NOT NULL\n AND l1_batch_number IS NULL\n ORDER BY\n miniblock_number,\n index_in_block\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "is_priority", + "type_info": "Bool" + }, + { + "ordinal": 2, + "name": "full_fee", + "type_info": "Numeric" + }, + { + "ordinal": 3, + "name": "layer_2_tip_fee", + "type_info": "Numeric" + }, + { + "ordinal": 4, + "name": "initiator_address", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "nonce", + "type_info": "Int8" + }, + { + "ordinal": 6, + "name": "signature", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "input", + "type_info": "Bytea" + }, + { + "ordinal": 8, + "name": "data", + "type_info": "Jsonb" + }, + { + "ordinal": 9, + "name": "received_at", + "type_info": "Timestamp" + }, + { + "ordinal": 10, + "name": "priority_op_id", + "type_info": "Int8" + }, + { + "ordinal": 11, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 12, + "name": "index_in_block", + "type_info": "Int4" + }, + { + "ordinal": 13, + "name": "error", + "type_info": "Varchar" + }, + { + "ordinal": 14, + "name": "gas_limit", + "type_info": "Numeric" + }, + { + "ordinal": 15, + "name": "gas_per_storage_limit", + "type_info": "Numeric" + }, + { + "ordinal": 16, + "name": "gas_per_pubdata_limit", + "type_info": "Numeric" + }, + { + "ordinal": 17, + "name": "tx_format", + "type_info": "Int4" + }, + { + "ordinal": 18, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 19, + "name": "updated_at", + "type_info": "Timestamp" + }, + { + "ordinal": 20, + "name": "execution_info", + "type_info": "Jsonb" + }, + { + "ordinal": 21, + "name": "contract_address", + "type_info": "Bytea" + }, + { + "ordinal": 22, + "name": "in_mempool", + "type_info": "Bool" + }, + { + "ordinal": 23, + "name": "l1_block_number", + "type_info": "Int4" + }, + { + "ordinal": 24, + "name": "value", + "type_info": "Numeric" + }, + { + "ordinal": 25, + "name": "paymaster", + "type_info": "Bytea" + }, + { + "ordinal": 26, + "name": "paymaster_input", + "type_info": "Bytea" + }, + { + "ordinal": 27, + "name": "max_fee_per_gas", + "type_info": "Numeric" + }, + { + "ordinal": 28, + "name": "max_priority_fee_per_gas", + "type_info": "Numeric" + }, + { + "ordinal": 29, + "name": "effective_gas_price", + "type_info": "Numeric" + }, + { + "ordinal": 30, + "name": "miniblock_number", + "type_info": "Int8" + }, + { + "ordinal": 31, + "name": "l1_batch_tx_index", + "type_info": "Int4" + }, + { + "ordinal": 32, + "name": "refunded_gas", + "type_info": "Int8" + }, + { + "ordinal": 33, + "name": "l1_tx_mint", + "type_info": "Numeric" + }, + { + "ordinal": 34, + "name": "l1_tx_refund_recipient", + "type_info": "Bytea" + }, + { + "ordinal": 35, + "name": "upgrade_id", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + true, + true, + false, + true, + true, + true, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + false, + true, + true, + true + ] + }, + "hash": "1689c212d411ebd99a22210519ea2d505a1aabf52ff4136d2ed1b39c70dd1632" +} diff --git a/core/lib/dal/.sqlx/query-1766c0a21ba5918dd08f4babd8dbfdf10fb1cb43781219586c169fb976204331.json b/core/lib/dal/.sqlx/query-1766c0a21ba5918dd08f4babd8dbfdf10fb1cb43781219586c169fb976204331.json new file mode 100644 index 000000000000..74c11e4c9a01 --- /dev/null +++ b/core/lib/dal/.sqlx/query-1766c0a21ba5918dd08f4babd8dbfdf10fb1cb43781219586c169fb976204331.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_number\n FROM\n initial_writes\n WHERE\n hashed_key = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [ + false + ] + }, + "hash": "1766c0a21ba5918dd08f4babd8dbfdf10fb1cb43781219586c169fb976204331" +} diff --git a/core/lib/dal/.sqlx/query-1862d3a78e4e9068df1b8ce3bbe9f3f0b5d629fdb5c36ea1bfb93ed246be968e.json b/core/lib/dal/.sqlx/query-1862d3a78e4e9068df1b8ce3bbe9f3f0b5d629fdb5c36ea1bfb93ed246be968e.json new file mode 100644 index 000000000000..1bb2d641befb --- /dev/null +++ b/core/lib/dal/.sqlx/query-1862d3a78e4e9068df1b8ce3bbe9f3f0b5d629fdb5c36ea1bfb93ed246be968e.json @@ -0,0 +1,88 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n transactions.is_priority,\n transactions.initiator_address,\n transactions.gas_limit,\n transactions.gas_per_pubdata_limit,\n transactions.received_at,\n transactions.miniblock_number,\n transactions.error,\n transactions.effective_gas_price,\n transactions.refunded_gas,\n commit_tx.tx_hash AS \"eth_commit_tx_hash?\",\n prove_tx.tx_hash AS \"eth_prove_tx_hash?\",\n execute_tx.tx_hash AS \"eth_execute_tx_hash?\"\n FROM\n transactions\n LEFT JOIN miniblocks ON miniblocks.number = transactions.miniblock_number\n LEFT JOIN l1_batches ON l1_batches.number = miniblocks.l1_batch_number\n LEFT JOIN eth_txs_history AS commit_tx ON (\n l1_batches.eth_commit_tx_id = commit_tx.eth_tx_id\n AND commit_tx.confirmed_at IS NOT NULL\n )\n LEFT JOIN eth_txs_history AS prove_tx ON (\n l1_batches.eth_prove_tx_id = prove_tx.eth_tx_id\n AND prove_tx.confirmed_at IS NOT NULL\n )\n LEFT JOIN eth_txs_history AS execute_tx ON (\n l1_batches.eth_execute_tx_id = execute_tx.eth_tx_id\n AND execute_tx.confirmed_at IS NOT NULL\n )\n WHERE\n transactions.hash = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "is_priority", + "type_info": "Bool" + }, + { + "ordinal": 1, + "name": "initiator_address", + "type_info": "Bytea" + }, + { + "ordinal": 2, + "name": "gas_limit", + "type_info": "Numeric" + }, + { + "ordinal": 3, + "name": "gas_per_pubdata_limit", + "type_info": "Numeric" + }, + { + "ordinal": 4, + "name": "received_at", + "type_info": "Timestamp" + }, + { + "ordinal": 5, + "name": "miniblock_number", + "type_info": "Int8" + }, + { + "ordinal": 6, + "name": "error", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "effective_gas_price", + "type_info": "Numeric" + }, + { + "ordinal": 8, + "name": "refunded_gas", + "type_info": "Int8" + }, + { + "ordinal": 9, + "name": "eth_commit_tx_hash?", + "type_info": "Text" + }, + { + "ordinal": 10, + "name": "eth_prove_tx_hash?", + "type_info": "Text" + }, + { + "ordinal": 11, + "name": "eth_execute_tx_hash?", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [ + false, + false, + true, + true, + false, + true, + true, + true, + false, + false, + false, + false + ] + }, + "hash": "1862d3a78e4e9068df1b8ce3bbe9f3f0b5d629fdb5c36ea1bfb93ed246be968e" +} diff --git a/core/lib/dal/.sqlx/query-19314d74e94b610e2da6d728ca37ea964610e131d45f720f7a7b2a130fe9ed89.json b/core/lib/dal/.sqlx/query-19314d74e94b610e2da6d728ca37ea964610e131d45f720f7a7b2a130fe9ed89.json new file mode 100644 index 000000000000..88093dcee18e --- /dev/null +++ b/core/lib/dal/.sqlx/query-19314d74e94b610e2da6d728ca37ea964610e131d45f720f7a7b2a130fe9ed89.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE contract_verification_requests\n SET\n status = 'failed',\n updated_at = NOW(),\n error = $2,\n compilation_errors = $3,\n panic_message = $4\n WHERE\n id = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Text", + "Jsonb", + "Text" + ] + }, + "nullable": [] + }, + "hash": "19314d74e94b610e2da6d728ca37ea964610e131d45f720f7a7b2a130fe9ed89" +} diff --git a/core/lib/dal/.sqlx/query-19545806b8f772075096e69f8665d98a3d9f7df162ae22a98c3c7620fcd13bd2.json b/core/lib/dal/.sqlx/query-19545806b8f772075096e69f8665d98a3d9f7df162ae22a98c3c7620fcd13bd2.json new file mode 100644 index 000000000000..3273d9654aa4 --- /dev/null +++ b/core/lib/dal/.sqlx/query-19545806b8f772075096e69f8665d98a3d9f7df162ae22a98c3c7620fcd13bd2.json @@ -0,0 +1,80 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n *\n FROM\n protocol_versions\n ORDER BY\n id DESC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "recursion_scheduler_level_vk_hash", + "type_info": "Bytea" + }, + { + "ordinal": 3, + "name": "recursion_node_level_vk_hash", + "type_info": "Bytea" + }, + { + "ordinal": 4, + "name": "recursion_leaf_level_vk_hash", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "recursion_circuits_set_vks_hash", + "type_info": "Bytea" + }, + { + "ordinal": 6, + "name": "bootloader_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "default_account_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 8, + "name": "verifier_address", + "type_info": "Bytea" + }, + { + "ordinal": 9, + "name": "upgrade_tx_hash", + "type_info": "Bytea" + }, + { + "ordinal": 10, + "name": "created_at", + "type_info": "Timestamp" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + false + ] + }, + "hash": "19545806b8f772075096e69f8665d98a3d9f7df162ae22a98c3c7620fcd13bd2" +} diff --git a/core/lib/dal/.sqlx/query-19b89495be8aa735db039ccc8a262786c58e54f132588c48f07d9537cf21d3ed.json b/core/lib/dal/.sqlx/query-19b89495be8aa735db039ccc8a262786c58e54f132588c48f07d9537cf21d3ed.json new file mode 100644 index 000000000000..b1156c907d47 --- /dev/null +++ b/core/lib/dal/.sqlx/query-19b89495be8aa735db039ccc8a262786c58e54f132588c48f07d9537cf21d3ed.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT sent_at_block FROM eth_txs_history WHERE eth_tx_id = $1 AND sent_at_block IS NOT NULL ORDER BY created_at ASC LIMIT 1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "sent_at_block", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [ + true + ] + }, + "hash": "19b89495be8aa735db039ccc8a262786c58e54f132588c48f07d9537cf21d3ed" +} diff --git a/core/lib/dal/.sqlx/query-1ad3bbd791f3ff0d31683bf59187b84c5fd52f0352f0f0e311d054cb9e45b07e.json b/core/lib/dal/.sqlx/query-1ad3bbd791f3ff0d31683bf59187b84c5fd52f0352f0f0e311d054cb9e45b07e.json new file mode 100644 index 000000000000..460f81615bf4 --- /dev/null +++ b/core/lib/dal/.sqlx/query-1ad3bbd791f3ff0d31683bf59187b84c5fd52f0352f0f0e311d054cb9e45b07e.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT DISTINCT\n ON (hashed_key) hashed_key\n FROM\n (\n SELECT\n *\n FROM\n storage_logs\n WHERE\n miniblock_number > $1\n ) inn\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hashed_key", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "1ad3bbd791f3ff0d31683bf59187b84c5fd52f0352f0f0e311d054cb9e45b07e" +} diff --git a/core/lib/dal/.sqlx/query-1b4ebbfc96b4fd66ecbe64a6be80a01a6c7cbe9297cbb55d42533fddc18719b6.json b/core/lib/dal/.sqlx/query-1b4ebbfc96b4fd66ecbe64a6be80a01a6c7cbe9297cbb55d42533fddc18719b6.json new file mode 100644 index 000000000000..8b9995b3b0f7 --- /dev/null +++ b/core/lib/dal/.sqlx/query-1b4ebbfc96b4fd66ecbe64a6be80a01a6c7cbe9297cbb55d42533fddc18719b6.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n MAX(priority_op_id) AS \"op_id\"\n FROM\n transactions\n WHERE\n is_priority = TRUE\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "op_id", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "1b4ebbfc96b4fd66ecbe64a6be80a01a6c7cbe9297cbb55d42533fddc18719b6" +} diff --git a/core/lib/dal/.sqlx/query-1bc6597117db032b87df33040d61610ffa7f169d560e79e89b99eedf681c6773.json b/core/lib/dal/.sqlx/query-1bc6597117db032b87df33040d61610ffa7f169d560e79e89b99eedf681c6773.json new file mode 100644 index 000000000000..0351691c3955 --- /dev/null +++ b/core/lib/dal/.sqlx/query-1bc6597117db032b87df33040d61610ffa7f169d560e79e89b99eedf681c6773.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n scheduler_witness_jobs_fri (\n l1_batch_number,\n scheduler_partial_input_blob_url,\n protocol_version,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, 'waiting_for_proofs', NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO\n UPDATE\n SET\n updated_at = NOW()\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Text", + "Int4" + ] + }, + "nullable": [] + }, + "hash": "1bc6597117db032b87df33040d61610ffa7f169d560e79e89b99eedf681c6773" +} diff --git a/core/lib/dal/.sqlx/query-1c14d2def60fa5ff91788ddb55e68cee71742b732112038a642e2a07305053c2.json b/core/lib/dal/.sqlx/query-1c14d2def60fa5ff91788ddb55e68cee71742b732112038a642e2a07305053c2.json new file mode 100644 index 000000000000..71dfada3d59a --- /dev/null +++ b/core/lib/dal/.sqlx/query-1c14d2def60fa5ff91788ddb55e68cee71742b732112038a642e2a07305053c2.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE transactions\n SET\n in_mempool = FALSE\n WHERE\n in_mempool = TRUE\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "1c14d2def60fa5ff91788ddb55e68cee71742b732112038a642e2a07305053c2" +} diff --git a/core/lib/dal/.sqlx/query-1c60010ded4e79886890a745a050fa6d65c05d8144bdfd143480834ead4bd8d5.json b/core/lib/dal/.sqlx/query-1c60010ded4e79886890a745a050fa6d65c05d8144bdfd143480834ead4bd8d5.json new file mode 100644 index 000000000000..a9d5b42d2148 --- /dev/null +++ b/core/lib/dal/.sqlx/query-1c60010ded4e79886890a745a050fa6d65c05d8144bdfd143480834ead4bd8d5.json @@ -0,0 +1,76 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE contract_verification_requests\n SET\n status = 'in_progress',\n attempts = attempts + 1,\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n id = (\n SELECT\n id\n FROM\n contract_verification_requests\n WHERE\n status = 'queued'\n OR (\n status = 'in_progress'\n AND processing_started_at < NOW() - $1::INTERVAL\n )\n ORDER BY\n created_at\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n id,\n contract_address,\n source_code,\n contract_name,\n zk_compiler_version,\n compiler_version,\n optimization_used,\n optimizer_mode,\n constructor_arguments,\n is_system\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "contract_address", + "type_info": "Bytea" + }, + { + "ordinal": 2, + "name": "source_code", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "contract_name", + "type_info": "Text" + }, + { + "ordinal": 4, + "name": "zk_compiler_version", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "compiler_version", + "type_info": "Text" + }, + { + "ordinal": 6, + "name": "optimization_used", + "type_info": "Bool" + }, + { + "ordinal": 7, + "name": "optimizer_mode", + "type_info": "Text" + }, + { + "ordinal": 8, + "name": "constructor_arguments", + "type_info": "Bytea" + }, + { + "ordinal": 9, + "name": "is_system", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Interval" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + true, + false, + false + ] + }, + "hash": "1c60010ded4e79886890a745a050fa6d65c05d8144bdfd143480834ead4bd8d5" +} diff --git a/core/lib/dal/.sqlx/query-1c994d418ada78586de829fc2d34d26e48e968c79834858c98b7a7f9dfc81910.json b/core/lib/dal/.sqlx/query-1c994d418ada78586de829fc2d34d26e48e968c79834858c98b7a7f9dfc81910.json new file mode 100644 index 000000000000..747105fb444b --- /dev/null +++ b/core/lib/dal/.sqlx/query-1c994d418ada78586de829fc2d34d26e48e968c79834858c98b7a7f9dfc81910.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM l2_to_l1_logs\n WHERE\n miniblock_number > $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "1c994d418ada78586de829fc2d34d26e48e968c79834858c98b7a7f9dfc81910" +} diff --git a/core/lib/dal/.sqlx/query-1d2cc4b485536af350089cf7950be3b85419fde77038dd3de6c55aa9c55d375c.json b/core/lib/dal/.sqlx/query-1d2cc4b485536af350089cf7950be3b85419fde77038dd3de6c55aa9c55d375c.json new file mode 100644 index 000000000000..b8929febf761 --- /dev/null +++ b/core/lib/dal/.sqlx/query-1d2cc4b485536af350089cf7950be3b85419fde77038dd3de6c55aa9c55d375c.json @@ -0,0 +1,61 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n storage.value AS \"value!\",\n tokens.l1_address AS \"l1_address!\",\n tokens.l2_address AS \"l2_address!\",\n tokens.symbol AS \"symbol!\",\n tokens.name AS \"name!\",\n tokens.decimals AS \"decimals!\",\n tokens.usd_price AS \"usd_price?\"\n FROM\n storage\n INNER JOIN tokens ON storage.address = tokens.l2_address\n OR (\n storage.address = $2\n AND tokens.l2_address = $3\n )\n WHERE\n storage.hashed_key = ANY ($1)\n AND storage.value != $4\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "value!", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "l1_address!", + "type_info": "Bytea" + }, + { + "ordinal": 2, + "name": "l2_address!", + "type_info": "Bytea" + }, + { + "ordinal": 3, + "name": "symbol!", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "name!", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "decimals!", + "type_info": "Int4" + }, + { + "ordinal": 6, + "name": "usd_price?", + "type_info": "Numeric" + } + ], + "parameters": { + "Left": [ + "ByteaArray", + "Bytea", + "Bytea", + "Bytea" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + true + ] + }, + "hash": "1d2cc4b485536af350089cf7950be3b85419fde77038dd3de6c55aa9c55d375c" +} diff --git a/core/lib/dal/.sqlx/query-1d6b698b241cb6c5efd070a98165f6760cfeac185330d1d9c5cdb5b383ed8ed4.json b/core/lib/dal/.sqlx/query-1d6b698b241cb6c5efd070a98165f6760cfeac185330d1d9c5cdb5b383ed8ed4.json new file mode 100644 index 000000000000..7531f7ed4c00 --- /dev/null +++ b/core/lib/dal/.sqlx/query-1d6b698b241cb6c5efd070a98165f6760cfeac185330d1d9c5cdb5b383ed8ed4.json @@ -0,0 +1,30 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n contract_verification_requests (\n contract_address,\n source_code,\n contract_name,\n zk_compiler_version,\n compiler_version,\n optimization_used,\n optimizer_mode,\n constructor_arguments,\n is_system,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, $8, $9, 'queued', NOW(), NOW())\n RETURNING\n id\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Bytea", + "Text", + "Text", + "Text", + "Text", + "Bool", + "Text", + "Bytea", + "Bool" + ] + }, + "nullable": [ + false + ] + }, + "hash": "1d6b698b241cb6c5efd070a98165f6760cfeac185330d1d9c5cdb5b383ed8ed4" +} diff --git a/core/lib/dal/.sqlx/query-1dcb3afb0c1947f92981f61d95c099c4591ce3f8d51f3df99db0165e086f96af.json b/core/lib/dal/.sqlx/query-1dcb3afb0c1947f92981f61d95c099c4591ce3f8d51f3df99db0165e086f96af.json new file mode 100644 index 000000000000..dd142601d007 --- /dev/null +++ b/core/lib/dal/.sqlx/query-1dcb3afb0c1947f92981f61d95c099c4591ce3f8d51f3df99db0165e086f96af.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n bytecode\n FROM\n factory_deps\n WHERE\n bytecode_hash = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "bytecode", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [ + false + ] + }, + "hash": "1dcb3afb0c1947f92981f61d95c099c4591ce3f8d51f3df99db0165e086f96af" +} diff --git a/core/lib/dal/.sqlx/query-1ea37ef1c3df72e5e9c50cfa1675fc7f60618209d0132e7937a1347b7e94b212.json b/core/lib/dal/.sqlx/query-1ea37ef1c3df72e5e9c50cfa1675fc7f60618209d0132e7937a1347b7e94b212.json new file mode 100644 index 000000000000..1ae6117e4a15 --- /dev/null +++ b/core/lib/dal/.sqlx/query-1ea37ef1c3df72e5e9c50cfa1675fc7f60618209d0132e7937a1347b7e94b212.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n number\n FROM\n l1_batches\n WHERE\n eth_prove_tx_id IS NOT NULL\n AND eth_execute_tx_id IS NULL\n ORDER BY\n number\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "1ea37ef1c3df72e5e9c50cfa1675fc7f60618209d0132e7937a1347b7e94b212" +} diff --git a/core/lib/dal/.sqlx/query-1ed2d7e5e98b15420a21650809d710ce910d0c9138d85cb55e16459c757dea03.json b/core/lib/dal/.sqlx/query-1ed2d7e5e98b15420a21650809d710ce910d0c9138d85cb55e16459c757dea03.json new file mode 100644 index 000000000000..9cf4cc1e68e1 --- /dev/null +++ b/core/lib/dal/.sqlx/query-1ed2d7e5e98b15420a21650809d710ce910d0c9138d85cb55e16459c757dea03.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n protocol_version\n FROM\n l1_batches\n ORDER BY\n number DESC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "protocol_version", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + true + ] + }, + "hash": "1ed2d7e5e98b15420a21650809d710ce910d0c9138d85cb55e16459c757dea03" +} diff --git a/core/lib/dal/.sqlx/query-1f25016c41169aa4ab14db2faf7b2d0413d0f89c309de4b31254c309116ea60c.json b/core/lib/dal/.sqlx/query-1f25016c41169aa4ab14db2faf7b2d0413d0f89c309de4b31254c309116ea60c.json new file mode 100644 index 000000000000..b535ae5a8636 --- /dev/null +++ b/core/lib/dal/.sqlx/query-1f25016c41169aa4ab14db2faf7b2d0413d0f89c309de4b31254c309116ea60c.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE tokens\n SET\n token_list_name = $2,\n token_list_symbol = $3,\n token_list_decimals = $4,\n well_known = TRUE,\n updated_at = NOW()\n WHERE\n l1_address = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Varchar", + "Varchar", + "Int4" + ] + }, + "nullable": [] + }, + "hash": "1f25016c41169aa4ab14db2faf7b2d0413d0f89c309de4b31254c309116ea60c" +} diff --git a/core/lib/dal/.sqlx/query-1f46524410ce0f193dc6547499bde995ddddc621ee2149f08f905af2d8aadd03.json b/core/lib/dal/.sqlx/query-1f46524410ce0f193dc6547499bde995ddddc621ee2149f08f905af2d8aadd03.json new file mode 100644 index 000000000000..077554611f4f --- /dev/null +++ b/core/lib/dal/.sqlx/query-1f46524410ce0f193dc6547499bde995ddddc621ee2149f08f905af2d8aadd03.json @@ -0,0 +1,34 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE transactions\n SET\n hash = data_table.hash,\n signature = data_table.signature,\n gas_limit = data_table.gas_limit,\n max_fee_per_gas = data_table.max_fee_per_gas,\n max_priority_fee_per_gas = data_table.max_priority_fee_per_gas,\n gas_per_pubdata_limit = data_table.gas_per_pubdata_limit,\n input = data_table.input,\n data = data_table.data,\n tx_format = data_table.tx_format,\n miniblock_number = $21,\n index_in_block = data_table.index_in_block,\n error = NULLIF(data_table.error, ''),\n effective_gas_price = data_table.effective_gas_price,\n execution_info = data_table.new_execution_info,\n refunded_gas = data_table.refunded_gas,\n value = data_table.value,\n contract_address = data_table.contract_address,\n paymaster = data_table.paymaster,\n paymaster_input = data_table.paymaster_input,\n in_mempool = FALSE,\n updated_at = NOW()\n FROM\n (\n SELECT\n data_table_temp.*\n FROM\n (\n SELECT\n UNNEST($1::bytea[]) AS initiator_address,\n UNNEST($2::INT[]) AS nonce,\n UNNEST($3::bytea[]) AS hash,\n UNNEST($4::bytea[]) AS signature,\n UNNEST($5::NUMERIC[]) AS gas_limit,\n UNNEST($6::NUMERIC[]) AS max_fee_per_gas,\n UNNEST($7::NUMERIC[]) AS max_priority_fee_per_gas,\n UNNEST($8::NUMERIC[]) AS gas_per_pubdata_limit,\n UNNEST($9::INT[]) AS tx_format,\n UNNEST($10::INTEGER[]) AS index_in_block,\n UNNEST($11::VARCHAR[]) AS error,\n UNNEST($12::NUMERIC[]) AS effective_gas_price,\n UNNEST($13::jsonb[]) AS new_execution_info,\n UNNEST($14::bytea[]) AS input,\n UNNEST($15::jsonb[]) AS data,\n UNNEST($16::BIGINT[]) AS refunded_gas,\n UNNEST($17::NUMERIC[]) AS value,\n UNNEST($18::bytea[]) AS contract_address,\n UNNEST($19::bytea[]) AS paymaster,\n UNNEST($20::bytea[]) AS paymaster_input\n ) AS data_table_temp\n JOIN transactions ON transactions.initiator_address = data_table_temp.initiator_address\n AND transactions.nonce = data_table_temp.nonce\n ORDER BY\n transactions.hash\n ) AS data_table\n WHERE\n transactions.initiator_address = data_table.initiator_address\n AND transactions.nonce = data_table.nonce\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "ByteaArray", + "Int4Array", + "ByteaArray", + "ByteaArray", + "NumericArray", + "NumericArray", + "NumericArray", + "NumericArray", + "Int4Array", + "Int4Array", + "VarcharArray", + "NumericArray", + "JsonbArray", + "ByteaArray", + "JsonbArray", + "Int8Array", + "NumericArray", + "ByteaArray", + "ByteaArray", + "ByteaArray", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "1f46524410ce0f193dc6547499bde995ddddc621ee2149f08f905af2d8aadd03" +} diff --git a/core/lib/dal/.sqlx/query-2003dcf7bc807c7d345368538accd9b0128f82306e27e4c7258116082a54ab95.json b/core/lib/dal/.sqlx/query-2003dcf7bc807c7d345368538accd9b0128f82306e27e4c7258116082a54ab95.json new file mode 100644 index 000000000000..77177e405f12 --- /dev/null +++ b/core/lib/dal/.sqlx/query-2003dcf7bc807c7d345368538accd9b0128f82306e27e4c7258116082a54ab95.json @@ -0,0 +1,29 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n transactions.hash,\n transactions.received_at\n FROM\n transactions\n LEFT JOIN miniblocks ON miniblocks.number = miniblock_number\n WHERE\n received_at > $1\n ORDER BY\n received_at ASC\n LIMIT\n $2\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "received_at", + "type_info": "Timestamp" + } + ], + "parameters": { + "Left": [ + "Timestamp", + "Int8" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "2003dcf7bc807c7d345368538accd9b0128f82306e27e4c7258116082a54ab95" +} diff --git a/core/lib/dal/.sqlx/query-20f84f9ec21459d8c7ad53241758eeab159533211d2ddbef41e6ff0ba937d04a.json b/core/lib/dal/.sqlx/query-20f84f9ec21459d8c7ad53241758eeab159533211d2ddbef41e6ff0ba937d04a.json new file mode 100644 index 000000000000..5f7048a8a20a --- /dev/null +++ b/core/lib/dal/.sqlx/query-20f84f9ec21459d8c7ad53241758eeab159533211d2ddbef41e6ff0ba937d04a.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE l1_batches\n SET\n skip_proof = TRUE\n WHERE\n number = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "20f84f9ec21459d8c7ad53241758eeab159533211d2ddbef41e6ff0ba937d04a" +} diff --git a/core/lib/dal/.sqlx/query-23be43bf705d679ca751c89353716065fcad42c6b621efb3a135a16b477dcfd9.json b/core/lib/dal/.sqlx/query-23be43bf705d679ca751c89353716065fcad42c6b621efb3a135a16b477dcfd9.json new file mode 100644 index 000000000000..8c63a924c0aa --- /dev/null +++ b/core/lib/dal/.sqlx/query-23be43bf705d679ca751c89353716065fcad42c6b621efb3a135a16b477dcfd9.json @@ -0,0 +1,86 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n *\n FROM\n eth_txs\n WHERE\n confirmed_eth_tx_history_id IS NULL\n AND id <= (\n SELECT\n COALESCE(MAX(eth_tx_id), 0)\n FROM\n eth_txs_history\n WHERE\n sent_at_block IS NOT NULL\n )\n ORDER BY\n id\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "nonce", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "raw_tx", + "type_info": "Bytea" + }, + { + "ordinal": 3, + "name": "contract_address", + "type_info": "Text" + }, + { + "ordinal": 4, + "name": "tx_type", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "gas_used", + "type_info": "Int8" + }, + { + "ordinal": 6, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 7, + "name": "updated_at", + "type_info": "Timestamp" + }, + { + "ordinal": 8, + "name": "has_failed", + "type_info": "Bool" + }, + { + "ordinal": 9, + "name": "sent_at_block", + "type_info": "Int4" + }, + { + "ordinal": 10, + "name": "confirmed_eth_tx_history_id", + "type_info": "Int4" + }, + { + "ordinal": 11, + "name": "predicted_gas_cost", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false, + false, + false, + true, + false, + false, + false, + true, + true, + false + ] + }, + "hash": "23be43bf705d679ca751c89353716065fcad42c6b621efb3a135a16b477dcfd9" +} diff --git a/core/lib/dal/.sqlx/query-245dc5bb82cc82df38e4440a7746ca08324bc86a72e4ea85c9c7962a6c8c9e30.json b/core/lib/dal/.sqlx/query-245dc5bb82cc82df38e4440a7746ca08324bc86a72e4ea85c9c7962a6c8c9e30.json new file mode 100644 index 000000000000..0b9c4aa59b7a --- /dev/null +++ b/core/lib/dal/.sqlx/query-245dc5bb82cc82df38e4440a7746ca08324bc86a72e4ea85c9c7962a6c8c9e30.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE l1_batches\n SET\n eth_prove_tx_id = $1,\n updated_at = NOW()\n WHERE\n number BETWEEN $2 AND $3\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4", + "Int8", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "245dc5bb82cc82df38e4440a7746ca08324bc86a72e4ea85c9c7962a6c8c9e30" +} diff --git a/core/lib/dal/.sqlx/query-24722ee4ced7f03e60b1b5ecaaa5234d536b064951a67d826ac49b7a3a095a1a.json b/core/lib/dal/.sqlx/query-24722ee4ced7f03e60b1b5ecaaa5234d536b064951a67d826ac49b7a3a095a1a.json new file mode 100644 index 000000000000..194f4faedb1b --- /dev/null +++ b/core/lib/dal/.sqlx/query-24722ee4ced7f03e60b1b5ecaaa5234d536b064951a67d826ac49b7a3a095a1a.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n hashed_key,\n INDEX\n FROM\n initial_writes\n WHERE\n l1_batch_number = $1\n ORDER BY\n INDEX\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hashed_key", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "index", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "24722ee4ced7f03e60b1b5ecaaa5234d536b064951a67d826ac49b7a3a095a1a" +} diff --git a/core/lib/dal/.sqlx/query-249cb862d44196cb6dc3945e907717b0dd3cec64b0b29f59b273f1c6952e01da.json b/core/lib/dal/.sqlx/query-249cb862d44196cb6dc3945e907717b0dd3cec64b0b29f59b273f1c6952e01da.json new file mode 100644 index 000000000000..38419af111f0 --- /dev/null +++ b/core/lib/dal/.sqlx/query-249cb862d44196cb6dc3945e907717b0dd3cec64b0b29f59b273f1c6952e01da.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n bytecode_hash\n FROM\n factory_deps\n WHERE\n miniblock_number > $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "bytecode_hash", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "249cb862d44196cb6dc3945e907717b0dd3cec64b0b29f59b273f1c6952e01da" +} diff --git a/core/lib/dal/.sqlx/query-2506e9edfd4b41ca1e187909631ae942bab5d71daaed7017e3fa62dc5e42ab0a.json b/core/lib/dal/.sqlx/query-2506e9edfd4b41ca1e187909631ae942bab5d71daaed7017e3fa62dc5e42ab0a.json new file mode 100644 index 000000000000..c4f8057011d4 --- /dev/null +++ b/core/lib/dal/.sqlx/query-2506e9edfd4b41ca1e187909631ae942bab5d71daaed7017e3fa62dc5e42ab0a.json @@ -0,0 +1,32 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n hashed_key,\n l1_batch_number,\n INDEX\n FROM\n initial_writes\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hashed_key", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "index", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "2506e9edfd4b41ca1e187909631ae942bab5d71daaed7017e3fa62dc5e42ab0a" +} diff --git a/core/lib/dal/.sqlx/query-26cb272c2a46a267c47681e0f1f07997b7e24682da56f84d812da2b9aeb14ca2.json b/core/lib/dal/.sqlx/query-26cb272c2a46a267c47681e0f1f07997b7e24682da56f84d812da2b9aeb14ca2.json new file mode 100644 index 000000000000..58ba7c33f2b6 --- /dev/null +++ b/core/lib/dal/.sqlx/query-26cb272c2a46a267c47681e0f1f07997b7e24682da56f84d812da2b9aeb14ca2.json @@ -0,0 +1,40 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n miniblock_number AS \"miniblock_number!\",\n hash,\n index_in_block AS \"index_in_block!\",\n l1_batch_tx_index AS \"l1_batch_tx_index!\"\n FROM\n transactions\n WHERE\n l1_batch_number = $1\n ORDER BY\n miniblock_number,\n index_in_block\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "miniblock_number!", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 2, + "name": "index_in_block!", + "type_info": "Int4" + }, + { + "ordinal": 3, + "name": "l1_batch_tx_index!", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + true, + false, + true, + true + ] + }, + "hash": "26cb272c2a46a267c47681e0f1f07997b7e24682da56f84d812da2b9aeb14ca2" +} diff --git a/core/lib/dal/.sqlx/query-26e0b7eb1871d94ddc98254fece6381a9c4165e2727542eaeef3bbedd13a4f20.json b/core/lib/dal/.sqlx/query-26e0b7eb1871d94ddc98254fece6381a9c4165e2727542eaeef3bbedd13a4f20.json new file mode 100644 index 000000000000..30738bc2094a --- /dev/null +++ b/core/lib/dal/.sqlx/query-26e0b7eb1871d94ddc98254fece6381a9c4165e2727542eaeef3bbedd13a4f20.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE proof_generation_details\n SET\n status = $1,\n updated_at = NOW()\n WHERE\n l1_batch_number = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "26e0b7eb1871d94ddc98254fece6381a9c4165e2727542eaeef3bbedd13a4f20" +} diff --git a/core/lib/dal/.sqlx/query-2737fea02599cdc163854b1395c42d4ef93ca238fd2fbc9155e6d012d0d1e113.json b/core/lib/dal/.sqlx/query-2737fea02599cdc163854b1395c42d4ef93ca238fd2fbc9155e6d012d0d1e113.json new file mode 100644 index 000000000000..67b9c0566821 --- /dev/null +++ b/core/lib/dal/.sqlx/query-2737fea02599cdc163854b1395c42d4ef93ca238fd2fbc9155e6d012d0d1e113.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE transactions\n SET\n error = $1,\n updated_at = NOW()\n WHERE\n hash = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "2737fea02599cdc163854b1395c42d4ef93ca238fd2fbc9155e6d012d0d1e113" +} diff --git a/core/lib/dal/.sqlx/query-2757b30c4641a346eb0226c706223efc18e51e6d4092188e081f4fafe92fe0ef.json b/core/lib/dal/.sqlx/query-2757b30c4641a346eb0226c706223efc18e51e6d4092188e081f4fafe92fe0ef.json new file mode 100644 index 000000000000..bb47b8254aca --- /dev/null +++ b/core/lib/dal/.sqlx/query-2757b30c4641a346eb0226c706223efc18e51e6d4092188e081f4fafe92fe0ef.json @@ -0,0 +1,34 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n bootloader_code_hash,\n default_account_code_hash,\n id\n FROM\n protocol_versions\n WHERE\n timestamp <= $1\n ORDER BY\n id DESC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "bootloader_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "default_account_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 2, + "name": "id", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "2757b30c4641a346eb0226c706223efc18e51e6d4092188e081f4fafe92fe0ef" +} diff --git a/core/lib/dal/.sqlx/query-280cf015e40353e2833c0a70b77095596297be0d728a0aa2d9b180fb72de222b.json b/core/lib/dal/.sqlx/query-280cf015e40353e2833c0a70b77095596297be0d728a0aa2d9b180fb72de222b.json new file mode 100644 index 000000000000..5b49941ed18f --- /dev/null +++ b/core/lib/dal/.sqlx/query-280cf015e40353e2833c0a70b77095596297be0d728a0aa2d9b180fb72de222b.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n attempts\n FROM\n basic_witness_input_producer_jobs\n WHERE\n l1_batch_number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "attempts", + "type_info": "Int2" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "280cf015e40353e2833c0a70b77095596297be0d728a0aa2d9b180fb72de222b" +} diff --git a/core/lib/dal/.sqlx/query-293258ecb299be5f5e81696d14883f115cd97586bd795ee31f58fc14e56d58cb.json b/core/lib/dal/.sqlx/query-293258ecb299be5f5e81696d14883f115cd97586bd795ee31f58fc14e56d58cb.json new file mode 100644 index 000000000000..2b07c3b02e04 --- /dev/null +++ b/core/lib/dal/.sqlx/query-293258ecb299be5f5e81696d14883f115cd97586bd795ee31f58fc14e56d58cb.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM events\n WHERE\n miniblock_number > $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "293258ecb299be5f5e81696d14883f115cd97586bd795ee31f58fc14e56d58cb" +} diff --git a/core/lib/dal/.sqlx/query-2955e976281f9cbd98b7378c5ab52964b268b93c32fd280c49bf9f932884300d.json b/core/lib/dal/.sqlx/query-2955e976281f9cbd98b7378c5ab52964b268b93c32fd280c49bf9f932884300d.json new file mode 100644 index 000000000000..7c3a261d1f6e --- /dev/null +++ b/core/lib/dal/.sqlx/query-2955e976281f9cbd98b7378c5ab52964b268b93c32fd280c49bf9f932884300d.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n timestamp\n FROM\n l1_batches\n WHERE\n eth_prove_tx_id IS NULL\n AND number > 0\n ORDER BY\n number\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "timestamp", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "2955e976281f9cbd98b7378c5ab52964b268b93c32fd280c49bf9f932884300d" +} diff --git a/core/lib/dal/.sqlx/query-2979b6c9ce76a4e6eaaa3f9bad5cf831d63d692111d87282aed8e85df6b0411f.json b/core/lib/dal/.sqlx/query-2979b6c9ce76a4e6eaaa3f9bad5cf831d63d692111d87282aed8e85df6b0411f.json new file mode 100644 index 000000000000..84d906823e14 --- /dev/null +++ b/core/lib/dal/.sqlx/query-2979b6c9ce76a4e6eaaa3f9bad5cf831d63d692111d87282aed8e85df6b0411f.json @@ -0,0 +1,104 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n number,\n timestamp,\n hash,\n l1_tx_count,\n l2_tx_count,\n fee_account_address AS \"fee_account_address!\",\n base_fee_per_gas,\n l1_gas_price,\n l2_fair_gas_price,\n gas_per_pubdata_limit,\n bootloader_code_hash,\n default_aa_code_hash,\n protocol_version,\n virtual_blocks,\n fair_pubdata_price\n FROM\n miniblocks\n ORDER BY\n number DESC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 3, + "name": "l1_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 4, + "name": "l2_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 5, + "name": "fee_account_address!", + "type_info": "Bytea" + }, + { + "ordinal": 6, + "name": "base_fee_per_gas", + "type_info": "Numeric" + }, + { + "ordinal": 7, + "name": "l1_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 8, + "name": "l2_fair_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 9, + "name": "gas_per_pubdata_limit", + "type_info": "Int8" + }, + { + "ordinal": 10, + "name": "bootloader_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 11, + "name": "default_aa_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 12, + "name": "protocol_version", + "type_info": "Int4" + }, + { + "ordinal": 13, + "name": "virtual_blocks", + "type_info": "Int8" + }, + { + "ordinal": 14, + "name": "fair_pubdata_price", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + false, + true + ] + }, + "hash": "2979b6c9ce76a4e6eaaa3f9bad5cf831d63d692111d87282aed8e85df6b0411f" +} diff --git a/core/lib/dal/.sqlx/query-2b1aa207a058f66265acf2c21b8ed5d8007789c0fc1eab948f6d7339dfb69147.json b/core/lib/dal/.sqlx/query-2b1aa207a058f66265acf2c21b8ed5d8007789c0fc1eab948f6d7339dfb69147.json new file mode 100644 index 000000000000..96b48892516d --- /dev/null +++ b/core/lib/dal/.sqlx/query-2b1aa207a058f66265acf2c21b8ed5d8007789c0fc1eab948f6d7339dfb69147.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM transactions\n WHERE\n miniblock_number IS NULL\n AND received_at < NOW() - $1::INTERVAL\n AND is_priority = FALSE\n AND error IS NULL\n RETURNING\n hash\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hash", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Interval" + ] + }, + "nullable": [ + false + ] + }, + "hash": "2b1aa207a058f66265acf2c21b8ed5d8007789c0fc1eab948f6d7339dfb69147" +} diff --git a/core/lib/dal/.sqlx/query-2b626262c8003817ee02978f77452554ccfb5b83f00efdc12bed0f60ef439785.json b/core/lib/dal/.sqlx/query-2b626262c8003817ee02978f77452554ccfb5b83f00efdc12bed0f60ef439785.json new file mode 100644 index 000000000000..db810604cd88 --- /dev/null +++ b/core/lib/dal/.sqlx/query-2b626262c8003817ee02978f77452554ccfb5b83f00efdc12bed0f60ef439785.json @@ -0,0 +1,25 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n id\n FROM\n prover_jobs_fri\n WHERE\n l1_batch_number = $1\n AND circuit_id = $2\n AND aggregation_round = $3\n AND depth = $4\n AND status = 'successful'\n ORDER BY\n sequence_number ASC;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8", + "Int2", + "Int2", + "Int4" + ] + }, + "nullable": [ + false + ] + }, + "hash": "2b626262c8003817ee02978f77452554ccfb5b83f00efdc12bed0f60ef439785" +} diff --git a/core/lib/dal/.sqlx/query-2c71a819c6ed22a3ab79675840e00f7b1176d59a83520288f5428b67ebd52130.json b/core/lib/dal/.sqlx/query-2c71a819c6ed22a3ab79675840e00f7b1176d59a83520288f5428b67ebd52130.json new file mode 100644 index 000000000000..e8e6d8e760b4 --- /dev/null +++ b/core/lib/dal/.sqlx/query-2c71a819c6ed22a3ab79675840e00f7b1176d59a83520288f5428b67ebd52130.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM initial_writes\n WHERE\n l1_batch_number > $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "2c71a819c6ed22a3ab79675840e00f7b1176d59a83520288f5428b67ebd52130" +} diff --git a/core/lib/dal/.sqlx/query-2c827c1c3cfa3552b90d4746c5df45d57f1f8b2558fdb374bf02e84d3c825a23.json b/core/lib/dal/.sqlx/query-2c827c1c3cfa3552b90d4746c5df45d57f1f8b2558fdb374bf02e84d3c825a23.json new file mode 100644 index 000000000000..9ec94fee0d34 --- /dev/null +++ b/core/lib/dal/.sqlx/query-2c827c1c3cfa3552b90d4746c5df45d57f1f8b2558fdb374bf02e84d3c825a23.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n MAX(number) AS \"number\"\n FROM\n miniblocks\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "2c827c1c3cfa3552b90d4746c5df45d57f1f8b2558fdb374bf02e84d3c825a23" +} diff --git a/core/lib/dal/.sqlx/query-2d0c2e9ec4187641baef8a33229bffc78d92adb3c1e3ca60b12163e38c67047e.json b/core/lib/dal/.sqlx/query-2d0c2e9ec4187641baef8a33229bffc78d92adb3c1e3ca60b12163e38c67047e.json new file mode 100644 index 000000000000..f61f39e3b0b0 --- /dev/null +++ b/core/lib/dal/.sqlx/query-2d0c2e9ec4187641baef8a33229bffc78d92adb3c1e3ca60b12163e38c67047e.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n COUNT(*) AS \"count!\"\n FROM\n contracts_verification_info\n WHERE\n address = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count!", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [ + null + ] + }, + "hash": "2d0c2e9ec4187641baef8a33229bffc78d92adb3c1e3ca60b12163e38c67047e" +} diff --git a/core/lib/dal/.sqlx/query-2d1e0f2e043c193052c9cc20f9efeb5f094160627bc09db4bda2dda9a8c11c44.json b/core/lib/dal/.sqlx/query-2d1e0f2e043c193052c9cc20f9efeb5f094160627bc09db4bda2dda9a8c11c44.json new file mode 100644 index 000000000000..1d9c276b0786 --- /dev/null +++ b/core/lib/dal/.sqlx/query-2d1e0f2e043c193052c9cc20f9efeb5f094160627bc09db4bda2dda9a8c11c44.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n contracts_verification_info (address, verification_info)\n VALUES\n ($1, $2)\n ON CONFLICT (address) DO\n UPDATE\n SET\n verification_info = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Jsonb" + ] + }, + "nullable": [] + }, + "hash": "2d1e0f2e043c193052c9cc20f9efeb5f094160627bc09db4bda2dda9a8c11c44" +} diff --git a/core/lib/dal/.sqlx/query-2d31fcce581975a82d6156b52e35fb7a093b73727f75e0cb7db9cea480c95f5c.json b/core/lib/dal/.sqlx/query-2d31fcce581975a82d6156b52e35fb7a093b73727f75e0cb7db9cea480c95f5c.json new file mode 100644 index 000000000000..c4bcd6ea4915 --- /dev/null +++ b/core/lib/dal/.sqlx/query-2d31fcce581975a82d6156b52e35fb7a093b73727f75e0cb7db9cea480c95f5c.json @@ -0,0 +1,35 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE prover_jobs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n id IN (\n SELECT\n id\n FROM\n prover_jobs_fri\n WHERE\n (\n status = 'in_progress'\n AND processing_started_at <= NOW() - $1::INTERVAL\n AND attempts < $2\n )\n OR (\n status = 'in_gpu_proof'\n AND processing_started_at <= NOW() - $1::INTERVAL\n AND attempts < $2\n )\n OR (\n status = 'failed'\n AND attempts < $2\n )\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n id,\n status,\n attempts\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "status", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "attempts", + "type_info": "Int2" + } + ], + "parameters": { + "Left": [ + "Interval", + "Int2" + ] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "2d31fcce581975a82d6156b52e35fb7a093b73727f75e0cb7db9cea480c95f5c" +} diff --git a/core/lib/dal/.sqlx/query-2d862097cfae49a1fb28ec0a05176085385c3a79d72f49669b4215a9454323c2.json b/core/lib/dal/.sqlx/query-2d862097cfae49a1fb28ec0a05176085385c3a79d72f49669b4215a9454323c2.json new file mode 100644 index 000000000000..e08f0c855175 --- /dev/null +++ b/core/lib/dal/.sqlx/query-2d862097cfae49a1fb28ec0a05176085385c3a79d72f49669b4215a9454323c2.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n INDEX\n FROM\n initial_writes\n WHERE\n l1_batch_number <= $1\n ORDER BY\n l1_batch_number DESC,\n INDEX DESC\n LIMIT\n 1;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "index", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "2d862097cfae49a1fb28ec0a05176085385c3a79d72f49669b4215a9454323c2" +} diff --git a/core/lib/dal/.sqlx/query-2d87b294817859e42258136b1cb78f42a877039094c3d6354928a03dad29451a.json b/core/lib/dal/.sqlx/query-2d87b294817859e42258136b1cb78f42a877039094c3d6354928a03dad29451a.json new file mode 100644 index 000000000000..dbd2e21c1a3e --- /dev/null +++ b/core/lib/dal/.sqlx/query-2d87b294817859e42258136b1cb78f42a877039094c3d6354928a03dad29451a.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM storage_logs\n WHERE\n miniblock_number = $1\n AND operation_number != ALL ($2)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Int4Array" + ] + }, + "nullable": [] + }, + "hash": "2d87b294817859e42258136b1cb78f42a877039094c3d6354928a03dad29451a" +} diff --git a/core/lib/dal/.sqlx/query-2dd7dbaeb2572404451e78a96f540e73a2778633bbf9d8e591ec912634639af9.json b/core/lib/dal/.sqlx/query-2dd7dbaeb2572404451e78a96f540e73a2778633bbf9d8e591ec912634639af9.json new file mode 100644 index 000000000000..bb81e7c31943 --- /dev/null +++ b/core/lib/dal/.sqlx/query-2dd7dbaeb2572404451e78a96f540e73a2778633bbf9d8e591ec912634639af9.json @@ -0,0 +1,232 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n *\n FROM\n transactions\n WHERE\n miniblock_number = $1\n ORDER BY\n index_in_block\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "is_priority", + "type_info": "Bool" + }, + { + "ordinal": 2, + "name": "full_fee", + "type_info": "Numeric" + }, + { + "ordinal": 3, + "name": "layer_2_tip_fee", + "type_info": "Numeric" + }, + { + "ordinal": 4, + "name": "initiator_address", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "nonce", + "type_info": "Int8" + }, + { + "ordinal": 6, + "name": "signature", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "input", + "type_info": "Bytea" + }, + { + "ordinal": 8, + "name": "data", + "type_info": "Jsonb" + }, + { + "ordinal": 9, + "name": "received_at", + "type_info": "Timestamp" + }, + { + "ordinal": 10, + "name": "priority_op_id", + "type_info": "Int8" + }, + { + "ordinal": 11, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 12, + "name": "index_in_block", + "type_info": "Int4" + }, + { + "ordinal": 13, + "name": "error", + "type_info": "Varchar" + }, + { + "ordinal": 14, + "name": "gas_limit", + "type_info": "Numeric" + }, + { + "ordinal": 15, + "name": "gas_per_storage_limit", + "type_info": "Numeric" + }, + { + "ordinal": 16, + "name": "gas_per_pubdata_limit", + "type_info": "Numeric" + }, + { + "ordinal": 17, + "name": "tx_format", + "type_info": "Int4" + }, + { + "ordinal": 18, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 19, + "name": "updated_at", + "type_info": "Timestamp" + }, + { + "ordinal": 20, + "name": "execution_info", + "type_info": "Jsonb" + }, + { + "ordinal": 21, + "name": "contract_address", + "type_info": "Bytea" + }, + { + "ordinal": 22, + "name": "in_mempool", + "type_info": "Bool" + }, + { + "ordinal": 23, + "name": "l1_block_number", + "type_info": "Int4" + }, + { + "ordinal": 24, + "name": "value", + "type_info": "Numeric" + }, + { + "ordinal": 25, + "name": "paymaster", + "type_info": "Bytea" + }, + { + "ordinal": 26, + "name": "paymaster_input", + "type_info": "Bytea" + }, + { + "ordinal": 27, + "name": "max_fee_per_gas", + "type_info": "Numeric" + }, + { + "ordinal": 28, + "name": "max_priority_fee_per_gas", + "type_info": "Numeric" + }, + { + "ordinal": 29, + "name": "effective_gas_price", + "type_info": "Numeric" + }, + { + "ordinal": 30, + "name": "miniblock_number", + "type_info": "Int8" + }, + { + "ordinal": 31, + "name": "l1_batch_tx_index", + "type_info": "Int4" + }, + { + "ordinal": 32, + "name": "refunded_gas", + "type_info": "Int8" + }, + { + "ordinal": 33, + "name": "l1_tx_mint", + "type_info": "Numeric" + }, + { + "ordinal": 34, + "name": "l1_tx_refund_recipient", + "type_info": "Bytea" + }, + { + "ordinal": 35, + "name": "upgrade_id", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + true, + true, + false, + true, + true, + true, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + false, + true, + true, + true + ] + }, + "hash": "2dd7dbaeb2572404451e78a96f540e73a2778633bbf9d8e591ec912634639af9" +} diff --git a/core/lib/dal/.sqlx/query-2ddba807ac8ec5260bf92c77073eb89c728357c0744f209090824695a5d35fa3.json b/core/lib/dal/.sqlx/query-2ddba807ac8ec5260bf92c77073eb89c728357c0744f209090824695a5d35fa3.json new file mode 100644 index 000000000000..68b48f325091 --- /dev/null +++ b/core/lib/dal/.sqlx/query-2ddba807ac8ec5260bf92c77073eb89c728357c0744f209090824695a5d35fa3.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE transactions\n SET\n l1_batch_number = NULL,\n miniblock_number = NULL,\n error = NULL,\n index_in_block = NULL,\n execution_info = '{}'\n WHERE\n miniblock_number > $1\n RETURNING\n hash\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hash", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "2ddba807ac8ec5260bf92c77073eb89c728357c0744f209090824695a5d35fa3" +} diff --git a/core/lib/dal/.sqlx/query-2e0ea9434195270cc65cdca1f674d6b3b1d15b818974e4e403f4ac418ed40c2c.json b/core/lib/dal/.sqlx/query-2e0ea9434195270cc65cdca1f674d6b3b1d15b818974e4e403f4ac418ed40c2c.json new file mode 100644 index 000000000000..c2cba82b7a6b --- /dev/null +++ b/core/lib/dal/.sqlx/query-2e0ea9434195270cc65cdca1f674d6b3b1d15b818974e4e403f4ac418ed40c2c.json @@ -0,0 +1,26 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n eth_txs_history (\n eth_tx_id,\n base_fee_per_gas,\n priority_fee_per_gas,\n tx_hash,\n signed_raw_tx,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, $4, $5, NOW(), NOW())\n ON CONFLICT (tx_hash) DO NOTHING\n RETURNING\n id\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int4", + "Int8", + "Int8", + "Text", + "Bytea" + ] + }, + "nullable": [ + false + ] + }, + "hash": "2e0ea9434195270cc65cdca1f674d6b3b1d15b818974e4e403f4ac418ed40c2c" +} diff --git a/core/lib/dal/.sqlx/query-2e5b9ae1b81b0abfe7a962c93b3119a0a60dc9804175b2baf8b45939c74bd583.json b/core/lib/dal/.sqlx/query-2e5b9ae1b81b0abfe7a962c93b3119a0a60dc9804175b2baf8b45939c74bd583.json new file mode 100644 index 000000000000..205487768306 --- /dev/null +++ b/core/lib/dal/.sqlx/query-2e5b9ae1b81b0abfe7a962c93b3119a0a60dc9804175b2baf8b45939c74bd583.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n compiler_versions (VERSION, compiler, created_at, updated_at)\n SELECT\n u.version,\n $2,\n NOW(),\n NOW()\n FROM\n UNNEST($1::TEXT[]) AS u (VERSION)\n ON CONFLICT (VERSION, compiler) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "TextArray", + "Text" + ] + }, + "nullable": [] + }, + "hash": "2e5b9ae1b81b0abfe7a962c93b3119a0a60dc9804175b2baf8b45939c74bd583" +} diff --git a/core/lib/dal/.sqlx/query-2eb25bfcfc1114de825dc4eeb0605d7d1c9e649663f6e9444c4425821d0a5b71.json b/core/lib/dal/.sqlx/query-2eb25bfcfc1114de825dc4eeb0605d7d1c9e649663f6e9444c4425821d0a5b71.json new file mode 100644 index 000000000000..6b0ddef258fc --- /dev/null +++ b/core/lib/dal/.sqlx/query-2eb25bfcfc1114de825dc4eeb0605d7d1c9e649663f6e9444c4425821d0a5b71.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n eth_commit_tx_id\n FROM\n l1_batches\n WHERE\n number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "eth_commit_tx_id", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + true + ] + }, + "hash": "2eb25bfcfc1114de825dc4eeb0605d7d1c9e649663f6e9444c4425821d0a5b71" +} diff --git a/core/lib/dal/.sqlx/query-31334f2878b1ac7d828d5bc22d65ef6676b2eac623c0f78634cae9072fe0498a.json b/core/lib/dal/.sqlx/query-31334f2878b1ac7d828d5bc22d65ef6676b2eac623c0f78634cae9072fe0498a.json new file mode 100644 index 000000000000..31b129a89288 --- /dev/null +++ b/core/lib/dal/.sqlx/query-31334f2878b1ac7d828d5bc22d65ef6676b2eac623c0f78634cae9072fe0498a.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n snapshots (\n l1_batch_number,\n storage_logs_filepaths,\n factory_deps_filepath,\n created_at,\n updated_at\n )\n VALUES\n ($1, ARRAY_FILL(''::TEXT, ARRAY[$2::INTEGER]), $3, NOW(), NOW())\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Int4", + "Text" + ] + }, + "nullable": [] + }, + "hash": "31334f2878b1ac7d828d5bc22d65ef6676b2eac623c0f78634cae9072fe0498a" +} diff --git a/core/lib/dal/.sqlx/query-31f12a8c44124bb2ce31889ac5295f3823926f69cb1d54874878e6d6c301bfd8.json b/core/lib/dal/.sqlx/query-31f12a8c44124bb2ce31889ac5295f3823926f69cb1d54874878e6d6c301bfd8.json new file mode 100644 index 000000000000..c63ea98db44b --- /dev/null +++ b/core/lib/dal/.sqlx/query-31f12a8c44124bb2ce31889ac5295f3823926f69cb1d54874878e6d6c301bfd8.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n COUNT(*) AS \"count!\"\n FROM\n l1_batches\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count!", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "31f12a8c44124bb2ce31889ac5295f3823926f69cb1d54874878e6d6c301bfd8" +} diff --git a/core/lib/dal/.sqlx/query-322d919ff1ef4675623a58af2b0e9ebdda648667d48d6b27ddf155f2fe01d77a.json b/core/lib/dal/.sqlx/query-322d919ff1ef4675623a58af2b0e9ebdda648667d48d6b27ddf155f2fe01d77a.json new file mode 100644 index 000000000000..804940f674df --- /dev/null +++ b/core/lib/dal/.sqlx/query-322d919ff1ef4675623a58af2b0e9ebdda648667d48d6b27ddf155f2fe01d77a.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE l1_batches\n SET\n commitment = $2,\n aux_data_hash = $3,\n updated_at = NOW()\n WHERE\n number = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Bytea", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "322d919ff1ef4675623a58af2b0e9ebdda648667d48d6b27ddf155f2fe01d77a" +} diff --git a/core/lib/dal/.sqlx/query-32792c6aee69cb8c8b928a209a3b04ba5868d1897553df85aac15b169ebb0732.json b/core/lib/dal/.sqlx/query-32792c6aee69cb8c8b928a209a3b04ba5868d1897553df85aac15b169ebb0732.json new file mode 100644 index 000000000000..32b36d7fed96 --- /dev/null +++ b/core/lib/dal/.sqlx/query-32792c6aee69cb8c8b928a209a3b04ba5868d1897553df85aac15b169ebb0732.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n basic_witness_input_producer_jobs (l1_batch_number, status, created_at, updated_at)\n VALUES\n ($1, $2, NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + { + "Custom": { + "name": "basic_witness_input_producer_job_status", + "kind": { + "Enum": [ + "Queued", + "ManuallySkipped", + "InProgress", + "Successful", + "Failed" + ] + } + } + } + ] + }, + "nullable": [] + }, + "hash": "32792c6aee69cb8c8b928a209a3b04ba5868d1897553df85aac15b169ebb0732" +} diff --git a/core/lib/dal/.sqlx/query-33d6be45b246523ad76f9ae512322ff6372f63ecadb504a329499b02e7d3550e.json b/core/lib/dal/.sqlx/query-33d6be45b246523ad76f9ae512322ff6372f63ecadb504a329499b02e7d3550e.json new file mode 100644 index 000000000000..76483cd73d31 --- /dev/null +++ b/core/lib/dal/.sqlx/query-33d6be45b246523ad76f9ae512322ff6372f63ecadb504a329499b02e7d3550e.json @@ -0,0 +1,26 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE leaf_aggregation_witness_jobs_fri\n SET\n status = 'queued'\n WHERE\n (l1_batch_number, circuit_id) IN (\n SELECT\n prover_jobs_fri.l1_batch_number,\n prover_jobs_fri.circuit_id\n FROM\n prover_jobs_fri\n JOIN leaf_aggregation_witness_jobs_fri lawj ON prover_jobs_fri.l1_batch_number = lawj.l1_batch_number\n AND prover_jobs_fri.circuit_id = lawj.circuit_id\n WHERE\n lawj.status = 'waiting_for_proofs'\n AND prover_jobs_fri.status = 'successful'\n AND prover_jobs_fri.aggregation_round = 0\n GROUP BY\n prover_jobs_fri.l1_batch_number,\n prover_jobs_fri.circuit_id,\n lawj.number_of_basic_circuits\n HAVING\n COUNT(*) = lawj.number_of_basic_circuits\n )\n RETURNING\n l1_batch_number,\n circuit_id;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "circuit_id", + "type_info": "Int2" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false + ] + }, + "hash": "33d6be45b246523ad76f9ae512322ff6372f63ecadb504a329499b02e7d3550e" +} diff --git a/core/lib/dal/.sqlx/query-3490fe0b778a03c73111bf8cbf426b0b3185a231bbf0b8b132a1a95bc157e827.json b/core/lib/dal/.sqlx/query-3490fe0b778a03c73111bf8cbf426b0b3185a231bbf0b8b132a1a95bc157e827.json new file mode 100644 index 000000000000..3275e94936a1 --- /dev/null +++ b/core/lib/dal/.sqlx/query-3490fe0b778a03c73111bf8cbf426b0b3185a231bbf0b8b132a1a95bc157e827.json @@ -0,0 +1,34 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n hashed_key,\n l1_batch_number,\n INDEX\n FROM\n initial_writes\n WHERE\n hashed_key = ANY ($1::bytea[])\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hashed_key", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "index", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "ByteaArray" + ] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "3490fe0b778a03c73111bf8cbf426b0b3185a231bbf0b8b132a1a95bc157e827" +} diff --git a/core/lib/dal/.sqlx/query-35b87a3b7db0af87c6a95e9fe7ef9044ae85b579c7051301b40bd5f94df1f530.json b/core/lib/dal/.sqlx/query-35b87a3b7db0af87c6a95e9fe7ef9044ae85b579c7051301b40bd5f94df1f530.json new file mode 100644 index 000000000000..a11e154326ec --- /dev/null +++ b/core/lib/dal/.sqlx/query-35b87a3b7db0af87c6a95e9fe7ef9044ae85b579c7051301b40bd5f94df1f530.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE prover_jobs_fri\n SET\n status = 'failed',\n error = $1,\n updated_at = NOW()\n WHERE\n id = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "35b87a3b7db0af87c6a95e9fe7ef9044ae85b579c7051301b40bd5f94df1f530" +} diff --git a/core/lib/dal/.sqlx/query-38a8b00e320b16e99f6ea0e5954e2f7e49cd6600bd3d56cf41795c2c9e082e4c.json b/core/lib/dal/.sqlx/query-38a8b00e320b16e99f6ea0e5954e2f7e49cd6600bd3d56cf41795c2c9e082e4c.json new file mode 100644 index 000000000000..9b989a9ba251 --- /dev/null +++ b/core/lib/dal/.sqlx/query-38a8b00e320b16e99f6ea0e5954e2f7e49cd6600bd3d56cf41795c2c9e082e4c.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n MAX(number) AS \"number\"\n FROM\n l1_batches\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "38a8b00e320b16e99f6ea0e5954e2f7e49cd6600bd3d56cf41795c2c9e082e4c" +} diff --git a/core/lib/dal/.sqlx/query-3ad766526138a1cf9ca3acd9025bab23414ee459daa4734772ece7bcc6e5fd7f.json b/core/lib/dal/.sqlx/query-3ad766526138a1cf9ca3acd9025bab23414ee459daa4734772ece7bcc6e5fd7f.json new file mode 100644 index 000000000000..197832e8fce5 --- /dev/null +++ b/core/lib/dal/.sqlx/query-3ad766526138a1cf9ca3acd9025bab23414ee459daa4734772ece7bcc6e5fd7f.json @@ -0,0 +1,229 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n number,\n l1_batches.timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n parent_hash,\n commitment,\n compressed_write_logs,\n compressed_contracts,\n eth_prove_tx_id,\n eth_commit_tx_id,\n eth_execute_tx_id,\n merkle_root_hash,\n l2_to_l1_logs,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_compressed_messages,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n l1_batches.bootloader_code_hash,\n l1_batches.default_aa_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n JOIN protocol_versions ON protocol_versions.id = l1_batches.protocol_version\n WHERE\n eth_commit_tx_id IS NULL\n AND number != 0\n AND protocol_versions.bootloader_code_hash = $1\n AND protocol_versions.default_account_code_hash = $2\n AND commitment IS NOT NULL\n AND (\n protocol_versions.id = $3\n OR protocol_versions.upgrade_tx_hash IS NULL\n )\n ORDER BY\n number\n LIMIT\n $4\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "l1_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 3, + "name": "l2_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 4, + "name": "bloom", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "priority_ops_onchain_data", + "type_info": "ByteaArray" + }, + { + "ordinal": 6, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "parent_hash", + "type_info": "Bytea" + }, + { + "ordinal": 8, + "name": "commitment", + "type_info": "Bytea" + }, + { + "ordinal": 9, + "name": "compressed_write_logs", + "type_info": "Bytea" + }, + { + "ordinal": 10, + "name": "compressed_contracts", + "type_info": "Bytea" + }, + { + "ordinal": 11, + "name": "eth_prove_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 12, + "name": "eth_commit_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 13, + "name": "eth_execute_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 14, + "name": "merkle_root_hash", + "type_info": "Bytea" + }, + { + "ordinal": 15, + "name": "l2_to_l1_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 16, + "name": "l2_to_l1_messages", + "type_info": "ByteaArray" + }, + { + "ordinal": 17, + "name": "used_contract_hashes", + "type_info": "Jsonb" + }, + { + "ordinal": 18, + "name": "compressed_initial_writes", + "type_info": "Bytea" + }, + { + "ordinal": 19, + "name": "compressed_repeated_writes", + "type_info": "Bytea" + }, + { + "ordinal": 20, + "name": "l2_l1_compressed_messages", + "type_info": "Bytea" + }, + { + "ordinal": 21, + "name": "l2_l1_merkle_root", + "type_info": "Bytea" + }, + { + "ordinal": 22, + "name": "rollup_last_leaf_index", + "type_info": "Int8" + }, + { + "ordinal": 23, + "name": "zkporter_is_available", + "type_info": "Bool" + }, + { + "ordinal": 24, + "name": "bootloader_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 25, + "name": "default_aa_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 26, + "name": "aux_data_hash", + "type_info": "Bytea" + }, + { + "ordinal": 27, + "name": "pass_through_data_hash", + "type_info": "Bytea" + }, + { + "ordinal": 28, + "name": "meta_parameters_hash", + "type_info": "Bytea" + }, + { + "ordinal": 29, + "name": "protocol_version", + "type_info": "Int4" + }, + { + "ordinal": 30, + "name": "compressed_state_diffs", + "type_info": "Bytea" + }, + { + "ordinal": 31, + "name": "system_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 32, + "name": "events_queue_commitment", + "type_info": "Bytea" + }, + { + "ordinal": 33, + "name": "bootloader_initial_content_commitment", + "type_info": "Bytea" + }, + { + "ordinal": 34, + "name": "pubdata_input", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Bytea", + "Bytea", + "Int4", + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + true, + true + ] + }, + "hash": "3ad766526138a1cf9ca3acd9025bab23414ee459daa4734772ece7bcc6e5fd7f" +} diff --git a/core/lib/dal/.sqlx/query-3b013b93ea4a6766162c9f0c60517a7ffc993cf436ad3aeeae82ed3e330b07bd.json b/core/lib/dal/.sqlx/query-3b013b93ea4a6766162c9f0c60517a7ffc993cf436ad3aeeae82ed3e330b07bd.json new file mode 100644 index 000000000000..6e7bffec4854 --- /dev/null +++ b/core/lib/dal/.sqlx/query-3b013b93ea4a6766162c9f0c60517a7ffc993cf436ad3aeeae82ed3e330b07bd.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n certificate\n FROM\n miniblocks_consensus\n ORDER BY\n number ASC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "certificate", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "3b013b93ea4a6766162c9f0c60517a7ffc993cf436ad3aeeae82ed3e330b07bd" +} diff --git a/core/lib/dal/.sqlx/query-3b3fbcffd2702047045c2f358e8ac77b63879ab97a32eed8392b48cc46116a28.json b/core/lib/dal/.sqlx/query-3b3fbcffd2702047045c2f358e8ac77b63879ab97a32eed8392b48cc46116a28.json new file mode 100644 index 000000000000..326915adb2fc --- /dev/null +++ b/core/lib/dal/.sqlx/query-3b3fbcffd2702047045c2f358e8ac77b63879ab97a32eed8392b48cc46116a28.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM call_traces\n WHERE\n tx_hash = ANY ($1)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "ByteaArray" + ] + }, + "nullable": [] + }, + "hash": "3b3fbcffd2702047045c2f358e8ac77b63879ab97a32eed8392b48cc46116a28" +} diff --git a/core/lib/dal/.sqlx/query-3b4d5009ec22f54cc7d305aa11d96ec397767a063dc21aa3add974cb9b070361.json b/core/lib/dal/.sqlx/query-3b4d5009ec22f54cc7d305aa11d96ec397767a063dc21aa3add974cb9b070361.json new file mode 100644 index 000000000000..38890ae58f2e --- /dev/null +++ b/core/lib/dal/.sqlx/query-3b4d5009ec22f54cc7d305aa11d96ec397767a063dc21aa3add974cb9b070361.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n factory_deps (bytecode_hash, bytecode, miniblock_number, created_at, updated_at)\n SELECT\n u.bytecode_hash,\n u.bytecode,\n $3,\n NOW(),\n NOW()\n FROM\n UNNEST($1::bytea[], $2::bytea[]) AS u (bytecode_hash, bytecode)\n ON CONFLICT (bytecode_hash) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "ByteaArray", + "ByteaArray", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "3b4d5009ec22f54cc7d305aa11d96ec397767a063dc21aa3add974cb9b070361" +} diff --git a/core/lib/dal/.sqlx/query-3c1d5f985be7e378211aa339c2c6387f2f3eda07a630503324bd6576dbdf8231.json b/core/lib/dal/.sqlx/query-3c1d5f985be7e378211aa339c2c6387f2f3eda07a630503324bd6576dbdf8231.json new file mode 100644 index 000000000000..ad5c726ea130 --- /dev/null +++ b/core/lib/dal/.sqlx/query-3c1d5f985be7e378211aa339c2c6387f2f3eda07a630503324bd6576dbdf8231.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n trace\n FROM\n transaction_traces\n WHERE\n tx_hash = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "trace", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [ + false + ] + }, + "hash": "3c1d5f985be7e378211aa339c2c6387f2f3eda07a630503324bd6576dbdf8231" +} diff --git a/core/lib/dal/.sqlx/query-3c2280a0a07f2916baba64bc9511c711c5531fcee28048b5da988a4e748c0c3a.json b/core/lib/dal/.sqlx/query-3c2280a0a07f2916baba64bc9511c711c5531fcee28048b5da988a4e748c0c3a.json new file mode 100644 index 000000000000..521af97a5822 --- /dev/null +++ b/core/lib/dal/.sqlx/query-3c2280a0a07f2916baba64bc9511c711c5531fcee28048b5da988a4e748c0c3a.json @@ -0,0 +1,226 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n parent_hash,\n commitment,\n compressed_write_logs,\n compressed_contracts,\n eth_prove_tx_id,\n eth_commit_tx_id,\n eth_execute_tx_id,\n merkle_root_hash,\n l2_to_l1_logs,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_compressed_messages,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n WHERE\n eth_prove_tx_id IS NOT NULL\n AND eth_execute_tx_id IS NULL\n ORDER BY\n number\n LIMIT\n $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "l1_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 3, + "name": "l2_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 4, + "name": "bloom", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "priority_ops_onchain_data", + "type_info": "ByteaArray" + }, + { + "ordinal": 6, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "parent_hash", + "type_info": "Bytea" + }, + { + "ordinal": 8, + "name": "commitment", + "type_info": "Bytea" + }, + { + "ordinal": 9, + "name": "compressed_write_logs", + "type_info": "Bytea" + }, + { + "ordinal": 10, + "name": "compressed_contracts", + "type_info": "Bytea" + }, + { + "ordinal": 11, + "name": "eth_prove_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 12, + "name": "eth_commit_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 13, + "name": "eth_execute_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 14, + "name": "merkle_root_hash", + "type_info": "Bytea" + }, + { + "ordinal": 15, + "name": "l2_to_l1_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 16, + "name": "l2_to_l1_messages", + "type_info": "ByteaArray" + }, + { + "ordinal": 17, + "name": "used_contract_hashes", + "type_info": "Jsonb" + }, + { + "ordinal": 18, + "name": "compressed_initial_writes", + "type_info": "Bytea" + }, + { + "ordinal": 19, + "name": "compressed_repeated_writes", + "type_info": "Bytea" + }, + { + "ordinal": 20, + "name": "l2_l1_compressed_messages", + "type_info": "Bytea" + }, + { + "ordinal": 21, + "name": "l2_l1_merkle_root", + "type_info": "Bytea" + }, + { + "ordinal": 22, + "name": "rollup_last_leaf_index", + "type_info": "Int8" + }, + { + "ordinal": 23, + "name": "zkporter_is_available", + "type_info": "Bool" + }, + { + "ordinal": 24, + "name": "bootloader_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 25, + "name": "default_aa_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 26, + "name": "aux_data_hash", + "type_info": "Bytea" + }, + { + "ordinal": 27, + "name": "pass_through_data_hash", + "type_info": "Bytea" + }, + { + "ordinal": 28, + "name": "meta_parameters_hash", + "type_info": "Bytea" + }, + { + "ordinal": 29, + "name": "protocol_version", + "type_info": "Int4" + }, + { + "ordinal": 30, + "name": "compressed_state_diffs", + "type_info": "Bytea" + }, + { + "ordinal": 31, + "name": "system_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 32, + "name": "events_queue_commitment", + "type_info": "Bytea" + }, + { + "ordinal": 33, + "name": "bootloader_initial_content_commitment", + "type_info": "Bytea" + }, + { + "ordinal": 34, + "name": "pubdata_input", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + true, + true + ] + }, + "hash": "3c2280a0a07f2916baba64bc9511c711c5531fcee28048b5da988a4e748c0c3a" +} diff --git a/core/lib/dal/.sqlx/query-3c3abbf689fa64c6da7de69fd916769dbb04d3a61cf232892236c974660ffe64.json b/core/lib/dal/.sqlx/query-3c3abbf689fa64c6da7de69fd916769dbb04d3a61cf232892236c974660ffe64.json new file mode 100644 index 000000000000..56d8b1fa9956 --- /dev/null +++ b/core/lib/dal/.sqlx/query-3c3abbf689fa64c6da7de69fd916769dbb04d3a61cf232892236c974660ffe64.json @@ -0,0 +1,35 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE scheduler_witness_jobs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n (\n status = 'in_progress'\n AND processing_started_at <= NOW() - $1::INTERVAL\n AND attempts < $2\n )\n OR (\n status = 'failed'\n AND attempts < $2\n )\n RETURNING\n l1_batch_number,\n status,\n attempts\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "status", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "attempts", + "type_info": "Int2" + } + ], + "parameters": { + "Left": [ + "Interval", + "Int2" + ] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "3c3abbf689fa64c6da7de69fd916769dbb04d3a61cf232892236c974660ffe64" +} diff --git a/core/lib/dal/.sqlx/query-3c531ad0631090934ed46c538249360a7eab2efc70d97b901f8948f6909d4cd2.json b/core/lib/dal/.sqlx/query-3c531ad0631090934ed46c538249360a7eab2efc70d97b901f8948f6909d4cd2.json new file mode 100644 index 000000000000..d8f17c7f772e --- /dev/null +++ b/core/lib/dal/.sqlx/query-3c531ad0631090934ed46c538249360a7eab2efc70d97b901f8948f6909d4cd2.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batches.fee_account_address\n FROM\n l1_batches\n INNER JOIN miniblocks ON miniblocks.l1_batch_number = l1_batches.number\n WHERE\n miniblocks.number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "fee_account_address", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "3c531ad0631090934ed46c538249360a7eab2efc70d97b901f8948f6909d4cd2" +} diff --git a/core/lib/dal/.sqlx/query-3c60ca71b8a3b544f5fe9d7f2fbb249026665c9fb17b6f53a2154473547cbbfd.json b/core/lib/dal/.sqlx/query-3c60ca71b8a3b544f5fe9d7f2fbb249026665c9fb17b6f53a2154473547cbbfd.json new file mode 100644 index 000000000000..8797c84ce887 --- /dev/null +++ b/core/lib/dal/.sqlx/query-3c60ca71b8a3b544f5fe9d7f2fbb249026665c9fb17b6f53a2154473547cbbfd.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n certificate\n FROM\n miniblocks_consensus\n WHERE\n number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "certificate", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "3c60ca71b8a3b544f5fe9d7f2fbb249026665c9fb17b6f53a2154473547cbbfd" +} diff --git a/core/lib/dal/.sqlx/query-3e170eea3a5ea5c7389c15f76c6489745438eae73a07b577aa25bd08adf95354.json b/core/lib/dal/.sqlx/query-3e170eea3a5ea5c7389c15f76c6489745438eae73a07b577aa25bd08adf95354.json new file mode 100644 index 000000000000..2290d558cead --- /dev/null +++ b/core/lib/dal/.sqlx/query-3e170eea3a5ea5c7389c15f76c6489745438eae73a07b577aa25bd08adf95354.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM tokens\n WHERE\n l2_address IN (\n SELECT\n SUBSTRING(key, 12, 20)\n FROM\n storage_logs\n WHERE\n storage_logs.address = $1\n AND miniblock_number > $2\n AND NOT EXISTS (\n SELECT\n 1\n FROM\n storage_logs AS s\n WHERE\n s.hashed_key = storage_logs.hashed_key\n AND (s.miniblock_number, s.operation_number) >= (storage_logs.miniblock_number, storage_logs.operation_number)\n AND s.value = $3\n )\n )\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Int8", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "3e170eea3a5ea5c7389c15f76c6489745438eae73a07b577aa25bd08adf95354" +} diff --git a/core/lib/dal/.sqlx/query-3ec365c5c81f4678a905ae5bbd48b87ead36f593488437c6f67da629ca81e4fa.json b/core/lib/dal/.sqlx/query-3ec365c5c81f4678a905ae5bbd48b87ead36f593488437c6f67da629ca81e4fa.json new file mode 100644 index 000000000000..5815e65636cb --- /dev/null +++ b/core/lib/dal/.sqlx/query-3ec365c5c81f4678a905ae5bbd48b87ead36f593488437c6f67da629ca81e4fa.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE scheduler_witness_jobs_fri\n SET\n status = 'queued'\n WHERE\n l1_batch_number = $1\n AND status != 'successful'\n AND status != 'in_progress'\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "3ec365c5c81f4678a905ae5bbd48b87ead36f593488437c6f67da629ca81e4fa" +} diff --git a/core/lib/dal/.sqlx/query-41c9f45d6eb727aafad0d8c18024cee5c602d275bb812022cc8fdabf0a60e151.json b/core/lib/dal/.sqlx/query-41c9f45d6eb727aafad0d8c18024cee5c602d275bb812022cc8fdabf0a60e151.json new file mode 100644 index 000000000000..8c51c26131bd --- /dev/null +++ b/core/lib/dal/.sqlx/query-41c9f45d6eb727aafad0d8c18024cee5c602d275bb812022cc8fdabf0a60e151.json @@ -0,0 +1,56 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n eth_txs_history.id,\n eth_txs_history.eth_tx_id,\n eth_txs_history.tx_hash,\n eth_txs_history.base_fee_per_gas,\n eth_txs_history.priority_fee_per_gas,\n eth_txs_history.signed_raw_tx,\n eth_txs.nonce\n FROM\n eth_txs_history\n JOIN eth_txs ON eth_txs.id = eth_txs_history.eth_tx_id\n WHERE\n eth_txs_history.sent_at_block IS NULL\n AND eth_txs.confirmed_eth_tx_history_id IS NULL\n ORDER BY\n eth_txs_history.id DESC\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "eth_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 2, + "name": "tx_hash", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "base_fee_per_gas", + "type_info": "Int8" + }, + { + "ordinal": 4, + "name": "priority_fee_per_gas", + "type_info": "Int8" + }, + { + "ordinal": 5, + "name": "signed_raw_tx", + "type_info": "Bytea" + }, + { + "ordinal": 6, + "name": "nonce", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false, + false, + false, + true, + false + ] + }, + "hash": "41c9f45d6eb727aafad0d8c18024cee5c602d275bb812022cc8fdabf0a60e151" +} diff --git a/core/lib/dal/.sqlx/query-43c7e352d09f69de1a182196aea4de79b67833f17d252b5b0e8e00cd6e75b5c1.json b/core/lib/dal/.sqlx/query-43c7e352d09f69de1a182196aea4de79b67833f17d252b5b0e8e00cd6e75b5c1.json new file mode 100644 index 000000000000..56fcdb389430 --- /dev/null +++ b/core/lib/dal/.sqlx/query-43c7e352d09f69de1a182196aea4de79b67833f17d252b5b0e8e00cd6e75b5c1.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n MIN(number) AS \"number\"\n FROM\n l1_batches\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "43c7e352d09f69de1a182196aea4de79b67833f17d252b5b0e8e00cd6e75b5c1" +} diff --git a/core/lib/dal/.sqlx/query-44490ad52b8dbcd978a96677ffac5437752a4cf3ac92ec09b334089a8dc5b4ca.json b/core/lib/dal/.sqlx/query-44490ad52b8dbcd978a96677ffac5437752a4cf3ac92ec09b334089a8dc5b4ca.json new file mode 100644 index 000000000000..cb2d1b149ecf --- /dev/null +++ b/core/lib/dal/.sqlx/query-44490ad52b8dbcd978a96677ffac5437752a4cf3ac92ec09b334089a8dc5b4ca.json @@ -0,0 +1,106 @@ +{ + "db_name": "PostgreSQL", + "query": "\n WITH\n mb AS (\n SELECT\n l1_gas_price,\n l2_fair_gas_price\n FROM\n miniblocks\n WHERE\n l1_batch_number = $1\n LIMIT\n 1\n )\n SELECT\n l1_batches.number,\n l1_batches.timestamp,\n l1_batches.l1_tx_count,\n l1_batches.l2_tx_count,\n l1_batches.hash AS \"root_hash?\",\n commit_tx.tx_hash AS \"commit_tx_hash?\",\n commit_tx.confirmed_at AS \"committed_at?\",\n prove_tx.tx_hash AS \"prove_tx_hash?\",\n prove_tx.confirmed_at AS \"proven_at?\",\n execute_tx.tx_hash AS \"execute_tx_hash?\",\n execute_tx.confirmed_at AS \"executed_at?\",\n mb.l1_gas_price,\n mb.l2_fair_gas_price,\n l1_batches.bootloader_code_hash,\n l1_batches.default_aa_code_hash\n FROM\n l1_batches\n INNER JOIN mb ON TRUE\n LEFT JOIN eth_txs_history AS commit_tx ON (\n l1_batches.eth_commit_tx_id = commit_tx.eth_tx_id\n AND commit_tx.confirmed_at IS NOT NULL\n )\n LEFT JOIN eth_txs_history AS prove_tx ON (\n l1_batches.eth_prove_tx_id = prove_tx.eth_tx_id\n AND prove_tx.confirmed_at IS NOT NULL\n )\n LEFT JOIN eth_txs_history AS execute_tx ON (\n l1_batches.eth_execute_tx_id = execute_tx.eth_tx_id\n AND execute_tx.confirmed_at IS NOT NULL\n )\n WHERE\n l1_batches.number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "l1_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 3, + "name": "l2_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 4, + "name": "root_hash?", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "commit_tx_hash?", + "type_info": "Text" + }, + { + "ordinal": 6, + "name": "committed_at?", + "type_info": "Timestamp" + }, + { + "ordinal": 7, + "name": "prove_tx_hash?", + "type_info": "Text" + }, + { + "ordinal": 8, + "name": "proven_at?", + "type_info": "Timestamp" + }, + { + "ordinal": 9, + "name": "execute_tx_hash?", + "type_info": "Text" + }, + { + "ordinal": 10, + "name": "executed_at?", + "type_info": "Timestamp" + }, + { + "ordinal": 11, + "name": "l1_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 12, + "name": "l2_fair_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 13, + "name": "bootloader_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 14, + "name": "default_aa_code_hash", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + true + ] + }, + "hash": "44490ad52b8dbcd978a96677ffac5437752a4cf3ac92ec09b334089a8dc5b4ca" +} diff --git a/core/lib/dal/.sqlx/query-46c4696fff5a4b8cc5cb46b05645da82065836fe17687ffad04126a6a8b2b27c.json b/core/lib/dal/.sqlx/query-46c4696fff5a4b8cc5cb46b05645da82065836fe17687ffad04126a6a8b2b27c.json new file mode 100644 index 000000000000..5ebb1951966d --- /dev/null +++ b/core/lib/dal/.sqlx/query-46c4696fff5a4b8cc5cb46b05645da82065836fe17687ffad04126a6a8b2b27c.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE leaf_aggregation_witness_jobs_fri\n SET\n status = 'successful',\n updated_at = NOW(),\n time_taken = $1\n WHERE\n id = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Time", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "46c4696fff5a4b8cc5cb46b05645da82065836fe17687ffad04126a6a8b2b27c" +} diff --git a/core/lib/dal/.sqlx/query-4a70d73b85e9b96125d8b9385ed12823e1699490087a060455af49b637d82665.json b/core/lib/dal/.sqlx/query-4a70d73b85e9b96125d8b9385ed12823e1699490087a060455af49b637d82665.json new file mode 100644 index 000000000000..d009cf0e9620 --- /dev/null +++ b/core/lib/dal/.sqlx/query-4a70d73b85e9b96125d8b9385ed12823e1699490087a060455af49b637d82665.json @@ -0,0 +1,228 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n parent_hash,\n commitment,\n compressed_write_logs,\n compressed_contracts,\n eth_prove_tx_id,\n eth_commit_tx_id,\n eth_execute_tx_id,\n merkle_root_hash,\n l2_to_l1_logs,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_compressed_messages,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n WHERE\n number BETWEEN $1 AND $2\n ORDER BY\n number\n LIMIT\n $3\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "l1_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 3, + "name": "l2_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 4, + "name": "bloom", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "priority_ops_onchain_data", + "type_info": "ByteaArray" + }, + { + "ordinal": 6, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "parent_hash", + "type_info": "Bytea" + }, + { + "ordinal": 8, + "name": "commitment", + "type_info": "Bytea" + }, + { + "ordinal": 9, + "name": "compressed_write_logs", + "type_info": "Bytea" + }, + { + "ordinal": 10, + "name": "compressed_contracts", + "type_info": "Bytea" + }, + { + "ordinal": 11, + "name": "eth_prove_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 12, + "name": "eth_commit_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 13, + "name": "eth_execute_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 14, + "name": "merkle_root_hash", + "type_info": "Bytea" + }, + { + "ordinal": 15, + "name": "l2_to_l1_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 16, + "name": "l2_to_l1_messages", + "type_info": "ByteaArray" + }, + { + "ordinal": 17, + "name": "used_contract_hashes", + "type_info": "Jsonb" + }, + { + "ordinal": 18, + "name": "compressed_initial_writes", + "type_info": "Bytea" + }, + { + "ordinal": 19, + "name": "compressed_repeated_writes", + "type_info": "Bytea" + }, + { + "ordinal": 20, + "name": "l2_l1_compressed_messages", + "type_info": "Bytea" + }, + { + "ordinal": 21, + "name": "l2_l1_merkle_root", + "type_info": "Bytea" + }, + { + "ordinal": 22, + "name": "rollup_last_leaf_index", + "type_info": "Int8" + }, + { + "ordinal": 23, + "name": "zkporter_is_available", + "type_info": "Bool" + }, + { + "ordinal": 24, + "name": "bootloader_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 25, + "name": "default_aa_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 26, + "name": "aux_data_hash", + "type_info": "Bytea" + }, + { + "ordinal": 27, + "name": "pass_through_data_hash", + "type_info": "Bytea" + }, + { + "ordinal": 28, + "name": "meta_parameters_hash", + "type_info": "Bytea" + }, + { + "ordinal": 29, + "name": "protocol_version", + "type_info": "Int4" + }, + { + "ordinal": 30, + "name": "compressed_state_diffs", + "type_info": "Bytea" + }, + { + "ordinal": 31, + "name": "system_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 32, + "name": "events_queue_commitment", + "type_info": "Bytea" + }, + { + "ordinal": 33, + "name": "bootloader_initial_content_commitment", + "type_info": "Bytea" + }, + { + "ordinal": 34, + "name": "pubdata_input", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8", + "Int8", + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + true, + true + ] + }, + "hash": "4a70d73b85e9b96125d8b9385ed12823e1699490087a060455af49b637d82665" +} diff --git a/core/lib/dal/.sqlx/query-4d263992ed6d5abbd7d3ca43af9d772d8801b0ae673b7173ae08a1fa6cbf67b2.json b/core/lib/dal/.sqlx/query-4d263992ed6d5abbd7d3ca43af9d772d8801b0ae673b7173ae08a1fa6cbf67b2.json new file mode 100644 index 000000000000..b0fb8d4be23c --- /dev/null +++ b/core/lib/dal/.sqlx/query-4d263992ed6d5abbd7d3ca43af9d772d8801b0ae673b7173ae08a1fa6cbf67b2.json @@ -0,0 +1,59 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE prover_jobs_fri\n SET\n status = 'in_progress',\n attempts = attempts + 1,\n updated_at = NOW(),\n processing_started_at = NOW(),\n picked_by = $2\n WHERE\n id = (\n SELECT\n id\n FROM\n prover_jobs_fri\n WHERE\n status = 'queued'\n AND protocol_version = ANY ($1)\n ORDER BY\n aggregation_round DESC,\n l1_batch_number ASC,\n id ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n prover_jobs_fri.id,\n prover_jobs_fri.l1_batch_number,\n prover_jobs_fri.circuit_id,\n prover_jobs_fri.aggregation_round,\n prover_jobs_fri.sequence_number,\n prover_jobs_fri.depth,\n prover_jobs_fri.is_node_final_proof\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "circuit_id", + "type_info": "Int2" + }, + { + "ordinal": 3, + "name": "aggregation_round", + "type_info": "Int2" + }, + { + "ordinal": 4, + "name": "sequence_number", + "type_info": "Int4" + }, + { + "ordinal": 5, + "name": "depth", + "type_info": "Int4" + }, + { + "ordinal": 6, + "name": "is_node_final_proof", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Int4Array", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false + ] + }, + "hash": "4d263992ed6d5abbd7d3ca43af9d772d8801b0ae673b7173ae08a1fa6cbf67b2" +} diff --git a/core/lib/dal/.sqlx/query-4d50dabc25d392e6b9d0dbe0e386ea7ef2c1178b1b0394a17442185b79f2d77d.json b/core/lib/dal/.sqlx/query-4d50dabc25d392e6b9d0dbe0e386ea7ef2c1178b1b0394a17442185b79f2d77d.json new file mode 100644 index 000000000000..e9a9425da3ce --- /dev/null +++ b/core/lib/dal/.sqlx/query-4d50dabc25d392e6b9d0dbe0e386ea7ef2c1178b1b0394a17442185b79f2d77d.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT eth_txs.id FROM eth_txs_history JOIN eth_txs ON eth_txs.confirmed_eth_tx_history_id = eth_txs_history.id WHERE eth_txs_history.tx_hash = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "4d50dabc25d392e6b9d0dbe0e386ea7ef2c1178b1b0394a17442185b79f2d77d" +} diff --git a/core/lib/dal/.sqlx/query-4d84bb4e180b7267bee5e3c1f83c6d47e8e1b4b5124c82c1f35d405204fcf783.json b/core/lib/dal/.sqlx/query-4d84bb4e180b7267bee5e3c1f83c6d47e8e1b4b5124c82c1f35d405204fcf783.json new file mode 100644 index 000000000000..44d1506ac937 --- /dev/null +++ b/core/lib/dal/.sqlx/query-4d84bb4e180b7267bee5e3c1f83c6d47e8e1b4b5124c82c1f35d405204fcf783.json @@ -0,0 +1,82 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n *\n FROM\n eth_txs_history\n WHERE\n eth_tx_id = $1\n ORDER BY\n created_at DESC\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "eth_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 2, + "name": "tx_hash", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 4, + "name": "updated_at", + "type_info": "Timestamp" + }, + { + "ordinal": 5, + "name": "base_fee_per_gas", + "type_info": "Int8" + }, + { + "ordinal": 6, + "name": "priority_fee_per_gas", + "type_info": "Int8" + }, + { + "ordinal": 7, + "name": "confirmed_at", + "type_info": "Timestamp" + }, + { + "ordinal": 8, + "name": "signed_raw_tx", + "type_info": "Bytea" + }, + { + "ordinal": 9, + "name": "sent_at_block", + "type_info": "Int4" + }, + { + "ordinal": 10, + "name": "sent_at", + "type_info": "Timestamp" + } + ], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true + ] + }, + "hash": "4d84bb4e180b7267bee5e3c1f83c6d47e8e1b4b5124c82c1f35d405204fcf783" +} diff --git a/core/lib/dal/.sqlx/query-4d92a133a36afd682a84fbfd75aafca34d61347e0e2e29fb07ca3d1b8b1f309c.json b/core/lib/dal/.sqlx/query-4d92a133a36afd682a84fbfd75aafca34d61347e0e2e29fb07ca3d1b8b1f309c.json new file mode 100644 index 000000000000..f7ae37f4b7b3 --- /dev/null +++ b/core/lib/dal/.sqlx/query-4d92a133a36afd682a84fbfd75aafca34d61347e0e2e29fb07ca3d1b8b1f309c.json @@ -0,0 +1,18 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n prover_fri_protocol_versions (\n id,\n recursion_scheduler_level_vk_hash,\n recursion_node_level_vk_hash,\n recursion_leaf_level_vk_hash,\n recursion_circuits_set_vks_hash,\n created_at\n )\n VALUES\n ($1, $2, $3, $4, $5, NOW())\n ON CONFLICT (id) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4", + "Bytea", + "Bytea", + "Bytea", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "4d92a133a36afd682a84fbfd75aafca34d61347e0e2e29fb07ca3d1b8b1f309c" +} diff --git a/core/lib/dal/.sqlx/query-51891ab674b8f5cf2d7c12420d1c026c3181f42a49f1f4b6e227c95641931a54.json b/core/lib/dal/.sqlx/query-51891ab674b8f5cf2d7c12420d1c026c3181f42a49f1f4b6e227c95641931a54.json new file mode 100644 index 000000000000..ed13428a5695 --- /dev/null +++ b/core/lib/dal/.sqlx/query-51891ab674b8f5cf2d7c12420d1c026c3181f42a49f1f4b6e227c95641931a54.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n timestamp\n FROM\n miniblocks\n WHERE\n number = COALESCE(\n (\n SELECT\n MAX(number) + 1\n FROM\n miniblocks\n WHERE\n l1_batch_number = $1\n ),\n (\n SELECT\n MAX(miniblock_number) + 1\n FROM\n snapshot_recovery\n WHERE\n l1_batch_number = $1\n )\n )\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "timestamp", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "51891ab674b8f5cf2d7c12420d1c026c3181f42a49f1f4b6e227c95641931a54" +} diff --git a/core/lib/dal/.sqlx/query-525123d4ec2b427f1c171f30d0937d8d542b4f14cf560972c005ab3cc13d1f63.json b/core/lib/dal/.sqlx/query-525123d4ec2b427f1c171f30d0937d8d542b4f14cf560972c005ab3cc13d1f63.json new file mode 100644 index 000000000000..7764425aa214 --- /dev/null +++ b/core/lib/dal/.sqlx/query-525123d4ec2b427f1c171f30d0937d8d542b4f14cf560972c005ab3cc13d1f63.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n hash\n FROM\n miniblocks\n WHERE\n number BETWEEN $1 AND $2\n ORDER BY\n number\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hash", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8", + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "525123d4ec2b427f1c171f30d0937d8d542b4f14cf560972c005ab3cc13d1f63" +} diff --git a/core/lib/dal/.sqlx/query-532a80b0873871896dd318beba5ec427a099492905a1feee512dc43f39d10047.json b/core/lib/dal/.sqlx/query-532a80b0873871896dd318beba5ec427a099492905a1feee512dc43f39d10047.json new file mode 100644 index 000000000000..629dca2ea7f0 --- /dev/null +++ b/core/lib/dal/.sqlx/query-532a80b0873871896dd318beba5ec427a099492905a1feee512dc43f39d10047.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE eth_txs_history\n SET\n sent_at_block = $2,\n sent_at = NOW()\n WHERE\n id = $1\n AND sent_at_block IS NULL\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4", + "Int4" + ] + }, + "nullable": [] + }, + "hash": "532a80b0873871896dd318beba5ec427a099492905a1feee512dc43f39d10047" +} diff --git a/core/lib/dal/.sqlx/query-534822a226068cde83ad8c30b569a8f447824a5ab466bb6eea1710e8aeaa2c56.json b/core/lib/dal/.sqlx/query-534822a226068cde83ad8c30b569a8f447824a5ab466bb6eea1710e8aeaa2c56.json new file mode 100644 index 000000000000..a85b4895b451 --- /dev/null +++ b/core/lib/dal/.sqlx/query-534822a226068cde83ad8c30b569a8f447824a5ab466bb6eea1710e8aeaa2c56.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE proof_compression_jobs_fri\n SET\n status = $1,\n updated_at = NOW()\n WHERE\n l1_batch_number = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "534822a226068cde83ad8c30b569a8f447824a5ab466bb6eea1710e8aeaa2c56" +} diff --git a/core/lib/dal/.sqlx/query-53f78fdee39b113d2f55f6f951bd94f28b7b2b60d551d552a9b0bab1f1791e39.json b/core/lib/dal/.sqlx/query-53f78fdee39b113d2f55f6f951bd94f28b7b2b60d551d552a9b0bab1f1791e39.json new file mode 100644 index 000000000000..15a10f7ce3c5 --- /dev/null +++ b/core/lib/dal/.sqlx/query-53f78fdee39b113d2f55f6f951bd94f28b7b2b60d551d552a9b0bab1f1791e39.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n attempts\n FROM\n leaf_aggregation_witness_jobs_fri\n WHERE\n id = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "attempts", + "type_info": "Int2" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "53f78fdee39b113d2f55f6f951bd94f28b7b2b60d551d552a9b0bab1f1791e39" +} diff --git a/core/lib/dal/.sqlx/query-546c729829083b7eba94fea742c162d717ffcf46fdf5d2ce5d32555353b6da6b.json b/core/lib/dal/.sqlx/query-546c729829083b7eba94fea742c162d717ffcf46fdf5d2ce5d32555353b6da6b.json new file mode 100644 index 000000000000..70b94f739098 --- /dev/null +++ b/core/lib/dal/.sqlx/query-546c729829083b7eba94fea742c162d717ffcf46fdf5d2ce5d32555353b6da6b.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE transactions\n SET\n in_mempool = FALSE\n FROM\n UNNEST($1::bytea[]) AS s (address)\n WHERE\n transactions.in_mempool = TRUE\n AND transactions.initiator_address = s.address\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "ByteaArray" + ] + }, + "nullable": [] + }, + "hash": "546c729829083b7eba94fea742c162d717ffcf46fdf5d2ce5d32555353b6da6b" +} diff --git a/core/lib/dal/.sqlx/query-5503575d9377785894de6cf6139a8d4768c6a803a1a90889e5a1b8254c315231.json b/core/lib/dal/.sqlx/query-5503575d9377785894de6cf6139a8d4768c6a803a1a90889e5a1b8254c315231.json new file mode 100644 index 000000000000..5f27c7549b47 --- /dev/null +++ b/core/lib/dal/.sqlx/query-5503575d9377785894de6cf6139a8d4768c6a803a1a90889e5a1b8254c315231.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO eth_txs (raw_tx, nonce, tx_type, contract_address, predicted_gas_cost, created_at, updated_at) VALUES ('\\x00', 0, $1, '', 0, now(), now()) RETURNING id", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "5503575d9377785894de6cf6139a8d4768c6a803a1a90889e5a1b8254c315231" +} diff --git a/core/lib/dal/.sqlx/query-555f396946bdb8b84a5d77abbfc1397212b4767039a6c0e22697cf40969729af.json b/core/lib/dal/.sqlx/query-555f396946bdb8b84a5d77abbfc1397212b4767039a6c0e22697cf40969729af.json new file mode 100644 index 000000000000..1cb61dc4460e --- /dev/null +++ b/core/lib/dal/.sqlx/query-555f396946bdb8b84a5d77abbfc1397212b4767039a6c0e22697cf40969729af.json @@ -0,0 +1,56 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n hashed_key,\n address,\n key,\n value,\n operation_number,\n tx_hash,\n miniblock_number\n FROM\n storage_logs\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hashed_key", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "address", + "type_info": "Bytea" + }, + { + "ordinal": 2, + "name": "key", + "type_info": "Bytea" + }, + { + "ordinal": 3, + "name": "value", + "type_info": "Bytea" + }, + { + "ordinal": 4, + "name": "operation_number", + "type_info": "Int4" + }, + { + "ordinal": 5, + "name": "tx_hash", + "type_info": "Bytea" + }, + { + "ordinal": 6, + "name": "miniblock_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false + ] + }, + "hash": "555f396946bdb8b84a5d77abbfc1397212b4767039a6c0e22697cf40969729af" +} diff --git a/core/lib/dal/.sqlx/query-556f9b9e82d3a9399660dfa4bbf252f26335699a4e7f0347d7e894320245271d.json b/core/lib/dal/.sqlx/query-556f9b9e82d3a9399660dfa4bbf252f26335699a4e7f0347d7e894320245271d.json new file mode 100644 index 000000000000..1dcfa982c51d --- /dev/null +++ b/core/lib/dal/.sqlx/query-556f9b9e82d3a9399660dfa4bbf252f26335699a4e7f0347d7e894320245271d.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n events_queue (l1_batch_number, serialized_events_queue)\n VALUES\n ($1, $2)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Jsonb" + ] + }, + "nullable": [] + }, + "hash": "556f9b9e82d3a9399660dfa4bbf252f26335699a4e7f0347d7e894320245271d" +} diff --git a/core/lib/dal/.sqlx/query-55b0b4c569c0aaf9741afc85400ecd50a04799ffd36be0e17c56f47fcdbc8f60.json b/core/lib/dal/.sqlx/query-55b0b4c569c0aaf9741afc85400ecd50a04799ffd36be0e17c56f47fcdbc8f60.json new file mode 100644 index 000000000000..6478bb53538d --- /dev/null +++ b/core/lib/dal/.sqlx/query-55b0b4c569c0aaf9741afc85400ecd50a04799ffd36be0e17c56f47fcdbc8f60.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM l1_batches\n WHERE\n number > $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "55b0b4c569c0aaf9741afc85400ecd50a04799ffd36be0e17c56f47fcdbc8f60" +} diff --git a/core/lib/dal/.sqlx/query-5659480e5d79dab3399e35539b240e7eb9f598999c28015a504605f88bf84b33.json b/core/lib/dal/.sqlx/query-5659480e5d79dab3399e35539b240e7eb9f598999c28015a504605f88bf84b33.json new file mode 100644 index 000000000000..399b0d028459 --- /dev/null +++ b/core/lib/dal/.sqlx/query-5659480e5d79dab3399e35539b240e7eb9f598999c28015a504605f88bf84b33.json @@ -0,0 +1,88 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n *\n FROM\n eth_txs\n WHERE\n id > (\n SELECT\n COALESCE(MAX(eth_tx_id), 0)\n FROM\n eth_txs_history\n )\n ORDER BY\n id\n LIMIT\n $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "nonce", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "raw_tx", + "type_info": "Bytea" + }, + { + "ordinal": 3, + "name": "contract_address", + "type_info": "Text" + }, + { + "ordinal": 4, + "name": "tx_type", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "gas_used", + "type_info": "Int8" + }, + { + "ordinal": 6, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 7, + "name": "updated_at", + "type_info": "Timestamp" + }, + { + "ordinal": 8, + "name": "has_failed", + "type_info": "Bool" + }, + { + "ordinal": 9, + "name": "sent_at_block", + "type_info": "Int4" + }, + { + "ordinal": 10, + "name": "confirmed_eth_tx_history_id", + "type_info": "Int4" + }, + { + "ordinal": 11, + "name": "predicted_gas_cost", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + true, + false, + false, + false, + true, + true, + false + ] + }, + "hash": "5659480e5d79dab3399e35539b240e7eb9f598999c28015a504605f88bf84b33" +} diff --git a/core/lib/dal/.sqlx/query-57fe009542ca9dc763e3823ee73662bf3bfdda11bb57f65db4980982a4200bed.json b/core/lib/dal/.sqlx/query-57fe009542ca9dc763e3823ee73662bf3bfdda11bb57f65db4980982a4200bed.json new file mode 100644 index 000000000000..909686f9d0ee --- /dev/null +++ b/core/lib/dal/.sqlx/query-57fe009542ca9dc763e3823ee73662bf3bfdda11bb57f65db4980982a4200bed.json @@ -0,0 +1,106 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n number,\n timestamp,\n hash,\n l1_tx_count,\n l2_tx_count,\n fee_account_address AS \"fee_account_address!\",\n base_fee_per_gas,\n l1_gas_price,\n l2_fair_gas_price,\n gas_per_pubdata_limit,\n bootloader_code_hash,\n default_aa_code_hash,\n protocol_version,\n virtual_blocks,\n fair_pubdata_price\n FROM\n miniblocks\n WHERE\n number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 3, + "name": "l1_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 4, + "name": "l2_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 5, + "name": "fee_account_address!", + "type_info": "Bytea" + }, + { + "ordinal": 6, + "name": "base_fee_per_gas", + "type_info": "Numeric" + }, + { + "ordinal": 7, + "name": "l1_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 8, + "name": "l2_fair_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 9, + "name": "gas_per_pubdata_limit", + "type_info": "Int8" + }, + { + "ordinal": 10, + "name": "bootloader_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 11, + "name": "default_aa_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 12, + "name": "protocol_version", + "type_info": "Int4" + }, + { + "ordinal": 13, + "name": "virtual_blocks", + "type_info": "Int8" + }, + { + "ordinal": 14, + "name": "fair_pubdata_price", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + false, + true + ] + }, + "hash": "57fe009542ca9dc763e3823ee73662bf3bfdda11bb57f65db4980982a4200bed" +} diff --git a/core/lib/dal/.sqlx/query-5821f1446983260168cec366af26009503182c300877e74a8539f231050e6f85.json b/core/lib/dal/.sqlx/query-5821f1446983260168cec366af26009503182c300877e74a8539f231050e6f85.json new file mode 100644 index 000000000000..86877a48dd4d --- /dev/null +++ b/core/lib/dal/.sqlx/query-5821f1446983260168cec366af26009503182c300877e74a8539f231050e6f85.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE witness_inputs_fri\n SET\n status = $1,\n updated_at = NOW()\n WHERE\n l1_batch_number = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "5821f1446983260168cec366af26009503182c300877e74a8539f231050e6f85" +} diff --git a/core/lib/dal/.sqlx/query-58aed39245c72d231b268ce83105bb2036d21f60d4c6934f9145730ac35c04de.json b/core/lib/dal/.sqlx/query-58aed39245c72d231b268ce83105bb2036d21f60d4c6934f9145730ac35c04de.json new file mode 100644 index 000000000000..502d14e05ea5 --- /dev/null +++ b/core/lib/dal/.sqlx/query-58aed39245c72d231b268ce83105bb2036d21f60d4c6934f9145730ac35c04de.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_number\n FROM\n proof_generation_details\n WHERE\n status = 'ready_to_be_proven'\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "58aed39245c72d231b268ce83105bb2036d21f60d4c6934f9145730ac35c04de" +} diff --git a/core/lib/dal/.sqlx/query-59cb0dd78fadc121e2b1ebbc8a063f089c91aead2bc9abb284697e65840f1e8f.json b/core/lib/dal/.sqlx/query-59cb0dd78fadc121e2b1ebbc8a063f089c91aead2bc9abb284697e65840f1e8f.json new file mode 100644 index 000000000000..8a0cb19b3904 --- /dev/null +++ b/core/lib/dal/.sqlx/query-59cb0dd78fadc121e2b1ebbc8a063f089c91aead2bc9abb284697e65840f1e8f.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE tokens\n SET\n usd_price = $2,\n usd_price_updated_at = $3,\n updated_at = NOW()\n WHERE\n l1_address = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Numeric", + "Timestamp" + ] + }, + "nullable": [] + }, + "hash": "59cb0dd78fadc121e2b1ebbc8a063f089c91aead2bc9abb284697e65840f1e8f" +} diff --git a/core/lib/dal/.sqlx/query-5d493cbce749cc5b56d4069423597b16599abaf51df0f19effe1a536376cf6a6.json b/core/lib/dal/.sqlx/query-5d493cbce749cc5b56d4069423597b16599abaf51df0f19effe1a536376cf6a6.json new file mode 100644 index 000000000000..eba36994fb34 --- /dev/null +++ b/core/lib/dal/.sqlx/query-5d493cbce749cc5b56d4069423597b16599abaf51df0f19effe1a536376cf6a6.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n bootloader_code_hash,\n default_account_code_hash\n FROM\n protocol_versions\n WHERE\n id = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "bootloader_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "default_account_code_hash", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "5d493cbce749cc5b56d4069423597b16599abaf51df0f19effe1a536376cf6a6" +} diff --git a/core/lib/dal/.sqlx/query-5e781f84ec41edd0941fa84de837effac442434c6e734d977e6682a7484abe7f.json b/core/lib/dal/.sqlx/query-5e781f84ec41edd0941fa84de837effac442434c6e734d977e6682a7484abe7f.json new file mode 100644 index 000000000000..4958f38f5358 --- /dev/null +++ b/core/lib/dal/.sqlx/query-5e781f84ec41edd0941fa84de837effac442434c6e734d977e6682a7484abe7f.json @@ -0,0 +1,35 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE proof_compression_jobs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n (\n status = 'in_progress'\n AND processing_started_at <= NOW() - $1::INTERVAL\n AND attempts < $2\n )\n OR (\n status = 'failed'\n AND attempts < $2\n )\n RETURNING\n l1_batch_number,\n status,\n attempts\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "status", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "attempts", + "type_info": "Int2" + } + ], + "parameters": { + "Left": [ + "Interval", + "Int2" + ] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "5e781f84ec41edd0941fa84de837effac442434c6e734d977e6682a7484abe7f" +} diff --git a/core/lib/dal/.sqlx/query-5f6885b5457aaa78e10917ae5b8cd0bc0e8923a6bae64f22f09242766835ee0c.json b/core/lib/dal/.sqlx/query-5f6885b5457aaa78e10917ae5b8cd0bc0e8923a6bae64f22f09242766835ee0c.json new file mode 100644 index 000000000000..b57400c28f5e --- /dev/null +++ b/core/lib/dal/.sqlx/query-5f6885b5457aaa78e10917ae5b8cd0bc0e8923a6bae64f22f09242766835ee0c.json @@ -0,0 +1,74 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n id,\n contract_address,\n source_code,\n contract_name,\n zk_compiler_version,\n compiler_version,\n optimization_used,\n optimizer_mode,\n constructor_arguments,\n is_system\n FROM\n contract_verification_requests\n WHERE\n status = 'successful'\n ORDER BY\n id\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "contract_address", + "type_info": "Bytea" + }, + { + "ordinal": 2, + "name": "source_code", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "contract_name", + "type_info": "Text" + }, + { + "ordinal": 4, + "name": "zk_compiler_version", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "compiler_version", + "type_info": "Text" + }, + { + "ordinal": 6, + "name": "optimization_used", + "type_info": "Bool" + }, + { + "ordinal": 7, + "name": "optimizer_mode", + "type_info": "Text" + }, + { + "ordinal": 8, + "name": "constructor_arguments", + "type_info": "Bytea" + }, + { + "ordinal": 9, + "name": "is_system", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + true, + false, + false + ] + }, + "hash": "5f6885b5457aaa78e10917ae5b8cd0bc0e8923a6bae64f22f09242766835ee0c" +} diff --git a/core/lib/dal/.sqlx/query-5f8fc05ae782846898295d210dd3d55ff2b1510868dfe80d14fffa3f5ff07b83.json b/core/lib/dal/.sqlx/query-5f8fc05ae782846898295d210dd3d55ff2b1510868dfe80d14fffa3f5ff07b83.json new file mode 100644 index 000000000000..4879c6095a12 --- /dev/null +++ b/core/lib/dal/.sqlx/query-5f8fc05ae782846898295d210dd3d55ff2b1510868dfe80d14fffa3f5ff07b83.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE l1_batches\n SET\n predicted_commit_gas_cost = $2,\n updated_at = NOW()\n WHERE\n number = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "5f8fc05ae782846898295d210dd3d55ff2b1510868dfe80d14fffa3f5ff07b83" +} diff --git a/core/lib/dal/.sqlx/query-61b2b858d4636809c21838635aa52aeb5f06c26f68d131dd242f6ed68816c513.json b/core/lib/dal/.sqlx/query-61b2b858d4636809c21838635aa52aeb5f06c26f68d131dd242f6ed68816c513.json new file mode 100644 index 000000000000..c713af9a210d --- /dev/null +++ b/core/lib/dal/.sqlx/query-61b2b858d4636809c21838635aa52aeb5f06c26f68d131dd242f6ed68816c513.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_number\n FROM\n prover_jobs_fri\n WHERE\n status <> 'skipped'\n AND status <> 'successful'\n AND aggregation_round = $1\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int2" + ] + }, + "nullable": [ + false + ] + }, + "hash": "61b2b858d4636809c21838635aa52aeb5f06c26f68d131dd242f6ed68816c513" +} diff --git a/core/lib/dal/.sqlx/query-61bc330d6d1b5fddec78342c1b0f00e82b0b3ad9ae36bf4fe44d7e85b74c6f49.json b/core/lib/dal/.sqlx/query-61bc330d6d1b5fddec78342c1b0f00e82b0b3ad9ae36bf4fe44d7e85b74c6f49.json new file mode 100644 index 000000000000..2c0454b0dd8b --- /dev/null +++ b/core/lib/dal/.sqlx/query-61bc330d6d1b5fddec78342c1b0f00e82b0b3ad9ae36bf4fe44d7e85b74c6f49.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n MAX(priority_op_id) AS \"op_id\"\n FROM\n transactions\n WHERE\n is_priority = TRUE\n AND miniblock_number IS NOT NULL\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "op_id", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "61bc330d6d1b5fddec78342c1b0f00e82b0b3ad9ae36bf4fe44d7e85b74c6f49" +} diff --git a/core/lib/dal/.sqlx/query-6621de90a024cc85946f17948e5c171cd0e4d38bd6e9cfec58b2d7f53a3204e1.json b/core/lib/dal/.sqlx/query-6621de90a024cc85946f17948e5c171cd0e4d38bd6e9cfec58b2d7f53a3204e1.json new file mode 100644 index 000000000000..8ba437fe2cee --- /dev/null +++ b/core/lib/dal/.sqlx/query-6621de90a024cc85946f17948e5c171cd0e4d38bd6e9cfec58b2d7f53a3204e1.json @@ -0,0 +1,235 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE transactions\n SET\n in_mempool = TRUE\n FROM\n (\n SELECT\n hash\n FROM\n (\n SELECT\n hash\n FROM\n transactions\n WHERE\n miniblock_number IS NULL\n AND in_mempool = FALSE\n AND error IS NULL\n AND (\n is_priority = TRUE\n OR (\n max_fee_per_gas >= $2\n AND gas_per_pubdata_limit >= $3\n )\n )\n AND tx_format != $4\n ORDER BY\n is_priority DESC,\n priority_op_id,\n received_at\n LIMIT\n $1\n ) AS subquery1\n ORDER BY\n hash\n ) AS subquery2\n WHERE\n transactions.hash = subquery2.hash\n RETURNING\n transactions.*\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "is_priority", + "type_info": "Bool" + }, + { + "ordinal": 2, + "name": "full_fee", + "type_info": "Numeric" + }, + { + "ordinal": 3, + "name": "layer_2_tip_fee", + "type_info": "Numeric" + }, + { + "ordinal": 4, + "name": "initiator_address", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "nonce", + "type_info": "Int8" + }, + { + "ordinal": 6, + "name": "signature", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "input", + "type_info": "Bytea" + }, + { + "ordinal": 8, + "name": "data", + "type_info": "Jsonb" + }, + { + "ordinal": 9, + "name": "received_at", + "type_info": "Timestamp" + }, + { + "ordinal": 10, + "name": "priority_op_id", + "type_info": "Int8" + }, + { + "ordinal": 11, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 12, + "name": "index_in_block", + "type_info": "Int4" + }, + { + "ordinal": 13, + "name": "error", + "type_info": "Varchar" + }, + { + "ordinal": 14, + "name": "gas_limit", + "type_info": "Numeric" + }, + { + "ordinal": 15, + "name": "gas_per_storage_limit", + "type_info": "Numeric" + }, + { + "ordinal": 16, + "name": "gas_per_pubdata_limit", + "type_info": "Numeric" + }, + { + "ordinal": 17, + "name": "tx_format", + "type_info": "Int4" + }, + { + "ordinal": 18, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 19, + "name": "updated_at", + "type_info": "Timestamp" + }, + { + "ordinal": 20, + "name": "execution_info", + "type_info": "Jsonb" + }, + { + "ordinal": 21, + "name": "contract_address", + "type_info": "Bytea" + }, + { + "ordinal": 22, + "name": "in_mempool", + "type_info": "Bool" + }, + { + "ordinal": 23, + "name": "l1_block_number", + "type_info": "Int4" + }, + { + "ordinal": 24, + "name": "value", + "type_info": "Numeric" + }, + { + "ordinal": 25, + "name": "paymaster", + "type_info": "Bytea" + }, + { + "ordinal": 26, + "name": "paymaster_input", + "type_info": "Bytea" + }, + { + "ordinal": 27, + "name": "max_fee_per_gas", + "type_info": "Numeric" + }, + { + "ordinal": 28, + "name": "max_priority_fee_per_gas", + "type_info": "Numeric" + }, + { + "ordinal": 29, + "name": "effective_gas_price", + "type_info": "Numeric" + }, + { + "ordinal": 30, + "name": "miniblock_number", + "type_info": "Int8" + }, + { + "ordinal": 31, + "name": "l1_batch_tx_index", + "type_info": "Int4" + }, + { + "ordinal": 32, + "name": "refunded_gas", + "type_info": "Int8" + }, + { + "ordinal": 33, + "name": "l1_tx_mint", + "type_info": "Numeric" + }, + { + "ordinal": 34, + "name": "l1_tx_refund_recipient", + "type_info": "Bytea" + }, + { + "ordinal": 35, + "name": "upgrade_id", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int8", + "Numeric", + "Numeric", + "Int4" + ] + }, + "nullable": [ + false, + false, + true, + true, + false, + true, + true, + true, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + false, + true, + true, + true + ] + }, + "hash": "6621de90a024cc85946f17948e5c171cd0e4d38bd6e9cfec58b2d7f53a3204e1" +} diff --git a/core/lib/dal/.sqlx/query-6692ff6c0fbb2fc94f5cd2837a43ce80f9b2b27758651ccfc09df61a4ae8a363.json b/core/lib/dal/.sqlx/query-6692ff6c0fbb2fc94f5cd2837a43ce80f9b2b27758651ccfc09df61a4ae8a363.json new file mode 100644 index 000000000000..586cace76178 --- /dev/null +++ b/core/lib/dal/.sqlx/query-6692ff6c0fbb2fc94f5cd2837a43ce80f9b2b27758651ccfc09df61a4ae8a363.json @@ -0,0 +1,88 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n *\n FROM\n eth_txs\n WHERE\n id = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "nonce", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "raw_tx", + "type_info": "Bytea" + }, + { + "ordinal": 3, + "name": "contract_address", + "type_info": "Text" + }, + { + "ordinal": 4, + "name": "tx_type", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "gas_used", + "type_info": "Int8" + }, + { + "ordinal": 6, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 7, + "name": "updated_at", + "type_info": "Timestamp" + }, + { + "ordinal": 8, + "name": "has_failed", + "type_info": "Bool" + }, + { + "ordinal": 9, + "name": "sent_at_block", + "type_info": "Int4" + }, + { + "ordinal": 10, + "name": "confirmed_eth_tx_history_id", + "type_info": "Int4" + }, + { + "ordinal": 11, + "name": "predicted_gas_cost", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + true, + false, + false, + false, + true, + true, + false + ] + }, + "hash": "6692ff6c0fbb2fc94f5cd2837a43ce80f9b2b27758651ccfc09df61a4ae8a363" +} diff --git a/core/lib/dal/.sqlx/query-66e012ce974c38d9fe84cfc7eb28927f9e976319a305e0928ff366d535a97104.json b/core/lib/dal/.sqlx/query-66e012ce974c38d9fe84cfc7eb28927f9e976319a305e0928ff366d535a97104.json new file mode 100644 index 000000000000..e07fbfbd70be --- /dev/null +++ b/core/lib/dal/.sqlx/query-66e012ce974c38d9fe84cfc7eb28927f9e976319a305e0928ff366d535a97104.json @@ -0,0 +1,92 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n eth_txs (\n raw_tx,\n nonce,\n tx_type,\n contract_address,\n predicted_gas_cost,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, $4, $5, NOW(), NOW())\n RETURNING\n *\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "nonce", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "raw_tx", + "type_info": "Bytea" + }, + { + "ordinal": 3, + "name": "contract_address", + "type_info": "Text" + }, + { + "ordinal": 4, + "name": "tx_type", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "gas_used", + "type_info": "Int8" + }, + { + "ordinal": 6, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 7, + "name": "updated_at", + "type_info": "Timestamp" + }, + { + "ordinal": 8, + "name": "has_failed", + "type_info": "Bool" + }, + { + "ordinal": 9, + "name": "sent_at_block", + "type_info": "Int4" + }, + { + "ordinal": 10, + "name": "confirmed_eth_tx_history_id", + "type_info": "Int4" + }, + { + "ordinal": 11, + "name": "predicted_gas_cost", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Bytea", + "Int8", + "Text", + "Text", + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + true, + false, + false, + false, + true, + true, + false + ] + }, + "hash": "66e012ce974c38d9fe84cfc7eb28927f9e976319a305e0928ff366d535a97104" +} diff --git a/core/lib/dal/.sqlx/query-6874b501c82e6062ab22622095070d67840b2484ea3a03ac49eb3d50ea153163.json b/core/lib/dal/.sqlx/query-6874b501c82e6062ab22622095070d67840b2484ea3a03ac49eb3d50ea153163.json new file mode 100644 index 000000000000..5ccda40f56fc --- /dev/null +++ b/core/lib/dal/.sqlx/query-6874b501c82e6062ab22622095070d67840b2484ea3a03ac49eb3d50ea153163.json @@ -0,0 +1,124 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n miniblocks.number,\n COALESCE(\n miniblocks.l1_batch_number,\n (\n SELECT\n (MAX(number) + 1)\n FROM\n l1_batches\n )\n ) AS \"l1_batch_number!\",\n miniblocks.timestamp,\n miniblocks.l1_tx_count,\n miniblocks.l2_tx_count,\n miniblocks.hash AS \"root_hash?\",\n commit_tx.tx_hash AS \"commit_tx_hash?\",\n commit_tx.confirmed_at AS \"committed_at?\",\n prove_tx.tx_hash AS \"prove_tx_hash?\",\n prove_tx.confirmed_at AS \"proven_at?\",\n execute_tx.tx_hash AS \"execute_tx_hash?\",\n execute_tx.confirmed_at AS \"executed_at?\",\n miniblocks.l1_gas_price,\n miniblocks.l2_fair_gas_price,\n miniblocks.bootloader_code_hash,\n miniblocks.default_aa_code_hash,\n miniblocks.protocol_version,\n miniblocks.fee_account_address\n FROM\n miniblocks\n LEFT JOIN l1_batches ON miniblocks.l1_batch_number = l1_batches.number\n LEFT JOIN eth_txs_history AS commit_tx ON (\n l1_batches.eth_commit_tx_id = commit_tx.eth_tx_id\n AND commit_tx.confirmed_at IS NOT NULL\n )\n LEFT JOIN eth_txs_history AS prove_tx ON (\n l1_batches.eth_prove_tx_id = prove_tx.eth_tx_id\n AND prove_tx.confirmed_at IS NOT NULL\n )\n LEFT JOIN eth_txs_history AS execute_tx ON (\n l1_batches.eth_execute_tx_id = execute_tx.eth_tx_id\n AND execute_tx.confirmed_at IS NOT NULL\n )\n WHERE\n miniblocks.number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "l1_batch_number!", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 3, + "name": "l1_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 4, + "name": "l2_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 5, + "name": "root_hash?", + "type_info": "Bytea" + }, + { + "ordinal": 6, + "name": "commit_tx_hash?", + "type_info": "Text" + }, + { + "ordinal": 7, + "name": "committed_at?", + "type_info": "Timestamp" + }, + { + "ordinal": 8, + "name": "prove_tx_hash?", + "type_info": "Text" + }, + { + "ordinal": 9, + "name": "proven_at?", + "type_info": "Timestamp" + }, + { + "ordinal": 10, + "name": "execute_tx_hash?", + "type_info": "Text" + }, + { + "ordinal": 11, + "name": "executed_at?", + "type_info": "Timestamp" + }, + { + "ordinal": 12, + "name": "l1_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 13, + "name": "l2_fair_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 14, + "name": "bootloader_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 15, + "name": "default_aa_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 16, + "name": "protocol_version", + "type_info": "Int4" + }, + { + "ordinal": 17, + "name": "fee_account_address", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + null, + false, + false, + false, + false, + false, + true, + false, + true, + false, + true, + false, + false, + true, + true, + true, + false + ] + }, + "hash": "6874b501c82e6062ab22622095070d67840b2484ea3a03ac49eb3d50ea153163" +} diff --git a/core/lib/dal/.sqlx/query-68936a53e5b80576f3f341523e6843eb48b5e26ee92cd8476f50251e8c32610d.json b/core/lib/dal/.sqlx/query-68936a53e5b80576f3f341523e6843eb48b5e26ee92cd8476f50251e8c32610d.json new file mode 100644 index 000000000000..69b24831d73f --- /dev/null +++ b/core/lib/dal/.sqlx/query-68936a53e5b80576f3f341523e6843eb48b5e26ee92cd8476f50251e8c32610d.json @@ -0,0 +1,26 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n COUNT(*) AS \"count!\"\n FROM\n l1_batches\n WHERE\n number = $1\n AND hash = $2\n AND merkle_root_hash = $3\n AND parent_hash = $4\n AND l2_l1_merkle_root = $5\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count!", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8", + "Bytea", + "Bytea", + "Bytea", + "Bytea" + ] + }, + "nullable": [ + null + ] + }, + "hash": "68936a53e5b80576f3f341523e6843eb48b5e26ee92cd8476f50251e8c32610d" +} diff --git a/core/lib/dal/.sqlx/query-68c891ee9d71cffe709731f2804b734d5d255e36e48668b3bfc25a0f86ea52e7.json b/core/lib/dal/.sqlx/query-68c891ee9d71cffe709731f2804b734d5d255e36e48668b3bfc25a0f86ea52e7.json new file mode 100644 index 000000000000..1d5336030a44 --- /dev/null +++ b/core/lib/dal/.sqlx/query-68c891ee9d71cffe709731f2804b734d5d255e36e48668b3bfc25a0f86ea52e7.json @@ -0,0 +1,40 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n transactions (\n hash,\n is_priority,\n initiator_address,\n nonce,\n signature,\n gas_limit,\n max_fee_per_gas,\n max_priority_fee_per_gas,\n gas_per_pubdata_limit,\n input,\n data,\n tx_format,\n contract_address,\n value,\n paymaster,\n paymaster_input,\n execution_info,\n received_at,\n created_at,\n updated_at\n )\n VALUES\n (\n $1,\n FALSE,\n $2,\n $3,\n $4,\n $5,\n $6,\n $7,\n $8,\n $9,\n $10,\n $11,\n $12,\n $13,\n $14,\n $15,\n JSONB_BUILD_OBJECT('gas_used', $16::BIGINT, 'storage_writes', $17::INT, 'contracts_used', $18::INT),\n $19,\n NOW(),\n NOW()\n )\n ON CONFLICT (initiator_address, nonce) DO\n UPDATE\n SET\n hash = $1,\n signature = $4,\n gas_limit = $5,\n max_fee_per_gas = $6,\n max_priority_fee_per_gas = $7,\n gas_per_pubdata_limit = $8,\n input = $9,\n data = $10,\n tx_format = $11,\n contract_address = $12,\n value = $13,\n paymaster = $14,\n paymaster_input = $15,\n execution_info = JSONB_BUILD_OBJECT('gas_used', $16::BIGINT, 'storage_writes', $17::INT, 'contracts_used', $18::INT),\n in_mempool = FALSE,\n received_at = $19,\n created_at = NOW(),\n updated_at = NOW(),\n error = NULL\n WHERE\n transactions.is_priority = FALSE\n AND transactions.miniblock_number IS NULL\n RETURNING\n (\n SELECT\n hash\n FROM\n transactions\n WHERE\n transactions.initiator_address = $2\n AND transactions.nonce = $3\n ) IS NOT NULL AS \"is_replaced!\"\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "is_replaced!", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Bytea", + "Bytea", + "Int8", + "Bytea", + "Numeric", + "Numeric", + "Numeric", + "Numeric", + "Bytea", + "Jsonb", + "Int4", + "Bytea", + "Numeric", + "Bytea", + "Bytea", + "Int8", + "Int4", + "Int4", + "Timestamp" + ] + }, + "nullable": [ + null + ] + }, + "hash": "68c891ee9d71cffe709731f2804b734d5d255e36e48668b3bfc25a0f86ea52e7" +} diff --git a/core/lib/dal/.sqlx/query-6ae2ed34230beae0e86c584e293e7ee767e4c98706246eb113498c0f817f5f38.json b/core/lib/dal/.sqlx/query-6ae2ed34230beae0e86c584e293e7ee767e4c98706246eb113498c0f817f5f38.json new file mode 100644 index 000000000000..08dff439a7c8 --- /dev/null +++ b/core/lib/dal/.sqlx/query-6ae2ed34230beae0e86c584e293e7ee767e4c98706246eb113498c0f817f5f38.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n gpu_prover_queue_fri (\n instance_host,\n instance_port,\n instance_status,\n specialized_prover_group_id,\n zone,\n created_at,\n updated_at\n )\n VALUES\n (CAST($1::TEXT AS inet), $2, 'available', $3, $4, NOW(), NOW())\n ON CONFLICT (instance_host, instance_port, zone) DO\n UPDATE\n SET\n instance_status = 'available',\n specialized_prover_group_id = $3,\n zone = $4,\n updated_at = NOW()\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int4", + "Int2", + "Text" + ] + }, + "nullable": [] + }, + "hash": "6ae2ed34230beae0e86c584e293e7ee767e4c98706246eb113498c0f817f5f38" +} diff --git a/core/lib/dal/.sqlx/query-6b327df84d2b3b31d02db35fd5d91a8d67abcdb743a619ed0d1b9c16206a3c20.json b/core/lib/dal/.sqlx/query-6b327df84d2b3b31d02db35fd5d91a8d67abcdb743a619ed0d1b9c16206a3c20.json new file mode 100644 index 000000000000..d00622a1f5fa --- /dev/null +++ b/core/lib/dal/.sqlx/query-6b327df84d2b3b31d02db35fd5d91a8d67abcdb743a619ed0d1b9c16206a3c20.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM eth_txs\n WHERE\n id >= (\n SELECT\n MIN(id)\n FROM\n eth_txs\n WHERE\n has_failed = TRUE\n )\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "6b327df84d2b3b31d02db35fd5d91a8d67abcdb743a619ed0d1b9c16206a3c20" +} diff --git a/core/lib/dal/.sqlx/query-6bd3094be764e6378fe52b5bb533260b49ce42daaf9dbe8075daf0a8e0ad9914.json b/core/lib/dal/.sqlx/query-6bd3094be764e6378fe52b5bb533260b49ce42daaf9dbe8075daf0a8e0ad9914.json new file mode 100644 index 000000000000..c90296e322ca --- /dev/null +++ b/core/lib/dal/.sqlx/query-6bd3094be764e6378fe52b5bb533260b49ce42daaf9dbe8075daf0a8e0ad9914.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM basic_witness_input_producer_jobs\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "6bd3094be764e6378fe52b5bb533260b49ce42daaf9dbe8075daf0a8e0ad9914" +} diff --git a/core/lib/dal/.sqlx/query-6c0d03b1fbe6f47546bc34c6b2eab01cb2c55bf86d2c8c99abb1b7ca21cf75c0.json b/core/lib/dal/.sqlx/query-6c0d03b1fbe6f47546bc34c6b2eab01cb2c55bf86d2c8c99abb1b7ca21cf75c0.json new file mode 100644 index 000000000000..0ad799dd49d8 --- /dev/null +++ b/core/lib/dal/.sqlx/query-6c0d03b1fbe6f47546bc34c6b2eab01cb2c55bf86d2c8c99abb1b7ca21cf75c0.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE miniblocks\n SET\n protocol_version = $1\n WHERE\n l1_batch_number IS NULL\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [] + }, + "hash": "6c0d03b1fbe6f47546bc34c6b2eab01cb2c55bf86d2c8c99abb1b7ca21cf75c0" +} diff --git a/core/lib/dal/.sqlx/query-6ed5cc84e8097c4febf6c935193f45ef713ef7f9909ce26653faceddb549a383.json b/core/lib/dal/.sqlx/query-6ed5cc84e8097c4febf6c935193f45ef713ef7f9909ce26653faceddb549a383.json new file mode 100644 index 000000000000..9d3050eaa838 --- /dev/null +++ b/core/lib/dal/.sqlx/query-6ed5cc84e8097c4febf6c935193f45ef713ef7f9909ce26653faceddb549a383.json @@ -0,0 +1,106 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n number,\n l1_tx_count,\n l2_tx_count,\n timestamp,\n l2_to_l1_logs,\n l2_to_l1_messages,\n bloom,\n priority_ops_onchain_data,\n used_contract_hashes,\n bootloader_code_hash,\n default_aa_code_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n pubdata_input\n FROM\n l1_batches\n WHERE\n number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "l1_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 2, + "name": "l2_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 3, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 4, + "name": "l2_to_l1_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 5, + "name": "l2_to_l1_messages", + "type_info": "ByteaArray" + }, + { + "ordinal": 6, + "name": "bloom", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "priority_ops_onchain_data", + "type_info": "ByteaArray" + }, + { + "ordinal": 8, + "name": "used_contract_hashes", + "type_info": "Jsonb" + }, + { + "ordinal": 9, + "name": "bootloader_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 10, + "name": "default_aa_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 11, + "name": "protocol_version", + "type_info": "Int4" + }, + { + "ordinal": 12, + "name": "compressed_state_diffs", + "type_info": "Bytea" + }, + { + "ordinal": 13, + "name": "system_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 14, + "name": "pubdata_input", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + true + ] + }, + "hash": "6ed5cc84e8097c4febf6c935193f45ef713ef7f9909ce26653faceddb549a383" +} diff --git a/core/lib/dal/.sqlx/query-708b2b3e40887e6d8d2d7aa20448a58479487686d774e6b2b1391347bdafe06d.json b/core/lib/dal/.sqlx/query-708b2b3e40887e6d8d2d7aa20448a58479487686d774e6b2b1391347bdafe06d.json new file mode 100644 index 000000000000..a63bd3ebeeb9 --- /dev/null +++ b/core/lib/dal/.sqlx/query-708b2b3e40887e6d8d2d7aa20448a58479487686d774e6b2b1391347bdafe06d.json @@ -0,0 +1,29 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n number,\n hash\n FROM\n miniblocks\n WHERE\n number >= $1\n ORDER BY\n number ASC\n LIMIT\n $2\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "hash", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8", + "Int8" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "708b2b3e40887e6d8d2d7aa20448a58479487686d774e6b2b1391347bdafe06d" +} diff --git a/core/lib/dal/.sqlx/query-72a4f50355324cce85ebaef9fa32826095e9290f0c1157094bd0c44e06012e42.json b/core/lib/dal/.sqlx/query-72a4f50355324cce85ebaef9fa32826095e9290f0c1157094bd0c44e06012e42.json new file mode 100644 index 000000000000..707b7ce9e75c --- /dev/null +++ b/core/lib/dal/.sqlx/query-72a4f50355324cce85ebaef9fa32826095e9290f0c1157094bd0c44e06012e42.json @@ -0,0 +1,232 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n *\n FROM\n transactions\n WHERE\n hash = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "is_priority", + "type_info": "Bool" + }, + { + "ordinal": 2, + "name": "full_fee", + "type_info": "Numeric" + }, + { + "ordinal": 3, + "name": "layer_2_tip_fee", + "type_info": "Numeric" + }, + { + "ordinal": 4, + "name": "initiator_address", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "nonce", + "type_info": "Int8" + }, + { + "ordinal": 6, + "name": "signature", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "input", + "type_info": "Bytea" + }, + { + "ordinal": 8, + "name": "data", + "type_info": "Jsonb" + }, + { + "ordinal": 9, + "name": "received_at", + "type_info": "Timestamp" + }, + { + "ordinal": 10, + "name": "priority_op_id", + "type_info": "Int8" + }, + { + "ordinal": 11, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 12, + "name": "index_in_block", + "type_info": "Int4" + }, + { + "ordinal": 13, + "name": "error", + "type_info": "Varchar" + }, + { + "ordinal": 14, + "name": "gas_limit", + "type_info": "Numeric" + }, + { + "ordinal": 15, + "name": "gas_per_storage_limit", + "type_info": "Numeric" + }, + { + "ordinal": 16, + "name": "gas_per_pubdata_limit", + "type_info": "Numeric" + }, + { + "ordinal": 17, + "name": "tx_format", + "type_info": "Int4" + }, + { + "ordinal": 18, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 19, + "name": "updated_at", + "type_info": "Timestamp" + }, + { + "ordinal": 20, + "name": "execution_info", + "type_info": "Jsonb" + }, + { + "ordinal": 21, + "name": "contract_address", + "type_info": "Bytea" + }, + { + "ordinal": 22, + "name": "in_mempool", + "type_info": "Bool" + }, + { + "ordinal": 23, + "name": "l1_block_number", + "type_info": "Int4" + }, + { + "ordinal": 24, + "name": "value", + "type_info": "Numeric" + }, + { + "ordinal": 25, + "name": "paymaster", + "type_info": "Bytea" + }, + { + "ordinal": 26, + "name": "paymaster_input", + "type_info": "Bytea" + }, + { + "ordinal": 27, + "name": "max_fee_per_gas", + "type_info": "Numeric" + }, + { + "ordinal": 28, + "name": "max_priority_fee_per_gas", + "type_info": "Numeric" + }, + { + "ordinal": 29, + "name": "effective_gas_price", + "type_info": "Numeric" + }, + { + "ordinal": 30, + "name": "miniblock_number", + "type_info": "Int8" + }, + { + "ordinal": 31, + "name": "l1_batch_tx_index", + "type_info": "Int4" + }, + { + "ordinal": 32, + "name": "refunded_gas", + "type_info": "Int8" + }, + { + "ordinal": 33, + "name": "l1_tx_mint", + "type_info": "Numeric" + }, + { + "ordinal": 34, + "name": "l1_tx_refund_recipient", + "type_info": "Bytea" + }, + { + "ordinal": 35, + "name": "upgrade_id", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [ + false, + false, + true, + true, + false, + true, + true, + true, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + false, + true, + true, + true + ] + }, + "hash": "72a4f50355324cce85ebaef9fa32826095e9290f0c1157094bd0c44e06012e42" +} diff --git a/core/lib/dal/.sqlx/query-72ff9df79e78129cb96d14ece0198129b44534062f524823666ed432d2fcd345.json b/core/lib/dal/.sqlx/query-72ff9df79e78129cb96d14ece0198129b44534062f524823666ed432d2fcd345.json new file mode 100644 index 000000000000..75f288ee14f6 --- /dev/null +++ b/core/lib/dal/.sqlx/query-72ff9df79e78129cb96d14ece0198129b44534062f524823666ed432d2fcd345.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "\n VACUUM storage_logs\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "72ff9df79e78129cb96d14ece0198129b44534062f524823666ed432d2fcd345" +} diff --git a/core/lib/dal/.sqlx/query-73c4bf1e35d49faaab9f7828e80f396f9d193615d70184d4327378a7fc8a5665.json b/core/lib/dal/.sqlx/query-73c4bf1e35d49faaab9f7828e80f396f9d193615d70184d4327378a7fc8a5665.json new file mode 100644 index 000000000000..aa38e1c40357 --- /dev/null +++ b/core/lib/dal/.sqlx/query-73c4bf1e35d49faaab9f7828e80f396f9d193615d70184d4327378a7fc8a5665.json @@ -0,0 +1,30 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE basic_witness_input_producer_jobs\n SET\n status = $1,\n updated_at = NOW(),\n time_taken = $3,\n input_blob_url = $4\n WHERE\n l1_batch_number = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + { + "Custom": { + "name": "basic_witness_input_producer_job_status", + "kind": { + "Enum": [ + "Queued", + "ManuallySkipped", + "InProgress", + "Successful", + "Failed" + ] + } + } + }, + "Int8", + "Time", + "Text" + ] + }, + "nullable": [] + }, + "hash": "73c4bf1e35d49faaab9f7828e80f396f9d193615d70184d4327378a7fc8a5665" +} diff --git a/core/lib/dal/.sqlx/query-73f0401ac19c4e1efd73d02b8dcdd913ed9fbd69b8354b7d18b01d3fb62f6be8.json b/core/lib/dal/.sqlx/query-73f0401ac19c4e1efd73d02b8dcdd913ed9fbd69b8354b7d18b01d3fb62f6be8.json new file mode 100644 index 000000000000..7c366776a5ab --- /dev/null +++ b/core/lib/dal/.sqlx/query-73f0401ac19c4e1efd73d02b8dcdd913ed9fbd69b8354b7d18b01d3fb62f6be8.json @@ -0,0 +1,44 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_number,\n l1_batch_root_hash,\n miniblock_number,\n miniblock_root_hash,\n storage_logs_chunks_processed\n FROM\n snapshot_recovery\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "l1_batch_root_hash", + "type_info": "Bytea" + }, + { + "ordinal": 2, + "name": "miniblock_number", + "type_info": "Int8" + }, + { + "ordinal": 3, + "name": "miniblock_root_hash", + "type_info": "Bytea" + }, + { + "ordinal": 4, + "name": "storage_logs_chunks_processed", + "type_info": "BoolArray" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false, + false, + false + ] + }, + "hash": "73f0401ac19c4e1efd73d02b8dcdd913ed9fbd69b8354b7d18b01d3fb62f6be8" +} diff --git a/core/lib/dal/.sqlx/query-7560ba61643a8ec8eeefbe6034226313c255ce356a9a4e25c098484d3129c914.json b/core/lib/dal/.sqlx/query-7560ba61643a8ec8eeefbe6034226313c255ce356a9a4e25c098484d3129c914.json new file mode 100644 index 000000000000..9ff3ab86250d --- /dev/null +++ b/core/lib/dal/.sqlx/query-7560ba61643a8ec8eeefbe6034226313c255ce356a9a4e25c098484d3129c914.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM eth_txs_history\n WHERE\n id = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [] + }, + "hash": "7560ba61643a8ec8eeefbe6034226313c255ce356a9a4e25c098484d3129c914" +} diff --git a/core/lib/dal/.sqlx/query-759b80414b5bcbfe03a0e1e15b37f92c4cfad9313b1461e12242d9becb59e0b0.json b/core/lib/dal/.sqlx/query-759b80414b5bcbfe03a0e1e15b37f92c4cfad9313b1461e12242d9becb59e0b0.json new file mode 100644 index 000000000000..d488293cf81f --- /dev/null +++ b/core/lib/dal/.sqlx/query-759b80414b5bcbfe03a0e1e15b37f92c4cfad9313b1461e12242d9becb59e0b0.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n MAX(operation_number) AS \"max?\"\n FROM\n storage_logs\n WHERE\n miniblock_number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "max?", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + null + ] + }, + "hash": "759b80414b5bcbfe03a0e1e15b37f92c4cfad9313b1461e12242d9becb59e0b0" +} diff --git a/core/lib/dal/.sqlx/query-75f6eaa518e7840374c4e44b0788bf92c7f2c55386c8208e3a82b30456abd5b4.json b/core/lib/dal/.sqlx/query-75f6eaa518e7840374c4e44b0788bf92c7f2c55386c8208e3a82b30456abd5b4.json new file mode 100644 index 000000000000..71edd403d0b6 --- /dev/null +++ b/core/lib/dal/.sqlx/query-75f6eaa518e7840374c4e44b0788bf92c7f2c55386c8208e3a82b30456abd5b4.json @@ -0,0 +1,90 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE witness_inputs_fri\n SET\n status = 'in_progress',\n attempts = attempts + 1,\n updated_at = NOW(),\n processing_started_at = NOW(),\n picked_by = $3\n WHERE\n l1_batch_number = (\n SELECT\n l1_batch_number\n FROM\n witness_inputs_fri\n WHERE\n l1_batch_number <= $1\n AND status = 'queued'\n AND protocol_version = ANY ($2)\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n witness_inputs_fri.*\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "merkle_tree_paths_blob_url", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "attempts", + "type_info": "Int2" + }, + { + "ordinal": 3, + "name": "status", + "type_info": "Text" + }, + { + "ordinal": 4, + "name": "error", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 6, + "name": "updated_at", + "type_info": "Timestamp" + }, + { + "ordinal": 7, + "name": "processing_started_at", + "type_info": "Timestamp" + }, + { + "ordinal": 8, + "name": "time_taken", + "type_info": "Time" + }, + { + "ordinal": 9, + "name": "is_blob_cleaned", + "type_info": "Bool" + }, + { + "ordinal": 10, + "name": "protocol_version", + "type_info": "Int4" + }, + { + "ordinal": 11, + "name": "picked_by", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Int8", + "Int4Array", + "Text" + ] + }, + "nullable": [ + false, + true, + false, + false, + true, + false, + false, + true, + true, + true, + true, + true + ] + }, + "hash": "75f6eaa518e7840374c4e44b0788bf92c7f2c55386c8208e3a82b30456abd5b4" +} diff --git a/core/lib/dal/.sqlx/query-75fa24c29dc312cbfa89bf1f4a04a42b4ead6964edd17bfcacb4a828492bba60.json b/core/lib/dal/.sqlx/query-75fa24c29dc312cbfa89bf1f4a04a42b4ead6964edd17bfcacb4a828492bba60.json new file mode 100644 index 000000000000..ff743f1028c2 --- /dev/null +++ b/core/lib/dal/.sqlx/query-75fa24c29dc312cbfa89bf1f4a04a42b4ead6964edd17bfcacb4a828492bba60.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n state AS \"state!\"\n FROM\n consensus_replica_state\n WHERE\n fake_key\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "state!", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "75fa24c29dc312cbfa89bf1f4a04a42b4ead6964edd17bfcacb4a828492bba60" +} diff --git a/core/lib/dal/.sqlx/query-76cb9ad97b70d584b19af194576dcf2324f380932698386aa8f9751b1fa24a7b.json b/core/lib/dal/.sqlx/query-76cb9ad97b70d584b19af194576dcf2324f380932698386aa8f9751b1fa24a7b.json new file mode 100644 index 000000000000..e5b4f3476c9f --- /dev/null +++ b/core/lib/dal/.sqlx/query-76cb9ad97b70d584b19af194576dcf2324f380932698386aa8f9751b1fa24a7b.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n call_traces (tx_hash, call_trace)\n SELECT\n u.tx_hash,\n u.call_trace\n FROM\n UNNEST($1::bytea[], $2::bytea[]) AS u (tx_hash, call_trace)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "ByteaArray", + "ByteaArray" + ] + }, + "nullable": [] + }, + "hash": "76cb9ad97b70d584b19af194576dcf2324f380932698386aa8f9751b1fa24a7b" +} diff --git a/core/lib/dal/.sqlx/query-77a43830ca31eac85a3c03d87696bf94a013e49bf50ce23f4de4968781df0796.json b/core/lib/dal/.sqlx/query-77a43830ca31eac85a3c03d87696bf94a013e49bf50ce23f4de4968781df0796.json new file mode 100644 index 000000000000..acff9eeebeeb --- /dev/null +++ b/core/lib/dal/.sqlx/query-77a43830ca31eac85a3c03d87696bf94a013e49bf50ce23f4de4968781df0796.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE l1_batches\n SET\n hash = $1\n WHERE\n number = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "77a43830ca31eac85a3c03d87696bf94a013e49bf50ce23f4de4968781df0796" +} diff --git a/core/lib/dal/.sqlx/query-77b35855fbb989f6314469b419726dc7bb98e0f7feaf14656307e20bd2bb0b6c.json b/core/lib/dal/.sqlx/query-77b35855fbb989f6314469b419726dc7bb98e0f7feaf14656307e20bd2bb0b6c.json new file mode 100644 index 000000000000..30149eb79c9b --- /dev/null +++ b/core/lib/dal/.sqlx/query-77b35855fbb989f6314469b419726dc7bb98e0f7feaf14656307e20bd2bb0b6c.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n consensus_replica_state (fake_key, state)\n VALUES\n (TRUE, $1)\n ON CONFLICT (fake_key) DO\n UPDATE\n SET\n state = excluded.state\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Jsonb" + ] + }, + "nullable": [] + }, + "hash": "77b35855fbb989f6314469b419726dc7bb98e0f7feaf14656307e20bd2bb0b6c" +} diff --git a/core/lib/dal/.sqlx/query-7a2145e2234a7896031bbc1ce82715e903f3b399886c2c73e838bd924fed6776.json b/core/lib/dal/.sqlx/query-7a2145e2234a7896031bbc1ce82715e903f3b399886c2c73e838bd924fed6776.json new file mode 100644 index 000000000000..73a8c33695b1 --- /dev/null +++ b/core/lib/dal/.sqlx/query-7a2145e2234a7896031bbc1ce82715e903f3b399886c2c73e838bd924fed6776.json @@ -0,0 +1,18 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE node_aggregation_witness_jobs_fri\n SET\n aggregations_url = $1,\n number_of_dependent_jobs = $5,\n updated_at = NOW()\n WHERE\n l1_batch_number = $2\n AND circuit_id = $3\n AND depth = $4\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int8", + "Int2", + "Int4", + "Int4" + ] + }, + "nullable": [] + }, + "hash": "7a2145e2234a7896031bbc1ce82715e903f3b399886c2c73e838bd924fed6776" +} diff --git a/core/lib/dal/.sqlx/query-7a8fffe8d4e3085e00c98f770d250d625f057acf1440b6550375ce5509a816a6.json b/core/lib/dal/.sqlx/query-7a8fffe8d4e3085e00c98f770d250d625f057acf1440b6550375ce5509a816a6.json new file mode 100644 index 000000000000..da78974f61a2 --- /dev/null +++ b/core/lib/dal/.sqlx/query-7a8fffe8d4e3085e00c98f770d250d625f057acf1440b6550375ce5509a816a6.json @@ -0,0 +1,107 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE leaf_aggregation_witness_jobs_fri\n SET\n status = 'in_progress',\n attempts = attempts + 1,\n updated_at = NOW(),\n processing_started_at = NOW(),\n picked_by = $2\n WHERE\n id = (\n SELECT\n id\n FROM\n leaf_aggregation_witness_jobs_fri\n WHERE\n status = 'queued'\n AND protocol_version = ANY ($1)\n ORDER BY\n l1_batch_number ASC,\n id ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n leaf_aggregation_witness_jobs_fri.*\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "circuit_id", + "type_info": "Int2" + }, + { + "ordinal": 3, + "name": "closed_form_inputs_blob_url", + "type_info": "Text" + }, + { + "ordinal": 4, + "name": "attempts", + "type_info": "Int2" + }, + { + "ordinal": 5, + "name": "status", + "type_info": "Text" + }, + { + "ordinal": 6, + "name": "error", + "type_info": "Text" + }, + { + "ordinal": 7, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 8, + "name": "updated_at", + "type_info": "Timestamp" + }, + { + "ordinal": 9, + "name": "processing_started_at", + "type_info": "Timestamp" + }, + { + "ordinal": 10, + "name": "time_taken", + "type_info": "Time" + }, + { + "ordinal": 11, + "name": "is_blob_cleaned", + "type_info": "Bool" + }, + { + "ordinal": 12, + "name": "number_of_basic_circuits", + "type_info": "Int4" + }, + { + "ordinal": 13, + "name": "protocol_version", + "type_info": "Int4" + }, + { + "ordinal": 14, + "name": "picked_by", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Int4Array", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + true, + false, + false, + true, + false, + false, + true, + true, + true, + true, + true, + true + ] + }, + "hash": "7a8fffe8d4e3085e00c98f770d250d625f057acf1440b6550375ce5509a816a6" +} diff --git a/core/lib/dal/.sqlx/query-7fccc28bd829bce334f37197ee6b139e943f3ad2a41387b610606a42b7f03283.json b/core/lib/dal/.sqlx/query-7fccc28bd829bce334f37197ee6b139e943f3ad2a41387b610606a42b7f03283.json new file mode 100644 index 000000000000..76a34db9699f --- /dev/null +++ b/core/lib/dal/.sqlx/query-7fccc28bd829bce334f37197ee6b139e943f3ad2a41387b610606a42b7f03283.json @@ -0,0 +1,29 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n transactions (\n hash,\n is_priority,\n initiator_address,\n gas_limit,\n max_fee_per_gas,\n gas_per_pubdata_limit,\n data,\n upgrade_id,\n contract_address,\n l1_block_number,\n value,\n paymaster,\n paymaster_input,\n tx_format,\n l1_tx_mint,\n l1_tx_refund_recipient,\n received_at,\n created_at,\n updated_at\n )\n VALUES\n (\n $1,\n TRUE,\n $2,\n $3,\n $4,\n $5,\n $6,\n $7,\n $8,\n $9,\n $10,\n $11,\n $12,\n $13,\n $14,\n $15,\n $16,\n NOW(),\n NOW()\n )\n ON CONFLICT (hash) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Bytea", + "Numeric", + "Numeric", + "Numeric", + "Jsonb", + "Int4", + "Bytea", + "Int4", + "Numeric", + "Bytea", + "Bytea", + "Int4", + "Numeric", + "Bytea", + "Timestamp" + ] + }, + "nullable": [] + }, + "hash": "7fccc28bd829bce334f37197ee6b139e943f3ad2a41387b610606a42b7f03283" +} diff --git a/core/lib/dal/.sqlx/query-806b82a9effd885ba537a2a1c7d7227120a8279db1875d26ccae5ee0785f46a9.json b/core/lib/dal/.sqlx/query-806b82a9effd885ba537a2a1c7d7227120a8279db1875d26ccae5ee0785f46a9.json new file mode 100644 index 000000000000..c8e8a7aa6033 --- /dev/null +++ b/core/lib/dal/.sqlx/query-806b82a9effd885ba537a2a1c7d7227120a8279db1875d26ccae5ee0785f46a9.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n attempts\n FROM\n node_aggregation_witness_jobs_fri\n WHERE\n id = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "attempts", + "type_info": "Int2" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "806b82a9effd885ba537a2a1c7d7227120a8279db1875d26ccae5ee0785f46a9" +} diff --git a/core/lib/dal/.sqlx/query-8182690d0326b820d23fba49d391578db18c29cdca85b8b6aad86fe2a9bf6bbe.json b/core/lib/dal/.sqlx/query-8182690d0326b820d23fba49d391578db18c29cdca85b8b6aad86fe2a9bf6bbe.json new file mode 100644 index 000000000000..fac64c1ea3f9 --- /dev/null +++ b/core/lib/dal/.sqlx/query-8182690d0326b820d23fba49d391578db18c29cdca85b8b6aad86fe2a9bf6bbe.json @@ -0,0 +1,32 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE node_aggregation_witness_jobs_fri\n SET\n status = 'queued'\n WHERE\n (l1_batch_number, circuit_id, depth) IN (\n SELECT\n prover_jobs_fri.l1_batch_number,\n prover_jobs_fri.circuit_id,\n prover_jobs_fri.depth\n FROM\n prover_jobs_fri\n JOIN node_aggregation_witness_jobs_fri nawj ON prover_jobs_fri.l1_batch_number = nawj.l1_batch_number\n AND prover_jobs_fri.circuit_id = nawj.circuit_id\n AND prover_jobs_fri.depth = nawj.depth\n WHERE\n nawj.status = 'waiting_for_proofs'\n AND prover_jobs_fri.status = 'successful'\n AND prover_jobs_fri.aggregation_round = 2\n GROUP BY\n prover_jobs_fri.l1_batch_number,\n prover_jobs_fri.circuit_id,\n prover_jobs_fri.depth,\n nawj.number_of_dependent_jobs\n HAVING\n COUNT(*) = nawj.number_of_dependent_jobs\n )\n RETURNING\n l1_batch_number,\n circuit_id,\n depth;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "circuit_id", + "type_info": "Int2" + }, + { + "ordinal": 2, + "name": "depth", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "8182690d0326b820d23fba49d391578db18c29cdca85b8b6aad86fe2a9bf6bbe" +} diff --git a/core/lib/dal/.sqlx/query-81869cb392e9fcbb71ceaa857af77b39429d56072f63b3530c576fb31d7a56f9.json b/core/lib/dal/.sqlx/query-81869cb392e9fcbb71ceaa857af77b39429d56072f63b3530c576fb31d7a56f9.json new file mode 100644 index 000000000000..b8d80a904e48 --- /dev/null +++ b/core/lib/dal/.sqlx/query-81869cb392e9fcbb71ceaa857af77b39429d56072f63b3530c576fb31d7a56f9.json @@ -0,0 +1,18 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n storage (hashed_key, address, key, value, tx_hash, created_at, updated_at)\n SELECT\n u.hashed_key,\n u.address,\n u.key,\n u.value,\n u.tx_hash,\n NOW(),\n NOW()\n FROM\n UNNEST($1::bytea[], $2::bytea[], $3::bytea[], $4::bytea[], $5::bytea[]) AS u (hashed_key, address, key, value, tx_hash)\n ON CONFLICT (hashed_key) DO\n UPDATE\n SET\n tx_hash = excluded.tx_hash,\n value = excluded.value,\n updated_at = NOW()\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "ByteaArray", + "ByteaArray", + "ByteaArray", + "ByteaArray", + "ByteaArray" + ] + }, + "nullable": [] + }, + "hash": "81869cb392e9fcbb71ceaa857af77b39429d56072f63b3530c576fb31d7a56f9" +} diff --git a/core/lib/dal/.sqlx/query-83a931ceddf34e1c760649d613f534014b9ab9ca7725e14fb17aa050d9f35eb8.json b/core/lib/dal/.sqlx/query-83a931ceddf34e1c760649d613f534014b9ab9ca7725e14fb17aa050d9f35eb8.json new file mode 100644 index 000000000000..8d9458dce0a4 --- /dev/null +++ b/core/lib/dal/.sqlx/query-83a931ceddf34e1c760649d613f534014b9ab9ca7725e14fb17aa050d9f35eb8.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n base_fee_per_gas\n FROM\n miniblocks\n WHERE\n number <= $1\n ORDER BY\n number DESC\n LIMIT\n $2\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "base_fee_per_gas", + "type_info": "Numeric" + } + ], + "parameters": { + "Left": [ + "Int8", + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "83a931ceddf34e1c760649d613f534014b9ab9ca7725e14fb17aa050d9f35eb8" +} diff --git a/core/lib/dal/.sqlx/query-8625ca45ce76b8c8633d390e35e0c5f885240d99ea69140a4636b00469d08497.json b/core/lib/dal/.sqlx/query-8625ca45ce76b8c8633d390e35e0c5f885240d99ea69140a4636b00469d08497.json new file mode 100644 index 000000000000..f7906122f109 --- /dev/null +++ b/core/lib/dal/.sqlx/query-8625ca45ce76b8c8633d390e35e0c5f885240d99ea69140a4636b00469d08497.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n tx_hash\n FROM\n eth_txs_history\n WHERE\n eth_tx_id = $1\n AND confirmed_at IS NOT NULL\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "tx_hash", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [ + false + ] + }, + "hash": "8625ca45ce76b8c8633d390e35e0c5f885240d99ea69140a4636b00469d08497" +} diff --git a/core/lib/dal/.sqlx/query-877d20634068170326ab5801b69c70aff49e60b7def3d93b9206e650c259168b.json b/core/lib/dal/.sqlx/query-877d20634068170326ab5801b69c70aff49e60b7def3d93b9206e650c259168b.json new file mode 100644 index 000000000000..3052b3a04d1a --- /dev/null +++ b/core/lib/dal/.sqlx/query-877d20634068170326ab5801b69c70aff49e60b7def3d93b9206e650c259168b.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n timestamp\n FROM\n l1_batches\n WHERE\n eth_execute_tx_id IS NULL\n AND number > 0\n ORDER BY\n number\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "timestamp", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "877d20634068170326ab5801b69c70aff49e60b7def3d93b9206e650c259168b" +} diff --git a/core/lib/dal/.sqlx/query-87f27295de500591f01ed76731df2aed7049c3f44a6d25556967ea867e0caf25.json b/core/lib/dal/.sqlx/query-87f27295de500591f01ed76731df2aed7049c3f44a6d25556967ea867e0caf25.json new file mode 100644 index 000000000000..dbeaede9ecd2 --- /dev/null +++ b/core/lib/dal/.sqlx/query-87f27295de500591f01ed76731df2aed7049c3f44a6d25556967ea867e0caf25.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n call_trace\n FROM\n call_traces\n WHERE\n tx_hash = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "call_trace", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [ + false + ] + }, + "hash": "87f27295de500591f01ed76731df2aed7049c3f44a6d25556967ea867e0caf25" +} diff --git a/core/lib/dal/.sqlx/query-883ab3d601e2dfef03ad36e5987577821fc8ce2f81cb029d0f64801d5f743388.json b/core/lib/dal/.sqlx/query-883ab3d601e2dfef03ad36e5987577821fc8ce2f81cb029d0f64801d5f743388.json new file mode 100644 index 000000000000..bca333c57042 --- /dev/null +++ b/core/lib/dal/.sqlx/query-883ab3d601e2dfef03ad36e5987577821fc8ce2f81cb029d0f64801d5f743388.json @@ -0,0 +1,227 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n parent_hash,\n commitment,\n compressed_write_logs,\n compressed_contracts,\n eth_prove_tx_id,\n eth_commit_tx_id,\n eth_execute_tx_id,\n merkle_root_hash,\n l2_to_l1_logs,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_compressed_messages,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n system_logs,\n compressed_state_diffs,\n protocol_version,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n (\n SELECT\n l1_batches.*,\n ROW_NUMBER() OVER (\n ORDER BY\n number ASC\n ) AS ROW_NUMBER\n FROM\n l1_batches\n WHERE\n eth_commit_tx_id IS NOT NULL\n AND l1_batches.skip_proof = TRUE\n AND l1_batches.number > $1\n ORDER BY\n number\n LIMIT\n $2\n ) inn\n LEFT JOIN commitments ON commitments.l1_batch_number = inn.number\n WHERE\n number - ROW_NUMBER = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "l1_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 3, + "name": "l2_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 4, + "name": "bloom", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "priority_ops_onchain_data", + "type_info": "ByteaArray" + }, + { + "ordinal": 6, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "parent_hash", + "type_info": "Bytea" + }, + { + "ordinal": 8, + "name": "commitment", + "type_info": "Bytea" + }, + { + "ordinal": 9, + "name": "compressed_write_logs", + "type_info": "Bytea" + }, + { + "ordinal": 10, + "name": "compressed_contracts", + "type_info": "Bytea" + }, + { + "ordinal": 11, + "name": "eth_prove_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 12, + "name": "eth_commit_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 13, + "name": "eth_execute_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 14, + "name": "merkle_root_hash", + "type_info": "Bytea" + }, + { + "ordinal": 15, + "name": "l2_to_l1_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 16, + "name": "l2_to_l1_messages", + "type_info": "ByteaArray" + }, + { + "ordinal": 17, + "name": "used_contract_hashes", + "type_info": "Jsonb" + }, + { + "ordinal": 18, + "name": "compressed_initial_writes", + "type_info": "Bytea" + }, + { + "ordinal": 19, + "name": "compressed_repeated_writes", + "type_info": "Bytea" + }, + { + "ordinal": 20, + "name": "l2_l1_compressed_messages", + "type_info": "Bytea" + }, + { + "ordinal": 21, + "name": "l2_l1_merkle_root", + "type_info": "Bytea" + }, + { + "ordinal": 22, + "name": "rollup_last_leaf_index", + "type_info": "Int8" + }, + { + "ordinal": 23, + "name": "zkporter_is_available", + "type_info": "Bool" + }, + { + "ordinal": 24, + "name": "bootloader_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 25, + "name": "default_aa_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 26, + "name": "aux_data_hash", + "type_info": "Bytea" + }, + { + "ordinal": 27, + "name": "pass_through_data_hash", + "type_info": "Bytea" + }, + { + "ordinal": 28, + "name": "meta_parameters_hash", + "type_info": "Bytea" + }, + { + "ordinal": 29, + "name": "system_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 30, + "name": "compressed_state_diffs", + "type_info": "Bytea" + }, + { + "ordinal": 31, + "name": "protocol_version", + "type_info": "Int4" + }, + { + "ordinal": 32, + "name": "events_queue_commitment", + "type_info": "Bytea" + }, + { + "ordinal": 33, + "name": "bootloader_initial_content_commitment", + "type_info": "Bytea" + }, + { + "ordinal": 34, + "name": "pubdata_input", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8", + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + true, + true, + true, + true + ] + }, + "hash": "883ab3d601e2dfef03ad36e5987577821fc8ce2f81cb029d0f64801d5f743388" +} diff --git a/core/lib/dal/.sqlx/query-88c629334e30bb9f5c81c858aa51af63b86e8da6d908d48998012231e1d66a60.json b/core/lib/dal/.sqlx/query-88c629334e30bb9f5c81c858aa51af63b86e8da6d908d48998012231e1d66a60.json new file mode 100644 index 000000000000..16fbffd5b667 --- /dev/null +++ b/core/lib/dal/.sqlx/query-88c629334e30bb9f5c81c858aa51af63b86e8da6d908d48998012231e1d66a60.json @@ -0,0 +1,29 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n timestamp,\n virtual_blocks\n FROM\n miniblocks\n WHERE\n number BETWEEN $1 AND $2\n ORDER BY\n number\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "virtual_blocks", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8", + "Int8" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "88c629334e30bb9f5c81c858aa51af63b86e8da6d908d48998012231e1d66a60" +} diff --git a/core/lib/dal/.sqlx/query-8903ba5db3f87851c12da133573b4207b69cc48b4ba648e797211631be612b69.json b/core/lib/dal/.sqlx/query-8903ba5db3f87851c12da133573b4207b69cc48b4ba648e797211631be612b69.json new file mode 100644 index 000000000000..3d47a756f3e6 --- /dev/null +++ b/core/lib/dal/.sqlx/query-8903ba5db3f87851c12da133573b4207b69cc48b4ba648e797211631be612b69.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n bytecode_hash,\n bytecode\n FROM\n factory_deps\n INNER JOIN miniblocks ON miniblocks.number = factory_deps.miniblock_number\n WHERE\n miniblocks.l1_batch_number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "bytecode_hash", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "bytecode", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "8903ba5db3f87851c12da133573b4207b69cc48b4ba648e797211631be612b69" +} diff --git a/core/lib/dal/.sqlx/query-894665c2c467bd1aaeb331b112c567e2667c63a033baa6b427bd8a0898c08bf2.json b/core/lib/dal/.sqlx/query-894665c2c467bd1aaeb331b112c567e2667c63a033baa6b427bd8a0898c08bf2.json new file mode 100644 index 000000000000..06d3461c3fa3 --- /dev/null +++ b/core/lib/dal/.sqlx/query-894665c2c467bd1aaeb331b112c567e2667c63a033baa6b427bd8a0898c08bf2.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n protocol_version\n FROM\n miniblocks\n WHERE\n number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "protocol_version", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + true + ] + }, + "hash": "894665c2c467bd1aaeb331b112c567e2667c63a033baa6b427bd8a0898c08bf2" +} diff --git a/core/lib/dal/.sqlx/query-8a7a57ca3d4d65da3e0877c003902c690c33686c889d318b1d64bdd7fa6374db.json b/core/lib/dal/.sqlx/query-8a7a57ca3d4d65da3e0877c003902c690c33686c889d318b1d64bdd7fa6374db.json new file mode 100644 index 000000000000..ea6562d1a67f --- /dev/null +++ b/core/lib/dal/.sqlx/query-8a7a57ca3d4d65da3e0877c003902c690c33686c889d318b1d64bdd7fa6374db.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_block_number\n FROM\n transactions\n WHERE\n priority_op_id IS NOT NULL\n ORDER BY\n priority_op_id DESC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_block_number", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + true + ] + }, + "hash": "8a7a57ca3d4d65da3e0877c003902c690c33686c889d318b1d64bdd7fa6374db" +} diff --git a/core/lib/dal/.sqlx/query-8b9e5d525c026de97c0a732b1adc8dc4bd57e32dfefe1017acba9a15fc14b895.json b/core/lib/dal/.sqlx/query-8b9e5d525c026de97c0a732b1adc8dc4bd57e32dfefe1017acba9a15fc14b895.json new file mode 100644 index 000000000000..de369bccec54 --- /dev/null +++ b/core/lib/dal/.sqlx/query-8b9e5d525c026de97c0a732b1adc8dc4bd57e32dfefe1017acba9a15fc14b895.json @@ -0,0 +1,36 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n storage_logs.hashed_key,\n storage_logs.value,\n initial_writes.index\n FROM\n storage_logs\n INNER JOIN initial_writes ON storage_logs.hashed_key = initial_writes.hashed_key\n WHERE\n storage_logs.miniblock_number = $1\n AND storage_logs.hashed_key >= $2::bytea\n AND storage_logs.hashed_key <= $3::bytea\n ORDER BY\n storage_logs.hashed_key\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hashed_key", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "value", + "type_info": "Bytea" + }, + { + "ordinal": 2, + "name": "index", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8", + "Bytea", + "Bytea" + ] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "8b9e5d525c026de97c0a732b1adc8dc4bd57e32dfefe1017acba9a15fc14b895" +} diff --git a/core/lib/dal/.sqlx/query-8bf8613d5b5365b85bc0e363fbaf92d22215fa81c39f7ff91b247260efa4406b.json b/core/lib/dal/.sqlx/query-8bf8613d5b5365b85bc0e363fbaf92d22215fa81c39f7ff91b247260efa4406b.json new file mode 100644 index 000000000000..b99201a80558 --- /dev/null +++ b/core/lib/dal/.sqlx/query-8bf8613d5b5365b85bc0e363fbaf92d22215fa81c39f7ff91b247260efa4406b.json @@ -0,0 +1,229 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n number,\n l1_batches.timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n parent_hash,\n commitment,\n compressed_write_logs,\n compressed_contracts,\n eth_prove_tx_id,\n eth_commit_tx_id,\n eth_execute_tx_id,\n merkle_root_hash,\n l2_to_l1_logs,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_compressed_messages,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n l1_batches.bootloader_code_hash,\n l1_batches.default_aa_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n JOIN protocol_versions ON protocol_versions.id = l1_batches.protocol_version\n WHERE\n eth_commit_tx_id IS NULL\n AND number != 0\n AND protocol_versions.bootloader_code_hash = $1\n AND protocol_versions.default_account_code_hash = $2\n AND commitment IS NOT NULL\n AND (\n protocol_versions.id = $3\n OR protocol_versions.upgrade_tx_hash IS NULL\n )\n AND events_queue_commitment IS NOT NULL\n AND bootloader_initial_content_commitment IS NOT NULL\n ORDER BY\n number\n LIMIT\n $4\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "l1_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 3, + "name": "l2_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 4, + "name": "bloom", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "priority_ops_onchain_data", + "type_info": "ByteaArray" + }, + { + "ordinal": 6, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "parent_hash", + "type_info": "Bytea" + }, + { + "ordinal": 8, + "name": "commitment", + "type_info": "Bytea" + }, + { + "ordinal": 9, + "name": "compressed_write_logs", + "type_info": "Bytea" + }, + { + "ordinal": 10, + "name": "compressed_contracts", + "type_info": "Bytea" + }, + { + "ordinal": 11, + "name": "eth_prove_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 12, + "name": "eth_commit_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 13, + "name": "eth_execute_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 14, + "name": "merkle_root_hash", + "type_info": "Bytea" + }, + { + "ordinal": 15, + "name": "l2_to_l1_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 16, + "name": "l2_to_l1_messages", + "type_info": "ByteaArray" + }, + { + "ordinal": 17, + "name": "used_contract_hashes", + "type_info": "Jsonb" + }, + { + "ordinal": 18, + "name": "compressed_initial_writes", + "type_info": "Bytea" + }, + { + "ordinal": 19, + "name": "compressed_repeated_writes", + "type_info": "Bytea" + }, + { + "ordinal": 20, + "name": "l2_l1_compressed_messages", + "type_info": "Bytea" + }, + { + "ordinal": 21, + "name": "l2_l1_merkle_root", + "type_info": "Bytea" + }, + { + "ordinal": 22, + "name": "rollup_last_leaf_index", + "type_info": "Int8" + }, + { + "ordinal": 23, + "name": "zkporter_is_available", + "type_info": "Bool" + }, + { + "ordinal": 24, + "name": "bootloader_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 25, + "name": "default_aa_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 26, + "name": "aux_data_hash", + "type_info": "Bytea" + }, + { + "ordinal": 27, + "name": "pass_through_data_hash", + "type_info": "Bytea" + }, + { + "ordinal": 28, + "name": "meta_parameters_hash", + "type_info": "Bytea" + }, + { + "ordinal": 29, + "name": "protocol_version", + "type_info": "Int4" + }, + { + "ordinal": 30, + "name": "compressed_state_diffs", + "type_info": "Bytea" + }, + { + "ordinal": 31, + "name": "system_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 32, + "name": "events_queue_commitment", + "type_info": "Bytea" + }, + { + "ordinal": 33, + "name": "bootloader_initial_content_commitment", + "type_info": "Bytea" + }, + { + "ordinal": 34, + "name": "pubdata_input", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Bytea", + "Bytea", + "Int4", + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + true, + true + ] + }, + "hash": "8bf8613d5b5365b85bc0e363fbaf92d22215fa81c39f7ff91b247260efa4406b" +} diff --git a/core/lib/dal/.sqlx/query-8cd11172fc47ff8d37c22ba4163cd2d08a708c3af75fee57379a709baa3c4bed.json b/core/lib/dal/.sqlx/query-8cd11172fc47ff8d37c22ba4163cd2d08a708c3af75fee57379a709baa3c4bed.json new file mode 100644 index 000000000000..ba3ee8a51d7b --- /dev/null +++ b/core/lib/dal/.sqlx/query-8cd11172fc47ff8d37c22ba4163cd2d08a708c3af75fee57379a709baa3c4bed.json @@ -0,0 +1,94 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n address,\n topic1,\n topic2,\n topic3,\n topic4,\n value,\n NULL::bytea AS \"block_hash\",\n NULL::BIGINT AS \"l1_batch_number?\",\n miniblock_number,\n tx_hash,\n tx_index_in_block,\n event_index_in_block,\n event_index_in_tx\n FROM\n events\n WHERE\n tx_hash = ANY ($1)\n ORDER BY\n miniblock_number ASC,\n tx_index_in_block ASC,\n event_index_in_block ASC\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "address", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "topic1", + "type_info": "Bytea" + }, + { + "ordinal": 2, + "name": "topic2", + "type_info": "Bytea" + }, + { + "ordinal": 3, + "name": "topic3", + "type_info": "Bytea" + }, + { + "ordinal": 4, + "name": "topic4", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "value", + "type_info": "Bytea" + }, + { + "ordinal": 6, + "name": "block_hash", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "l1_batch_number?", + "type_info": "Int8" + }, + { + "ordinal": 8, + "name": "miniblock_number", + "type_info": "Int8" + }, + { + "ordinal": 9, + "name": "tx_hash", + "type_info": "Bytea" + }, + { + "ordinal": 10, + "name": "tx_index_in_block", + "type_info": "Int4" + }, + { + "ordinal": 11, + "name": "event_index_in_block", + "type_info": "Int4" + }, + { + "ordinal": 12, + "name": "event_index_in_tx", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "ByteaArray" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + null, + null, + false, + false, + false, + false, + false + ] + }, + "hash": "8cd11172fc47ff8d37c22ba4163cd2d08a708c3af75fee57379a709baa3c4bed" +} diff --git a/core/lib/dal/.sqlx/query-8f5e89ccadd4ea1da7bfe9793a1cbb724af0f0216433a70f19d784e3f2afbc9f.json b/core/lib/dal/.sqlx/query-8f5e89ccadd4ea1da7bfe9793a1cbb724af0f0216433a70f19d784e3f2afbc9f.json new file mode 100644 index 000000000000..cf7822e8ec84 --- /dev/null +++ b/core/lib/dal/.sqlx/query-8f5e89ccadd4ea1da7bfe9793a1cbb724af0f0216433a70f19d784e3f2afbc9f.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n protocol_version\n FROM\n witness_inputs_fri\n WHERE\n l1_batch_number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "protocol_version", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + true + ] + }, + "hash": "8f5e89ccadd4ea1da7bfe9793a1cbb724af0f0216433a70f19d784e3f2afbc9f" +} diff --git a/core/lib/dal/.sqlx/query-90f7657bae05c4bad6902c6bfb1b8ba0b771cb45573aca81db254f6bcfc17c77.json b/core/lib/dal/.sqlx/query-90f7657bae05c4bad6902c6bfb1b8ba0b771cb45573aca81db254f6bcfc17c77.json new file mode 100644 index 000000000000..dfd7cd9c5557 --- /dev/null +++ b/core/lib/dal/.sqlx/query-90f7657bae05c4bad6902c6bfb1b8ba0b771cb45573aca81db254f6bcfc17c77.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n nonce\n FROM\n eth_txs\n ORDER BY\n id DESC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "nonce", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "90f7657bae05c4bad6902c6bfb1b8ba0b771cb45573aca81db254f6bcfc17c77" +} diff --git a/core/lib/dal/.sqlx/query-9334df89c9562d4b35611b8e5ffb17305343df99ebc55f240278b5c4e63f89f5.json b/core/lib/dal/.sqlx/query-9334df89c9562d4b35611b8e5ffb17305343df99ebc55f240278b5c4e63f89f5.json new file mode 100644 index 000000000000..92e74026bf57 --- /dev/null +++ b/core/lib/dal/.sqlx/query-9334df89c9562d4b35611b8e5ffb17305343df99ebc55f240278b5c4e63f89f5.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n value\n FROM\n storage\n WHERE\n hashed_key = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "value", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [ + false + ] + }, + "hash": "9334df89c9562d4b35611b8e5ffb17305343df99ebc55f240278b5c4e63f89f5" +} diff --git a/core/lib/dal/.sqlx/query-95ea0522a3eff6c0d2d0b1c58fd2767e112b95f4d103c27acd6f7ede108bd300.json b/core/lib/dal/.sqlx/query-95ea0522a3eff6c0d2d0b1c58fd2767e112b95f4d103c27acd6f7ede108bd300.json new file mode 100644 index 000000000000..3c822fe50d17 --- /dev/null +++ b/core/lib/dal/.sqlx/query-95ea0522a3eff6c0d2d0b1c58fd2767e112b95f4d103c27acd6f7ede108bd300.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE eth_txs\n SET\n gas_used = $1,\n confirmed_eth_tx_history_id = $2\n WHERE\n id = $3\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Int4", + "Int4" + ] + }, + "nullable": [] + }, + "hash": "95ea0522a3eff6c0d2d0b1c58fd2767e112b95f4d103c27acd6f7ede108bd300" +} diff --git a/core/lib/dal/.sqlx/query-966dddc881bfe6fd94b56f587424125a2633ddb6abaa129f2b12389140d83c3f.json b/core/lib/dal/.sqlx/query-966dddc881bfe6fd94b56f587424125a2633ddb6abaa129f2b12389140d83c3f.json new file mode 100644 index 000000000000..bf4eb3f9462d --- /dev/null +++ b/core/lib/dal/.sqlx/query-966dddc881bfe6fd94b56f587424125a2633ddb6abaa129f2b12389140d83c3f.json @@ -0,0 +1,40 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n recursion_scheduler_level_vk_hash,\n recursion_node_level_vk_hash,\n recursion_leaf_level_vk_hash,\n recursion_circuits_set_vks_hash\n FROM\n protocol_versions\n WHERE\n id = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "recursion_scheduler_level_vk_hash", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "recursion_node_level_vk_hash", + "type_info": "Bytea" + }, + { + "ordinal": 2, + "name": "recursion_leaf_level_vk_hash", + "type_info": "Bytea" + }, + { + "ordinal": 3, + "name": "recursion_circuits_set_vks_hash", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [ + false, + false, + false, + false + ] + }, + "hash": "966dddc881bfe6fd94b56f587424125a2633ddb6abaa129f2b12389140d83c3f" +} diff --git a/core/lib/dal/.sqlx/query-9955b9215096f781442153518c4f0a9676e26f422506545ccc90b7e8a36c8d47.json b/core/lib/dal/.sqlx/query-9955b9215096f781442153518c4f0a9676e26f422506545ccc90b7e8a36c8d47.json new file mode 100644 index 000000000000..c05539164cee --- /dev/null +++ b/core/lib/dal/.sqlx/query-9955b9215096f781442153518c4f0a9676e26f422506545ccc90b7e8a36c8d47.json @@ -0,0 +1,35 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n factory_deps.bytecode,\n transactions.data AS \"data?\",\n transactions.contract_address AS \"contract_address?\"\n FROM\n (\n SELECT\n *\n FROM\n storage_logs\n WHERE\n storage_logs.hashed_key = $1\n ORDER BY\n miniblock_number DESC,\n operation_number DESC\n LIMIT\n 1\n ) storage_logs\n JOIN factory_deps ON factory_deps.bytecode_hash = storage_logs.value\n LEFT JOIN transactions ON transactions.hash = storage_logs.tx_hash\n WHERE\n storage_logs.value != $2\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "bytecode", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "data?", + "type_info": "Jsonb" + }, + { + "ordinal": 2, + "name": "contract_address?", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Bytea", + "Bytea" + ] + }, + "nullable": [ + false, + false, + true + ] + }, + "hash": "9955b9215096f781442153518c4f0a9676e26f422506545ccc90b7e8a36c8d47" +} diff --git a/core/lib/dal/.sqlx/query-995cecd37a5235d1acc2e6fc418d9b6a1a6fe629f9a02c8e33330a0efda64068.json b/core/lib/dal/.sqlx/query-995cecd37a5235d1acc2e6fc418d9b6a1a6fe629f9a02c8e33330a0efda64068.json new file mode 100644 index 000000000000..49e0a4a8f07d --- /dev/null +++ b/core/lib/dal/.sqlx/query-995cecd37a5235d1acc2e6fc418d9b6a1a6fe629f9a02c8e33330a0efda64068.json @@ -0,0 +1,32 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_number,\n factory_deps_filepath,\n storage_logs_filepaths\n FROM\n snapshots\n ORDER BY\n l1_batch_number DESC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "factory_deps_filepath", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "storage_logs_filepaths", + "type_info": "TextArray" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "995cecd37a5235d1acc2e6fc418d9b6a1a6fe629f9a02c8e33330a0efda64068" +} diff --git a/core/lib/dal/.sqlx/query-99acb091650478fe0feb367b1d64561347b81f8931cc2addefa907c9aa9355e6.json b/core/lib/dal/.sqlx/query-99acb091650478fe0feb367b1d64561347b81f8931cc2addefa907c9aa9355e6.json new file mode 100644 index 000000000000..2aa6a538125b --- /dev/null +++ b/core/lib/dal/.sqlx/query-99acb091650478fe0feb367b1d64561347b81f8931cc2addefa907c9aa9355e6.json @@ -0,0 +1,82 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n *\n FROM\n protocol_versions\n WHERE\n id < $1\n ORDER BY\n id DESC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "recursion_scheduler_level_vk_hash", + "type_info": "Bytea" + }, + { + "ordinal": 3, + "name": "recursion_node_level_vk_hash", + "type_info": "Bytea" + }, + { + "ordinal": 4, + "name": "recursion_leaf_level_vk_hash", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "recursion_circuits_set_vks_hash", + "type_info": "Bytea" + }, + { + "ordinal": 6, + "name": "bootloader_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "default_account_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 8, + "name": "verifier_address", + "type_info": "Bytea" + }, + { + "ordinal": 9, + "name": "upgrade_tx_hash", + "type_info": "Bytea" + }, + { + "ordinal": 10, + "name": "created_at", + "type_info": "Timestamp" + } + ], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + false + ] + }, + "hash": "99acb091650478fe0feb367b1d64561347b81f8931cc2addefa907c9aa9355e6" +} diff --git a/core/lib/dal/.sqlx/query-99d9ee2a0d0450acefa0d9b6c031e30606fddf6631c859ab03819ec476bcf005.json b/core/lib/dal/.sqlx/query-99d9ee2a0d0450acefa0d9b6c031e30606fddf6631c859ab03819ec476bcf005.json new file mode 100644 index 000000000000..ab00c7b26ce3 --- /dev/null +++ b/core/lib/dal/.sqlx/query-99d9ee2a0d0450acefa0d9b6c031e30606fddf6631c859ab03819ec476bcf005.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n hashed_key\n FROM\n initial_writes\n WHERE\n hashed_key = ANY ($1)\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hashed_key", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "ByteaArray" + ] + }, + "nullable": [ + false + ] + }, + "hash": "99d9ee2a0d0450acefa0d9b6c031e30606fddf6631c859ab03819ec476bcf005" +} diff --git a/core/lib/dal/.sqlx/query-99dd6f04e82585d81ac23bc4871578179e6269c6ff36877cedee264067ccdafc.json b/core/lib/dal/.sqlx/query-99dd6f04e82585d81ac23bc4871578179e6269c6ff36877cedee264067ccdafc.json new file mode 100644 index 000000000000..b8c14c534625 --- /dev/null +++ b/core/lib/dal/.sqlx/query-99dd6f04e82585d81ac23bc4871578179e6269c6ff36877cedee264067ccdafc.json @@ -0,0 +1,65 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE basic_witness_input_producer_jobs\n SET\n status = $1,\n attempts = attempts + 1,\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n l1_batch_number = (\n SELECT\n l1_batch_number\n FROM\n basic_witness_input_producer_jobs\n WHERE\n status = $2\n OR (\n status = $1\n AND processing_started_at < NOW() - $4::INTERVAL\n )\n OR (\n status = $3\n AND attempts < $5\n )\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n basic_witness_input_producer_jobs.l1_batch_number\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + { + "Custom": { + "name": "basic_witness_input_producer_job_status", + "kind": { + "Enum": [ + "Queued", + "ManuallySkipped", + "InProgress", + "Successful", + "Failed" + ] + } + } + }, + { + "Custom": { + "name": "basic_witness_input_producer_job_status", + "kind": { + "Enum": [ + "Queued", + "ManuallySkipped", + "InProgress", + "Successful", + "Failed" + ] + } + } + }, + { + "Custom": { + "name": "basic_witness_input_producer_job_status", + "kind": { + "Enum": [ + "Queued", + "ManuallySkipped", + "InProgress", + "Successful", + "Failed" + ] + } + } + }, + "Interval", + "Int2" + ] + }, + "nullable": [ + false + ] + }, + "hash": "99dd6f04e82585d81ac23bc4871578179e6269c6ff36877cedee264067ccdafc" +} diff --git a/core/lib/dal/.sqlx/query-9b90f7a7ffee3cd8439f90a6f79693831e2ab6d6d3c1805df5aa51d76994ec19.json b/core/lib/dal/.sqlx/query-9b90f7a7ffee3cd8439f90a6f79693831e2ab6d6d3c1805df5aa51d76994ec19.json new file mode 100644 index 000000000000..a890a6ca07e0 --- /dev/null +++ b/core/lib/dal/.sqlx/query-9b90f7a7ffee3cd8439f90a6f79693831e2ab6d6d3c1805df5aa51d76994ec19.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n witness_inputs_fri (\n l1_batch_number,\n merkle_tree_paths_blob_url,\n protocol_version,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, 'queued', NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Text", + "Int4" + ] + }, + "nullable": [] + }, + "hash": "9b90f7a7ffee3cd8439f90a6f79693831e2ab6d6d3c1805df5aa51d76994ec19" +} diff --git a/core/lib/dal/.sqlx/query-9c2a5f32c627d3a5c6f1e87b31ce3b0fd67aa1f5f7ea0de673a2fbe1f742db86.json b/core/lib/dal/.sqlx/query-9c2a5f32c627d3a5c6f1e87b31ce3b0fd67aa1f5f7ea0de673a2fbe1f742db86.json new file mode 100644 index 000000000000..f9a53d707632 --- /dev/null +++ b/core/lib/dal/.sqlx/query-9c2a5f32c627d3a5c6f1e87b31ce3b0fd67aa1f5f7ea0de673a2fbe1f742db86.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n timestamp\n FROM\n miniblocks\n WHERE\n number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "timestamp", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "9c2a5f32c627d3a5c6f1e87b31ce3b0fd67aa1f5f7ea0de673a2fbe1f742db86" +} diff --git a/core/lib/dal/.sqlx/query-9cfcde703a48b110791d2ae1103c9317c01d6e35db3b07d0a31f436e7e3c7c40.json b/core/lib/dal/.sqlx/query-9cfcde703a48b110791d2ae1103c9317c01d6e35db3b07d0a31f436e7e3c7c40.json new file mode 100644 index 000000000000..c4beef961733 --- /dev/null +++ b/core/lib/dal/.sqlx/query-9cfcde703a48b110791d2ae1103c9317c01d6e35db3b07d0a31f436e7e3c7c40.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE contract_verification_requests\n SET\n status = 'successful',\n updated_at = NOW()\n WHERE\n id = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "9cfcde703a48b110791d2ae1103c9317c01d6e35db3b07d0a31f436e7e3c7c40" +} diff --git a/core/lib/dal/.sqlx/query-9de5acb3de1b96ff8eb62a6324e8e221a8ef9014458cc7f1dbc60c056a0768a0.json b/core/lib/dal/.sqlx/query-9de5acb3de1b96ff8eb62a6324e8e221a8ef9014458cc7f1dbc60c056a0768a0.json new file mode 100644 index 000000000000..674377635ced --- /dev/null +++ b/core/lib/dal/.sqlx/query-9de5acb3de1b96ff8eb62a6324e8e221a8ef9014458cc7f1dbc60c056a0768a0.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE snapshots\n SET\n storage_logs_filepaths[$2] = $3,\n updated_at = NOW()\n WHERE\n l1_batch_number = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Int4", + "Text" + ] + }, + "nullable": [] + }, + "hash": "9de5acb3de1b96ff8eb62a6324e8e221a8ef9014458cc7f1dbc60c056a0768a0" +} diff --git a/core/lib/dal/.sqlx/query-9ee07a22405279e1e44d47ec5226a834aeac9156b974ff225d734683c1905469.json b/core/lib/dal/.sqlx/query-9ee07a22405279e1e44d47ec5226a834aeac9156b974ff225d734683c1905469.json new file mode 100644 index 000000000000..3269ceb7987d --- /dev/null +++ b/core/lib/dal/.sqlx/query-9ee07a22405279e1e44d47ec5226a834aeac9156b974ff225d734683c1905469.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n miniblocks (\n number,\n timestamp,\n hash,\n l1_tx_count,\n l2_tx_count,\n fee_account_address,\n base_fee_per_gas,\n l1_gas_price,\n l2_fair_gas_price,\n gas_per_pubdata_limit,\n bootloader_code_hash,\n default_aa_code_hash,\n protocol_version,\n virtual_blocks,\n fair_pubdata_price,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, NOW(), NOW())\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Int8", + "Bytea", + "Int4", + "Int4", + "Bytea", + "Numeric", + "Int8", + "Int8", + "Int8", + "Bytea", + "Bytea", + "Int4", + "Int8", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "9ee07a22405279e1e44d47ec5226a834aeac9156b974ff225d734683c1905469" +} diff --git a/core/lib/dal/.sqlx/query-9ef2f43e6201cc00a0e1425a666a36532fee1450733849852dfd20e18ded1f03.json b/core/lib/dal/.sqlx/query-9ef2f43e6201cc00a0e1425a666a36532fee1450733849852dfd20e18ded1f03.json new file mode 100644 index 000000000000..fd770071cf86 --- /dev/null +++ b/core/lib/dal/.sqlx/query-9ef2f43e6201cc00a0e1425a666a36532fee1450733849852dfd20e18ded1f03.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE scheduler_witness_jobs_fri\n SET\n status = 'failed',\n error = $1,\n updated_at = NOW()\n WHERE\n l1_batch_number = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "9ef2f43e6201cc00a0e1425a666a36532fee1450733849852dfd20e18ded1f03" +} diff --git a/core/lib/dal/.sqlx/query-9f637f37dc3a29ce7412ab4347071bd180729779a0e98ae7a6bb4386aca99716.json b/core/lib/dal/.sqlx/query-9f637f37dc3a29ce7412ab4347071bd180729779a0e98ae7a6bb4386aca99716.json new file mode 100644 index 000000000000..fc18e9f6cb55 --- /dev/null +++ b/core/lib/dal/.sqlx/query-9f637f37dc3a29ce7412ab4347071bd180729779a0e98ae7a6bb4386aca99716.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n bytecode_hash,\n bytecode\n FROM\n factory_deps\n WHERE\n miniblock_number <= $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "bytecode_hash", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "bytecode", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "9f637f37dc3a29ce7412ab4347071bd180729779a0e98ae7a6bb4386aca99716" +} diff --git a/core/lib/dal/.sqlx/query-a0e2b2c034cc5f668f0b3d43b94d2e2326d7ace079b095def52723a45b65d3f3.json b/core/lib/dal/.sqlx/query-a0e2b2c034cc5f668f0b3d43b94d2e2326d7ace079b095def52723a45b65d3f3.json new file mode 100644 index 000000000000..7dc19564f7fa --- /dev/null +++ b/core/lib/dal/.sqlx/query-a0e2b2c034cc5f668f0b3d43b94d2e2326d7ace079b095def52723a45b65d3f3.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE witness_inputs_fri\n SET\n status = 'failed',\n error = $1,\n updated_at = NOW()\n WHERE\n l1_batch_number = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "a0e2b2c034cc5f668f0b3d43b94d2e2326d7ace079b095def52723a45b65d3f3" +} diff --git a/core/lib/dal/.sqlx/query-a2d02b71e3dcc29a2c0c20b44392cfbaf09164aecfa5eed8d7142518ad96abea.json b/core/lib/dal/.sqlx/query-a2d02b71e3dcc29a2c0c20b44392cfbaf09164aecfa5eed8d7142518ad96abea.json new file mode 100644 index 000000000000..fc36e47b54c8 --- /dev/null +++ b/core/lib/dal/.sqlx/query-a2d02b71e3dcc29a2c0c20b44392cfbaf09164aecfa5eed8d7142518ad96abea.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n initial_bootloader_heap_content\n FROM\n l1_batches\n WHERE\n number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "initial_bootloader_heap_content", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "a2d02b71e3dcc29a2c0c20b44392cfbaf09164aecfa5eed8d7142518ad96abea" +} diff --git a/core/lib/dal/.sqlx/query-a45dd1d1344bf6b3447a2d72949067ee3bff92b04766e98336ca9338a19aef46.json b/core/lib/dal/.sqlx/query-a45dd1d1344bf6b3447a2d72949067ee3bff92b04766e98336ca9338a19aef46.json new file mode 100644 index 000000000000..69ce70a7f4a2 --- /dev/null +++ b/core/lib/dal/.sqlx/query-a45dd1d1344bf6b3447a2d72949067ee3bff92b04766e98336ca9338a19aef46.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n hashed_key,\n value AS \"value!\"\n FROM\n storage\n WHERE\n hashed_key = ANY ($1)\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hashed_key", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "value!", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "ByteaArray" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "a45dd1d1344bf6b3447a2d72949067ee3bff92b04766e98336ca9338a19aef46" +} diff --git a/core/lib/dal/.sqlx/query-a4861c931e84d897c27f666de1c5ca679a0459a012899a373c67393d30d12601.json b/core/lib/dal/.sqlx/query-a4861c931e84d897c27f666de1c5ca679a0459a012899a373c67393d30d12601.json new file mode 100644 index 000000000000..104a7fb25560 --- /dev/null +++ b/core/lib/dal/.sqlx/query-a4861c931e84d897c27f666de1c5ca679a0459a012899a373c67393d30d12601.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE scheduler_dependency_tracker_fri\n SET\n status = 'queued'\n WHERE\n l1_batch_number = ANY ($1)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8Array" + ] + }, + "nullable": [] + }, + "hash": "a4861c931e84d897c27f666de1c5ca679a0459a012899a373c67393d30d12601" +} diff --git a/core/lib/dal/.sqlx/query-a48c92f557e5e3a2674ce0dee9cd92f5a547150590b8c221c4065eab11175c7a.json b/core/lib/dal/.sqlx/query-a48c92f557e5e3a2674ce0dee9cd92f5a547150590b8c221c4065eab11175c7a.json new file mode 100644 index 000000000000..49e547e5564c --- /dev/null +++ b/core/lib/dal/.sqlx/query-a48c92f557e5e3a2674ce0dee9cd92f5a547150590b8c221c4065eab11175c7a.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n MAX(INDEX) AS \"max?\"\n FROM\n initial_writes\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "max?", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "a48c92f557e5e3a2674ce0dee9cd92f5a547150590b8c221c4065eab11175c7a" +} diff --git a/core/lib/dal/.sqlx/query-a4a4b0bfbe05eac100c42a717e8d7cbb0bc526ebe61a07f735d4ab587058b22c.json b/core/lib/dal/.sqlx/query-a4a4b0bfbe05eac100c42a717e8d7cbb0bc526ebe61a07f735d4ab587058b22c.json new file mode 100644 index 000000000000..f19add71350a --- /dev/null +++ b/core/lib/dal/.sqlx/query-a4a4b0bfbe05eac100c42a717e8d7cbb0bc526ebe61a07f735d4ab587058b22c.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n hash\n FROM\n miniblocks\n WHERE\n number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hash", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "a4a4b0bfbe05eac100c42a717e8d7cbb0bc526ebe61a07f735d4ab587058b22c" +} diff --git a/core/lib/dal/.sqlx/query-a4fcd075b68467bb119e49e6b20a69138206dfeb41f3daff4a3eef1de0bed4e4.json b/core/lib/dal/.sqlx/query-a4fcd075b68467bb119e49e6b20a69138206dfeb41f3daff4a3eef1de0bed4e4.json new file mode 100644 index 000000000000..39b0c391ef59 --- /dev/null +++ b/core/lib/dal/.sqlx/query-a4fcd075b68467bb119e49e6b20a69138206dfeb41f3daff4a3eef1de0bed4e4.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n initial_writes (hashed_key, INDEX, l1_batch_number, created_at, updated_at)\n SELECT\n u.hashed_key,\n u.index,\n $3,\n NOW(),\n NOW()\n FROM\n UNNEST($1::bytea[], $2::BIGINT[]) AS u (hashed_key, INDEX)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "ByteaArray", + "Int8Array", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "a4fcd075b68467bb119e49e6b20a69138206dfeb41f3daff4a3eef1de0bed4e4" +} diff --git a/core/lib/dal/.sqlx/query-a74d029f58801ec05d8d14a3b065d93e391600ab9da2e5fd4e8b139ab3d77583.json b/core/lib/dal/.sqlx/query-a74d029f58801ec05d8d14a3b065d93e391600ab9da2e5fd4e8b139ab3d77583.json new file mode 100644 index 000000000000..c4f1f4bbcd0d --- /dev/null +++ b/core/lib/dal/.sqlx/query-a74d029f58801ec05d8d14a3b065d93e391600ab9da2e5fd4e8b139ab3d77583.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE proof_generation_details\n SET\n status = 'generated',\n proof_blob_url = $1,\n updated_at = NOW()\n WHERE\n l1_batch_number = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "a74d029f58801ec05d8d14a3b065d93e391600ab9da2e5fd4e8b139ab3d77583" +} diff --git a/core/lib/dal/.sqlx/query-a83f853b1d63365e88975a926816c6e7b4595f3e7c3dca1d1590de5437187733.json b/core/lib/dal/.sqlx/query-a83f853b1d63365e88975a926816c6e7b4595f3e7c3dca1d1590de5437187733.json new file mode 100644 index 000000000000..0dab103fa24f --- /dev/null +++ b/core/lib/dal/.sqlx/query-a83f853b1d63365e88975a926816c6e7b4595f3e7c3dca1d1590de5437187733.json @@ -0,0 +1,29 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE l1_batches\n SET\n hash = $1,\n merkle_root_hash = $2,\n commitment = $3,\n default_aa_code_hash = $4,\n compressed_repeated_writes = $5,\n compressed_initial_writes = $6,\n l2_l1_compressed_messages = $7,\n l2_l1_merkle_root = $8,\n zkporter_is_available = $9,\n bootloader_code_hash = $10,\n rollup_last_leaf_index = $11,\n aux_data_hash = $12,\n pass_through_data_hash = $13,\n meta_parameters_hash = $14,\n compressed_state_diffs = $15,\n updated_at = NOW()\n WHERE\n number = $16\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Bytea", + "Bytea", + "Bytea", + "Bytea", + "Bytea", + "Bytea", + "Bytea", + "Bool", + "Bytea", + "Int8", + "Bytea", + "Bytea", + "Bytea", + "Bytea", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "a83f853b1d63365e88975a926816c6e7b4595f3e7c3dca1d1590de5437187733" +} diff --git a/core/lib/dal/.sqlx/query-a84ee70bec8c03bd51e1c6bad44c9a64904026506914abae2946e5d353d6a604.json b/core/lib/dal/.sqlx/query-a84ee70bec8c03bd51e1c6bad44c9a64904026506914abae2946e5d353d6a604.json new file mode 100644 index 000000000000..3275df2a3d58 --- /dev/null +++ b/core/lib/dal/.sqlx/query-a84ee70bec8c03bd51e1c6bad44c9a64904026506914abae2946e5d353d6a604.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n id\n FROM\n prover_jobs_fri\n WHERE\n l1_batch_number = $1\n AND status = 'successful'\n AND aggregation_round = $2\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8", + "Int2" + ] + }, + "nullable": [ + false + ] + }, + "hash": "a84ee70bec8c03bd51e1c6bad44c9a64904026506914abae2946e5d353d6a604" +} diff --git a/core/lib/dal/.sqlx/query-a91c23c4d33771122cec2589c6fe2757dbc13be6b30f5840744e5e0569adc66e.json b/core/lib/dal/.sqlx/query-a91c23c4d33771122cec2589c6fe2757dbc13be6b30f5840744e5e0569adc66e.json new file mode 100644 index 000000000000..7c757648b383 --- /dev/null +++ b/core/lib/dal/.sqlx/query-a91c23c4d33771122cec2589c6fe2757dbc13be6b30f5840744e5e0569adc66e.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n upgrade_tx_hash\n FROM\n protocol_versions\n WHERE\n id = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "upgrade_tx_hash", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [ + true + ] + }, + "hash": "a91c23c4d33771122cec2589c6fe2757dbc13be6b30f5840744e5e0569adc66e" +} diff --git a/core/lib/dal/.sqlx/query-aa91697157517322b0dbb53dca99f41220c51f58a03c61d6b7789eab0504e320.json b/core/lib/dal/.sqlx/query-aa91697157517322b0dbb53dca99f41220c51f58a03c61d6b7789eab0504e320.json new file mode 100644 index 000000000000..27d482317286 --- /dev/null +++ b/core/lib/dal/.sqlx/query-aa91697157517322b0dbb53dca99f41220c51f58a03c61d6b7789eab0504e320.json @@ -0,0 +1,32 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE node_aggregation_witness_jobs_fri\n SET\n status = 'queued'\n WHERE\n (l1_batch_number, circuit_id, depth) IN (\n SELECT\n prover_jobs_fri.l1_batch_number,\n prover_jobs_fri.circuit_id,\n prover_jobs_fri.depth\n FROM\n prover_jobs_fri\n JOIN node_aggregation_witness_jobs_fri nawj ON prover_jobs_fri.l1_batch_number = nawj.l1_batch_number\n AND prover_jobs_fri.circuit_id = nawj.circuit_id\n AND prover_jobs_fri.depth = nawj.depth\n WHERE\n nawj.status = 'waiting_for_proofs'\n AND prover_jobs_fri.status = 'successful'\n AND prover_jobs_fri.aggregation_round = 1\n AND prover_jobs_fri.depth = 0\n GROUP BY\n prover_jobs_fri.l1_batch_number,\n prover_jobs_fri.circuit_id,\n prover_jobs_fri.depth,\n nawj.number_of_dependent_jobs\n HAVING\n COUNT(*) = nawj.number_of_dependent_jobs\n )\n RETURNING\n l1_batch_number,\n circuit_id,\n depth;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "circuit_id", + "type_info": "Int2" + }, + { + "ordinal": 2, + "name": "depth", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "aa91697157517322b0dbb53dca99f41220c51f58a03c61d6b7789eab0504e320" +} diff --git a/core/lib/dal/.sqlx/query-aaf4fb97c95a5290fb1620cd868477dcf21955e0921ba648ba2e751dbfc3cb45.json b/core/lib/dal/.sqlx/query-aaf4fb97c95a5290fb1620cd868477dcf21955e0921ba648ba2e751dbfc3cb45.json new file mode 100644 index 000000000000..614b853c6250 --- /dev/null +++ b/core/lib/dal/.sqlx/query-aaf4fb97c95a5290fb1620cd868477dcf21955e0921ba648ba2e751dbfc3cb45.json @@ -0,0 +1,38 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n COUNT(*) AS \"count!\",\n circuit_id AS \"circuit_id!\",\n aggregation_round AS \"aggregation_round!\",\n status AS \"status!\"\n FROM\n prover_jobs_fri\n WHERE\n status <> 'skipped'\n AND status <> 'successful'\n GROUP BY\n circuit_id,\n aggregation_round,\n status\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count!", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "circuit_id!", + "type_info": "Int2" + }, + { + "ordinal": 2, + "name": "aggregation_round!", + "type_info": "Int2" + }, + { + "ordinal": 3, + "name": "status!", + "type_info": "Text" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null, + false, + false, + false + ] + }, + "hash": "aaf4fb97c95a5290fb1620cd868477dcf21955e0921ba648ba2e751dbfc3cb45" +} diff --git a/core/lib/dal/.sqlx/query-ac505ae6cfc744b07b52997db789bdc9efc6b89fc0444caf8271edd7dfe4a3bc.json b/core/lib/dal/.sqlx/query-ac505ae6cfc744b07b52997db789bdc9efc6b89fc0444caf8271edd7dfe4a3bc.json new file mode 100644 index 000000000000..2dad4563cc70 --- /dev/null +++ b/core/lib/dal/.sqlx/query-ac505ae6cfc744b07b52997db789bdc9efc6b89fc0444caf8271edd7dfe4a3bc.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n id\n FROM\n protocol_versions\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "ac505ae6cfc744b07b52997db789bdc9efc6b89fc0444caf8271edd7dfe4a3bc" +} diff --git a/core/lib/dal/.sqlx/query-ada54322a28012b1b761f3631c4cd6ca26aa2fa565fcf208b6985f461c1868f2.json b/core/lib/dal/.sqlx/query-ada54322a28012b1b761f3631c4cd6ca26aa2fa565fcf208b6985f461c1868f2.json new file mode 100644 index 000000000000..04fde45469fa --- /dev/null +++ b/core/lib/dal/.sqlx/query-ada54322a28012b1b761f3631c4cd6ca26aa2fa565fcf208b6985f461c1868f2.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE eth_txs_history\n SET\n updated_at = NOW(),\n confirmed_at = NOW()\n WHERE\n tx_hash = $1\n RETURNING\n id,\n eth_tx_id\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "eth_tx_id", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "ada54322a28012b1b761f3631c4cd6ca26aa2fa565fcf208b6985f461c1868f2" +} diff --git a/core/lib/dal/.sqlx/query-aeda34b1beadca72e3e600ea9ae63f436a4f16dbeb784d0d28be392ad96b1c49.json b/core/lib/dal/.sqlx/query-aeda34b1beadca72e3e600ea9ae63f436a4f16dbeb784d0d28be392ad96b1c49.json new file mode 100644 index 000000000000..b411d3ce8309 --- /dev/null +++ b/core/lib/dal/.sqlx/query-aeda34b1beadca72e3e600ea9ae63f436a4f16dbeb784d0d28be392ad96b1c49.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE eth_txs\n SET\n has_failed = TRUE\n WHERE\n id = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [] + }, + "hash": "aeda34b1beadca72e3e600ea9ae63f436a4f16dbeb784d0d28be392ad96b1c49" +} diff --git a/core/lib/dal/.sqlx/query-aefea1f3e87f28791cc547f193a895006e23ec73018f4b4e0a364a741f5c9781.json b/core/lib/dal/.sqlx/query-aefea1f3e87f28791cc547f193a895006e23ec73018f4b4e0a364a741f5c9781.json new file mode 100644 index 000000000000..c82bed1169ca --- /dev/null +++ b/core/lib/dal/.sqlx/query-aefea1f3e87f28791cc547f193a895006e23ec73018f4b4e0a364a741f5c9781.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_number\n FROM\n miniblocks\n WHERE\n number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + true + ] + }, + "hash": "aefea1f3e87f28791cc547f193a895006e23ec73018f4b4e0a364a741f5c9781" +} diff --git a/core/lib/dal/.sqlx/query-af72fabd90eb43fb315f46d7fe9f724216807ffd481cd6f7f19968e42e52b284.json b/core/lib/dal/.sqlx/query-af72fabd90eb43fb315f46d7fe9f724216807ffd481cd6f7f19968e42e52b284.json new file mode 100644 index 000000000000..6674fab59eab --- /dev/null +++ b/core/lib/dal/.sqlx/query-af72fabd90eb43fb315f46d7fe9f724216807ffd481cd6f7f19968e42e52b284.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE prover_jobs_fri\n SET\n status = 'sent_to_server',\n updated_at = NOW()\n WHERE\n l1_batch_number = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "af72fabd90eb43fb315f46d7fe9f724216807ffd481cd6f7f19968e42e52b284" +} diff --git a/core/lib/dal/.sqlx/query-afc24bd1407dba82cd3dc9e7ee71ac4ab2d73bda6022700aeb0a630a2563a4b4.json b/core/lib/dal/.sqlx/query-afc24bd1407dba82cd3dc9e7ee71ac4ab2d73bda6022700aeb0a630a2563a4b4.json new file mode 100644 index 000000000000..ede2995ff558 --- /dev/null +++ b/core/lib/dal/.sqlx/query-afc24bd1407dba82cd3dc9e7ee71ac4ab2d73bda6022700aeb0a630a2563a4b4.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE leaf_aggregation_witness_jobs_fri\n SET\n status = 'failed',\n error = $1,\n updated_at = NOW()\n WHERE\n id = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "afc24bd1407dba82cd3dc9e7ee71ac4ab2d73bda6022700aeb0a630a2563a4b4" +} diff --git a/core/lib/dal/.sqlx/query-b17c71983da060f08616e001b42f8dcbcb014b4f808c6232abd9a83354c995ac.json b/core/lib/dal/.sqlx/query-b17c71983da060f08616e001b42f8dcbcb014b4f808c6232abd9a83354c995ac.json new file mode 100644 index 000000000000..82209e00b65a --- /dev/null +++ b/core/lib/dal/.sqlx/query-b17c71983da060f08616e001b42f8dcbcb014b4f808c6232abd9a83354c995ac.json @@ -0,0 +1,35 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE node_aggregation_witness_jobs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n (\n status = 'in_progress'\n AND processing_started_at <= NOW() - $1::INTERVAL\n AND attempts < $2\n )\n OR (\n status = 'failed'\n AND attempts < $2\n )\n RETURNING\n id,\n status,\n attempts\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "status", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "attempts", + "type_info": "Int2" + } + ], + "parameters": { + "Left": [ + "Interval", + "Int2" + ] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "b17c71983da060f08616e001b42f8dcbcb014b4f808c6232abd9a83354c995ac" +} diff --git a/core/lib/dal/.sqlx/query-b23ddb16513d69331056b94d466663a9c5ea62ea7c99a77941eb8f05d4454125.json b/core/lib/dal/.sqlx/query-b23ddb16513d69331056b94d466663a9c5ea62ea7c99a77941eb8f05d4454125.json new file mode 100644 index 000000000000..fd8600d59aaf --- /dev/null +++ b/core/lib/dal/.sqlx/query-b23ddb16513d69331056b94d466663a9c5ea62ea7c99a77941eb8f05d4454125.json @@ -0,0 +1,18 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n leaf_aggregation_witness_jobs_fri (\n l1_batch_number,\n circuit_id,\n closed_form_inputs_blob_url,\n number_of_basic_circuits,\n protocol_version,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, $4, $5, 'waiting_for_proofs', NOW(), NOW())\n ON CONFLICT (l1_batch_number, circuit_id) DO\n UPDATE\n SET\n updated_at = NOW()\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Int2", + "Text", + "Int4", + "Int4" + ] + }, + "nullable": [] + }, + "hash": "b23ddb16513d69331056b94d466663a9c5ea62ea7c99a77941eb8f05d4454125" +} diff --git a/core/lib/dal/.sqlx/query-b259e6bacd98fa68003e0c87bb28cc77bd2dcee4a04d1afc9779714854623a79.json b/core/lib/dal/.sqlx/query-b259e6bacd98fa68003e0c87bb28cc77bd2dcee4a04d1afc9779714854623a79.json new file mode 100644 index 000000000000..90c940c3977c --- /dev/null +++ b/core/lib/dal/.sqlx/query-b259e6bacd98fa68003e0c87bb28cc77bd2dcee4a04d1afc9779714854623a79.json @@ -0,0 +1,94 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n miniblock_number,\n log_index_in_miniblock,\n log_index_in_tx,\n tx_hash,\n NULL::bytea AS \"block_hash\",\n NULL::BIGINT AS \"l1_batch_number?\",\n shard_id,\n is_service,\n tx_index_in_miniblock,\n tx_index_in_l1_batch,\n sender,\n key,\n value\n FROM\n l2_to_l1_logs\n WHERE\n tx_hash = ANY ($1)\n ORDER BY\n tx_index_in_l1_batch ASC,\n log_index_in_tx ASC\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "miniblock_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "log_index_in_miniblock", + "type_info": "Int4" + }, + { + "ordinal": 2, + "name": "log_index_in_tx", + "type_info": "Int4" + }, + { + "ordinal": 3, + "name": "tx_hash", + "type_info": "Bytea" + }, + { + "ordinal": 4, + "name": "block_hash", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "l1_batch_number?", + "type_info": "Int8" + }, + { + "ordinal": 6, + "name": "shard_id", + "type_info": "Int4" + }, + { + "ordinal": 7, + "name": "is_service", + "type_info": "Bool" + }, + { + "ordinal": 8, + "name": "tx_index_in_miniblock", + "type_info": "Int4" + }, + { + "ordinal": 9, + "name": "tx_index_in_l1_batch", + "type_info": "Int4" + }, + { + "ordinal": 10, + "name": "sender", + "type_info": "Bytea" + }, + { + "ordinal": 11, + "name": "key", + "type_info": "Bytea" + }, + { + "ordinal": 12, + "name": "value", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "ByteaArray" + ] + }, + "nullable": [ + false, + false, + false, + false, + null, + null, + false, + false, + false, + false, + false, + false, + false + ] + }, + "hash": "b259e6bacd98fa68003e0c87bb28cc77bd2dcee4a04d1afc9779714854623a79" +} diff --git a/core/lib/dal/.sqlx/query-b321c5ba22358cbb1fd9c627f1e7b56187686173327498ac75424593547c19c5.json b/core/lib/dal/.sqlx/query-b321c5ba22358cbb1fd9c627f1e7b56187686173327498ac75424593547c19c5.json new file mode 100644 index 000000000000..bdd22927d386 --- /dev/null +++ b/core/lib/dal/.sqlx/query-b321c5ba22358cbb1fd9c627f1e7b56187686173327498ac75424593547c19c5.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n attempts\n FROM\n scheduler_witness_jobs_fri\n WHERE\n l1_batch_number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "attempts", + "type_info": "Int2" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "b321c5ba22358cbb1fd9c627f1e7b56187686173327498ac75424593547c19c5" +} diff --git a/core/lib/dal/.sqlx/query-b33e8da69281efe7750043e409d9871731c41cef01da3d6aaf2c53f7b17c47b2.json b/core/lib/dal/.sqlx/query-b33e8da69281efe7750043e409d9871731c41cef01da3d6aaf2c53f7b17c47b2.json new file mode 100644 index 000000000000..1ece82073712 --- /dev/null +++ b/core/lib/dal/.sqlx/query-b33e8da69281efe7750043e409d9871731c41cef01da3d6aaf2c53f7b17c47b2.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n value\n FROM\n storage_logs\n WHERE\n storage_logs.hashed_key = $1\n AND storage_logs.miniblock_number <= $2\n ORDER BY\n storage_logs.miniblock_number DESC,\n storage_logs.operation_number DESC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "value", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Bytea", + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "b33e8da69281efe7750043e409d9871731c41cef01da3d6aaf2c53f7b17c47b2" +} diff --git a/core/lib/dal/.sqlx/query-b367ecb1ebee86ec598c4079591f8c12deeca6b8843fe3869cc2b02b30da5de6.json b/core/lib/dal/.sqlx/query-b367ecb1ebee86ec598c4079591f8c12deeca6b8843fe3869cc2b02b30da5de6.json new file mode 100644 index 000000000000..724c01ea6c53 --- /dev/null +++ b/core/lib/dal/.sqlx/query-b367ecb1ebee86ec598c4079591f8c12deeca6b8843fe3869cc2b02b30da5de6.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n attempts\n FROM\n proof_compression_jobs_fri\n WHERE\n l1_batch_number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "attempts", + "type_info": "Int2" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "b367ecb1ebee86ec598c4079591f8c12deeca6b8843fe3869cc2b02b30da5de6" +} diff --git a/core/lib/dal/.sqlx/query-b3d71dbe14bcd94131b29b64dcb49b6370c211a7fc24ad03a5f0e327f9d18040.json b/core/lib/dal/.sqlx/query-b3d71dbe14bcd94131b29b64dcb49b6370c211a7fc24ad03a5f0e327f9d18040.json new file mode 100644 index 000000000000..0ca284a3f57f --- /dev/null +++ b/core/lib/dal/.sqlx/query-b3d71dbe14bcd94131b29b64dcb49b6370c211a7fc24ad03a5f0e327f9d18040.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n attempts\n FROM\n witness_inputs_fri\n WHERE\n l1_batch_number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "attempts", + "type_info": "Int2" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "b3d71dbe14bcd94131b29b64dcb49b6370c211a7fc24ad03a5f0e327f9d18040" +} diff --git a/core/lib/dal/.sqlx/query-b4304b9afb9f838eee1fe95af5fd964d4bb39b9dcd18fb03bc11ce2fb32b7fb3.json b/core/lib/dal/.sqlx/query-b4304b9afb9f838eee1fe95af5fd964d4bb39b9dcd18fb03bc11ce2fb32b7fb3.json new file mode 100644 index 000000000000..fa6f91edfb32 --- /dev/null +++ b/core/lib/dal/.sqlx/query-b4304b9afb9f838eee1fe95af5fd964d4bb39b9dcd18fb03bc11ce2fb32b7fb3.json @@ -0,0 +1,83 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE scheduler_witness_jobs_fri\n SET\n status = 'in_progress',\n attempts = attempts + 1,\n updated_at = NOW(),\n processing_started_at = NOW(),\n picked_by = $2\n WHERE\n l1_batch_number = (\n SELECT\n l1_batch_number\n FROM\n scheduler_witness_jobs_fri\n WHERE\n status = 'queued'\n AND protocol_version = ANY ($1)\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n scheduler_witness_jobs_fri.*\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "scheduler_partial_input_blob_url", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "status", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "processing_started_at", + "type_info": "Timestamp" + }, + { + "ordinal": 4, + "name": "time_taken", + "type_info": "Time" + }, + { + "ordinal": 5, + "name": "error", + "type_info": "Text" + }, + { + "ordinal": 6, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 7, + "name": "updated_at", + "type_info": "Timestamp" + }, + { + "ordinal": 8, + "name": "attempts", + "type_info": "Int2" + }, + { + "ordinal": 9, + "name": "protocol_version", + "type_info": "Int4" + }, + { + "ordinal": 10, + "name": "picked_by", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Int4Array", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + true, + true, + true, + false, + false, + false, + true, + true + ] + }, + "hash": "b4304b9afb9f838eee1fe95af5fd964d4bb39b9dcd18fb03bc11ce2fb32b7fb3" +} diff --git a/core/lib/dal/.sqlx/query-b452354c888bfc19b5f4012582061b86b1abd915739533f9982fea9d8e21b9e9.json b/core/lib/dal/.sqlx/query-b452354c888bfc19b5f4012582061b86b1abd915739533f9982fea9d8e21b9e9.json new file mode 100644 index 000000000000..e87b9a2cddd6 --- /dev/null +++ b/core/lib/dal/.sqlx/query-b452354c888bfc19b5f4012582061b86b1abd915739533f9982fea9d8e21b9e9.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM factory_deps\n WHERE\n miniblock_number > $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "b452354c888bfc19b5f4012582061b86b1abd915739533f9982fea9d8e21b9e9" +} diff --git a/core/lib/dal/.sqlx/query-b4794e6a0c2366d5d95ab373c310103263af3ff5cb6c9dc5df59d3cd2a5e56b4.json b/core/lib/dal/.sqlx/query-b4794e6a0c2366d5d95ab373c310103263af3ff5cb6c9dc5df59d3cd2a5e56b4.json new file mode 100644 index 000000000000..14b4115b30e8 --- /dev/null +++ b/core/lib/dal/.sqlx/query-b4794e6a0c2366d5d95ab373c310103263af3ff5cb6c9dc5df59d3cd2a5e56b4.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE gpu_prover_queue_fri\n SET\n instance_status = $1,\n updated_at = NOW()\n WHERE\n instance_host = $2::TEXT::inet\n AND instance_port = $3\n AND zone = $4\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text", + "Int4", + "Text" + ] + }, + "nullable": [] + }, + "hash": "b4794e6a0c2366d5d95ab373c310103263af3ff5cb6c9dc5df59d3cd2a5e56b4" +} diff --git a/core/lib/dal/.sqlx/query-b49478150dbc8731c531ef3eddc0c2cfff08e6fef3c3824d20dfdf2d0f73e671.json b/core/lib/dal/.sqlx/query-b49478150dbc8731c531ef3eddc0c2cfff08e6fef3c3824d20dfdf2d0f73e671.json new file mode 100644 index 000000000000..59a4d95f1f22 --- /dev/null +++ b/core/lib/dal/.sqlx/query-b49478150dbc8731c531ef3eddc0c2cfff08e6fef3c3824d20dfdf2d0f73e671.json @@ -0,0 +1,34 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n hash,\n number,\n timestamp\n FROM\n miniblocks\n WHERE\n number > $1\n ORDER BY\n number ASC\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "number", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "timestamp", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "b49478150dbc8731c531ef3eddc0c2cfff08e6fef3c3824d20dfdf2d0f73e671" +} diff --git a/core/lib/dal/.sqlx/query-b4a0444897b60c7061363a48b2b5386a2fd53492f3df05545edbfb0ec0f059d2.json b/core/lib/dal/.sqlx/query-b4a0444897b60c7061363a48b2b5386a2fd53492f3df05545edbfb0ec0f059d2.json new file mode 100644 index 000000000000..804f6c5ac332 --- /dev/null +++ b/core/lib/dal/.sqlx/query-b4a0444897b60c7061363a48b2b5386a2fd53492f3df05545edbfb0ec0f059d2.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE eth_txs\n SET\n confirmed_eth_tx_history_id = $1\n WHERE\n id = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4", + "Int4" + ] + }, + "nullable": [] + }, + "hash": "b4a0444897b60c7061363a48b2b5386a2fd53492f3df05545edbfb0ec0f059d2" +} diff --git a/core/lib/dal/.sqlx/query-b5fd77f515fe168908cc90e44d0697e36b3c2a997038c30553f7727cdfa17361.json b/core/lib/dal/.sqlx/query-b5fd77f515fe168908cc90e44d0697e36b3c2a997038c30553f7727cdfa17361.json new file mode 100644 index 000000000000..b8ba0465614a --- /dev/null +++ b/core/lib/dal/.sqlx/query-b5fd77f515fe168908cc90e44d0697e36b3c2a997038c30553f7727cdfa17361.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE transactions\n SET\n miniblock_number = $1,\n index_in_block = data_table.index_in_block,\n error = NULLIF(data_table.error, ''),\n in_mempool = FALSE,\n execution_info = execution_info || data_table.new_execution_info,\n refunded_gas = data_table.refunded_gas,\n effective_gas_price = data_table.effective_gas_price,\n updated_at = NOW()\n FROM\n (\n SELECT\n UNNEST($2::bytea[]) AS hash,\n UNNEST($3::INTEGER[]) AS index_in_block,\n UNNEST($4::VARCHAR[]) AS error,\n UNNEST($5::jsonb[]) AS new_execution_info,\n UNNEST($6::BIGINT[]) AS refunded_gas,\n UNNEST($7::NUMERIC[]) AS effective_gas_price\n ) AS data_table\n WHERE\n transactions.hash = data_table.hash\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "ByteaArray", + "Int4Array", + "VarcharArray", + "JsonbArray", + "Int8Array", + "NumericArray" + ] + }, + "nullable": [] + }, + "hash": "b5fd77f515fe168908cc90e44d0697e36b3c2a997038c30553f7727cdfa17361" +} diff --git a/core/lib/dal/.sqlx/query-b678edd9f6ea97b8f086566811f651aa072f030c70a5e6de38843a1d9afdf329.json b/core/lib/dal/.sqlx/query-b678edd9f6ea97b8f086566811f651aa072f030c70a5e6de38843a1d9afdf329.json new file mode 100644 index 000000000000..004d970d81ef --- /dev/null +++ b/core/lib/dal/.sqlx/query-b678edd9f6ea97b8f086566811f651aa072f030c70a5e6de38843a1d9afdf329.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n commitments (l1_batch_number, events_queue_commitment, bootloader_initial_content_commitment)\n VALUES\n ($1, $2, $3)\n ON CONFLICT (l1_batch_number) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Bytea", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "b678edd9f6ea97b8f086566811f651aa072f030c70a5e6de38843a1d9afdf329" +} diff --git a/core/lib/dal/.sqlx/query-b6837d2deed935da748339538c2c332a122d0b88271ae0127c65c4612b41a619.json b/core/lib/dal/.sqlx/query-b6837d2deed935da748339538c2c332a122d0b88271ae0127c65c4612b41a619.json new file mode 100644 index 000000000000..acd2d51f6eac --- /dev/null +++ b/core/lib/dal/.sqlx/query-b6837d2deed935da748339538c2c332a122d0b88271ae0127c65c4612b41a619.json @@ -0,0 +1,108 @@ +{ + "db_name": "PostgreSQL", + "query": "\n WITH\n sl AS (\n SELECT DISTINCT\n ON (storage_logs.tx_hash) *\n FROM\n storage_logs\n WHERE\n storage_logs.address = $1\n AND storage_logs.tx_hash = ANY ($3)\n ORDER BY\n storage_logs.tx_hash,\n storage_logs.miniblock_number DESC,\n storage_logs.operation_number DESC\n )\n SELECT\n transactions.hash AS tx_hash,\n transactions.index_in_block AS index_in_block,\n transactions.l1_batch_tx_index AS l1_batch_tx_index,\n transactions.miniblock_number AS \"block_number!\",\n transactions.error AS error,\n transactions.effective_gas_price AS effective_gas_price,\n transactions.initiator_address AS initiator_address,\n transactions.data -> 'to' AS \"transfer_to?\",\n transactions.data -> 'contractAddress' AS \"execute_contract_address?\",\n transactions.tx_format AS \"tx_format?\",\n transactions.refunded_gas AS refunded_gas,\n transactions.gas_limit AS gas_limit,\n miniblocks.hash AS \"block_hash\",\n miniblocks.l1_batch_number AS \"l1_batch_number?\",\n sl.key AS \"contract_address?\"\n FROM\n transactions\n JOIN miniblocks ON miniblocks.number = transactions.miniblock_number\n LEFT JOIN sl ON sl.value != $2\n AND sl.tx_hash = transactions.hash\n WHERE\n transactions.hash = ANY ($3)\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "tx_hash", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "index_in_block", + "type_info": "Int4" + }, + { + "ordinal": 2, + "name": "l1_batch_tx_index", + "type_info": "Int4" + }, + { + "ordinal": 3, + "name": "block_number!", + "type_info": "Int8" + }, + { + "ordinal": 4, + "name": "error", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "effective_gas_price", + "type_info": "Numeric" + }, + { + "ordinal": 6, + "name": "initiator_address", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "transfer_to?", + "type_info": "Jsonb" + }, + { + "ordinal": 8, + "name": "execute_contract_address?", + "type_info": "Jsonb" + }, + { + "ordinal": 9, + "name": "tx_format?", + "type_info": "Int4" + }, + { + "ordinal": 10, + "name": "refunded_gas", + "type_info": "Int8" + }, + { + "ordinal": 11, + "name": "gas_limit", + "type_info": "Numeric" + }, + { + "ordinal": 12, + "name": "block_hash", + "type_info": "Bytea" + }, + { + "ordinal": 13, + "name": "l1_batch_number?", + "type_info": "Int8" + }, + { + "ordinal": 14, + "name": "contract_address?", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Bytea", + "Bytea", + "ByteaArray" + ] + }, + "nullable": [ + false, + true, + true, + true, + true, + true, + false, + null, + null, + true, + false, + true, + false, + true, + true + ] + }, + "hash": "b6837d2deed935da748339538c2c332a122d0b88271ae0127c65c4612b41a619" +} diff --git a/core/lib/dal/.sqlx/query-b75e3d2fecbf5d85e93848b7a35180abbd76956e073432af8d8500327b74e488.json b/core/lib/dal/.sqlx/query-b75e3d2fecbf5d85e93848b7a35180abbd76956e073432af8d8500327b74e488.json new file mode 100644 index 000000000000..91d7b677959a --- /dev/null +++ b/core/lib/dal/.sqlx/query-b75e3d2fecbf5d85e93848b7a35180abbd76956e073432af8d8500327b74e488.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n VERSION\n FROM\n compiler_versions\n WHERE\n compiler = $1\n ORDER BY\n VERSION\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "version", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "b75e3d2fecbf5d85e93848b7a35180abbd76956e073432af8d8500327b74e488" +} diff --git a/core/lib/dal/.sqlx/query-b7bf6999002dd89dc1224468ca79c9a85e3c24fca1bf87905f7fc68fe2ce3276.json b/core/lib/dal/.sqlx/query-b7bf6999002dd89dc1224468ca79c9a85e3c24fca1bf87905f7fc68fe2ce3276.json new file mode 100644 index 000000000000..cb8de87ca641 --- /dev/null +++ b/core/lib/dal/.sqlx/query-b7bf6999002dd89dc1224468ca79c9a85e3c24fca1bf87905f7fc68fe2ce3276.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE transactions\n SET\n l1_batch_number = $3,\n l1_batch_tx_index = data_table.l1_batch_tx_index,\n updated_at = NOW()\n FROM\n (\n SELECT\n UNNEST($1::INT[]) AS l1_batch_tx_index,\n UNNEST($2::bytea[]) AS hash\n ) AS data_table\n WHERE\n transactions.hash = data_table.hash\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4Array", + "ByteaArray", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "b7bf6999002dd89dc1224468ca79c9a85e3c24fca1bf87905f7fc68fe2ce3276" +} diff --git a/core/lib/dal/.sqlx/query-ba2343a38e37d104786f9276d91f67d2ef1428c61ae84003c9b52b03204d1f0a.json b/core/lib/dal/.sqlx/query-ba2343a38e37d104786f9276d91f67d2ef1428c61ae84003c9b52b03204d1f0a.json new file mode 100644 index 000000000000..ff6082651184 --- /dev/null +++ b/core/lib/dal/.sqlx/query-ba2343a38e37d104786f9276d91f67d2ef1428c61ae84003c9b52b03204d1f0a.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM transactions\n WHERE\n in_mempool = TRUE\n AND initiator_address = ANY ($1)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "ByteaArray" + ] + }, + "nullable": [] + }, + "hash": "ba2343a38e37d104786f9276d91f67d2ef1428c61ae84003c9b52b03204d1f0a" +} diff --git a/core/lib/dal/.sqlx/query-bd51c9d93b103292f5acbdb266ba4b4e2af48907fa9321064ddb24ac02ab17cd.json b/core/lib/dal/.sqlx/query-bd51c9d93b103292f5acbdb266ba4b4e2af48907fa9321064ddb24ac02ab17cd.json new file mode 100644 index 000000000000..7f1fc9b176c5 --- /dev/null +++ b/core/lib/dal/.sqlx/query-bd51c9d93b103292f5acbdb266ba4b4e2af48907fa9321064ddb24ac02ab17cd.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n number\n FROM\n l1_batches\n LEFT JOIN eth_txs_history AS commit_tx ON (l1_batches.eth_commit_tx_id = commit_tx.eth_tx_id)\n WHERE\n commit_tx.confirmed_at IS NOT NULL\n ORDER BY\n number DESC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "bd51c9d93b103292f5acbdb266ba4b4e2af48907fa9321064ddb24ac02ab17cd" +} diff --git a/core/lib/dal/.sqlx/query-bd74435dc6dba3f4173858682ee5661d1df4ec053797d75cfd32272be4f485e7.json b/core/lib/dal/.sqlx/query-bd74435dc6dba3f4173858682ee5661d1df4ec053797d75cfd32272be4f485e7.json new file mode 100644 index 000000000000..e2386003538f --- /dev/null +++ b/core/lib/dal/.sqlx/query-bd74435dc6dba3f4173858682ee5661d1df4ec053797d75cfd32272be4f485e7.json @@ -0,0 +1,54 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n storage_logs.key AS \"key!\",\n storage_logs.value AS \"value!\",\n storage_logs.address AS \"address!\",\n storage_logs.miniblock_number AS \"miniblock_number!\",\n initial_writes.l1_batch_number AS \"l1_batch_number!\",\n initial_writes.index\n FROM\n (\n SELECT\n hashed_key,\n MAX(ARRAY[miniblock_number, operation_number]::INT[]) AS op\n FROM\n storage_logs\n WHERE\n miniblock_number <= $1\n AND hashed_key >= $2\n AND hashed_key < $3\n GROUP BY\n hashed_key\n ORDER BY\n hashed_key\n ) AS keys\n INNER JOIN storage_logs ON keys.hashed_key = storage_logs.hashed_key\n AND storage_logs.miniblock_number = keys.op[1]\n AND storage_logs.operation_number = keys.op[2]\n INNER JOIN initial_writes ON keys.hashed_key = initial_writes.hashed_key;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "key!", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "value!", + "type_info": "Bytea" + }, + { + "ordinal": 2, + "name": "address!", + "type_info": "Bytea" + }, + { + "ordinal": 3, + "name": "miniblock_number!", + "type_info": "Int8" + }, + { + "ordinal": 4, + "name": "l1_batch_number!", + "type_info": "Int8" + }, + { + "ordinal": 5, + "name": "index", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8", + "Bytea", + "Bytea" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false + ] + }, + "hash": "bd74435dc6dba3f4173858682ee5661d1df4ec053797d75cfd32272be4f485e7" +} diff --git a/core/lib/dal/.sqlx/query-bfb80956a18eabf266f5b5a9d62912d57f8eb2a38bdb7884fc812a2897a3a660.json b/core/lib/dal/.sqlx/query-bfb80956a18eabf266f5b5a9d62912d57f8eb2a38bdb7884fc812a2897a3a660.json new file mode 100644 index 000000000000..550cb5ec7438 --- /dev/null +++ b/core/lib/dal/.sqlx/query-bfb80956a18eabf266f5b5a9d62912d57f8eb2a38bdb7884fc812a2897a3a660.json @@ -0,0 +1,35 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE witness_inputs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n (\n status = 'in_progress'\n AND processing_started_at <= NOW() - $1::INTERVAL\n AND attempts < $2\n )\n OR (\n status = 'in_gpu_proof'\n AND processing_started_at <= NOW() - $1::INTERVAL\n AND attempts < $2\n )\n OR (\n status = 'failed'\n AND attempts < $2\n )\n RETURNING\n l1_batch_number,\n status,\n attempts\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "status", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "attempts", + "type_info": "Int2" + } + ], + "parameters": { + "Left": [ + "Interval", + "Int2" + ] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "bfb80956a18eabf266f5b5a9d62912d57f8eb2a38bdb7884fc812a2897a3a660" +} diff --git a/core/lib/dal/.sqlx/query-bfc84bcf0985446b337467dd1da709dbee508ad6d1cae43e477cf1bef8cb4aa9.json b/core/lib/dal/.sqlx/query-bfc84bcf0985446b337467dd1da709dbee508ad6d1cae43e477cf1bef8cb4aa9.json new file mode 100644 index 000000000000..8079d52a7036 --- /dev/null +++ b/core/lib/dal/.sqlx/query-bfc84bcf0985446b337467dd1da709dbee508ad6d1cae43e477cf1bef8cb4aa9.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT DISTINCT\n hashed_key\n FROM\n storage_logs\n WHERE\n miniblock_number BETWEEN $1 AND $2\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hashed_key", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8", + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "bfc84bcf0985446b337467dd1da709dbee508ad6d1cae43e477cf1bef8cb4aa9" +} diff --git a/core/lib/dal/.sqlx/query-c03df29f4661fa47c1412bd82ba379f3b2e9ff1bc6e8e38f473fb4950c8e4b77.json b/core/lib/dal/.sqlx/query-c03df29f4661fa47c1412bd82ba379f3b2e9ff1bc6e8e38f473fb4950c8e4b77.json new file mode 100644 index 000000000000..380a98bfabcf --- /dev/null +++ b/core/lib/dal/.sqlx/query-c03df29f4661fa47c1412bd82ba379f3b2e9ff1bc6e8e38f473fb4950c8e4b77.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n COUNT(*) AS \"count!\"\n FROM\n contract_verification_requests\n WHERE\n status = 'queued'\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count!", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "c03df29f4661fa47c1412bd82ba379f3b2e9ff1bc6e8e38f473fb4950c8e4b77" +} diff --git a/core/lib/dal/.sqlx/query-c10cf20825de4d24300c7ec50d4a653852f7e43670076eb2ebcd49542a870539.json b/core/lib/dal/.sqlx/query-c10cf20825de4d24300c7ec50d4a653852f7e43670076eb2ebcd49542a870539.json new file mode 100644 index 000000000000..b341120ad7f3 --- /dev/null +++ b/core/lib/dal/.sqlx/query-c10cf20825de4d24300c7ec50d4a653852f7e43670076eb2ebcd49542a870539.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n scheduler_dependency_tracker_fri (l1_batch_number, status, created_at, updated_at)\n VALUES\n ($1, 'waiting_for_proofs', NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO\n UPDATE\n SET\n updated_at = NOW()\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "c10cf20825de4d24300c7ec50d4a653852f7e43670076eb2ebcd49542a870539" +} diff --git a/core/lib/dal/.sqlx/query-c139df45a977290d1c2c7987fb9c1d66aeaeb6e2d36fddcf96775f01716a8a74.json b/core/lib/dal/.sqlx/query-c139df45a977290d1c2c7987fb9c1d66aeaeb6e2d36fddcf96775f01716a8a74.json new file mode 100644 index 000000000000..b04fb829dd6b --- /dev/null +++ b/core/lib/dal/.sqlx/query-c139df45a977290d1c2c7987fb9c1d66aeaeb6e2d36fddcf96775f01716a8a74.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM storage_logs\n WHERE\n miniblock_number > $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "c139df45a977290d1c2c7987fb9c1d66aeaeb6e2d36fddcf96775f01716a8a74" +} diff --git a/core/lib/dal/.sqlx/query-c14837e92dbb02f2fde7109f524432d865852afe0c60e11a2c1800d30599aa61.json b/core/lib/dal/.sqlx/query-c14837e92dbb02f2fde7109f524432d865852afe0c60e11a2c1800d30599aa61.json new file mode 100644 index 000000000000..8cac9f31ac05 --- /dev/null +++ b/core/lib/dal/.sqlx/query-c14837e92dbb02f2fde7109f524432d865852afe0c60e11a2c1800d30599aa61.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM compiler_versions\n WHERE\n compiler = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [] + }, + "hash": "c14837e92dbb02f2fde7109f524432d865852afe0c60e11a2c1800d30599aa61" +} diff --git a/core/lib/dal/.sqlx/query-c192377c08abab9306c5b0844368aa0f8525832cb4075e831c0d4b23c5675b99.json b/core/lib/dal/.sqlx/query-c192377c08abab9306c5b0844368aa0f8525832cb4075e831c0d4b23c5675b99.json new file mode 100644 index 000000000000..58c336bb8328 --- /dev/null +++ b/core/lib/dal/.sqlx/query-c192377c08abab9306c5b0844368aa0f8525832cb4075e831c0d4b23c5675b99.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n bytecode\n FROM\n (\n SELECT\n *\n FROM\n storage_logs\n WHERE\n storage_logs.hashed_key = $1\n AND storage_logs.miniblock_number <= $2\n ORDER BY\n storage_logs.miniblock_number DESC,\n storage_logs.operation_number DESC\n LIMIT\n 1\n ) t\n JOIN factory_deps ON value = factory_deps.bytecode_hash\n WHERE\n value != $3\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "bytecode", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Bytea", + "Int8", + "Bytea" + ] + }, + "nullable": [ + false + ] + }, + "hash": "c192377c08abab9306c5b0844368aa0f8525832cb4075e831c0d4b23c5675b99" +} diff --git a/core/lib/dal/.sqlx/query-c195037dcf6031a90f407f652657956350786f3596c7302bdeb8d813f9fbf621.json b/core/lib/dal/.sqlx/query-c195037dcf6031a90f407f652657956350786f3596c7302bdeb8d813f9fbf621.json new file mode 100644 index 000000000000..0b8a91d7bc8b --- /dev/null +++ b/core/lib/dal/.sqlx/query-c195037dcf6031a90f407f652657956350786f3596c7302bdeb8d813f9fbf621.json @@ -0,0 +1,106 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n number,\n l1_tx_count,\n l2_tx_count,\n timestamp,\n l2_to_l1_logs,\n l2_to_l1_messages,\n bloom,\n priority_ops_onchain_data,\n used_contract_hashes,\n bootloader_code_hash,\n default_aa_code_hash,\n protocol_version,\n system_logs,\n compressed_state_diffs,\n pubdata_input\n FROM\n l1_batches\n WHERE\n eth_commit_tx_id = $1\n OR eth_prove_tx_id = $1\n OR eth_execute_tx_id = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "l1_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 2, + "name": "l2_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 3, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 4, + "name": "l2_to_l1_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 5, + "name": "l2_to_l1_messages", + "type_info": "ByteaArray" + }, + { + "ordinal": 6, + "name": "bloom", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "priority_ops_onchain_data", + "type_info": "ByteaArray" + }, + { + "ordinal": 8, + "name": "used_contract_hashes", + "type_info": "Jsonb" + }, + { + "ordinal": 9, + "name": "bootloader_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 10, + "name": "default_aa_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 11, + "name": "protocol_version", + "type_info": "Int4" + }, + { + "ordinal": 12, + "name": "system_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 13, + "name": "compressed_state_diffs", + "type_info": "Bytea" + }, + { + "ordinal": 14, + "name": "pubdata_input", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + false, + true, + true + ] + }, + "hash": "c195037dcf6031a90f407f652657956350786f3596c7302bdeb8d813f9fbf621" +} diff --git a/core/lib/dal/.sqlx/query-c23d5ff919ade5898c6a912780ae899e360650afccb34f5cc301b5cbac4a3d36.json b/core/lib/dal/.sqlx/query-c23d5ff919ade5898c6a912780ae899e360650afccb34f5cc301b5cbac4a3d36.json new file mode 100644 index 000000000000..8922816c7e15 --- /dev/null +++ b/core/lib/dal/.sqlx/query-c23d5ff919ade5898c6a912780ae899e360650afccb34f5cc301b5cbac4a3d36.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE prover_jobs_fri\n SET\n status = $1,\n updated_at = NOW()\n WHERE\n id = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "c23d5ff919ade5898c6a912780ae899e360650afccb34f5cc301b5cbac4a3d36" +} diff --git a/core/lib/dal/.sqlx/query-c2fe6a5476e69c9588eec73baba9d0e2d571533d4d5f683919987b6f8cbb00e0.json b/core/lib/dal/.sqlx/query-c2fe6a5476e69c9588eec73baba9d0e2d571533d4d5f683919987b6f8cbb00e0.json new file mode 100644 index 000000000000..bdabc52d1379 --- /dev/null +++ b/core/lib/dal/.sqlx/query-c2fe6a5476e69c9588eec73baba9d0e2d571533d4d5f683919987b6f8cbb00e0.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n miniblocks_consensus (number, certificate)\n VALUES\n ($1, $2)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Jsonb" + ] + }, + "nullable": [] + }, + "hash": "c2fe6a5476e69c9588eec73baba9d0e2d571533d4d5f683919987b6f8cbb00e0" +} diff --git a/core/lib/dal/.sqlx/query-c36abacc705a2244d423599779e38d60d6e93bcb34fd20422e227714fccbf6b7.json b/core/lib/dal/.sqlx/query-c36abacc705a2244d423599779e38d60d6e93bcb34fd20422e227714fccbf6b7.json new file mode 100644 index 000000000000..ea4b266d8259 --- /dev/null +++ b/core/lib/dal/.sqlx/query-c36abacc705a2244d423599779e38d60d6e93bcb34fd20422e227714fccbf6b7.json @@ -0,0 +1,34 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n address,\n key,\n value\n FROM\n storage_logs\n WHERE\n miniblock_number BETWEEN (\n SELECT\n MIN(number)\n FROM\n miniblocks\n WHERE\n l1_batch_number = $1\n ) AND (\n SELECT\n MAX(number)\n FROM\n miniblocks\n WHERE\n l1_batch_number = $1\n )\n ORDER BY\n miniblock_number,\n operation_number\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "address", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "key", + "type_info": "Bytea" + }, + { + "ordinal": 2, + "name": "value", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "c36abacc705a2244d423599779e38d60d6e93bcb34fd20422e227714fccbf6b7" +} diff --git a/core/lib/dal/.sqlx/query-c37432fabd092fa235fc70e11430fb28594859564a0f888eae748ad1f9fcede5.json b/core/lib/dal/.sqlx/query-c37432fabd092fa235fc70e11430fb28594859564a0f888eae748ad1f9fcede5.json new file mode 100644 index 000000000000..906cd1081403 --- /dev/null +++ b/core/lib/dal/.sqlx/query-c37432fabd092fa235fc70e11430fb28594859564a0f888eae748ad1f9fcede5.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n call_trace\n FROM\n call_traces\n INNER JOIN transactions ON tx_hash = transactions.hash\n WHERE\n transactions.miniblock_number = $1\n ORDER BY\n transactions.index_in_block\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "call_trace", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "c37432fabd092fa235fc70e11430fb28594859564a0f888eae748ad1f9fcede5" +} diff --git a/core/lib/dal/.sqlx/query-c41312e01aa66897552e8be9acc8d43c31ec7441a7f6c5040e120810ebbb72f7.json b/core/lib/dal/.sqlx/query-c41312e01aa66897552e8be9acc8d43c31ec7441a7f6c5040e120810ebbb72f7.json new file mode 100644 index 000000000000..4c24afad4f4c --- /dev/null +++ b/core/lib/dal/.sqlx/query-c41312e01aa66897552e8be9acc8d43c31ec7441a7f6c5040e120810ebbb72f7.json @@ -0,0 +1,21 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n prover_jobs_fri (\n l1_batch_number,\n circuit_id,\n circuit_blob_url,\n aggregation_round,\n sequence_number,\n depth,\n is_node_final_proof,\n protocol_version,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, $8, 'queued', NOW(), NOW())\n ON CONFLICT (l1_batch_number, aggregation_round, circuit_id, depth, sequence_number) DO\n UPDATE\n SET\n updated_at = NOW()\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Int2", + "Text", + "Int2", + "Int4", + "Int4", + "Bool", + "Int4" + ] + }, + "nullable": [] + }, + "hash": "c41312e01aa66897552e8be9acc8d43c31ec7441a7f6c5040e120810ebbb72f7" +} diff --git a/core/lib/dal/.sqlx/query-c4426ae84862e720673485e3b59c116162becce06841476128f864b6028129df.json b/core/lib/dal/.sqlx/query-c4426ae84862e720673485e3b59c116162becce06841476128f864b6028129df.json new file mode 100644 index 000000000000..4b69afd7e9cd --- /dev/null +++ b/core/lib/dal/.sqlx/query-c4426ae84862e720673485e3b59c116162becce06841476128f864b6028129df.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE miniblocks\n SET\n fee_account_address = (\n SELECT\n l1_batches.fee_account_address\n FROM\n l1_batches\n ORDER BY\n l1_batches.number DESC\n LIMIT\n 1\n )\n WHERE\n l1_batch_number IS NULL\n AND fee_account_address = '\\x0000000000000000000000000000000000000000'::bytea\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "c4426ae84862e720673485e3b59c116162becce06841476128f864b6028129df" +} diff --git a/core/lib/dal/.sqlx/query-c4ea7812861a283448095acbb1164420a25eef488de2b67e91ed39657667bd4a.json b/core/lib/dal/.sqlx/query-c4ea7812861a283448095acbb1164420a25eef488de2b67e91ed39657667bd4a.json new file mode 100644 index 000000000000..6a74606e484f --- /dev/null +++ b/core/lib/dal/.sqlx/query-c4ea7812861a283448095acbb1164420a25eef488de2b67e91ed39657667bd4a.json @@ -0,0 +1,26 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_address,\n l2_address\n FROM\n tokens\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_address", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "l2_address", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false + ] + }, + "hash": "c4ea7812861a283448095acbb1164420a25eef488de2b67e91ed39657667bd4a" +} diff --git a/core/lib/dal/.sqlx/query-c5656667e5610ffb33e7b977ac92b7c4d79cbd404e0267794ec203df0cbb169d.json b/core/lib/dal/.sqlx/query-c5656667e5610ffb33e7b977ac92b7c4d79cbd404e0267794ec203df0cbb169d.json new file mode 100644 index 000000000000..34bff9031943 --- /dev/null +++ b/core/lib/dal/.sqlx/query-c5656667e5610ffb33e7b977ac92b7c4d79cbd404e0267794ec203df0cbb169d.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n COALESCE(MAX(number), 0) AS \"number!\"\n FROM\n l1_batches\n WHERE\n eth_prove_tx_id IS NOT NULL\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number!", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "c5656667e5610ffb33e7b977ac92b7c4d79cbd404e0267794ec203df0cbb169d" +} diff --git a/core/lib/dal/.sqlx/query-c5d6e1d5d834409bd793c8ce1fb2c212918b31dabebf08a84efdfe1feee85765.json b/core/lib/dal/.sqlx/query-c5d6e1d5d834409bd793c8ce1fb2c212918b31dabebf08a84efdfe1feee85765.json new file mode 100644 index 000000000000..6c16372b82d2 --- /dev/null +++ b/core/lib/dal/.sqlx/query-c5d6e1d5d834409bd793c8ce1fb2c212918b31dabebf08a84efdfe1feee85765.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE scheduler_dependency_tracker_fri\n SET\n status = 'queuing'\n WHERE\n l1_batch_number IN (\n SELECT\n l1_batch_number\n FROM\n scheduler_dependency_tracker_fri\n WHERE\n status != 'queued'\n AND circuit_1_final_prover_job_id IS NOT NULL\n AND circuit_2_final_prover_job_id IS NOT NULL\n AND circuit_3_final_prover_job_id IS NOT NULL\n AND circuit_4_final_prover_job_id IS NOT NULL\n AND circuit_5_final_prover_job_id IS NOT NULL\n AND circuit_6_final_prover_job_id IS NOT NULL\n AND circuit_7_final_prover_job_id IS NOT NULL\n AND circuit_8_final_prover_job_id IS NOT NULL\n AND circuit_9_final_prover_job_id IS NOT NULL\n AND circuit_10_final_prover_job_id IS NOT NULL\n AND circuit_11_final_prover_job_id IS NOT NULL\n AND circuit_12_final_prover_job_id IS NOT NULL\n AND circuit_13_final_prover_job_id IS NOT NULL\n )\n RETURNING\n l1_batch_number;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "c5d6e1d5d834409bd793c8ce1fb2c212918b31dabebf08a84efdfe1feee85765" +} diff --git a/core/lib/dal/.sqlx/query-c6d523c6ae857022318350a2f210d7eaeeb4549ed59b58f8d984be2a22a80355.json b/core/lib/dal/.sqlx/query-c6d523c6ae857022318350a2f210d7eaeeb4549ed59b58f8d984be2a22a80355.json new file mode 100644 index 000000000000..ebae1f42fbbb --- /dev/null +++ b/core/lib/dal/.sqlx/query-c6d523c6ae857022318350a2f210d7eaeeb4549ed59b58f8d984be2a22a80355.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n MAX(l1_batches.number)\n FROM\n l1_batches\n JOIN eth_txs ON (l1_batches.eth_commit_tx_id = eth_txs.id)\n JOIN eth_txs_history AS commit_tx ON (eth_txs.confirmed_eth_tx_history_id = commit_tx.id)\n WHERE\n commit_tx.confirmed_at IS NOT NULL\n AND eth_prove_tx_id IS NOT NULL\n AND eth_execute_tx_id IS NULL\n AND EXTRACT(\n epoch\n FROM\n commit_tx.confirmed_at\n ) < $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "max", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Numeric" + ] + }, + "nullable": [ + null + ] + }, + "hash": "c6d523c6ae857022318350a2f210d7eaeeb4549ed59b58f8d984be2a22a80355" +} diff --git a/core/lib/dal/.sqlx/query-c706a49ff54f6b424e24d061fe7ac429aac3c030f7e226a1264243d8cdae038d.json b/core/lib/dal/.sqlx/query-c706a49ff54f6b424e24d061fe7ac429aac3c030f7e226a1264243d8cdae038d.json new file mode 100644 index 000000000000..95ae04bed503 --- /dev/null +++ b/core/lib/dal/.sqlx/query-c706a49ff54f6b424e24d061fe7ac429aac3c030f7e226a1264243d8cdae038d.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE proof_compression_jobs_fri\n SET\n status = $1,\n updated_at = NOW(),\n time_taken = $2,\n l1_proof_blob_url = $3\n WHERE\n l1_batch_number = $4\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Time", + "Text", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "c706a49ff54f6b424e24d061fe7ac429aac3c030f7e226a1264243d8cdae038d" +} diff --git a/core/lib/dal/.sqlx/query-c809f42a221b18a767e9dd0286503d8bd356f2f9cc249cd8b90caa5a8b5918e3.json b/core/lib/dal/.sqlx/query-c809f42a221b18a767e9dd0286503d8bd356f2f9cc249cd8b90caa5a8b5918e3.json new file mode 100644 index 000000000000..b85f4c542bf8 --- /dev/null +++ b/core/lib/dal/.sqlx/query-c809f42a221b18a767e9dd0286503d8bd356f2f9cc249cd8b90caa5a8b5918e3.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n COUNT(*) AS \"count!\"\n FROM\n (\n SELECT\n *\n FROM\n storage_logs\n WHERE\n storage_logs.hashed_key = $1\n ORDER BY\n storage_logs.miniblock_number DESC,\n storage_logs.operation_number DESC\n LIMIT\n 1\n ) sl\n WHERE\n sl.value != $2\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count!", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Bytea", + "Bytea" + ] + }, + "nullable": [ + null + ] + }, + "hash": "c809f42a221b18a767e9dd0286503d8bd356f2f9cc249cd8b90caa5a8b5918e3" +} diff --git a/core/lib/dal/.sqlx/query-c8155c4e4701fc771918ac1bb4d16f8cc32e365e2ffbd17dc99885de427f2777.json b/core/lib/dal/.sqlx/query-c8155c4e4701fc771918ac1bb4d16f8cc32e365e2ffbd17dc99885de427f2777.json new file mode 100644 index 000000000000..78582f6242b4 --- /dev/null +++ b/core/lib/dal/.sqlx/query-c8155c4e4701fc771918ac1bb4d16f8cc32e365e2ffbd17dc99885de427f2777.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n timestamp\n FROM\n miniblocks\n WHERE\n l1_batch_number = $1\n ORDER BY\n number\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "timestamp", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "c8155c4e4701fc771918ac1bb4d16f8cc32e365e2ffbd17dc99885de427f2777" +} diff --git a/core/lib/dal/.sqlx/query-c9e05ebc7b61c1f409c330bc110bed26c831730944237b74bed98869c83b3ca5.json b/core/lib/dal/.sqlx/query-c9e05ebc7b61c1f409c330bc110bed26c831730944237b74bed98869c83b3ca5.json new file mode 100644 index 000000000000..433564c6ae05 --- /dev/null +++ b/core/lib/dal/.sqlx/query-c9e05ebc7b61c1f409c330bc110bed26c831730944237b74bed98869c83b3ca5.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n (\n SELECT\n l1_batch_number\n FROM\n miniblocks\n WHERE\n number = $1\n ) AS \"block_batch?\",\n COALESCE(\n (\n SELECT\n MAX(number) + 1\n FROM\n l1_batches\n ),\n (\n SELECT\n MAX(l1_batch_number) + 1\n FROM\n snapshot_recovery\n ),\n 0\n ) AS \"pending_batch!\"\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "block_batch?", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "pending_batch!", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + null, + null + ] + }, + "hash": "c9e05ebc7b61c1f409c330bc110bed26c831730944237b74bed98869c83b3ca5" +} diff --git a/core/lib/dal/.sqlx/query-ca9d06141265b8524ee28c55569cb21a635037d89ce24dd3ad58ffaadb59594a.json b/core/lib/dal/.sqlx/query-ca9d06141265b8524ee28c55569cb21a635037d89ce24dd3ad58ffaadb59594a.json new file mode 100644 index 000000000000..ff49f615ab50 --- /dev/null +++ b/core/lib/dal/.sqlx/query-ca9d06141265b8524ee28c55569cb21a635037d89ce24dd3ad58ffaadb59594a.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_number\n FROM\n proof_compression_jobs_fri\n WHERE\n status <> 'successful'\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "ca9d06141265b8524ee28c55569cb21a635037d89ce24dd3ad58ffaadb59594a" +} diff --git a/core/lib/dal/.sqlx/query-cb98d84fc34af1e4a4c2f427c5bb4afd384063ae394a847b26304dd18d490ab4.json b/core/lib/dal/.sqlx/query-cb98d84fc34af1e4a4c2f427c5bb4afd384063ae394a847b26304dd18d490ab4.json new file mode 100644 index 000000000000..732992595c73 --- /dev/null +++ b/core/lib/dal/.sqlx/query-cb98d84fc34af1e4a4c2f427c5bb4afd384063ae394a847b26304dd18d490ab4.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n timestamp,\n hash\n FROM\n l1_batches\n WHERE\n number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "hash", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + true + ] + }, + "hash": "cb98d84fc34af1e4a4c2f427c5bb4afd384063ae394a847b26304dd18d490ab4" +} diff --git a/core/lib/dal/.sqlx/query-ce5779092feb8a3d3e2c5e395783e67f08f2ead5f55bfb6594e50346bf9cf2ef.json b/core/lib/dal/.sqlx/query-ce5779092feb8a3d3e2c5e395783e67f08f2ead5f55bfb6594e50346bf9cf2ef.json new file mode 100644 index 000000000000..6f83fd55064d --- /dev/null +++ b/core/lib/dal/.sqlx/query-ce5779092feb8a3d3e2c5e395783e67f08f2ead5f55bfb6594e50346bf9cf2ef.json @@ -0,0 +1,32 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n MIN(l1_batch_number) AS \"l1_batch_number!\",\n circuit_id,\n aggregation_round\n FROM\n prover_jobs_fri\n WHERE\n status IN ('queued', 'in_gpu_proof', 'in_progress', 'failed')\n GROUP BY\n circuit_id,\n aggregation_round\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number!", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "circuit_id", + "type_info": "Int2" + }, + { + "ordinal": 2, + "name": "aggregation_round", + "type_info": "Int2" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null, + false, + false + ] + }, + "hash": "ce5779092feb8a3d3e2c5e395783e67f08f2ead5f55bfb6594e50346bf9cf2ef" +} diff --git a/core/lib/dal/.sqlx/query-cea366a9d0da60bf03c71be26862929e051270056ebf113a657a464f89c7fd57.json b/core/lib/dal/.sqlx/query-cea366a9d0da60bf03c71be26862929e051270056ebf113a657a464f89c7fd57.json new file mode 100644 index 000000000000..da21c126347f --- /dev/null +++ b/core/lib/dal/.sqlx/query-cea366a9d0da60bf03c71be26862929e051270056ebf113a657a464f89c7fd57.json @@ -0,0 +1,33 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n l1_batches (\n number,\n l1_tx_count,\n l2_tx_count,\n timestamp,\n l2_to_l1_logs,\n l2_to_l1_messages,\n bloom,\n priority_ops_onchain_data,\n predicted_commit_gas_cost,\n predicted_prove_gas_cost,\n predicted_execute_gas_cost,\n initial_bootloader_heap_content,\n used_contract_hashes,\n bootloader_code_hash,\n default_aa_code_hash,\n protocol_version,\n system_logs,\n storage_refunds,\n pubdata_input,\n predicted_circuits_by_type,\n created_at,\n updated_at\n )\n VALUES\n (\n $1,\n $2,\n $3,\n $4,\n $5,\n $6,\n $7,\n $8,\n $9,\n $10,\n $11,\n $12,\n $13,\n $14,\n $15,\n $16,\n $17,\n $18,\n $19,\n $20,\n NOW(),\n NOW()\n )\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Int4", + "Int4", + "Int8", + "ByteaArray", + "ByteaArray", + "Bytea", + "ByteaArray", + "Int8", + "Int8", + "Int8", + "Jsonb", + "Jsonb", + "Bytea", + "Bytea", + "Int4", + "ByteaArray", + "Int8Array", + "Bytea", + "Jsonb" + ] + }, + "nullable": [] + }, + "hash": "cea366a9d0da60bf03c71be26862929e051270056ebf113a657a464f89c7fd57" +} diff --git a/core/lib/dal/.sqlx/query-cea9fe027a6a0ada827f23b48ac32432295b2f7ee40bf13522a6edbd236f1970.json b/core/lib/dal/.sqlx/query-cea9fe027a6a0ada827f23b48ac32432295b2f7ee40bf13522a6edbd236f1970.json new file mode 100644 index 000000000000..b1eae968a897 --- /dev/null +++ b/core/lib/dal/.sqlx/query-cea9fe027a6a0ada827f23b48ac32432295b2f7ee40bf13522a6edbd236f1970.json @@ -0,0 +1,29 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n u.hashed_key AS \"hashed_key!\",\n (\n SELECT\n value\n FROM\n storage_logs\n WHERE\n hashed_key = u.hashed_key\n AND miniblock_number <= $2\n ORDER BY\n miniblock_number DESC,\n operation_number DESC\n LIMIT\n 1\n ) AS \"value?\"\n FROM\n UNNEST($1::bytea[]) AS u (hashed_key)\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hashed_key!", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "value?", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "ByteaArray", + "Int8" + ] + }, + "nullable": [ + null, + null + ] + }, + "hash": "cea9fe027a6a0ada827f23b48ac32432295b2f7ee40bf13522a6edbd236f1970" +} diff --git a/core/lib/dal/.sqlx/query-d14b52df2cd9f9e484c60ba00383b438f14b68535111cf2cedd363fc646aac99.json b/core/lib/dal/.sqlx/query-d14b52df2cd9f9e484c60ba00383b438f14b68535111cf2cedd363fc646aac99.json new file mode 100644 index 000000000000..0370a63d65e3 --- /dev/null +++ b/core/lib/dal/.sqlx/query-d14b52df2cd9f9e484c60ba00383b438f14b68535111cf2cedd363fc646aac99.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n timestamp\n FROM\n l1_batches\n WHERE\n eth_commit_tx_id IS NULL\n AND number > 0\n ORDER BY\n number\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "timestamp", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "d14b52df2cd9f9e484c60ba00383b438f14b68535111cf2cedd363fc646aac99" +} diff --git a/core/lib/dal/.sqlx/query-d3b09cbcddf6238b358d32d57678242aad3e9a47400f6d6837a35f4c54a216b9.json b/core/lib/dal/.sqlx/query-d3b09cbcddf6238b358d32d57678242aad3e9a47400f6d6837a35f4c54a216b9.json new file mode 100644 index 000000000000..8770a9b596ea --- /dev/null +++ b/core/lib/dal/.sqlx/query-d3b09cbcddf6238b358d32d57678242aad3e9a47400f6d6837a35f4c54a216b9.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n number\n FROM\n l1_batches\n LEFT JOIN eth_txs_history AS execute_tx ON (l1_batches.eth_execute_tx_id = execute_tx.eth_tx_id)\n WHERE\n execute_tx.confirmed_at IS NOT NULL\n ORDER BY\n number DESC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "d3b09cbcddf6238b358d32d57678242aad3e9a47400f6d6837a35f4c54a216b9" +} diff --git a/core/lib/dal/.sqlx/query-d70cfc158e31dd2d5c942d24f81fd17f833fb15b58b0110c7cc566946db98e76.json b/core/lib/dal/.sqlx/query-d70cfc158e31dd2d5c942d24f81fd17f833fb15b58b0110c7cc566946db98e76.json new file mode 100644 index 000000000000..bff9c151373f --- /dev/null +++ b/core/lib/dal/.sqlx/query-d70cfc158e31dd2d5c942d24f81fd17f833fb15b58b0110c7cc566946db98e76.json @@ -0,0 +1,94 @@ +{ + "db_name": "PostgreSQL", + "query": "\n WITH\n events_select AS (\n SELECT\n address,\n topic1,\n topic2,\n topic3,\n topic4,\n value,\n miniblock_number,\n tx_hash,\n tx_index_in_block,\n event_index_in_block,\n event_index_in_tx\n FROM\n events\n WHERE\n miniblock_number > $1\n ORDER BY\n miniblock_number ASC,\n event_index_in_block ASC\n )\n SELECT\n miniblocks.hash AS \"block_hash?\",\n address AS \"address!\",\n topic1 AS \"topic1!\",\n topic2 AS \"topic2!\",\n topic3 AS \"topic3!\",\n topic4 AS \"topic4!\",\n value AS \"value!\",\n miniblock_number AS \"miniblock_number!\",\n miniblocks.l1_batch_number AS \"l1_batch_number?\",\n tx_hash AS \"tx_hash!\",\n tx_index_in_block AS \"tx_index_in_block!\",\n event_index_in_block AS \"event_index_in_block!\",\n event_index_in_tx AS \"event_index_in_tx!\"\n FROM\n events_select\n INNER JOIN miniblocks ON events_select.miniblock_number = miniblocks.number\n ORDER BY\n miniblock_number ASC,\n event_index_in_block ASC\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "block_hash?", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "address!", + "type_info": "Bytea" + }, + { + "ordinal": 2, + "name": "topic1!", + "type_info": "Bytea" + }, + { + "ordinal": 3, + "name": "topic2!", + "type_info": "Bytea" + }, + { + "ordinal": 4, + "name": "topic3!", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "topic4!", + "type_info": "Bytea" + }, + { + "ordinal": 6, + "name": "value!", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "miniblock_number!", + "type_info": "Int8" + }, + { + "ordinal": 8, + "name": "l1_batch_number?", + "type_info": "Int8" + }, + { + "ordinal": 9, + "name": "tx_hash!", + "type_info": "Bytea" + }, + { + "ordinal": 10, + "name": "tx_index_in_block!", + "type_info": "Int4" + }, + { + "ordinal": 11, + "name": "event_index_in_block!", + "type_info": "Int4" + }, + { + "ordinal": 12, + "name": "event_index_in_tx!", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false + ] + }, + "hash": "d70cfc158e31dd2d5c942d24f81fd17f833fb15b58b0110c7cc566946db98e76" +} diff --git a/core/lib/dal/.sqlx/query-d712707e47e143c52330ea6e0513d2839f0f928c06b8020eecec38e895f99b42.json b/core/lib/dal/.sqlx/query-d712707e47e143c52330ea6e0513d2839f0f928c06b8020eecec38e895f99b42.json new file mode 100644 index 000000000000..362a4a9b83da --- /dev/null +++ b/core/lib/dal/.sqlx/query-d712707e47e143c52330ea6e0513d2839f0f928c06b8020eecec38e895f99b42.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n address,\n key\n FROM\n protective_reads\n WHERE\n l1_batch_number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "address", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "key", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "d712707e47e143c52330ea6e0513d2839f0f928c06b8020eecec38e895f99b42" +} diff --git a/core/lib/dal/.sqlx/query-d7e8eabd7b43ff62838fbc847e4813d2b2d411bd5faf8306cd48db500532b711.json b/core/lib/dal/.sqlx/query-d7e8eabd7b43ff62838fbc847e4813d2b2d411bd5faf8306cd48db500532b711.json new file mode 100644 index 000000000000..a049d76c24b7 --- /dev/null +++ b/core/lib/dal/.sqlx/query-d7e8eabd7b43ff62838fbc847e4813d2b2d411bd5faf8306cd48db500532b711.json @@ -0,0 +1,29 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_number,\n status\n FROM\n proof_compression_jobs_fri\n WHERE\n l1_batch_number = (\n SELECT\n MIN(l1_batch_number)\n FROM\n proof_compression_jobs_fri\n WHERE\n status = $1\n OR status = $2\n )\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "status", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "d7e8eabd7b43ff62838fbc847e4813d2b2d411bd5faf8306cd48db500532b711" +} diff --git a/core/lib/dal/.sqlx/query-d7ed82f0d012f72374edb2ebcec33c83477d65a6f8cb2673f67b3148cd95b436.json b/core/lib/dal/.sqlx/query-d7ed82f0d012f72374edb2ebcec33c83477d65a6f8cb2673f67b3148cd95b436.json new file mode 100644 index 000000000000..c415e3d33ce4 --- /dev/null +++ b/core/lib/dal/.sqlx/query-d7ed82f0d012f72374edb2ebcec33c83477d65a6f8cb2673f67b3148cd95b436.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n COUNT(*)\n FROM\n eth_txs\n WHERE\n has_failed = TRUE\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "d7ed82f0d012f72374edb2ebcec33c83477d65a6f8cb2673f67b3148cd95b436" +} diff --git a/core/lib/dal/.sqlx/query-d8e3ee346375e4b6a8b2c73a3827e88abd0f8164c2413dc83c91c29665ca645e.json b/core/lib/dal/.sqlx/query-d8e3ee346375e4b6a8b2c73a3827e88abd0f8164c2413dc83c91c29665ca645e.json new file mode 100644 index 000000000000..ae7bcea1882f --- /dev/null +++ b/core/lib/dal/.sqlx/query-d8e3ee346375e4b6a8b2c73a3827e88abd0f8164c2413dc83c91c29665ca645e.json @@ -0,0 +1,35 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE leaf_aggregation_witness_jobs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n (\n status = 'in_progress'\n AND processing_started_at <= NOW() - $1::INTERVAL\n AND attempts < $2\n )\n OR (\n status = 'failed'\n AND attempts < $2\n )\n RETURNING\n id,\n status,\n attempts\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "status", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "attempts", + "type_info": "Int2" + } + ], + "parameters": { + "Left": [ + "Interval", + "Int2" + ] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "d8e3ee346375e4b6a8b2c73a3827e88abd0f8164c2413dc83c91c29665ca645e" +} diff --git a/core/lib/dal/.sqlx/query-da51a5220c2b964303292592c34e8ee5e54b170de9da863bbdbc79e3f206640b.json b/core/lib/dal/.sqlx/query-da51a5220c2b964303292592c34e8ee5e54b170de9da863bbdbc79e3f206640b.json new file mode 100644 index 000000000000..9c24f8706454 --- /dev/null +++ b/core/lib/dal/.sqlx/query-da51a5220c2b964303292592c34e8ee5e54b170de9da863bbdbc79e3f206640b.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM storage\n WHERE\n hashed_key = ANY ($1)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "ByteaArray" + ] + }, + "nullable": [] + }, + "hash": "da51a5220c2b964303292592c34e8ee5e54b170de9da863bbdbc79e3f206640b" +} diff --git a/core/lib/dal/.sqlx/query-db3e74f0e83ffbf84a6d61e560f2060fbea775dc185f639139fbfd23e4d5f3c6.json b/core/lib/dal/.sqlx/query-db3e74f0e83ffbf84a6d61e560f2060fbea775dc185f639139fbfd23e4d5f3c6.json new file mode 100644 index 000000000000..d9f7527dfa00 --- /dev/null +++ b/core/lib/dal/.sqlx/query-db3e74f0e83ffbf84a6d61e560f2060fbea775dc185f639139fbfd23e4d5f3c6.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE node_aggregation_witness_jobs_fri\n SET\n status = 'successful',\n updated_at = NOW(),\n time_taken = $1\n WHERE\n id = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Time", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "db3e74f0e83ffbf84a6d61e560f2060fbea775dc185f639139fbfd23e4d5f3c6" +} diff --git a/core/lib/dal/.sqlx/query-dc16d0fac093a52480b66dfcb5976fb01e6629e8c982c265f2af1d5000090572.json b/core/lib/dal/.sqlx/query-dc16d0fac093a52480b66dfcb5976fb01e6629e8c982c265f2af1d5000090572.json new file mode 100644 index 000000000000..9669622f5cf2 --- /dev/null +++ b/core/lib/dal/.sqlx/query-dc16d0fac093a52480b66dfcb5976fb01e6629e8c982c265f2af1d5000090572.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT COUNT(miniblocks.number) FROM miniblocks WHERE l1_batch_number IS NULL", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "dc16d0fac093a52480b66dfcb5976fb01e6629e8c982c265f2af1d5000090572" +} diff --git a/core/lib/dal/.sqlx/query-dc481f59aae632ff6f5fa23f5c5c82627a936f7ea9f6c354eca4bea76fac6b10.json b/core/lib/dal/.sqlx/query-dc481f59aae632ff6f5fa23f5c5c82627a936f7ea9f6c354eca4bea76fac6b10.json new file mode 100644 index 000000000000..77263c2a4dd7 --- /dev/null +++ b/core/lib/dal/.sqlx/query-dc481f59aae632ff6f5fa23f5c5c82627a936f7ea9f6c354eca4bea76fac6b10.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n MAX(number) AS \"number\"\n FROM\n l1_batches\n WHERE\n hash IS NOT NULL\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "dc481f59aae632ff6f5fa23f5c5c82627a936f7ea9f6c354eca4bea76fac6b10" +} diff --git a/core/lib/dal/.sqlx/query-dc764e1636c4e958753c1fd54562e2ca92fdfdf01cfd0b11f5ce24f0458a5e48.json b/core/lib/dal/.sqlx/query-dc764e1636c4e958753c1fd54562e2ca92fdfdf01cfd0b11f5ce24f0458a5e48.json new file mode 100644 index 000000000000..b7320d0c3bb2 --- /dev/null +++ b/core/lib/dal/.sqlx/query-dc764e1636c4e958753c1fd54562e2ca92fdfdf01cfd0b11f5ce24f0458a5e48.json @@ -0,0 +1,26 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE l1_batches\n SET\n hash = $1,\n merkle_root_hash = $2,\n compressed_repeated_writes = $3,\n compressed_initial_writes = $4,\n l2_l1_compressed_messages = $5,\n l2_l1_merkle_root = $6,\n zkporter_is_available = $7,\n parent_hash = $8,\n rollup_last_leaf_index = $9,\n pass_through_data_hash = $10,\n meta_parameters_hash = $11,\n compressed_state_diffs = $12,\n updated_at = NOW()\n WHERE\n number = $13\n AND hash IS NULL\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Bytea", + "Bytea", + "Bytea", + "Bytea", + "Bytea", + "Bool", + "Bytea", + "Int8", + "Bytea", + "Bytea", + "Bytea", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "dc764e1636c4e958753c1fd54562e2ca92fdfdf01cfd0b11f5ce24f0458a5e48" +} diff --git a/core/lib/dal/.sqlx/query-dd55e46dfa5ba3692d9620088a3550b8db817630d1a9341db4a1f453f12e64fb.json b/core/lib/dal/.sqlx/query-dd55e46dfa5ba3692d9620088a3550b8db817630d1a9341db4a1f453f12e64fb.json new file mode 100644 index 000000000000..70449a85ea4b --- /dev/null +++ b/core/lib/dal/.sqlx/query-dd55e46dfa5ba3692d9620088a3550b8db817630d1a9341db4a1f453f12e64fb.json @@ -0,0 +1,34 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n status,\n error,\n compilation_errors\n FROM\n contract_verification_requests\n WHERE\n id = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "status", + "type_info": "Text" + }, + { + "ordinal": 1, + "name": "error", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "compilation_errors", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + true, + true + ] + }, + "hash": "dd55e46dfa5ba3692d9620088a3550b8db817630d1a9341db4a1f453f12e64fb" +} diff --git a/core/lib/dal/.sqlx/query-dd86833a1fa5240e2b225daf32fa594a00a78e400dc44fd3b2634529278ab38c.json b/core/lib/dal/.sqlx/query-dd86833a1fa5240e2b225daf32fa594a00a78e400dc44fd3b2634529278ab38c.json new file mode 100644 index 000000000000..a98e8e0004ca --- /dev/null +++ b/core/lib/dal/.sqlx/query-dd86833a1fa5240e2b225daf32fa594a00a78e400dc44fd3b2634529278ab38c.json @@ -0,0 +1,224 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n parent_hash,\n commitment,\n compressed_write_logs,\n compressed_contracts,\n eth_prove_tx_id,\n eth_commit_tx_id,\n eth_execute_tx_id,\n merkle_root_hash,\n l2_to_l1_logs,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_compressed_messages,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n WHERE\n number = 0\n OR eth_commit_tx_id IS NOT NULL\n AND commitment IS NOT NULL\n ORDER BY\n number DESC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "l1_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 3, + "name": "l2_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 4, + "name": "bloom", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "priority_ops_onchain_data", + "type_info": "ByteaArray" + }, + { + "ordinal": 6, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "parent_hash", + "type_info": "Bytea" + }, + { + "ordinal": 8, + "name": "commitment", + "type_info": "Bytea" + }, + { + "ordinal": 9, + "name": "compressed_write_logs", + "type_info": "Bytea" + }, + { + "ordinal": 10, + "name": "compressed_contracts", + "type_info": "Bytea" + }, + { + "ordinal": 11, + "name": "eth_prove_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 12, + "name": "eth_commit_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 13, + "name": "eth_execute_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 14, + "name": "merkle_root_hash", + "type_info": "Bytea" + }, + { + "ordinal": 15, + "name": "l2_to_l1_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 16, + "name": "l2_to_l1_messages", + "type_info": "ByteaArray" + }, + { + "ordinal": 17, + "name": "used_contract_hashes", + "type_info": "Jsonb" + }, + { + "ordinal": 18, + "name": "compressed_initial_writes", + "type_info": "Bytea" + }, + { + "ordinal": 19, + "name": "compressed_repeated_writes", + "type_info": "Bytea" + }, + { + "ordinal": 20, + "name": "l2_l1_compressed_messages", + "type_info": "Bytea" + }, + { + "ordinal": 21, + "name": "l2_l1_merkle_root", + "type_info": "Bytea" + }, + { + "ordinal": 22, + "name": "rollup_last_leaf_index", + "type_info": "Int8" + }, + { + "ordinal": 23, + "name": "zkporter_is_available", + "type_info": "Bool" + }, + { + "ordinal": 24, + "name": "bootloader_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 25, + "name": "default_aa_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 26, + "name": "aux_data_hash", + "type_info": "Bytea" + }, + { + "ordinal": 27, + "name": "pass_through_data_hash", + "type_info": "Bytea" + }, + { + "ordinal": 28, + "name": "meta_parameters_hash", + "type_info": "Bytea" + }, + { + "ordinal": 29, + "name": "protocol_version", + "type_info": "Int4" + }, + { + "ordinal": 30, + "name": "compressed_state_diffs", + "type_info": "Bytea" + }, + { + "ordinal": 31, + "name": "system_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 32, + "name": "events_queue_commitment", + "type_info": "Bytea" + }, + { + "ordinal": 33, + "name": "bootloader_initial_content_commitment", + "type_info": "Bytea" + }, + { + "ordinal": 34, + "name": "pubdata_input", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + true, + true + ] + }, + "hash": "dd86833a1fa5240e2b225daf32fa594a00a78e400dc44fd3b2634529278ab38c" +} diff --git a/core/lib/dal/.sqlx/query-de3a5a35b111bd831bebe6d9391bf58b311d81c5fc0a6fbaccf204976f76f378.json b/core/lib/dal/.sqlx/query-de3a5a35b111bd831bebe6d9391bf58b311d81c5fc0a6fbaccf204976f76f378.json new file mode 100644 index 000000000000..de753a93926f --- /dev/null +++ b/core/lib/dal/.sqlx/query-de3a5a35b111bd831bebe6d9391bf58b311d81c5fc0a6fbaccf204976f76f378.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l2_address\n FROM\n tokens\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l2_address", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "de3a5a35b111bd831bebe6d9391bf58b311d81c5fc0a6fbaccf204976f76f378" +} diff --git a/core/lib/dal/.sqlx/query-dea22358feed1418430505767d03aa4239d3a8be71b47178b4b8fb11fe898b31.json b/core/lib/dal/.sqlx/query-dea22358feed1418430505767d03aa4239d3a8be71b47178b4b8fb11fe898b31.json new file mode 100644 index 000000000000..ef070554c2fd --- /dev/null +++ b/core/lib/dal/.sqlx/query-dea22358feed1418430505767d03aa4239d3a8be71b47178b4b8fb11fe898b31.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE l1_batches\n SET\n eth_execute_tx_id = $1,\n updated_at = NOW()\n WHERE\n number BETWEEN $2 AND $3\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4", + "Int8", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "dea22358feed1418430505767d03aa4239d3a8be71b47178b4b8fb11fe898b31" +} diff --git a/core/lib/dal/.sqlx/query-df00e33809768120e395d8f740770a4e629b2a1cde641e74e4e55bb100df809f.json b/core/lib/dal/.sqlx/query-df00e33809768120e395d8f740770a4e629b2a1cde641e74e4e55bb100df809f.json new file mode 100644 index 000000000000..9ad3099d7765 --- /dev/null +++ b/core/lib/dal/.sqlx/query-df00e33809768120e395d8f740770a4e629b2a1cde641e74e4e55bb100df809f.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n attempts\n FROM\n prover_jobs_fri\n WHERE\n id = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "attempts", + "type_info": "Int2" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "df00e33809768120e395d8f740770a4e629b2a1cde641e74e4e55bb100df809f" +} diff --git a/core/lib/dal/.sqlx/query-e073cfdc7a00559994ce04eca15f35d55901fb1e6805f23413ea43e3637540a0.json b/core/lib/dal/.sqlx/query-e073cfdc7a00559994ce04eca15f35d55901fb1e6805f23413ea43e3637540a0.json new file mode 100644 index 000000000000..929e4de8c1b3 --- /dev/null +++ b/core/lib/dal/.sqlx/query-e073cfdc7a00559994ce04eca15f35d55901fb1e6805f23413ea43e3637540a0.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n bytecode,\n bytecode_hash\n FROM\n factory_deps\n WHERE\n bytecode_hash = ANY ($1)\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "bytecode", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "bytecode_hash", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "ByteaArray" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "e073cfdc7a00559994ce04eca15f35d55901fb1e6805f23413ea43e3637540a0" +} diff --git a/core/lib/dal/.sqlx/query-e3479d12d9dc97001cf03dc42d9b957e92cd375ec33fe16f855f319ffc0b208e.json b/core/lib/dal/.sqlx/query-e3479d12d9dc97001cf03dc42d9b957e92cd375ec33fe16f855f319ffc0b208e.json new file mode 100644 index 000000000000..32cc15c206db --- /dev/null +++ b/core/lib/dal/.sqlx/query-e3479d12d9dc97001cf03dc42d9b957e92cd375ec33fe16f855f319ffc0b208e.json @@ -0,0 +1,118 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n *\n FROM\n scheduler_dependency_tracker_fri\n WHERE\n l1_batch_number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "status", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "circuit_1_final_prover_job_id", + "type_info": "Int8" + }, + { + "ordinal": 3, + "name": "circuit_2_final_prover_job_id", + "type_info": "Int8" + }, + { + "ordinal": 4, + "name": "circuit_3_final_prover_job_id", + "type_info": "Int8" + }, + { + "ordinal": 5, + "name": "circuit_4_final_prover_job_id", + "type_info": "Int8" + }, + { + "ordinal": 6, + "name": "circuit_5_final_prover_job_id", + "type_info": "Int8" + }, + { + "ordinal": 7, + "name": "circuit_6_final_prover_job_id", + "type_info": "Int8" + }, + { + "ordinal": 8, + "name": "circuit_7_final_prover_job_id", + "type_info": "Int8" + }, + { + "ordinal": 9, + "name": "circuit_8_final_prover_job_id", + "type_info": "Int8" + }, + { + "ordinal": 10, + "name": "circuit_9_final_prover_job_id", + "type_info": "Int8" + }, + { + "ordinal": 11, + "name": "circuit_10_final_prover_job_id", + "type_info": "Int8" + }, + { + "ordinal": 12, + "name": "circuit_11_final_prover_job_id", + "type_info": "Int8" + }, + { + "ordinal": 13, + "name": "circuit_12_final_prover_job_id", + "type_info": "Int8" + }, + { + "ordinal": 14, + "name": "circuit_13_final_prover_job_id", + "type_info": "Int8" + }, + { + "ordinal": 15, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 16, + "name": "updated_at", + "type_info": "Timestamp" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ] + }, + "hash": "e3479d12d9dc97001cf03dc42d9b957e92cd375ec33fe16f855f319ffc0b208e" +} diff --git a/core/lib/dal/.sqlx/query-e5a90d17b2c25744df4585b53678c7ffd9a04eae27afbdf37a6ba8ff7ac85f3b.json b/core/lib/dal/.sqlx/query-e5a90d17b2c25744df4585b53678c7ffd9a04eae27afbdf37a6ba8ff7ac85f3b.json new file mode 100644 index 000000000000..5606beb7123e --- /dev/null +++ b/core/lib/dal/.sqlx/query-e5a90d17b2c25744df4585b53678c7ffd9a04eae27afbdf37a6ba8ff7ac85f3b.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n serialized_events_queue\n FROM\n events_queue\n WHERE\n l1_batch_number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "serialized_events_queue", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "e5a90d17b2c25744df4585b53678c7ffd9a04eae27afbdf37a6ba8ff7ac85f3b" +} diff --git a/core/lib/dal/.sqlx/query-e71c39b93ceba5416ff3d988290cb35d4d07d47f33fe1a5b9e9fe1f0ae09b705.json b/core/lib/dal/.sqlx/query-e71c39b93ceba5416ff3d988290cb35d4d07d47f33fe1a5b9e9fe1f0ae09b705.json new file mode 100644 index 000000000000..b61fbc645a0f --- /dev/null +++ b/core/lib/dal/.sqlx/query-e71c39b93ceba5416ff3d988290cb35d4d07d47f33fe1a5b9e9fe1f0ae09b705.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n usd_price,\n usd_price_updated_at\n FROM\n tokens\n WHERE\n l2_address = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "usd_price", + "type_info": "Numeric" + }, + { + "ordinal": 1, + "name": "usd_price_updated_at", + "type_info": "Timestamp" + } + ], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [ + true, + true + ] + }, + "hash": "e71c39b93ceba5416ff3d988290cb35d4d07d47f33fe1a5b9e9fe1f0ae09b705" +} diff --git a/core/lib/dal/.sqlx/query-e74a34a59e6afda689b0ec9e19071ababa66e4a443fbefbfffca72b7540b075b.json b/core/lib/dal/.sqlx/query-e74a34a59e6afda689b0ec9e19071ababa66e4a443fbefbfffca72b7540b075b.json new file mode 100644 index 000000000000..54ea6b6eb03a --- /dev/null +++ b/core/lib/dal/.sqlx/query-e74a34a59e6afda689b0ec9e19071ababa66e4a443fbefbfffca72b7540b075b.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n proof_compression_jobs_fri (l1_batch_number, status, created_at, updated_at)\n VALUES\n ($1, $2, NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Text" + ] + }, + "nullable": [] + }, + "hash": "e74a34a59e6afda689b0ec9e19071ababa66e4a443fbefbfffca72b7540b075b" +} diff --git a/core/lib/dal/.sqlx/query-e9adf5b5a1ab84c20a514a7775f91a9984685eaaaa0a8b223410d560a15a3034.json b/core/lib/dal/.sqlx/query-e9adf5b5a1ab84c20a514a7775f91a9984685eaaaa0a8b223410d560a15a3034.json new file mode 100644 index 000000000000..975c061632ac --- /dev/null +++ b/core/lib/dal/.sqlx/query-e9adf5b5a1ab84c20a514a7775f91a9984685eaaaa0a8b223410d560a15a3034.json @@ -0,0 +1,61 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE prover_jobs_fri\n SET\n status = 'in_progress',\n attempts = attempts + 1,\n processing_started_at = NOW(),\n updated_at = NOW(),\n picked_by = $4\n WHERE\n id = (\n SELECT\n pj.id\n FROM\n (\n SELECT\n *\n FROM\n UNNEST($1::SMALLINT[], $2::SMALLINT[])\n ) AS tuple (circuit_id, ROUND)\n JOIN LATERAL (\n SELECT\n *\n FROM\n prover_jobs_fri AS pj\n WHERE\n pj.status = 'queued'\n AND pj.protocol_version = ANY ($3)\n AND pj.circuit_id = tuple.circuit_id\n AND pj.aggregation_round = tuple.round\n ORDER BY\n pj.l1_batch_number ASC,\n pj.id ASC\n LIMIT\n 1\n ) AS pj ON TRUE\n ORDER BY\n pj.l1_batch_number ASC,\n pj.aggregation_round DESC,\n pj.id ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n prover_jobs_fri.id,\n prover_jobs_fri.l1_batch_number,\n prover_jobs_fri.circuit_id,\n prover_jobs_fri.aggregation_round,\n prover_jobs_fri.sequence_number,\n prover_jobs_fri.depth,\n prover_jobs_fri.is_node_final_proof\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "circuit_id", + "type_info": "Int2" + }, + { + "ordinal": 3, + "name": "aggregation_round", + "type_info": "Int2" + }, + { + "ordinal": 4, + "name": "sequence_number", + "type_info": "Int4" + }, + { + "ordinal": 5, + "name": "depth", + "type_info": "Int4" + }, + { + "ordinal": 6, + "name": "is_node_final_proof", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Int2Array", + "Int2Array", + "Int4Array", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false + ] + }, + "hash": "e9adf5b5a1ab84c20a514a7775f91a9984685eaaaa0a8b223410d560a15a3034" +} diff --git a/core/lib/dal/.sqlx/query-e9ca863d6e77edd39a9fc55700a6686e655206601854799139c22c017a214744.json b/core/lib/dal/.sqlx/query-e9ca863d6e77edd39a9fc55700a6686e655206601854799139c22c017a214744.json new file mode 100644 index 000000000000..0bdcbb99add0 --- /dev/null +++ b/core/lib/dal/.sqlx/query-e9ca863d6e77edd39a9fc55700a6686e655206601854799139c22c017a214744.json @@ -0,0 +1,19 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n node_aggregation_witness_jobs_fri (\n l1_batch_number,\n circuit_id,\n depth,\n aggregations_url,\n number_of_dependent_jobs,\n protocol_version,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, 'waiting_for_proofs', NOW(), NOW())\n ON CONFLICT (l1_batch_number, circuit_id, depth) DO\n UPDATE\n SET\n updated_at = NOW()\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Int2", + "Int4", + "Text", + "Int4", + "Int4" + ] + }, + "nullable": [] + }, + "hash": "e9ca863d6e77edd39a9fc55700a6686e655206601854799139c22c017a214744" +} diff --git a/core/lib/dal/.sqlx/query-ea904aa930d602d33b6fbc1bf1178a8a0ec739f4ddec8ffeb3a87253aeb18d30.json b/core/lib/dal/.sqlx/query-ea904aa930d602d33b6fbc1bf1178a8a0ec739f4ddec8ffeb3a87253aeb18d30.json new file mode 100644 index 000000000000..718b2a8f6872 --- /dev/null +++ b/core/lib/dal/.sqlx/query-ea904aa930d602d33b6fbc1bf1178a8a0ec739f4ddec8ffeb3a87253aeb18d30.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM miniblocks\n WHERE\n number > $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "ea904aa930d602d33b6fbc1bf1178a8a0ec739f4ddec8ffeb3a87253aeb18d30" +} diff --git a/core/lib/dal/.sqlx/query-eab03e888f20020462ede2cd59fc0d68195346daf5f38d102eab1c1b73b0f82f.json b/core/lib/dal/.sqlx/query-eab03e888f20020462ede2cd59fc0d68195346daf5f38d102eab1c1b73b0f82f.json new file mode 100644 index 000000000000..5cd05036f98c --- /dev/null +++ b/core/lib/dal/.sqlx/query-eab03e888f20020462ede2cd59fc0d68195346daf5f38d102eab1c1b73b0f82f.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT COUNT(*)\n FROM information_schema.columns\n WHERE table_name = 'l1_batches' AND column_name = 'fee_account_address'\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "eab03e888f20020462ede2cd59fc0d68195346daf5f38d102eab1c1b73b0f82f" +} diff --git a/core/lib/dal/.sqlx/query-eae299cb634a5b5b0409648436c4550d90b643424e3cac238d97cb79c9c140a4.json b/core/lib/dal/.sqlx/query-eae299cb634a5b5b0409648436c4550d90b643424e3cac238d97cb79c9c140a4.json new file mode 100644 index 000000000000..aa4751e12b7e --- /dev/null +++ b/core/lib/dal/.sqlx/query-eae299cb634a5b5b0409648436c4550d90b643424e3cac238d97cb79c9c140a4.json @@ -0,0 +1,94 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n miniblocks.number,\n COALESCE(\n miniblocks.l1_batch_number,\n (\n SELECT\n (MAX(number) + 1)\n FROM\n l1_batches\n )\n ) AS \"l1_batch_number!\",\n (\n SELECT\n MAX(m2.number)\n FROM\n miniblocks m2\n WHERE\n miniblocks.l1_batch_number = m2.l1_batch_number\n ) AS \"last_batch_miniblock?\",\n miniblocks.timestamp,\n miniblocks.l1_gas_price,\n miniblocks.l2_fair_gas_price,\n miniblocks.fair_pubdata_price,\n miniblocks.bootloader_code_hash,\n miniblocks.default_aa_code_hash,\n miniblocks.virtual_blocks,\n miniblocks.hash,\n miniblocks.protocol_version AS \"protocol_version!\",\n miniblocks.fee_account_address AS \"fee_account_address!\"\n FROM\n miniblocks\n WHERE\n miniblocks.number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "l1_batch_number!", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "last_batch_miniblock?", + "type_info": "Int8" + }, + { + "ordinal": 3, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 4, + "name": "l1_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 5, + "name": "l2_fair_gas_price", + "type_info": "Int8" + }, + { + "ordinal": 6, + "name": "fair_pubdata_price", + "type_info": "Int8" + }, + { + "ordinal": 7, + "name": "bootloader_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 8, + "name": "default_aa_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 9, + "name": "virtual_blocks", + "type_info": "Int8" + }, + { + "ordinal": 10, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 11, + "name": "protocol_version!", + "type_info": "Int4" + }, + { + "ordinal": 12, + "name": "fee_account_address!", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + null, + null, + false, + false, + false, + true, + true, + true, + false, + false, + true, + false + ] + }, + "hash": "eae299cb634a5b5b0409648436c4550d90b643424e3cac238d97cb79c9c140a4" +} diff --git a/core/lib/dal/.sqlx/query-eb83e9175b4f8c0351ac2d4b4d2940bd2aee55b66f6780ceae06c3e1ff92eb8b.json b/core/lib/dal/.sqlx/query-eb83e9175b4f8c0351ac2d4b4d2940bd2aee55b66f6780ceae06c3e1ff92eb8b.json new file mode 100644 index 000000000000..250e5beb89a1 --- /dev/null +++ b/core/lib/dal/.sqlx/query-eb83e9175b4f8c0351ac2d4b4d2940bd2aee55b66f6780ceae06c3e1ff92eb8b.json @@ -0,0 +1,18 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n snapshot_recovery (\n l1_batch_number,\n l1_batch_root_hash,\n miniblock_number,\n miniblock_root_hash,\n storage_logs_chunks_processed,\n updated_at,\n created_at\n )\n VALUES\n ($1, $2, $3, $4, $5, NOW(), NOW())\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Bytea", + "Int8", + "Bytea", + "BoolArray" + ] + }, + "nullable": [] + }, + "hash": "eb83e9175b4f8c0351ac2d4b4d2940bd2aee55b66f6780ceae06c3e1ff92eb8b" +} diff --git a/core/lib/dal/.sqlx/query-ec04b89218111a5dc8d5ade506ac3465e2211ef3013386feb12d4cc04e0eade9.json b/core/lib/dal/.sqlx/query-ec04b89218111a5dc8d5ade506ac3465e2211ef3013386feb12d4cc04e0eade9.json new file mode 100644 index 000000000000..7c0264b5646b --- /dev/null +++ b/core/lib/dal/.sqlx/query-ec04b89218111a5dc8d5ade506ac3465e2211ef3013386feb12d4cc04e0eade9.json @@ -0,0 +1,60 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE prover_jobs_fri\n SET\n status = 'successful',\n updated_at = NOW(),\n time_taken = $1,\n proof_blob_url = $2\n WHERE\n id = $3\n RETURNING\n prover_jobs_fri.id,\n prover_jobs_fri.l1_batch_number,\n prover_jobs_fri.circuit_id,\n prover_jobs_fri.aggregation_round,\n prover_jobs_fri.sequence_number,\n prover_jobs_fri.depth,\n prover_jobs_fri.is_node_final_proof\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "circuit_id", + "type_info": "Int2" + }, + { + "ordinal": 3, + "name": "aggregation_round", + "type_info": "Int2" + }, + { + "ordinal": 4, + "name": "sequence_number", + "type_info": "Int4" + }, + { + "ordinal": 5, + "name": "depth", + "type_info": "Int4" + }, + { + "ordinal": 6, + "name": "is_node_final_proof", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Time", + "Text", + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false + ] + }, + "hash": "ec04b89218111a5dc8d5ade506ac3465e2211ef3013386feb12d4cc04e0eade9" +} diff --git a/core/lib/dal/.sqlx/query-edc61e1285bf6d3837acc67af4f15aaade450980719933089824eb8c494d64a4.json b/core/lib/dal/.sqlx/query-edc61e1285bf6d3837acc67af4f15aaade450980719933089824eb8c494d64a4.json new file mode 100644 index 000000000000..2c7d7f1da5f0 --- /dev/null +++ b/core/lib/dal/.sqlx/query-edc61e1285bf6d3837acc67af4f15aaade450980719933089824eb8c494d64a4.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE witness_inputs_fri\n SET\n status = 'successful',\n updated_at = NOW(),\n time_taken = $1\n WHERE\n l1_batch_number = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Time", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "edc61e1285bf6d3837acc67af4f15aaade450980719933089824eb8c494d64a4" +} diff --git a/core/lib/dal/.sqlx/query-ee17d2b3edfe705d14811e3938d4312b2b780563a9fde48bae5e51650475670f.json b/core/lib/dal/.sqlx/query-ee17d2b3edfe705d14811e3938d4312b2b780563a9fde48bae5e51650475670f.json new file mode 100644 index 000000000000..5732126a7ffd --- /dev/null +++ b/core/lib/dal/.sqlx/query-ee17d2b3edfe705d14811e3938d4312b2b780563a9fde48bae5e51650475670f.json @@ -0,0 +1,82 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n *\n FROM\n eth_txs_history\n WHERE\n eth_tx_id = $1\n ORDER BY\n created_at DESC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "eth_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 2, + "name": "tx_hash", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 4, + "name": "updated_at", + "type_info": "Timestamp" + }, + { + "ordinal": 5, + "name": "base_fee_per_gas", + "type_info": "Int8" + }, + { + "ordinal": 6, + "name": "priority_fee_per_gas", + "type_info": "Int8" + }, + { + "ordinal": 7, + "name": "confirmed_at", + "type_info": "Timestamp" + }, + { + "ordinal": 8, + "name": "signed_raw_tx", + "type_info": "Bytea" + }, + { + "ordinal": 9, + "name": "sent_at_block", + "type_info": "Int4" + }, + { + "ordinal": 10, + "name": "sent_at", + "type_info": "Timestamp" + } + ], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true + ] + }, + "hash": "ee17d2b3edfe705d14811e3938d4312b2b780563a9fde48bae5e51650475670f" +} diff --git a/core/lib/dal/.sqlx/query-ef331469f78c6ff68a254a15b55d056cc9bae25bc070c5de8424f88fab20e5ea.json b/core/lib/dal/.sqlx/query-ef331469f78c6ff68a254a15b55d056cc9bae25bc070c5de8424f88fab20e5ea.json new file mode 100644 index 000000000000..60d4a49d6281 --- /dev/null +++ b/core/lib/dal/.sqlx/query-ef331469f78c6ff68a254a15b55d056cc9bae25bc070c5de8424f88fab20e5ea.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_number,\n l1_batch_tx_index\n FROM\n transactions\n WHERE\n hash = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "l1_batch_tx_index", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [ + true, + true + ] + }, + "hash": "ef331469f78c6ff68a254a15b55d056cc9bae25bc070c5de8424f88fab20e5ea" +} diff --git a/core/lib/dal/.sqlx/query-ef687be83e496d6647e4dfef9eabae63443c51deb818dd0affd1a0949b161737.json b/core/lib/dal/.sqlx/query-ef687be83e496d6647e4dfef9eabae63443c51deb818dd0affd1a0949b161737.json new file mode 100644 index 000000000000..79b20fabb284 --- /dev/null +++ b/core/lib/dal/.sqlx/query-ef687be83e496d6647e4dfef9eabae63443c51deb818dd0affd1a0949b161737.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n proof_compression_jobs_fri (l1_batch_number, fri_proof_blob_url, status, created_at, updated_at)\n VALUES\n ($1, $2, $3, NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "ef687be83e496d6647e4dfef9eabae63443c51deb818dd0affd1a0949b161737" +} diff --git a/core/lib/dal/.sqlx/query-f012d0922265269746396dac8f25ff66f2c3b2b83d45360818a8782e56aa3d66.json b/core/lib/dal/.sqlx/query-f012d0922265269746396dac8f25ff66f2c3b2b83d45360818a8782e56aa3d66.json new file mode 100644 index 000000000000..9815b5d3895e --- /dev/null +++ b/core/lib/dal/.sqlx/query-f012d0922265269746396dac8f25ff66f2c3b2b83d45360818a8782e56aa3d66.json @@ -0,0 +1,36 @@ +{ + "db_name": "PostgreSQL", + "query": "\n WITH\n sl AS (\n SELECT\n (\n SELECT\n ARRAY[hashed_key, value] AS kv\n FROM\n storage_logs\n WHERE\n storage_logs.miniblock_number = $1\n AND storage_logs.hashed_key >= u.start_key\n AND storage_logs.hashed_key <= u.end_key\n ORDER BY\n storage_logs.hashed_key\n LIMIT\n 1\n )\n FROM\n UNNEST($2::bytea[], $3::bytea[]) AS u (start_key, end_key)\n )\n SELECT\n sl.kv[1] AS \"hashed_key?\",\n sl.kv[2] AS \"value?\",\n initial_writes.index\n FROM\n sl\n LEFT OUTER JOIN initial_writes ON initial_writes.hashed_key = sl.kv[1]\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hashed_key?", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "value?", + "type_info": "Bytea" + }, + { + "ordinal": 2, + "name": "index", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8", + "ByteaArray", + "ByteaArray" + ] + }, + "nullable": [ + null, + null, + true + ] + }, + "hash": "f012d0922265269746396dac8f25ff66f2c3b2b83d45360818a8782e56aa3d66" +} diff --git a/core/lib/dal/.sqlx/query-f1a90090c192d68367e799188356efe8d41759bbdcdd6d39db93208f2664f03a.json b/core/lib/dal/.sqlx/query-f1a90090c192d68367e799188356efe8d41759bbdcdd6d39db93208f2664f03a.json new file mode 100644 index 000000000000..616173355a94 --- /dev/null +++ b/core/lib/dal/.sqlx/query-f1a90090c192d68367e799188356efe8d41759bbdcdd6d39db93208f2664f03a.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n INDEX\n FROM\n initial_writes\n WHERE\n hashed_key = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "index", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [ + false + ] + }, + "hash": "f1a90090c192d68367e799188356efe8d41759bbdcdd6d39db93208f2664f03a" +} diff --git a/core/lib/dal/.sqlx/query-f22c5d136fe68bbfcee60beb304cfdc050b85e6d773b13f9699f15c335d42593.json b/core/lib/dal/.sqlx/query-f22c5d136fe68bbfcee60beb304cfdc050b85e6d773b13f9699f15c335d42593.json new file mode 100644 index 000000000000..7ffda2c8a32e --- /dev/null +++ b/core/lib/dal/.sqlx/query-f22c5d136fe68bbfcee60beb304cfdc050b85e6d773b13f9699f15c335d42593.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_address\n FROM\n tokens\n WHERE\n market_volume > $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_address", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Numeric" + ] + }, + "nullable": [ + false + ] + }, + "hash": "f22c5d136fe68bbfcee60beb304cfdc050b85e6d773b13f9699f15c335d42593" +} diff --git a/core/lib/dal/.sqlx/query-f2f852a340c45ff69cbca42d7c592dfb0d28a797bee69872634f3105d2d51996.json b/core/lib/dal/.sqlx/query-f2f852a340c45ff69cbca42d7c592dfb0d28a797bee69872634f3105d2d51996.json new file mode 100644 index 000000000000..11c409c21802 --- /dev/null +++ b/core/lib/dal/.sqlx/query-f2f852a340c45ff69cbca42d7c592dfb0d28a797bee69872634f3105d2d51996.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE snapshot_recovery\n SET\n storage_logs_chunks_processed[$1] = TRUE,\n updated_at = NOW()\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [] + }, + "hash": "f2f852a340c45ff69cbca42d7c592dfb0d28a797bee69872634f3105d2d51996" +} diff --git a/core/lib/dal/.sqlx/query-f39372e37160df4897f62a800694867ed765dcb9dc60754df9df8700d4244bfb.json b/core/lib/dal/.sqlx/query-f39372e37160df4897f62a800694867ed765dcb9dc60754df9df8700d4244bfb.json new file mode 100644 index 000000000000..9495f8f7c828 --- /dev/null +++ b/core/lib/dal/.sqlx/query-f39372e37160df4897f62a800694867ed765dcb9dc60754df9df8700d4244bfb.json @@ -0,0 +1,44 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_address,\n l2_address,\n NAME,\n symbol,\n decimals\n FROM\n tokens\n WHERE\n well_known = TRUE\n ORDER BY\n symbol\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_address", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "l2_address", + "type_info": "Bytea" + }, + { + "ordinal": 2, + "name": "name", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "symbol", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "decimals", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false, + false, + false + ] + }, + "hash": "f39372e37160df4897f62a800694867ed765dcb9dc60754df9df8700d4244bfb" +} diff --git a/core/lib/dal/.sqlx/query-f4362a61ab05af3d71a3232d2f017db60405a887f9f7fa0ca60aa7fc879ce630.json b/core/lib/dal/.sqlx/query-f4362a61ab05af3d71a3232d2f017db60405a887f9f7fa0ca60aa7fc879ce630.json new file mode 100644 index 000000000000..59c28852a03e --- /dev/null +++ b/core/lib/dal/.sqlx/query-f4362a61ab05af3d71a3232d2f017db60405a887f9f7fa0ca60aa7fc879ce630.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE proof_compression_jobs_fri\n SET\n status = $1,\n error = $2,\n updated_at = NOW()\n WHERE\n l1_batch_number = $3\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "f4362a61ab05af3d71a3232d2f017db60405a887f9f7fa0ca60aa7fc879ce630" +} diff --git a/core/lib/dal/.sqlx/query-f63586d59264eab7388ad1de823227ecaa45d76d1ba260074898fe57c059a15a.json b/core/lib/dal/.sqlx/query-f63586d59264eab7388ad1de823227ecaa45d76d1ba260074898fe57c059a15a.json new file mode 100644 index 000000000000..d62e213ef57b --- /dev/null +++ b/core/lib/dal/.sqlx/query-f63586d59264eab7388ad1de823227ecaa45d76d1ba260074898fe57c059a15a.json @@ -0,0 +1,232 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n *\n FROM\n transactions\n WHERE\n l1_batch_number = $1\n ORDER BY\n miniblock_number,\n index_in_block\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "is_priority", + "type_info": "Bool" + }, + { + "ordinal": 2, + "name": "full_fee", + "type_info": "Numeric" + }, + { + "ordinal": 3, + "name": "layer_2_tip_fee", + "type_info": "Numeric" + }, + { + "ordinal": 4, + "name": "initiator_address", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "nonce", + "type_info": "Int8" + }, + { + "ordinal": 6, + "name": "signature", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "input", + "type_info": "Bytea" + }, + { + "ordinal": 8, + "name": "data", + "type_info": "Jsonb" + }, + { + "ordinal": 9, + "name": "received_at", + "type_info": "Timestamp" + }, + { + "ordinal": 10, + "name": "priority_op_id", + "type_info": "Int8" + }, + { + "ordinal": 11, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 12, + "name": "index_in_block", + "type_info": "Int4" + }, + { + "ordinal": 13, + "name": "error", + "type_info": "Varchar" + }, + { + "ordinal": 14, + "name": "gas_limit", + "type_info": "Numeric" + }, + { + "ordinal": 15, + "name": "gas_per_storage_limit", + "type_info": "Numeric" + }, + { + "ordinal": 16, + "name": "gas_per_pubdata_limit", + "type_info": "Numeric" + }, + { + "ordinal": 17, + "name": "tx_format", + "type_info": "Int4" + }, + { + "ordinal": 18, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 19, + "name": "updated_at", + "type_info": "Timestamp" + }, + { + "ordinal": 20, + "name": "execution_info", + "type_info": "Jsonb" + }, + { + "ordinal": 21, + "name": "contract_address", + "type_info": "Bytea" + }, + { + "ordinal": 22, + "name": "in_mempool", + "type_info": "Bool" + }, + { + "ordinal": 23, + "name": "l1_block_number", + "type_info": "Int4" + }, + { + "ordinal": 24, + "name": "value", + "type_info": "Numeric" + }, + { + "ordinal": 25, + "name": "paymaster", + "type_info": "Bytea" + }, + { + "ordinal": 26, + "name": "paymaster_input", + "type_info": "Bytea" + }, + { + "ordinal": 27, + "name": "max_fee_per_gas", + "type_info": "Numeric" + }, + { + "ordinal": 28, + "name": "max_priority_fee_per_gas", + "type_info": "Numeric" + }, + { + "ordinal": 29, + "name": "effective_gas_price", + "type_info": "Numeric" + }, + { + "ordinal": 30, + "name": "miniblock_number", + "type_info": "Int8" + }, + { + "ordinal": 31, + "name": "l1_batch_tx_index", + "type_info": "Int4" + }, + { + "ordinal": 32, + "name": "refunded_gas", + "type_info": "Int8" + }, + { + "ordinal": 33, + "name": "l1_tx_mint", + "type_info": "Numeric" + }, + { + "ordinal": 34, + "name": "l1_tx_refund_recipient", + "type_info": "Bytea" + }, + { + "ordinal": 35, + "name": "upgrade_id", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + true, + true, + false, + true, + true, + true, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + false, + true, + true, + true + ] + }, + "hash": "f63586d59264eab7388ad1de823227ecaa45d76d1ba260074898fe57c059a15a" +} diff --git a/core/lib/dal/.sqlx/query-f717ca5d0890759496739a678955e6f8b7f88a0894a7f9e27fc26f93997d37c7.json b/core/lib/dal/.sqlx/query-f717ca5d0890759496739a678955e6f8b7f88a0894a7f9e27fc26f93997d37c7.json new file mode 100644 index 000000000000..e6e12748d0d2 --- /dev/null +++ b/core/lib/dal/.sqlx/query-f717ca5d0890759496739a678955e6f8b7f88a0894a7f9e27fc26f93997d37c7.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE proof_compression_jobs_fri\n SET\n status = $1,\n attempts = attempts + 1,\n updated_at = NOW(),\n processing_started_at = NOW(),\n picked_by = $3\n WHERE\n l1_batch_number = (\n SELECT\n l1_batch_number\n FROM\n proof_compression_jobs_fri\n WHERE\n status = $2\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n proof_compression_jobs_fri.l1_batch_number\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text", + "Text", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "f717ca5d0890759496739a678955e6f8b7f88a0894a7f9e27fc26f93997d37c7" +} diff --git a/core/lib/dal/.sqlx/query-f76231781e5e267e9571c3f9daa902c4f720483abb5833ff15ecfa3a2602d4e5.json b/core/lib/dal/.sqlx/query-f76231781e5e267e9571c3f9daa902c4f720483abb5833ff15ecfa3a2602d4e5.json new file mode 100644 index 000000000000..392d44ef63d0 --- /dev/null +++ b/core/lib/dal/.sqlx/query-f76231781e5e267e9571c3f9daa902c4f720483abb5833ff15ecfa3a2602d4e5.json @@ -0,0 +1,226 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n number,\n timestamp,\n l1_tx_count,\n l2_tx_count,\n bloom,\n priority_ops_onchain_data,\n hash,\n parent_hash,\n commitment,\n compressed_write_logs,\n compressed_contracts,\n eth_prove_tx_id,\n eth_commit_tx_id,\n eth_execute_tx_id,\n merkle_root_hash,\n l2_to_l1_logs,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_compressed_messages,\n l2_l1_merkle_root,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n system_logs,\n compressed_state_diffs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n WHERE\n number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "timestamp", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "l1_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 3, + "name": "l2_tx_count", + "type_info": "Int4" + }, + { + "ordinal": 4, + "name": "bloom", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "priority_ops_onchain_data", + "type_info": "ByteaArray" + }, + { + "ordinal": 6, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 7, + "name": "parent_hash", + "type_info": "Bytea" + }, + { + "ordinal": 8, + "name": "commitment", + "type_info": "Bytea" + }, + { + "ordinal": 9, + "name": "compressed_write_logs", + "type_info": "Bytea" + }, + { + "ordinal": 10, + "name": "compressed_contracts", + "type_info": "Bytea" + }, + { + "ordinal": 11, + "name": "eth_prove_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 12, + "name": "eth_commit_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 13, + "name": "eth_execute_tx_id", + "type_info": "Int4" + }, + { + "ordinal": 14, + "name": "merkle_root_hash", + "type_info": "Bytea" + }, + { + "ordinal": 15, + "name": "l2_to_l1_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 16, + "name": "l2_to_l1_messages", + "type_info": "ByteaArray" + }, + { + "ordinal": 17, + "name": "used_contract_hashes", + "type_info": "Jsonb" + }, + { + "ordinal": 18, + "name": "compressed_initial_writes", + "type_info": "Bytea" + }, + { + "ordinal": 19, + "name": "compressed_repeated_writes", + "type_info": "Bytea" + }, + { + "ordinal": 20, + "name": "l2_l1_compressed_messages", + "type_info": "Bytea" + }, + { + "ordinal": 21, + "name": "l2_l1_merkle_root", + "type_info": "Bytea" + }, + { + "ordinal": 22, + "name": "rollup_last_leaf_index", + "type_info": "Int8" + }, + { + "ordinal": 23, + "name": "zkporter_is_available", + "type_info": "Bool" + }, + { + "ordinal": 24, + "name": "bootloader_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 25, + "name": "default_aa_code_hash", + "type_info": "Bytea" + }, + { + "ordinal": 26, + "name": "aux_data_hash", + "type_info": "Bytea" + }, + { + "ordinal": 27, + "name": "pass_through_data_hash", + "type_info": "Bytea" + }, + { + "ordinal": 28, + "name": "meta_parameters_hash", + "type_info": "Bytea" + }, + { + "ordinal": 29, + "name": "protocol_version", + "type_info": "Int4" + }, + { + "ordinal": 30, + "name": "system_logs", + "type_info": "ByteaArray" + }, + { + "ordinal": 31, + "name": "compressed_state_diffs", + "type_info": "Bytea" + }, + { + "ordinal": 32, + "name": "events_queue_commitment", + "type_info": "Bytea" + }, + { + "ordinal": 33, + "name": "bootloader_initial_content_commitment", + "type_info": "Bytea" + }, + { + "ordinal": 34, + "name": "pubdata_input", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + true, + true, + true + ] + }, + "hash": "f76231781e5e267e9571c3f9daa902c4f720483abb5833ff15ecfa3a2602d4e5" +} diff --git a/core/lib/dal/.sqlx/query-f91790ae5cc4b087bf942ba52dd63a1e89945f8d5e0f4da42ecf6313c4f5967e.json b/core/lib/dal/.sqlx/query-f91790ae5cc4b087bf942ba52dd63a1e89945f8d5e0f4da42ecf6313c4f5967e.json new file mode 100644 index 000000000000..cdf4b166270d --- /dev/null +++ b/core/lib/dal/.sqlx/query-f91790ae5cc4b087bf942ba52dd63a1e89945f8d5e0f4da42ecf6313c4f5967e.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n MIN(number) AS \"number\"\n FROM\n l1_batches\n WHERE\n hash IS NOT NULL\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "f91790ae5cc4b087bf942ba52dd63a1e89945f8d5e0f4da42ecf6313c4f5967e" +} diff --git a/core/lib/dal/.sqlx/query-f922c0718c9dda2f285f09cbabad425bac8ed3d2780c60c9b63afbcea131f9a0.json b/core/lib/dal/.sqlx/query-f922c0718c9dda2f285f09cbabad425bac8ed3d2780c60c9b63afbcea131f9a0.json new file mode 100644 index 000000000000..c10268b73326 --- /dev/null +++ b/core/lib/dal/.sqlx/query-f922c0718c9dda2f285f09cbabad425bac8ed3d2780c60c9b63afbcea131f9a0.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n transaction_traces (tx_hash, trace, created_at, updated_at)\n VALUES\n ($1, $2, NOW(), NOW())\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Jsonb" + ] + }, + "nullable": [] + }, + "hash": "f922c0718c9dda2f285f09cbabad425bac8ed3d2780c60c9b63afbcea131f9a0" +} diff --git a/core/lib/dal/.sqlx/query-fcc108fd59203644ff86ded0505c7dfb7aad7261e5fc402d845aedc3b91a4e99.json b/core/lib/dal/.sqlx/query-fcc108fd59203644ff86ded0505c7dfb7aad7261e5fc402d845aedc3b91a4e99.json new file mode 100644 index 000000000000..3dd33855e0e0 --- /dev/null +++ b/core/lib/dal/.sqlx/query-fcc108fd59203644ff86ded0505c7dfb7aad7261e5fc402d845aedc3b91a4e99.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n nonce AS \"nonce!\"\n FROM\n transactions\n WHERE\n initiator_address = $1\n AND nonce >= $2\n AND is_priority = FALSE\n AND (\n miniblock_number IS NOT NULL\n OR error IS NULL\n )\n ORDER BY\n nonce\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "nonce!", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Bytea", + "Int8" + ] + }, + "nullable": [ + true + ] + }, + "hash": "fcc108fd59203644ff86ded0505c7dfb7aad7261e5fc402d845aedc3b91a4e99" +} diff --git a/core/lib/dal/.sqlx/query-fcddeb96dcd1611dedb2091c1be304e8a35fd65bf37e976b7106f57c57e70b9b.json b/core/lib/dal/.sqlx/query-fcddeb96dcd1611dedb2091c1be304e8a35fd65bf37e976b7106f57c57e70b9b.json new file mode 100644 index 000000000000..effc22d6a43b --- /dev/null +++ b/core/lib/dal/.sqlx/query-fcddeb96dcd1611dedb2091c1be304e8a35fd65bf37e976b7106f57c57e70b9b.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE gpu_prover_queue_fri\n SET\n instance_status = 'available',\n updated_at = NOW()\n WHERE\n instance_host = $1::TEXT::inet\n AND instance_port = $2\n AND instance_status = 'full'\n AND zone = $3\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int4", + "Text" + ] + }, + "nullable": [] + }, + "hash": "fcddeb96dcd1611dedb2091c1be304e8a35fd65bf37e976b7106f57c57e70b9b" +} diff --git a/core/lib/dal/.sqlx/query-fde16cd2d3de03f4b61625fa453a58f82acd817932415f04bcbd05442ad80c2b.json b/core/lib/dal/.sqlx/query-fde16cd2d3de03f4b61625fa453a58f82acd817932415f04bcbd05442ad80c2b.json new file mode 100644 index 000000000000..f8ad468d70db --- /dev/null +++ b/core/lib/dal/.sqlx/query-fde16cd2d3de03f4b61625fa453a58f82acd817932415f04bcbd05442ad80c2b.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n bytecode\n FROM\n factory_deps\n WHERE\n bytecode_hash = $1\n AND miniblock_number <= $2\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "bytecode", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Bytea", + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "fde16cd2d3de03f4b61625fa453a58f82acd817932415f04bcbd05442ad80c2b" +} diff --git a/core/lib/dal/.sqlx/query-fdffa5841554286a924b217b5885d9ec9b3f628c3a4cf5e10580ea6e5e3a2429.json b/core/lib/dal/.sqlx/query-fdffa5841554286a924b217b5885d9ec9b3f628c3a4cf5e10580ea6e5e3a2429.json new file mode 100644 index 000000000000..bdcf7e5f0371 --- /dev/null +++ b/core/lib/dal/.sqlx/query-fdffa5841554286a924b217b5885d9ec9b3f628c3a4cf5e10580ea6e5e3a2429.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE miniblocks\n SET\n l1_batch_number = $1\n WHERE\n l1_batch_number IS NULL\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "fdffa5841554286a924b217b5885d9ec9b3f628c3a4cf5e10580ea6e5e3a2429" +} diff --git a/core/lib/dal/.sqlx/query-fe501f86f4bf6c5b8ccc2e039a4eb09b538a67d1c39fda052c4f4ddb23ce0084.json b/core/lib/dal/.sqlx/query-fe501f86f4bf6c5b8ccc2e039a4eb09b538a67d1c39fda052c4f4ddb23ce0084.json new file mode 100644 index 000000000000..5573cdd99530 --- /dev/null +++ b/core/lib/dal/.sqlx/query-fe501f86f4bf6c5b8ccc2e039a4eb09b538a67d1c39fda052c4f4ddb23ce0084.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l2_to_l1_logs\n FROM\n l1_batches\n WHERE\n number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l2_to_l1_logs", + "type_info": "ByteaArray" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "fe501f86f4bf6c5b8ccc2e039a4eb09b538a67d1c39fda052c4f4ddb23ce0084" +} diff --git a/core/lib/dal/.sqlx/query-fec7b791e371a4c58350b6537065223f4599d4128db588d8645f3d106de5f50b.json b/core/lib/dal/.sqlx/query-fec7b791e371a4c58350b6537065223f4599d4128db588d8645f3d106de5f50b.json new file mode 100644 index 000000000000..c34d38ac2d03 --- /dev/null +++ b/core/lib/dal/.sqlx/query-fec7b791e371a4c58350b6537065223f4599d4128db588d8645f3d106de5f50b.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n certificate\n FROM\n miniblocks_consensus\n ORDER BY\n number DESC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "certificate", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "fec7b791e371a4c58350b6537065223f4599d4128db588d8645f3d106de5f50b" +} diff --git a/core/lib/dal/Cargo.toml b/core/lib/dal/Cargo.toml index a43516e7adbc..7222b4f0ce8d 100644 --- a/core/lib/dal/Cargo.toml +++ b/core/lib/dal/Cargo.toml @@ -18,9 +18,9 @@ zksync_system_constants = { path = "../constants" } zksync_contracts = { path = "../contracts" } zksync_types = { path = "../types" } zksync_health_check = { path = "../health_check" } -zksync_consensus_roles = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "84cdd9e45fd84bc1fac0b394c899ae33aef91afa" } -zksync_consensus_storage = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "84cdd9e45fd84bc1fac0b394c899ae33aef91afa" } -zksync_protobuf = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "84cdd9e45fd84bc1fac0b394c899ae33aef91afa" } +zksync_consensus_roles = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } +zksync_consensus_storage = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } +zksync_protobuf = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } itertools = "0.10.1" thiserror = "1.0" @@ -29,29 +29,31 @@ url = "2" prost = "0.12.1" rand = "0.8" tokio = { version = "1", features = ["full"] } -sqlx = { version = "0.5.13", default-features = false, features = [ - "runtime-tokio-native-tls", +sqlx = { version = "0.7.3", default-features = false, features = [ + "runtime-tokio", + "tls-native-tls", "macros", "postgres", "bigdecimal", + "rust_decimal", "chrono", "json", - "offline", "migrate", "ipnetwork", ] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -bigdecimal = "0.2.2" +bigdecimal = "0.3.0" bincode = "1" -num = "0.3.1" +num = "0.4.0" hex = "0.4" once_cell = "1.7" strum = { version = "0.24", features = ["derive"] } tracing = "0.1" +chrono = { version = "0.4", features = ["serde"] } [dev-dependencies] assert_matches = "1.5.0" [build-dependencies] -zksync_protobuf_build = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "84cdd9e45fd84bc1fac0b394c899ae33aef91afa" } +zksync_protobuf_build = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } diff --git a/core/lib/dal/build.rs b/core/lib/dal/build.rs index 66896b3e02ff..f9986b596031 100644 --- a/core/lib/dal/build.rs +++ b/core/lib/dal/build.rs @@ -3,7 +3,7 @@ fn main() { zksync_protobuf_build::Config { input_root: "src/models/proto".into(), proto_root: "zksync/dal".into(), - dependencies: vec!["::zksync_consensus_roles::proto".parse().unwrap()], + dependencies: vec![], protobuf_crate: "::zksync_protobuf".parse().unwrap(), is_public: true, } diff --git a/core/lib/dal/migrations/20231212121822_add_miniblocks_fee_account_address.down.sql b/core/lib/dal/migrations/20231212121822_add_miniblocks_fee_account_address.down.sql new file mode 100644 index 000000000000..8a0717ff8391 --- /dev/null +++ b/core/lib/dal/migrations/20231212121822_add_miniblocks_fee_account_address.down.sql @@ -0,0 +1,5 @@ +ALTER TABLE l1_batches + ALTER COLUMN fee_account_address DROP DEFAULT, + ALTER COLUMN is_finished DROP DEFAULT; +ALTER TABLE miniblocks + DROP COLUMN fee_account_address; diff --git a/core/lib/dal/migrations/20231212121822_add_miniblocks_fee_account_address.up.sql b/core/lib/dal/migrations/20231212121822_add_miniblocks_fee_account_address.up.sql new file mode 100644 index 000000000000..e6ec1f492788 --- /dev/null +++ b/core/lib/dal/migrations/20231212121822_add_miniblocks_fee_account_address.up.sql @@ -0,0 +1,9 @@ +ALTER TABLE miniblocks + ADD COLUMN fee_account_address BYTEA NOT NULL DEFAULT '\x0000000000000000000000000000000000000000'::bytea; +-- ^ Add a default value so that DB queries don't fail even if the DB migration is not completed. + +-- Set default values for columns in `l1_batches` that will be removed, so that INSERTs can work +-- w/o setting these columns. +ALTER TABLE l1_batches + ALTER COLUMN fee_account_address SET DEFAULT '\x0000000000000000000000000000000000000000'::bytea, + ALTER COLUMN is_finished SET DEFAULT true; diff --git a/core/lib/dal/migrations/20231229181653_fair_pubdata_price.down.sql b/core/lib/dal/migrations/20231229181653_fair_pubdata_price.down.sql new file mode 100644 index 000000000000..9002b3924e09 --- /dev/null +++ b/core/lib/dal/migrations/20231229181653_fair_pubdata_price.down.sql @@ -0,0 +1 @@ +ALTER TABLE miniblocks DROP COLUMN fair_pubdata_price; diff --git a/core/lib/dal/migrations/20231229181653_fair_pubdata_price.up.sql b/core/lib/dal/migrations/20231229181653_fair_pubdata_price.up.sql new file mode 100644 index 000000000000..f79547b11234 --- /dev/null +++ b/core/lib/dal/migrations/20231229181653_fair_pubdata_price.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE miniblocks + ADD COLUMN IF NOT EXISTS fair_pubdata_price BIGINT; diff --git a/core/lib/dal/migrations/20240103123456_move_consensus_fields_to_new_table.down.sql b/core/lib/dal/migrations/20240103123456_move_consensus_fields_to_new_table.down.sql new file mode 100644 index 000000000000..ce7a2de360bd --- /dev/null +++ b/core/lib/dal/migrations/20240103123456_move_consensus_fields_to_new_table.down.sql @@ -0,0 +1,2 @@ +DROP TABLE miniblocks_consensus; +ALTER TABLE miniblocks ADD COLUMN consensus JSONB NULL; diff --git a/core/lib/dal/migrations/20240103123456_move_consensus_fields_to_new_table.up.sql b/core/lib/dal/migrations/20240103123456_move_consensus_fields_to_new_table.up.sql new file mode 100644 index 000000000000..8f5538ce631b --- /dev/null +++ b/core/lib/dal/migrations/20240103123456_move_consensus_fields_to_new_table.up.sql @@ -0,0 +1,11 @@ +ALTER TABLE miniblocks DROP COLUMN consensus; + +CREATE TABLE miniblocks_consensus ( + number BIGINT NOT NULL, + certificate JSONB NOT NULL, + PRIMARY KEY(number), + CHECK((certificate->'message'->'proposal'->'number')::jsonb::numeric = number), + CONSTRAINT miniblocks_fk FOREIGN KEY(number) + REFERENCES miniblocks(number) + ON DELETE CASCADE +); diff --git a/core/lib/dal/migrations/20240103125908_remove_old_prover_subsystems.down.sql b/core/lib/dal/migrations/20240103125908_remove_old_prover_subsystems.down.sql new file mode 100644 index 000000000000..5b5531589af3 --- /dev/null +++ b/core/lib/dal/migrations/20240103125908_remove_old_prover_subsystems.down.sql @@ -0,0 +1,52 @@ +-- Note that era can't revert to this point in time. +-- These tables are added only if engineers want to revert from a future codebase to a previous codebase. +-- This migration will enable backwards development (i.e. bisecting some error). + +CREATE TABLE IF NOT EXISTS gpu_prover_queue ( + id bigint NOT NULL PRIMARY KEY, + instance_host inet NOT NULL, + instance_port integer NOT NULL, + instance_status text NOT NULL, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + processing_started_at timestamp without time zone, + queue_free_slots integer, + queue_capacity integer, + specialized_prover_group_id smallint, + region text NOT NULL, + zone text NOT NULL, + num_gpu smallint, + CONSTRAINT valid_port CHECK (((instance_port >= 0) AND (instance_port <= 65535))) +); + +CREATE TABLE IF NOT EXISTS prover_jobs ( + id bigint NOT NULL PRIMARY KEY, + l1_batch_number bigint NOT NULL, + circuit_type text NOT NULL, + prover_input bytea NOT NULL, + status text NOT NULL, + error text, + processing_started_at timestamp without time zone, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + time_taken time without time zone DEFAULT '00:00:00'::time without time zone NOT NULL, + aggregation_round integer DEFAULT 0 NOT NULL, + result bytea, + sequence_number integer DEFAULT 0 NOT NULL, + attempts integer DEFAULT 0 NOT NULL, + circuit_input_blob_url text, + proccesed_by text, + is_blob_cleaned boolean DEFAULT false NOT NULL, + protocol_version integer +); + +CREATE TABLE IF NOT EXISTS prover_protocol_versions ( + id integer NOT NULL, + "timestamp" bigint NOT NULL, + recursion_scheduler_level_vk_hash bytea NOT NULL, + recursion_node_level_vk_hash bytea NOT NULL, + recursion_leaf_level_vk_hash bytea NOT NULL, + recursion_circuits_set_vks_hash bytea NOT NULL, + verifier_address bytea NOT NULL, + created_at timestamp without time zone NOT NULL +); diff --git a/core/lib/dal/migrations/20240103125908_remove_old_prover_subsystems.up.sql b/core/lib/dal/migrations/20240103125908_remove_old_prover_subsystems.up.sql new file mode 100644 index 000000000000..473706875fb4 --- /dev/null +++ b/core/lib/dal/migrations/20240103125908_remove_old_prover_subsystems.up.sql @@ -0,0 +1,5 @@ +DROP TABLE IF EXISTS gpu_prover_queue; + +DROP TABLE IF EXISTS prover_jobs; + +DROP TABLE IF EXISTS prover_protocol_versions; diff --git a/core/lib/dal/migrations/20240104121833_l1-batch-predicted-circuits.down.sql b/core/lib/dal/migrations/20240104121833_l1-batch-predicted-circuits.down.sql new file mode 100644 index 000000000000..925299304ebe --- /dev/null +++ b/core/lib/dal/migrations/20240104121833_l1-batch-predicted-circuits.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE l1_batches + DROP COLUMN IF EXISTS predicted_circuits; diff --git a/core/lib/dal/migrations/20240104121833_l1-batch-predicted-circuits.up.sql b/core/lib/dal/migrations/20240104121833_l1-batch-predicted-circuits.up.sql new file mode 100644 index 000000000000..a957fce4d984 --- /dev/null +++ b/core/lib/dal/migrations/20240104121833_l1-batch-predicted-circuits.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE l1_batches + ADD COLUMN IF NOT EXISTS predicted_circuits INT; diff --git a/core/lib/dal/migrations/20240110085604_add-l1-batch-circuit-statistic.down.sql b/core/lib/dal/migrations/20240110085604_add-l1-batch-circuit-statistic.down.sql new file mode 100644 index 000000000000..b2f0caf45ee5 --- /dev/null +++ b/core/lib/dal/migrations/20240110085604_add-l1-batch-circuit-statistic.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE l1_batches + DROP COLUMN IF EXISTS predicted_circuits_by_type; diff --git a/core/lib/dal/migrations/20240110085604_add-l1-batch-circuit-statistic.up.sql b/core/lib/dal/migrations/20240110085604_add-l1-batch-circuit-statistic.up.sql new file mode 100644 index 000000000000..836b8535d4e8 --- /dev/null +++ b/core/lib/dal/migrations/20240110085604_add-l1-batch-circuit-statistic.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE l1_batches + ADD COLUMN IF NOT EXISTS predicted_circuits_by_type JSONB; diff --git a/core/lib/dal/migrations/20240112194527_snapshots_applier_processed_chunks_format_change.down.sql b/core/lib/dal/migrations/20240112194527_snapshots_applier_processed_chunks_format_change.down.sql new file mode 100644 index 000000000000..598af2037d6c --- /dev/null +++ b/core/lib/dal/migrations/20240112194527_snapshots_applier_processed_chunks_format_change.down.sql @@ -0,0 +1,11 @@ +ALTER TABLE snapshot_recovery ADD COLUMN last_finished_chunk_id NOT NULL; +ALTER TABLE snapshot_recovery ADD COLUMN total_chunk_count NOT NULL; + +ALTER TABLE snapshot_recovery DROP COLUMN storage_logs_chunks_processed; + +ALTER TABLE factory_deps ADD CONSTRAINT factory_deps_miniblock_number_fkey + FOREIGN KEY (miniblock_number) REFERENCES miniblocks (number); +ALTER TABLE initial_writes ADD CONSTRAINT initial_writes_l1_batch_number_fkey + FOREIGN KEY (l1_batch_number) REFERENCES l1_batches (number); +ALTER TABLE storage_logs ADD CONSTRAINT storage_logs_miniblock_number_fkey + FOREIGN KEY (miniblock_number) REFERENCES miniblocks (number); diff --git a/core/lib/dal/migrations/20240112194527_snapshots_applier_processed_chunks_format_change.up.sql b/core/lib/dal/migrations/20240112194527_snapshots_applier_processed_chunks_format_change.up.sql new file mode 100644 index 000000000000..3f484c38638f --- /dev/null +++ b/core/lib/dal/migrations/20240112194527_snapshots_applier_processed_chunks_format_change.up.sql @@ -0,0 +1,8 @@ +ALTER TABLE snapshot_recovery DROP COLUMN last_finished_chunk_id; +ALTER TABLE snapshot_recovery DROP COLUMN total_chunk_count; + +ALTER TABLE snapshot_recovery ADD COLUMN storage_logs_chunks_processed BOOL[] NOT NULL; + +ALTER TABLE factory_deps DROP CONSTRAINT factory_deps_miniblock_number_fkey; +ALTER TABLE initial_writes DROP CONSTRAINT initial_writes_l1_batch_number_fkey; +ALTER TABLE storage_logs DROP CONSTRAINT storage_logs_miniblock_number_fkey; diff --git a/core/lib/dal/migrations/20240129133815_revert_removing_snapshot_recovery_columns.down.sql b/core/lib/dal/migrations/20240129133815_revert_removing_snapshot_recovery_columns.down.sql new file mode 100644 index 000000000000..5acb2419084b --- /dev/null +++ b/core/lib/dal/migrations/20240129133815_revert_removing_snapshot_recovery_columns.down.sql @@ -0,0 +1,3 @@ +ALTER TABLE snapshot_recovery + DROP COLUMN IF EXISTS last_finished_chunk_id, + DROP COLUMN IF EXISTS total_chunk_count; diff --git a/core/lib/dal/migrations/20240129133815_revert_removing_snapshot_recovery_columns.up.sql b/core/lib/dal/migrations/20240129133815_revert_removing_snapshot_recovery_columns.up.sql new file mode 100644 index 000000000000..d64008321e51 --- /dev/null +++ b/core/lib/dal/migrations/20240129133815_revert_removing_snapshot_recovery_columns.up.sql @@ -0,0 +1,5 @@ +-- Temporary revert of the previous `snapshot_recovery` so that the migration is backward-compatible. +-- Do not use these columns in code. +ALTER TABLE snapshot_recovery + ADD COLUMN IF NOT EXISTS last_finished_chunk_id INT, + ADD COLUMN IF NOT EXISTS total_chunk_count INT NOT NULL DEFAULT 0; diff --git a/core/lib/dal/migrations/20240131123456_add_consensus_fields_for_miniblocks.down.sql b/core/lib/dal/migrations/20240131123456_add_consensus_fields_for_miniblocks.down.sql new file mode 100644 index 000000000000..701c5e608548 --- /dev/null +++ b/core/lib/dal/migrations/20240131123456_add_consensus_fields_for_miniblocks.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE miniblocks + DROP COLUMN IF EXISTS consensus; diff --git a/core/lib/dal/migrations/20240131123456_add_consensus_fields_for_miniblocks.up.sql b/core/lib/dal/migrations/20240131123456_add_consensus_fields_for_miniblocks.up.sql new file mode 100644 index 000000000000..cdfd74990eaf --- /dev/null +++ b/core/lib/dal/migrations/20240131123456_add_consensus_fields_for_miniblocks.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE miniblocks + ADD COLUMN consensus JSONB NULL; diff --git a/core/lib/dal/migrations/20240202150009_transaction_batch_index.down.sql b/core/lib/dal/migrations/20240202150009_transaction_batch_index.down.sql new file mode 100644 index 000000000000..56795bbe2829 --- /dev/null +++ b/core/lib/dal/migrations/20240202150009_transaction_batch_index.down.sql @@ -0,0 +1,3 @@ +DROP INDEX IF EXISTS transactions_l1_batch_number_idx; +DROP INDEX IF EXISTS aggregated_proof_from_l1_batch_index; +DROP INDEX IF EXISTS aggregated_proof_to_l1_batch_index; \ No newline at end of file diff --git a/core/lib/dal/migrations/20240202150009_transaction_batch_index.up.sql b/core/lib/dal/migrations/20240202150009_transaction_batch_index.up.sql new file mode 100644 index 000000000000..7362bcd006c0 --- /dev/null +++ b/core/lib/dal/migrations/20240202150009_transaction_batch_index.up.sql @@ -0,0 +1,3 @@ +CREATE INDEX IF NOT EXISTS transactions_l1_batch_number_idx ON transactions (l1_batch_number); +CREATE INDEX IF NOT EXISTS aggregated_proof_from_l1_batch_index ON aggregated_proof (from_block_number); +CREATE INDEX IF NOT EXISTS aggregated_proof_to_l1_batch_index ON aggregated_proof (to_block_number); diff --git a/core/lib/dal/migrations/20240204153050_add-miniblocks-l1-batch-index.down.sql b/core/lib/dal/migrations/20240204153050_add-miniblocks-l1-batch-index.down.sql new file mode 100644 index 000000000000..2f1e3a52e8b2 --- /dev/null +++ b/core/lib/dal/migrations/20240204153050_add-miniblocks-l1-batch-index.down.sql @@ -0,0 +1 @@ +drop index ix_miniblocks_t2; diff --git a/core/lib/dal/migrations/20240204153050_add-miniblocks-l1-batch-index.up.sql b/core/lib/dal/migrations/20240204153050_add-miniblocks-l1-batch-index.up.sql new file mode 100644 index 000000000000..37e41b9a59b8 --- /dev/null +++ b/core/lib/dal/migrations/20240204153050_add-miniblocks-l1-batch-index.up.sql @@ -0,0 +1,2 @@ +create index if not exists ix_miniblocks_t2 + on miniblocks (l1_batch_number, number); diff --git a/core/lib/dal/sqlx-data.json b/core/lib/dal/sqlx-data.json deleted file mode 100644 index 36b8bad5787f..000000000000 --- a/core/lib/dal/sqlx-data.json +++ /dev/null @@ -1,12300 +0,0 @@ -{ - "db": "PostgreSQL", - "00b88ec7fcf40bb18e0018b7c76f6e1df560ab1e8935564355236e90b6147d2f": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Time", - "Int8" - ] - } - }, - "query": "\n UPDATE scheduler_witness_jobs_fri\n SET\n status = 'successful',\n updated_at = NOW(),\n time_taken = $1\n WHERE\n l1_batch_number = $2\n " - }, - "012bed5d34240ed28c331c8515c381d82925556a4801f678b8786235d525d784": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int4", - "Int8", - "Int8" - ] - } - }, - "query": "\n UPDATE l1_batches\n SET\n eth_commit_tx_id = $1,\n updated_at = NOW()\n WHERE\n number BETWEEN $2 AND $3\n " - }, - "015350f8d729ef490553550a68f07703b2581dda4fe3c00be6c5422c78980c4b": { - "describe": { - "columns": [ - { - "name": "max?", - "ordinal": 0, - "type_info": "Int4" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n MAX(id) AS \"max?\"\n FROM\n protocol_versions\n " - }, - "01ac5343beb09ec5bd45b39d560e57a83f37da8999849377dfad60b44989be39": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "l1_batch_number", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "circuit_id", - "ordinal": 2, - "type_info": "Int2" - }, - { - "name": "depth", - "ordinal": 3, - "type_info": "Int4" - }, - { - "name": "status", - "ordinal": 4, - "type_info": "Text" - }, - { - "name": "attempts", - "ordinal": 5, - "type_info": "Int2" - }, - { - "name": "aggregations_url", - "ordinal": 6, - "type_info": "Text" - }, - { - "name": "processing_started_at", - "ordinal": 7, - "type_info": "Timestamp" - }, - { - "name": "time_taken", - "ordinal": 8, - "type_info": "Time" - }, - { - "name": "error", - "ordinal": 9, - "type_info": "Text" - }, - { - "name": "created_at", - "ordinal": 10, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 11, - "type_info": "Timestamp" - }, - { - "name": "number_of_dependent_jobs", - "ordinal": 12, - "type_info": "Int4" - }, - { - "name": "protocol_version", - "ordinal": 13, - "type_info": "Int4" - }, - { - "name": "picked_by", - "ordinal": 14, - "type_info": "Text" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - true, - true, - true - ], - "parameters": { - "Left": [ - "Int4Array", - "Text" - ] - } - }, - "query": "\n UPDATE node_aggregation_witness_jobs_fri\n SET\n status = 'in_progress',\n attempts = attempts + 1,\n updated_at = NOW(),\n processing_started_at = NOW(),\n picked_by = $2\n WHERE\n id = (\n SELECT\n id\n FROM\n node_aggregation_witness_jobs_fri\n WHERE\n status = 'queued'\n AND protocol_version = ANY ($1)\n ORDER BY\n l1_batch_number ASC,\n depth ASC,\n id ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n node_aggregation_witness_jobs_fri.*\n " - }, - "01e4cde73867da612084c3f6fe882d56bbace9013f1d95ea0926eef1fb48039b": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "factory_deps_filepath", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "storage_logs_filepaths", - "ordinal": 2, - "type_info": "TextArray" - } - ], - "nullable": [ - false, - false, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n l1_batch_number,\n factory_deps_filepath,\n storage_logs_filepaths\n FROM\n snapshots\n WHERE\n l1_batch_number = $1\n " - }, - "01f72dfc1eee6360a8ef7809874a1b4ba7fe355ebc02ea49a054aa073ce324ba": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "ByteaArray", - "ByteaArray" - ] - } - }, - "query": "\n UPDATE storage\n SET\n value = u.value\n FROM\n UNNEST($1::bytea[], $2::bytea[]) AS u (key, value)\n WHERE\n u.key = hashed_key\n " - }, - "02285b8d0bc76c8cfd259872ac24f3670813e5a5356ddcb7ac482a0201d045f7": { - "describe": { - "columns": [ - { - "name": "tx_hash", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "index_in_block", - "ordinal": 1, - "type_info": "Int4" - }, - { - "name": "l1_batch_tx_index", - "ordinal": 2, - "type_info": "Int4" - }, - { - "name": "block_number!", - "ordinal": 3, - "type_info": "Int8" - }, - { - "name": "error", - "ordinal": 4, - "type_info": "Varchar" - }, - { - "name": "effective_gas_price", - "ordinal": 5, - "type_info": "Numeric" - }, - { - "name": "initiator_address", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "transfer_to?", - "ordinal": 7, - "type_info": "Jsonb" - }, - { - "name": "execute_contract_address?", - "ordinal": 8, - "type_info": "Jsonb" - }, - { - "name": "tx_format?", - "ordinal": 9, - "type_info": "Int4" - }, - { - "name": "refunded_gas", - "ordinal": 10, - "type_info": "Int8" - }, - { - "name": "gas_limit", - "ordinal": 11, - "type_info": "Numeric" - }, - { - "name": "block_hash", - "ordinal": 12, - "type_info": "Bytea" - }, - { - "name": "l1_batch_number?", - "ordinal": 13, - "type_info": "Int8" - }, - { - "name": "contract_address?", - "ordinal": 14, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - true, - true, - true, - true, - true, - false, - null, - null, - true, - false, - true, - false, - true, - false - ], - "parameters": { - "Left": [ - "Bytea", - "Bytea", - "Bytea" - ] - } - }, - "query": "\n WITH\n sl AS (\n SELECT\n *\n FROM\n storage_logs\n WHERE\n storage_logs.address = $1\n AND storage_logs.tx_hash = $2\n ORDER BY\n storage_logs.miniblock_number DESC,\n storage_logs.operation_number DESC\n LIMIT\n 1\n )\n SELECT\n transactions.hash AS tx_hash,\n transactions.index_in_block AS index_in_block,\n transactions.l1_batch_tx_index AS l1_batch_tx_index,\n transactions.miniblock_number AS \"block_number!\",\n transactions.error AS error,\n transactions.effective_gas_price AS effective_gas_price,\n transactions.initiator_address AS initiator_address,\n transactions.data -> 'to' AS \"transfer_to?\",\n transactions.data -> 'contractAddress' AS \"execute_contract_address?\",\n transactions.tx_format AS \"tx_format?\",\n transactions.refunded_gas AS refunded_gas,\n transactions.gas_limit AS gas_limit,\n miniblocks.hash AS \"block_hash\",\n miniblocks.l1_batch_number AS \"l1_batch_number?\",\n sl.key AS \"contract_address?\"\n FROM\n transactions\n JOIN miniblocks ON miniblocks.number = transactions.miniblock_number\n LEFT JOIN sl ON sl.value != $3\n WHERE\n transactions.hash = $2\n " - }, - "026ab7dd7407f10074a2966b5eac2563a3e061bcc6505d8c295b1b2517f85f1b": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n number\n FROM\n l1_batches\n LEFT JOIN eth_txs_history AS prove_tx ON (l1_batches.eth_prove_tx_id = prove_tx.eth_tx_id)\n WHERE\n prove_tx.confirmed_at IS NOT NULL\n ORDER BY\n number DESC\n LIMIT\n 1\n " - }, - "03c585c7e9f918e608757496088c7e3b6bdb2a08149d5f443310607d3c78988c": { - "describe": { - "columns": [ - { - "name": "storage_refunds", - "ordinal": 0, - "type_info": "Int8Array" - } - ], - "nullable": [ - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n storage_refunds\n FROM\n l1_batches\n WHERE\n number = $1\n " - }, - "04fbbd198108d2614a3b29fa795994723ebe57b3ed209069bd3db906921ef1a3": { - "describe": { - "columns": [ - { - "name": "min?", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "max?", - "ordinal": 1, - "type_info": "Int8" - } - ], - "nullable": [ - null, - null - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n MIN(miniblocks.number) AS \"min?\",\n MAX(miniblocks.number) AS \"max?\"\n FROM\n miniblocks\n WHERE\n l1_batch_number = $1\n " - }, - "05267e9774056bb0f984918ab861a2ee78eb59628d0429e89b27d185f83512be": { - "describe": { - "columns": [ - { - "name": "tx_hash", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "call_trace", - "ordinal": 1, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n *\n FROM\n call_traces\n WHERE\n tx_hash IN (\n SELECT\n hash\n FROM\n transactions\n WHERE\n miniblock_number = $1\n )\n " - }, - "0587fadb4f7a014caddf9e540cd2a1ece830de8777d945d48bd9c796fefb3253": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text", - "Int8" - ] - } - }, - "query": "\n UPDATE prover_jobs\n SET\n status = $1,\n updated_at = NOW()\n WHERE\n id = $2\n " - }, - "07310d96fc7e258154ad510684e33d196907ebd599e926d305e5ef9f26afa2fa": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int4" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int4", - "Text", - "Timestamp" - ] - } - }, - "query": "INSERT INTO eth_txs_history (eth_tx_id, base_fee_per_gas, priority_fee_per_gas, tx_hash, signed_raw_tx, created_at, updated_at, confirmed_at) VALUES ($1, 0, 0, $2, '\\x00', now(), now(), $3) RETURNING id" - }, - "08024b2ba970d2fdac2a71c9c7c73be42a289d034670ca4e644f5df1e4614ddf": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Text", - "Int4", - "Bytea", - "Int4", - "Text", - "Int4" - ] - } - }, - "query": "\n INSERT INTO\n prover_jobs (\n l1_batch_number,\n circuit_type,\n sequence_number,\n prover_input,\n aggregation_round,\n circuit_input_blob_url,\n protocol_version,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, 'queued', NOW(), NOW())\n ON CONFLICT (l1_batch_number, aggregation_round, sequence_number) DO NOTHING\n " - }, - "083991abb3f1c2183d1bd1fb2ad4710daa723e2d9a23317c347f6081465c3643": { - "describe": { - "columns": [ - { - "name": "attempts", - "ordinal": 0, - "type_info": "Int2" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - { - "Custom": { - "kind": { - "Enum": [ - "Queued", - "ManuallySkipped", - "InProgress", - "Successful", - "Failed" - ] - }, - "name": "basic_witness_input_producer_job_status" - } - }, - "Int8", - "Time", - "Text", - { - "Custom": { - "kind": { - "Enum": [ - "Queued", - "ManuallySkipped", - "InProgress", - "Successful", - "Failed" - ] - }, - "name": "basic_witness_input_producer_job_status" - } - } - ] - } - }, - "query": "\n UPDATE basic_witness_input_producer_jobs\n SET\n status = $1,\n updated_at = NOW(),\n time_taken = $3,\n error = $4\n WHERE\n l1_batch_number = $2\n AND status != $5\n RETURNING\n basic_witness_input_producer_jobs.attempts\n " - }, - "08e59ed8e2fd1a74e19d8bf0d131e4ee6682a89fb86f3b715a240805d44e6d87": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Text" - ] - } - }, - "query": "\n INSERT INTO\n proof_generation_details (l1_batch_number, status, proof_gen_data_blob_url, created_at, updated_at)\n VALUES\n ($1, 'ready_to_be_proven', $2, NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO NOTHING\n " - }, - "0914f0ad03d6a8c55d287f94917c6f03469d78bf4f45f5fd1eaf37171db2f04a": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n l1_batch_number\n FROM\n proof_generation_details\n WHERE\n status NOT IN ('generated', 'skipped')\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n " - }, - "0a3c928a616b5ebc0b977bd773edcde721ca1c652ae2f8db41fb75cecdecb674": { - "describe": { - "columns": [ - { - "name": "count", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "SELECT COUNT(*) FROM storage_logs WHERE miniblock_number = $1" - }, - "0a3cb11f5bdcb8da31dbd4e3016fced141fb29dd8b6c32dd2dc3452dc294fe1f": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int4", - "Int8", - "Bytea", - "Bytea", - "Bytea", - "Bytea", - "Bytea", - "Bytea", - "Bytea", - "Bytea" - ] - } - }, - "query": "\n INSERT INTO\n protocol_versions (\n id,\n timestamp,\n recursion_scheduler_level_vk_hash,\n recursion_node_level_vk_hash,\n recursion_leaf_level_vk_hash,\n recursion_circuits_set_vks_hash,\n bootloader_code_hash,\n default_account_code_hash,\n verifier_address,\n upgrade_tx_hash,\n created_at\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, NOW())\n " - }, - "0a53fc3c90a14038c9f3f32c3e2e5f7edcafa4fc6757264a96a46dbf7dd1f9cc": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Bytea", - "Bytea", - "Numeric", - "Numeric", - "Numeric", - "Jsonb", - "Int8", - "Numeric", - "Numeric", - "Bytea", - "Int4", - "Numeric", - "Bytea", - "Bytea", - "Int4", - "Numeric", - "Bytea", - "Timestamp" - ] - } - }, - "query": "\n INSERT INTO\n transactions (\n hash,\n is_priority,\n initiator_address,\n gas_limit,\n max_fee_per_gas,\n gas_per_pubdata_limit,\n data,\n priority_op_id,\n full_fee,\n layer_2_tip_fee,\n contract_address,\n l1_block_number,\n value,\n paymaster,\n paymaster_input,\n tx_format,\n l1_tx_mint,\n l1_tx_refund_recipient,\n received_at,\n created_at,\n updated_at\n )\n VALUES\n (\n $1,\n TRUE,\n $2,\n $3,\n $4,\n $5,\n $6,\n $7,\n $8,\n $9,\n $10,\n $11,\n $12,\n $13,\n $14,\n $15,\n $16,\n $17,\n $18,\n NOW(),\n NOW()\n )\n ON CONFLICT (hash) DO NOTHING\n " - }, - "0aaefa9d5518ed1a2d8f735435e8048558243ff878b59586eb3a8b22794395d8": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "timestamp", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "is_finished", - "ordinal": 2, - "type_info": "Bool" - }, - { - "name": "l1_tx_count", - "ordinal": 3, - "type_info": "Int4" - }, - { - "name": "l2_tx_count", - "ordinal": 4, - "type_info": "Int4" - }, - { - "name": "fee_account_address", - "ordinal": 5, - "type_info": "Bytea" - }, - { - "name": "bloom", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "priority_ops_onchain_data", - "ordinal": 7, - "type_info": "ByteaArray" - }, - { - "name": "hash", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "parent_hash", - "ordinal": 9, - "type_info": "Bytea" - }, - { - "name": "commitment", - "ordinal": 10, - "type_info": "Bytea" - }, - { - "name": "compressed_write_logs", - "ordinal": 11, - "type_info": "Bytea" - }, - { - "name": "compressed_contracts", - "ordinal": 12, - "type_info": "Bytea" - }, - { - "name": "eth_prove_tx_id", - "ordinal": 13, - "type_info": "Int4" - }, - { - "name": "eth_commit_tx_id", - "ordinal": 14, - "type_info": "Int4" - }, - { - "name": "eth_execute_tx_id", - "ordinal": 15, - "type_info": "Int4" - }, - { - "name": "merkle_root_hash", - "ordinal": 16, - "type_info": "Bytea" - }, - { - "name": "l2_to_l1_logs", - "ordinal": 17, - "type_info": "ByteaArray" - }, - { - "name": "l2_to_l1_messages", - "ordinal": 18, - "type_info": "ByteaArray" - }, - { - "name": "used_contract_hashes", - "ordinal": 19, - "type_info": "Jsonb" - }, - { - "name": "compressed_initial_writes", - "ordinal": 20, - "type_info": "Bytea" - }, - { - "name": "compressed_repeated_writes", - "ordinal": 21, - "type_info": "Bytea" - }, - { - "name": "l2_l1_compressed_messages", - "ordinal": 22, - "type_info": "Bytea" - }, - { - "name": "l2_l1_merkle_root", - "ordinal": 23, - "type_info": "Bytea" - }, - { - "name": "l1_gas_price", - "ordinal": 24, - "type_info": "Int8" - }, - { - "name": "l2_fair_gas_price", - "ordinal": 25, - "type_info": "Int8" - }, - { - "name": "rollup_last_leaf_index", - "ordinal": 26, - "type_info": "Int8" - }, - { - "name": "zkporter_is_available", - "ordinal": 27, - "type_info": "Bool" - }, - { - "name": "bootloader_code_hash", - "ordinal": 28, - "type_info": "Bytea" - }, - { - "name": "default_aa_code_hash", - "ordinal": 29, - "type_info": "Bytea" - }, - { - "name": "base_fee_per_gas", - "ordinal": 30, - "type_info": "Numeric" - }, - { - "name": "aux_data_hash", - "ordinal": 31, - "type_info": "Bytea" - }, - { - "name": "pass_through_data_hash", - "ordinal": 32, - "type_info": "Bytea" - }, - { - "name": "meta_parameters_hash", - "ordinal": 33, - "type_info": "Bytea" - }, - { - "name": "protocol_version", - "ordinal": 34, - "type_info": "Int4" - }, - { - "name": "compressed_state_diffs", - "ordinal": 35, - "type_info": "Bytea" - }, - { - "name": "system_logs", - "ordinal": 36, - "type_info": "ByteaArray" - }, - { - "name": "events_queue_commitment", - "ordinal": 37, - "type_info": "Bytea" - }, - { - "name": "bootloader_initial_content_commitment", - "ordinal": 38, - "type_info": "Bytea" - }, - { - "name": "pubdata_input", - "ordinal": 39, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - true, - true, - true, - true, - false, - false, - true, - true, - true, - true, - false, - true, - true, - true, - true, - true, - false, - true, - true, - true - ], - "parameters": { - "Left": [ - "Bytea", - "Bytea", - "Int4", - "Int8" - ] - } - }, - "query": "\n SELECT\n number,\n l1_batches.timestamp,\n is_finished,\n l1_tx_count,\n l2_tx_count,\n fee_account_address,\n bloom,\n priority_ops_onchain_data,\n hash,\n parent_hash,\n commitment,\n compressed_write_logs,\n compressed_contracts,\n eth_prove_tx_id,\n eth_commit_tx_id,\n eth_execute_tx_id,\n merkle_root_hash,\n l2_to_l1_logs,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_compressed_messages,\n l2_l1_merkle_root,\n l1_gas_price,\n l2_fair_gas_price,\n rollup_last_leaf_index,\n zkporter_is_available,\n l1_batches.bootloader_code_hash,\n l1_batches.default_aa_code_hash,\n base_fee_per_gas,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n JOIN protocol_versions ON protocol_versions.id = l1_batches.protocol_version\n WHERE\n eth_commit_tx_id IS NULL\n AND number != 0\n AND protocol_versions.bootloader_code_hash = $1\n AND protocol_versions.default_account_code_hash = $2\n AND commitment IS NOT NULL\n AND (\n protocol_versions.id = $3\n OR protocol_versions.upgrade_tx_hash IS NULL\n )\n ORDER BY\n number\n LIMIT\n $4\n " - }, - "0bdcf87f6910c7222b621f76f71bc6e326e15dca141050bc9d7dacae98a430e8": { - "describe": { - "columns": [ - { - "name": "hash", - "ordinal": 0, - "type_info": "Bytea" - } - ], - "nullable": [ - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n hash\n FROM\n l1_batches\n WHERE\n number = $1\n " - }, - "0c899c68886f76a232ffac0454cdfbf962636347864fc365fafa46c7a2da5f30": { - "describe": { - "columns": [ - { - "name": "virtual_blocks", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n virtual_blocks\n FROM\n miniblocks\n WHERE\n number = $1\n " - }, - "0c95fbfb3a816bd49fd06e3a4f0a52daa202279bf612a9278f663deb78bc6e41": { - "describe": { - "columns": [ - { - "name": "protocol_version", - "ordinal": 0, - "type_info": "Int4" - } - ], - "nullable": [ - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n protocol_version\n FROM\n l1_batches\n WHERE\n number = $1\n " - }, - "0d13b8947b1bafa9e5bc6fdc70a986511265c541d81b1d21f0a751ae1399c626": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "instance_host", - "ordinal": 1, - "type_info": "Inet" - }, - { - "name": "instance_port", - "ordinal": 2, - "type_info": "Int4" - }, - { - "name": "instance_status", - "ordinal": 3, - "type_info": "Text" - }, - { - "name": "specialized_prover_group_id", - "ordinal": 4, - "type_info": "Int2" - }, - { - "name": "zone", - "ordinal": 5, - "type_info": "Text" - }, - { - "name": "created_at", - "ordinal": 6, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 7, - "type_info": "Timestamp" - }, - { - "name": "processing_started_at", - "ordinal": 8, - "type_info": "Timestamp" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - true, - false, - false, - true - ], - "parameters": { - "Left": [ - "Interval", - "Int2", - "Text" - ] - } - }, - "query": "\n UPDATE gpu_prover_queue_fri\n SET\n instance_status = 'reserved',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n id IN (\n SELECT\n id\n FROM\n gpu_prover_queue_fri\n WHERE\n specialized_prover_group_id = $2\n AND zone = $3\n AND (\n instance_status = 'available'\n OR (\n instance_status = 'reserved'\n AND processing_started_at < NOW() - $1::INTERVAL\n )\n )\n ORDER BY\n updated_at ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n gpu_prover_queue_fri.*\n " - }, - "0e1317c908de3d9b9b87b51802cbe545198d7debecd65dc2165731c8a0c0f508": { - "describe": { - "columns": [ - { - "name": "l1_batch_number!", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "circuit_type", - "ordinal": 1, - "type_info": "Text" - } - ], - "nullable": [ - null, - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n MIN(l1_batch_number) AS \"l1_batch_number!\",\n circuit_type\n FROM\n prover_jobs\n WHERE\n aggregation_round = 0\n AND (\n status = 'queued'\n OR status = 'in_progress'\n OR status = 'in_gpu_proof'\n OR status = 'failed'\n )\n GROUP BY\n circuit_type\n " - }, - "10959c91f01ce0da196f4c6eaf0661a097308d9f81024fdfef24a14418202730": { - "describe": { - "columns": [ - { - "name": "verification_info", - "ordinal": 0, - "type_info": "Jsonb" - } - ], - "nullable": [ - true - ], - "parameters": { - "Left": [ - "Bytea" - ] - } - }, - "query": "\n SELECT\n verification_info\n FROM\n contracts_verification_info\n WHERE\n address = $1\n " - }, - "11af69fc254e54449b64c086667700a95e4c37a7a18531b3cdf120394cb055b9": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Interval" - ] - } - }, - "query": "\n UPDATE proof_generation_details\n SET\n status = 'picked_by_prover',\n updated_at = NOW(),\n prover_taken_at = NOW()\n WHERE\n l1_batch_number = (\n SELECT\n l1_batch_number\n FROM\n proof_generation_details\n WHERE\n status = 'ready_to_be_proven'\n OR (\n status = 'picked_by_prover'\n AND prover_taken_at < NOW() - $1::INTERVAL\n )\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n proof_generation_details.l1_batch_number\n " - }, - "12ab208f416e2875f89e558f0d4aff3a06b7a9c1866132d62e4449fa9436c7c4": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text", - "Int8" - ] - } - }, - "query": "\n UPDATE node_aggregation_witness_jobs_fri\n SET\n status = 'failed',\n error = $1,\n updated_at = NOW()\n WHERE\n id = $2\n " - }, - "12ab8ba692a42f528450f2adf8d263298abc0521734f807fbf45484158b167b2": { - "describe": { - "columns": [ - { - "name": "l1_address", - "ordinal": 0, - "type_info": "Bytea" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n l1_address\n FROM\n tokens\n WHERE\n well_known = FALSE\n " - }, - "136569d7eb4037fd77e0fac2246c68e8e15a831f1a45dc3b2240d5c6809d5ef2": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int4" - }, - { - "name": "timestamp", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "recursion_scheduler_level_vk_hash", - "ordinal": 2, - "type_info": "Bytea" - }, - { - "name": "recursion_node_level_vk_hash", - "ordinal": 3, - "type_info": "Bytea" - }, - { - "name": "recursion_leaf_level_vk_hash", - "ordinal": 4, - "type_info": "Bytea" - }, - { - "name": "recursion_circuits_set_vks_hash", - "ordinal": 5, - "type_info": "Bytea" - }, - { - "name": "bootloader_code_hash", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "default_account_code_hash", - "ordinal": 7, - "type_info": "Bytea" - }, - { - "name": "verifier_address", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "upgrade_tx_hash", - "ordinal": 9, - "type_info": "Bytea" - }, - { - "name": "created_at", - "ordinal": 10, - "type_info": "Timestamp" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - false - ], - "parameters": { - "Left": [ - "Int4" - ] - } - }, - "query": "\n SELECT\n *\n FROM\n protocol_versions\n WHERE\n id = $1\n " - }, - "15858168fea6808c6d59d0e6d8f28a20420763a3a22899ad0e5f4b953b615a9e": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int4" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Bytea", - "Bytea", - "Bytea", - "Bytea" - ] - } - }, - "query": "\n SELECT\n id\n FROM\n prover_fri_protocol_versions\n WHERE\n recursion_circuits_set_vks_hash = $1\n AND recursion_leaf_level_vk_hash = $2\n AND recursion_node_level_vk_hash = $3\n AND recursion_scheduler_level_vk_hash = $4\n " - }, - "15893d68429ba09662ee27935653c17c7a7939195dd2d9aa42512b1479d2ed20": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "l1_batch_number!", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "last_batch_miniblock?", - "ordinal": 2, - "type_info": "Int8" - }, - { - "name": "timestamp", - "ordinal": 3, - "type_info": "Int8" - }, - { - "name": "l1_gas_price", - "ordinal": 4, - "type_info": "Int8" - }, - { - "name": "l2_fair_gas_price", - "ordinal": 5, - "type_info": "Int8" - }, - { - "name": "bootloader_code_hash", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "default_aa_code_hash", - "ordinal": 7, - "type_info": "Bytea" - }, - { - "name": "virtual_blocks", - "ordinal": 8, - "type_info": "Int8" - }, - { - "name": "hash", - "ordinal": 9, - "type_info": "Bytea" - }, - { - "name": "consensus", - "ordinal": 10, - "type_info": "Jsonb" - }, - { - "name": "protocol_version!", - "ordinal": 11, - "type_info": "Int4" - }, - { - "name": "fee_account_address?", - "ordinal": 12, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - null, - null, - false, - false, - false, - true, - true, - false, - false, - true, - true, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n miniblocks.number,\n COALESCE(\n miniblocks.l1_batch_number,\n (\n SELECT\n (MAX(number) + 1)\n FROM\n l1_batches\n )\n ) AS \"l1_batch_number!\",\n (\n SELECT\n MAX(m2.number)\n FROM\n miniblocks m2\n WHERE\n miniblocks.l1_batch_number = m2.l1_batch_number\n ) AS \"last_batch_miniblock?\",\n miniblocks.timestamp,\n miniblocks.l1_gas_price,\n miniblocks.l2_fair_gas_price,\n miniblocks.bootloader_code_hash,\n miniblocks.default_aa_code_hash,\n miniblocks.virtual_blocks,\n miniblocks.hash,\n miniblocks.consensus,\n miniblocks.protocol_version AS \"protocol_version!\",\n l1_batches.fee_account_address AS \"fee_account_address?\"\n FROM\n miniblocks\n LEFT JOIN l1_batches ON miniblocks.l1_batch_number = l1_batches.number\n WHERE\n miniblocks.number = $1\n " - }, - "1689c212d411ebd99a22210519ea2d505a1aabf52ff4136d2ed1b39c70dd1632": { - "describe": { - "columns": [ - { - "name": "hash", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "is_priority", - "ordinal": 1, - "type_info": "Bool" - }, - { - "name": "full_fee", - "ordinal": 2, - "type_info": "Numeric" - }, - { - "name": "layer_2_tip_fee", - "ordinal": 3, - "type_info": "Numeric" - }, - { - "name": "initiator_address", - "ordinal": 4, - "type_info": "Bytea" - }, - { - "name": "nonce", - "ordinal": 5, - "type_info": "Int8" - }, - { - "name": "signature", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "input", - "ordinal": 7, - "type_info": "Bytea" - }, - { - "name": "data", - "ordinal": 8, - "type_info": "Jsonb" - }, - { - "name": "received_at", - "ordinal": 9, - "type_info": "Timestamp" - }, - { - "name": "priority_op_id", - "ordinal": 10, - "type_info": "Int8" - }, - { - "name": "l1_batch_number", - "ordinal": 11, - "type_info": "Int8" - }, - { - "name": "index_in_block", - "ordinal": 12, - "type_info": "Int4" - }, - { - "name": "error", - "ordinal": 13, - "type_info": "Varchar" - }, - { - "name": "gas_limit", - "ordinal": 14, - "type_info": "Numeric" - }, - { - "name": "gas_per_storage_limit", - "ordinal": 15, - "type_info": "Numeric" - }, - { - "name": "gas_per_pubdata_limit", - "ordinal": 16, - "type_info": "Numeric" - }, - { - "name": "tx_format", - "ordinal": 17, - "type_info": "Int4" - }, - { - "name": "created_at", - "ordinal": 18, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 19, - "type_info": "Timestamp" - }, - { - "name": "execution_info", - "ordinal": 20, - "type_info": "Jsonb" - }, - { - "name": "contract_address", - "ordinal": 21, - "type_info": "Bytea" - }, - { - "name": "in_mempool", - "ordinal": 22, - "type_info": "Bool" - }, - { - "name": "l1_block_number", - "ordinal": 23, - "type_info": "Int4" - }, - { - "name": "value", - "ordinal": 24, - "type_info": "Numeric" - }, - { - "name": "paymaster", - "ordinal": 25, - "type_info": "Bytea" - }, - { - "name": "paymaster_input", - "ordinal": 26, - "type_info": "Bytea" - }, - { - "name": "max_fee_per_gas", - "ordinal": 27, - "type_info": "Numeric" - }, - { - "name": "max_priority_fee_per_gas", - "ordinal": 28, - "type_info": "Numeric" - }, - { - "name": "effective_gas_price", - "ordinal": 29, - "type_info": "Numeric" - }, - { - "name": "miniblock_number", - "ordinal": 30, - "type_info": "Int8" - }, - { - "name": "l1_batch_tx_index", - "ordinal": 31, - "type_info": "Int4" - }, - { - "name": "refunded_gas", - "ordinal": 32, - "type_info": "Int8" - }, - { - "name": "l1_tx_mint", - "ordinal": 33, - "type_info": "Numeric" - }, - { - "name": "l1_tx_refund_recipient", - "ordinal": 34, - "type_info": "Bytea" - }, - { - "name": "upgrade_id", - "ordinal": 35, - "type_info": "Int4" - } - ], - "nullable": [ - false, - false, - true, - true, - false, - true, - true, - true, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - true, - false, - true, - false, - false, - false, - true, - true, - true, - true, - true, - false, - true, - true, - true - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n *\n FROM\n transactions\n WHERE\n miniblock_number IS NOT NULL\n AND l1_batch_number IS NULL\n ORDER BY\n miniblock_number,\n index_in_block\n " - }, - "16e62660fd14f6d3731e69fa696a36408510bb05c15285dfa7708bc0b044d0c5": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "timestamp", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "is_finished", - "ordinal": 2, - "type_info": "Bool" - }, - { - "name": "l1_tx_count", - "ordinal": 3, - "type_info": "Int4" - }, - { - "name": "l2_tx_count", - "ordinal": 4, - "type_info": "Int4" - }, - { - "name": "fee_account_address", - "ordinal": 5, - "type_info": "Bytea" - }, - { - "name": "bloom", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "priority_ops_onchain_data", - "ordinal": 7, - "type_info": "ByteaArray" - }, - { - "name": "hash", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "parent_hash", - "ordinal": 9, - "type_info": "Bytea" - }, - { - "name": "commitment", - "ordinal": 10, - "type_info": "Bytea" - }, - { - "name": "compressed_write_logs", - "ordinal": 11, - "type_info": "Bytea" - }, - { - "name": "compressed_contracts", - "ordinal": 12, - "type_info": "Bytea" - }, - { - "name": "eth_prove_tx_id", - "ordinal": 13, - "type_info": "Int4" - }, - { - "name": "eth_commit_tx_id", - "ordinal": 14, - "type_info": "Int4" - }, - { - "name": "eth_execute_tx_id", - "ordinal": 15, - "type_info": "Int4" - }, - { - "name": "merkle_root_hash", - "ordinal": 16, - "type_info": "Bytea" - }, - { - "name": "l2_to_l1_logs", - "ordinal": 17, - "type_info": "ByteaArray" - }, - { - "name": "l2_to_l1_messages", - "ordinal": 18, - "type_info": "ByteaArray" - }, - { - "name": "used_contract_hashes", - "ordinal": 19, - "type_info": "Jsonb" - }, - { - "name": "compressed_initial_writes", - "ordinal": 20, - "type_info": "Bytea" - }, - { - "name": "compressed_repeated_writes", - "ordinal": 21, - "type_info": "Bytea" - }, - { - "name": "l2_l1_compressed_messages", - "ordinal": 22, - "type_info": "Bytea" - }, - { - "name": "l2_l1_merkle_root", - "ordinal": 23, - "type_info": "Bytea" - }, - { - "name": "l1_gas_price", - "ordinal": 24, - "type_info": "Int8" - }, - { - "name": "l2_fair_gas_price", - "ordinal": 25, - "type_info": "Int8" - }, - { - "name": "rollup_last_leaf_index", - "ordinal": 26, - "type_info": "Int8" - }, - { - "name": "zkporter_is_available", - "ordinal": 27, - "type_info": "Bool" - }, - { - "name": "bootloader_code_hash", - "ordinal": 28, - "type_info": "Bytea" - }, - { - "name": "default_aa_code_hash", - "ordinal": 29, - "type_info": "Bytea" - }, - { - "name": "base_fee_per_gas", - "ordinal": 30, - "type_info": "Numeric" - }, - { - "name": "aux_data_hash", - "ordinal": 31, - "type_info": "Bytea" - }, - { - "name": "pass_through_data_hash", - "ordinal": 32, - "type_info": "Bytea" - }, - { - "name": "meta_parameters_hash", - "ordinal": 33, - "type_info": "Bytea" - }, - { - "name": "protocol_version", - "ordinal": 34, - "type_info": "Int4" - }, - { - "name": "compressed_state_diffs", - "ordinal": 35, - "type_info": "Bytea" - }, - { - "name": "system_logs", - "ordinal": 36, - "type_info": "ByteaArray" - }, - { - "name": "events_queue_commitment", - "ordinal": 37, - "type_info": "Bytea" - }, - { - "name": "bootloader_initial_content_commitment", - "ordinal": 38, - "type_info": "Bytea" - }, - { - "name": "pubdata_input", - "ordinal": 39, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - true, - true, - true, - true, - false, - false, - true, - true, - true, - true, - false, - true, - true, - true, - true, - true, - false, - true, - true, - true - ], - "parameters": { - "Left": [ - "Bytea", - "Bytea", - "Int4", - "Int8" - ] - } - }, - "query": "\n SELECT\n number,\n l1_batches.timestamp,\n is_finished,\n l1_tx_count,\n l2_tx_count,\n fee_account_address,\n bloom,\n priority_ops_onchain_data,\n hash,\n parent_hash,\n commitment,\n compressed_write_logs,\n compressed_contracts,\n eth_prove_tx_id,\n eth_commit_tx_id,\n eth_execute_tx_id,\n merkle_root_hash,\n l2_to_l1_logs,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_compressed_messages,\n l2_l1_merkle_root,\n l1_gas_price,\n l2_fair_gas_price,\n rollup_last_leaf_index,\n zkporter_is_available,\n l1_batches.bootloader_code_hash,\n l1_batches.default_aa_code_hash,\n base_fee_per_gas,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n JOIN protocol_versions ON protocol_versions.id = l1_batches.protocol_version\n WHERE\n eth_commit_tx_id IS NULL\n AND number != 0\n AND protocol_versions.bootloader_code_hash = $1\n AND protocol_versions.default_account_code_hash = $2\n AND commitment IS NOT NULL\n AND (\n protocol_versions.id = $3\n OR protocol_versions.upgrade_tx_hash IS NULL\n )\n AND events_queue_commitment IS NOT NULL\n AND bootloader_initial_content_commitment IS NOT NULL\n ORDER BY\n number\n LIMIT\n $4\n " - }, - "1766c0a21ba5918dd08f4babd8dbfdf10fb1cb43781219586c169fb976204331": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Bytea" - ] - } - }, - "query": "\n SELECT\n l1_batch_number\n FROM\n initial_writes\n WHERE\n hashed_key = $1\n " - }, - "1862d3a78e4e9068df1b8ce3bbe9f3f0b5d629fdb5c36ea1bfb93ed246be968e": { - "describe": { - "columns": [ - { - "name": "is_priority", - "ordinal": 0, - "type_info": "Bool" - }, - { - "name": "initiator_address", - "ordinal": 1, - "type_info": "Bytea" - }, - { - "name": "gas_limit", - "ordinal": 2, - "type_info": "Numeric" - }, - { - "name": "gas_per_pubdata_limit", - "ordinal": 3, - "type_info": "Numeric" - }, - { - "name": "received_at", - "ordinal": 4, - "type_info": "Timestamp" - }, - { - "name": "miniblock_number", - "ordinal": 5, - "type_info": "Int8" - }, - { - "name": "error", - "ordinal": 6, - "type_info": "Varchar" - }, - { - "name": "effective_gas_price", - "ordinal": 7, - "type_info": "Numeric" - }, - { - "name": "refunded_gas", - "ordinal": 8, - "type_info": "Int8" - }, - { - "name": "eth_commit_tx_hash?", - "ordinal": 9, - "type_info": "Text" - }, - { - "name": "eth_prove_tx_hash?", - "ordinal": 10, - "type_info": "Text" - }, - { - "name": "eth_execute_tx_hash?", - "ordinal": 11, - "type_info": "Text" - } - ], - "nullable": [ - false, - false, - true, - true, - false, - true, - true, - true, - false, - false, - false, - false - ], - "parameters": { - "Left": [ - "Bytea" - ] - } - }, - "query": "\n SELECT\n transactions.is_priority,\n transactions.initiator_address,\n transactions.gas_limit,\n transactions.gas_per_pubdata_limit,\n transactions.received_at,\n transactions.miniblock_number,\n transactions.error,\n transactions.effective_gas_price,\n transactions.refunded_gas,\n commit_tx.tx_hash AS \"eth_commit_tx_hash?\",\n prove_tx.tx_hash AS \"eth_prove_tx_hash?\",\n execute_tx.tx_hash AS \"eth_execute_tx_hash?\"\n FROM\n transactions\n LEFT JOIN miniblocks ON miniblocks.number = transactions.miniblock_number\n LEFT JOIN l1_batches ON l1_batches.number = miniblocks.l1_batch_number\n LEFT JOIN eth_txs_history AS commit_tx ON (\n l1_batches.eth_commit_tx_id = commit_tx.eth_tx_id\n AND commit_tx.confirmed_at IS NOT NULL\n )\n LEFT JOIN eth_txs_history AS prove_tx ON (\n l1_batches.eth_prove_tx_id = prove_tx.eth_tx_id\n AND prove_tx.confirmed_at IS NOT NULL\n )\n LEFT JOIN eth_txs_history AS execute_tx ON (\n l1_batches.eth_execute_tx_id = execute_tx.eth_tx_id\n AND execute_tx.confirmed_at IS NOT NULL\n )\n WHERE\n transactions.hash = $1\n " - }, - "18820f4ab0c3d2cc9187c5660f9f50e423eb6134659fe52bcc2b27ad16740c96": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "ByteaArray" - ] - } - }, - "query": "\n DELETE FROM transactions\n WHERE\n in_mempool = TRUE\n AND initiator_address = ANY ($1)\n " - }, - "19314d74e94b610e2da6d728ca37ea964610e131d45f720f7a7b2a130fe9ed89": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Text", - "Jsonb", - "Text" - ] - } - }, - "query": "\n UPDATE contract_verification_requests\n SET\n status = 'failed',\n updated_at = NOW(),\n error = $2,\n compilation_errors = $3,\n panic_message = $4\n WHERE\n id = $1\n " - }, - "19545806b8f772075096e69f8665d98a3d9f7df162ae22a98c3c7620fcd13bd2": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int4" - }, - { - "name": "timestamp", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "recursion_scheduler_level_vk_hash", - "ordinal": 2, - "type_info": "Bytea" - }, - { - "name": "recursion_node_level_vk_hash", - "ordinal": 3, - "type_info": "Bytea" - }, - { - "name": "recursion_leaf_level_vk_hash", - "ordinal": 4, - "type_info": "Bytea" - }, - { - "name": "recursion_circuits_set_vks_hash", - "ordinal": 5, - "type_info": "Bytea" - }, - { - "name": "bootloader_code_hash", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "default_account_code_hash", - "ordinal": 7, - "type_info": "Bytea" - }, - { - "name": "verifier_address", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "upgrade_tx_hash", - "ordinal": 9, - "type_info": "Bytea" - }, - { - "name": "created_at", - "ordinal": 10, - "type_info": "Timestamp" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n *\n FROM\n protocol_versions\n ORDER BY\n id DESC\n LIMIT\n 1\n " - }, - "19b89495be8aa735db039ccc8a262786c58e54f132588c48f07d9537cf21d3ed": { - "describe": { - "columns": [ - { - "name": "sent_at_block", - "ordinal": 0, - "type_info": "Int4" - } - ], - "nullable": [ - true - ], - "parameters": { - "Left": [ - "Int4" - ] - } - }, - "query": "SELECT sent_at_block FROM eth_txs_history WHERE eth_tx_id = $1 AND sent_at_block IS NOT NULL ORDER BY created_at ASC LIMIT 1" - }, - "1ad3bbd791f3ff0d31683bf59187b84c5fd52f0352f0f0e311d054cb9e45b07e": { - "describe": { - "columns": [ - { - "name": "hashed_key", - "ordinal": 0, - "type_info": "Bytea" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT DISTINCT\n ON (hashed_key) hashed_key\n FROM\n (\n SELECT\n *\n FROM\n storage_logs\n WHERE\n miniblock_number > $1\n ) inn\n " - }, - "1b4ebbfc96b4fd66ecbe64a6be80a01a6c7cbe9297cbb55d42533fddc18719b6": { - "describe": { - "columns": [ - { - "name": "op_id", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n MAX(priority_op_id) AS \"op_id\"\n FROM\n transactions\n WHERE\n is_priority = TRUE\n " - }, - "1bc6597117db032b87df33040d61610ffa7f169d560e79e89b99eedf681c6773": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Text", - "Int4" - ] - } - }, - "query": "\n INSERT INTO\n scheduler_witness_jobs_fri (\n l1_batch_number,\n scheduler_partial_input_blob_url,\n protocol_version,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, 'waiting_for_proofs', NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO\n UPDATE\n SET\n updated_at = NOW()\n " - }, - "1c60010ded4e79886890a745a050fa6d65c05d8144bdfd143480834ead4bd8d5": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "contract_address", - "ordinal": 1, - "type_info": "Bytea" - }, - { - "name": "source_code", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "contract_name", - "ordinal": 3, - "type_info": "Text" - }, - { - "name": "zk_compiler_version", - "ordinal": 4, - "type_info": "Text" - }, - { - "name": "compiler_version", - "ordinal": 5, - "type_info": "Text" - }, - { - "name": "optimization_used", - "ordinal": 6, - "type_info": "Bool" - }, - { - "name": "optimizer_mode", - "ordinal": 7, - "type_info": "Text" - }, - { - "name": "constructor_arguments", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "is_system", - "ordinal": 9, - "type_info": "Bool" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - true, - false, - false - ], - "parameters": { - "Left": [ - "Interval" - ] - } - }, - "query": "\n UPDATE contract_verification_requests\n SET\n status = 'in_progress',\n attempts = attempts + 1,\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n id = (\n SELECT\n id\n FROM\n contract_verification_requests\n WHERE\n status = 'queued'\n OR (\n status = 'in_progress'\n AND processing_started_at < NOW() - $1::INTERVAL\n )\n ORDER BY\n created_at\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n id,\n contract_address,\n source_code,\n contract_name,\n zk_compiler_version,\n compiler_version,\n optimization_used,\n optimizer_mode,\n constructor_arguments,\n is_system\n " - }, - "1c994d418ada78586de829fc2d34d26e48e968c79834858c98b7a7f9dfc81910": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n DELETE FROM l2_to_l1_logs\n WHERE\n miniblock_number > $1\n " - }, - "1d2cc4b485536af350089cf7950be3b85419fde77038dd3de6c55aa9c55d375c": { - "describe": { - "columns": [ - { - "name": "value!", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "l1_address!", - "ordinal": 1, - "type_info": "Bytea" - }, - { - "name": "l2_address!", - "ordinal": 2, - "type_info": "Bytea" - }, - { - "name": "symbol!", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "name!", - "ordinal": 4, - "type_info": "Varchar" - }, - { - "name": "decimals!", - "ordinal": 5, - "type_info": "Int4" - }, - { - "name": "usd_price?", - "ordinal": 6, - "type_info": "Numeric" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - true - ], - "parameters": { - "Left": [ - "ByteaArray", - "Bytea", - "Bytea", - "Bytea" - ] - } - }, - "query": "\n SELECT\n storage.value AS \"value!\",\n tokens.l1_address AS \"l1_address!\",\n tokens.l2_address AS \"l2_address!\",\n tokens.symbol AS \"symbol!\",\n tokens.name AS \"name!\",\n tokens.decimals AS \"decimals!\",\n tokens.usd_price AS \"usd_price?\"\n FROM\n storage\n INNER JOIN tokens ON storage.address = tokens.l2_address\n OR (\n storage.address = $2\n AND tokens.l2_address = $3\n )\n WHERE\n storage.hashed_key = ANY ($1)\n AND storage.value != $4\n " - }, - "1d6b698b241cb6c5efd070a98165f6760cfeac185330d1d9c5cdb5b383ed8ed4": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Bytea", - "Text", - "Text", - "Text", - "Text", - "Bool", - "Text", - "Bytea", - "Bool" - ] - } - }, - "query": "\n INSERT INTO\n contract_verification_requests (\n contract_address,\n source_code,\n contract_name,\n zk_compiler_version,\n compiler_version,\n optimization_used,\n optimizer_mode,\n constructor_arguments,\n is_system,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, $8, $9, 'queued', NOW(), NOW())\n RETURNING\n id\n " - }, - "1dcb3afb0c1947f92981f61d95c099c4591ce3f8d51f3df99db0165e086f96af": { - "describe": { - "columns": [ - { - "name": "bytecode", - "ordinal": 0, - "type_info": "Bytea" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Bytea" - ] - } - }, - "query": "\n SELECT\n bytecode\n FROM\n factory_deps\n WHERE\n bytecode_hash = $1\n " - }, - "1e54aebf94d27244638f04d1d35a5a088ceebfef0228701fcbed8255b74b1050": { - "describe": { - "columns": [ - { - "name": "hash", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "is_priority", - "ordinal": 1, - "type_info": "Bool" - }, - { - "name": "full_fee", - "ordinal": 2, - "type_info": "Numeric" - }, - { - "name": "layer_2_tip_fee", - "ordinal": 3, - "type_info": "Numeric" - }, - { - "name": "initiator_address", - "ordinal": 4, - "type_info": "Bytea" - }, - { - "name": "nonce", - "ordinal": 5, - "type_info": "Int8" - }, - { - "name": "signature", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "input", - "ordinal": 7, - "type_info": "Bytea" - }, - { - "name": "data", - "ordinal": 8, - "type_info": "Jsonb" - }, - { - "name": "received_at", - "ordinal": 9, - "type_info": "Timestamp" - }, - { - "name": "priority_op_id", - "ordinal": 10, - "type_info": "Int8" - }, - { - "name": "l1_batch_number", - "ordinal": 11, - "type_info": "Int8" - }, - { - "name": "index_in_block", - "ordinal": 12, - "type_info": "Int4" - }, - { - "name": "error", - "ordinal": 13, - "type_info": "Varchar" - }, - { - "name": "gas_limit", - "ordinal": 14, - "type_info": "Numeric" - }, - { - "name": "gas_per_storage_limit", - "ordinal": 15, - "type_info": "Numeric" - }, - { - "name": "gas_per_pubdata_limit", - "ordinal": 16, - "type_info": "Numeric" - }, - { - "name": "tx_format", - "ordinal": 17, - "type_info": "Int4" - }, - { - "name": "created_at", - "ordinal": 18, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 19, - "type_info": "Timestamp" - }, - { - "name": "execution_info", - "ordinal": 20, - "type_info": "Jsonb" - }, - { - "name": "contract_address", - "ordinal": 21, - "type_info": "Bytea" - }, - { - "name": "in_mempool", - "ordinal": 22, - "type_info": "Bool" - }, - { - "name": "l1_block_number", - "ordinal": 23, - "type_info": "Int4" - }, - { - "name": "value", - "ordinal": 24, - "type_info": "Numeric" - }, - { - "name": "paymaster", - "ordinal": 25, - "type_info": "Bytea" - }, - { - "name": "paymaster_input", - "ordinal": 26, - "type_info": "Bytea" - }, - { - "name": "max_fee_per_gas", - "ordinal": 27, - "type_info": "Numeric" - }, - { - "name": "max_priority_fee_per_gas", - "ordinal": 28, - "type_info": "Numeric" - }, - { - "name": "effective_gas_price", - "ordinal": 29, - "type_info": "Numeric" - }, - { - "name": "miniblock_number", - "ordinal": 30, - "type_info": "Int8" - }, - { - "name": "l1_batch_tx_index", - "ordinal": 31, - "type_info": "Int4" - }, - { - "name": "refunded_gas", - "ordinal": 32, - "type_info": "Int8" - }, - { - "name": "l1_tx_mint", - "ordinal": 33, - "type_info": "Numeric" - }, - { - "name": "l1_tx_refund_recipient", - "ordinal": 34, - "type_info": "Bytea" - }, - { - "name": "upgrade_id", - "ordinal": 35, - "type_info": "Int4" - } - ], - "nullable": [ - false, - false, - true, - true, - false, - true, - true, - true, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - true, - false, - true, - false, - false, - false, - true, - true, - true, - true, - true, - false, - true, - true, - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n *\n FROM\n transactions\n WHERE\n miniblock_number = $1\n ORDER BY\n index_in_block\n " - }, - "1ea37ef1c3df72e5e9c50cfa1675fc7f60618209d0132e7937a1347b7e94b212": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n number\n FROM\n l1_batches\n WHERE\n eth_prove_tx_id IS NOT NULL\n AND eth_execute_tx_id IS NULL\n ORDER BY\n number\n LIMIT\n 1\n " - }, - "1ed2d7e5e98b15420a21650809d710ce910d0c9138d85cb55e16459c757dea03": { - "describe": { - "columns": [ - { - "name": "protocol_version", - "ordinal": 0, - "type_info": "Int4" - } - ], - "nullable": [ - true - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n protocol_version\n FROM\n l1_batches\n ORDER BY\n number DESC\n LIMIT\n 1\n " - }, - "1f25016c41169aa4ab14db2faf7b2d0413d0f89c309de4b31254c309116ea60c": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Bytea", - "Varchar", - "Varchar", - "Int4" - ] - } - }, - "query": "\n UPDATE tokens\n SET\n token_list_name = $2,\n token_list_symbol = $3,\n token_list_decimals = $4,\n well_known = TRUE,\n updated_at = NOW()\n WHERE\n l1_address = $1\n " - }, - "1f46524410ce0f193dc6547499bde995ddddc621ee2149f08f905af2d8aadd03": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "ByteaArray", - "Int4Array", - "ByteaArray", - "ByteaArray", - "NumericArray", - "NumericArray", - "NumericArray", - "NumericArray", - "Int4Array", - "Int4Array", - "VarcharArray", - "NumericArray", - "JsonbArray", - "ByteaArray", - "JsonbArray", - "Int8Array", - "NumericArray", - "ByteaArray", - "ByteaArray", - "ByteaArray", - "Int8" - ] - } - }, - "query": "\n UPDATE transactions\n SET\n hash = data_table.hash,\n signature = data_table.signature,\n gas_limit = data_table.gas_limit,\n max_fee_per_gas = data_table.max_fee_per_gas,\n max_priority_fee_per_gas = data_table.max_priority_fee_per_gas,\n gas_per_pubdata_limit = data_table.gas_per_pubdata_limit,\n input = data_table.input,\n data = data_table.data,\n tx_format = data_table.tx_format,\n miniblock_number = $21,\n index_in_block = data_table.index_in_block,\n error = NULLIF(data_table.error, ''),\n effective_gas_price = data_table.effective_gas_price,\n execution_info = data_table.new_execution_info,\n refunded_gas = data_table.refunded_gas,\n value = data_table.value,\n contract_address = data_table.contract_address,\n paymaster = data_table.paymaster,\n paymaster_input = data_table.paymaster_input,\n in_mempool = FALSE,\n updated_at = NOW()\n FROM\n (\n SELECT\n data_table_temp.*\n FROM\n (\n SELECT\n UNNEST($1::bytea[]) AS initiator_address,\n UNNEST($2::INT[]) AS nonce,\n UNNEST($3::bytea[]) AS hash,\n UNNEST($4::bytea[]) AS signature,\n UNNEST($5::NUMERIC[]) AS gas_limit,\n UNNEST($6::NUMERIC[]) AS max_fee_per_gas,\n UNNEST($7::NUMERIC[]) AS max_priority_fee_per_gas,\n UNNEST($8::NUMERIC[]) AS gas_per_pubdata_limit,\n UNNEST($9::INT[]) AS tx_format,\n UNNEST($10::INTEGER[]) AS index_in_block,\n UNNEST($11::VARCHAR[]) AS error,\n UNNEST($12::NUMERIC[]) AS effective_gas_price,\n UNNEST($13::jsonb[]) AS new_execution_info,\n UNNEST($14::bytea[]) AS input,\n UNNEST($15::jsonb[]) AS data,\n UNNEST($16::BIGINT[]) AS refunded_gas,\n UNNEST($17::NUMERIC[]) AS value,\n UNNEST($18::bytea[]) AS contract_address,\n UNNEST($19::bytea[]) AS paymaster,\n UNNEST($20::bytea[]) AS paymaster_input\n ) AS data_table_temp\n JOIN transactions ON transactions.initiator_address = data_table_temp.initiator_address\n AND transactions.nonce = data_table_temp.nonce\n ORDER BY\n transactions.hash\n ) AS data_table\n WHERE\n transactions.initiator_address = data_table.initiator_address\n AND transactions.nonce = data_table.nonce\n " - }, - "1f75f2d88c1d2496e48b02f374e492cf2545944291dd0d42b937c0d0c7eefd47": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "timestamp", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "l1_tx_count", - "ordinal": 2, - "type_info": "Int4" - }, - { - "name": "l2_tx_count", - "ordinal": 3, - "type_info": "Int4" - }, - { - "name": "root_hash?", - "ordinal": 4, - "type_info": "Bytea" - }, - { - "name": "commit_tx_hash?", - "ordinal": 5, - "type_info": "Text" - }, - { - "name": "committed_at?", - "ordinal": 6, - "type_info": "Timestamp" - }, - { - "name": "prove_tx_hash?", - "ordinal": 7, - "type_info": "Text" - }, - { - "name": "proven_at?", - "ordinal": 8, - "type_info": "Timestamp" - }, - { - "name": "execute_tx_hash?", - "ordinal": 9, - "type_info": "Text" - }, - { - "name": "executed_at?", - "ordinal": 10, - "type_info": "Timestamp" - }, - { - "name": "l1_gas_price", - "ordinal": 11, - "type_info": "Int8" - }, - { - "name": "l2_fair_gas_price", - "ordinal": 12, - "type_info": "Int8" - }, - { - "name": "bootloader_code_hash", - "ordinal": 13, - "type_info": "Bytea" - }, - { - "name": "default_aa_code_hash", - "ordinal": 14, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false, - false, - false, - true, - false, - true, - false, - true, - false, - true, - false, - false, - true, - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n l1_batches.number,\n l1_batches.timestamp,\n l1_batches.l1_tx_count,\n l1_batches.l2_tx_count,\n l1_batches.hash AS \"root_hash?\",\n commit_tx.tx_hash AS \"commit_tx_hash?\",\n commit_tx.confirmed_at AS \"committed_at?\",\n prove_tx.tx_hash AS \"prove_tx_hash?\",\n prove_tx.confirmed_at AS \"proven_at?\",\n execute_tx.tx_hash AS \"execute_tx_hash?\",\n execute_tx.confirmed_at AS \"executed_at?\",\n l1_batches.l1_gas_price,\n l1_batches.l2_fair_gas_price,\n l1_batches.bootloader_code_hash,\n l1_batches.default_aa_code_hash\n FROM\n l1_batches\n LEFT JOIN eth_txs_history AS commit_tx ON (\n l1_batches.eth_commit_tx_id = commit_tx.eth_tx_id\n AND commit_tx.confirmed_at IS NOT NULL\n )\n LEFT JOIN eth_txs_history AS prove_tx ON (\n l1_batches.eth_prove_tx_id = prove_tx.eth_tx_id\n AND prove_tx.confirmed_at IS NOT NULL\n )\n LEFT JOIN eth_txs_history AS execute_tx ON (\n l1_batches.eth_execute_tx_id = execute_tx.eth_tx_id\n AND execute_tx.confirmed_at IS NOT NULL\n )\n WHERE\n l1_batches.number = $1\n " - }, - "2003dcf7bc807c7d345368538accd9b0128f82306e27e4c7258116082a54ab95": { - "describe": { - "columns": [ - { - "name": "hash", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "received_at", - "ordinal": 1, - "type_info": "Timestamp" - } - ], - "nullable": [ - false, - false - ], - "parameters": { - "Left": [ - "Timestamp", - "Int8" - ] - } - }, - "query": "\n SELECT\n transactions.hash,\n transactions.received_at\n FROM\n transactions\n LEFT JOIN miniblocks ON miniblocks.number = miniblock_number\n WHERE\n received_at > $1\n ORDER BY\n received_at ASC\n LIMIT\n $2\n " - }, - "2028ba507f3ccd474f0261e571eb19a3a7feec950cb3e503588cf55d954a493a": { - "describe": { - "columns": [ - { - "name": "bytecode", - "ordinal": 0, - "type_info": "Bytea" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n bytecode\n FROM\n factory_deps\n WHERE\n miniblock_number <= $1\n " - }, - "20f84f9ec21459d8c7ad53241758eeab159533211d2ddbef41e6ff0ba937d04a": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n UPDATE l1_batches\n SET\n skip_proof = TRUE\n WHERE\n number = $1\n " - }, - "23be43bf705d679ca751c89353716065fcad42c6b621efb3a135a16b477dcfd9": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int4" - }, - { - "name": "nonce", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "raw_tx", - "ordinal": 2, - "type_info": "Bytea" - }, - { - "name": "contract_address", - "ordinal": 3, - "type_info": "Text" - }, - { - "name": "tx_type", - "ordinal": 4, - "type_info": "Text" - }, - { - "name": "gas_used", - "ordinal": 5, - "type_info": "Int8" - }, - { - "name": "created_at", - "ordinal": 6, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 7, - "type_info": "Timestamp" - }, - { - "name": "has_failed", - "ordinal": 8, - "type_info": "Bool" - }, - { - "name": "sent_at_block", - "ordinal": 9, - "type_info": "Int4" - }, - { - "name": "confirmed_eth_tx_history_id", - "ordinal": 10, - "type_info": "Int4" - }, - { - "name": "predicted_gas_cost", - "ordinal": 11, - "type_info": "Int8" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - true, - false, - false, - false, - true, - true, - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n *\n FROM\n eth_txs\n WHERE\n confirmed_eth_tx_history_id IS NULL\n AND id <= (\n SELECT\n COALESCE(MAX(eth_tx_id), 0)\n FROM\n eth_txs_history\n WHERE\n sent_at_block IS NOT NULL\n )\n ORDER BY\n id\n " - }, - "245dc5bb82cc82df38e4440a7746ca08324bc86a72e4ea85c9c7962a6c8c9e30": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int4", - "Int8", - "Int8" - ] - } - }, - "query": "\n UPDATE l1_batches\n SET\n eth_prove_tx_id = $1,\n updated_at = NOW()\n WHERE\n number BETWEEN $2 AND $3\n " - }, - "24722ee4ced7f03e60b1b5ecaaa5234d536b064951a67d826ac49b7a3a095a1a": { - "describe": { - "columns": [ - { - "name": "hashed_key", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "index", - "ordinal": 1, - "type_info": "Int8" - } - ], - "nullable": [ - false, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n hashed_key,\n INDEX\n FROM\n initial_writes\n WHERE\n l1_batch_number = $1\n ORDER BY\n INDEX\n " - }, - "249cb862d44196cb6dc3945e907717b0dd3cec64b0b29f59b273f1c6952e01da": { - "describe": { - "columns": [ - { - "name": "bytecode_hash", - "ordinal": 0, - "type_info": "Bytea" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n bytecode_hash\n FROM\n factory_deps\n WHERE\n miniblock_number > $1\n " - }, - "25aad4298d2459ef5aea7c4ea82eda1da000848ed4abf309b68989da33e1ce5a": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "l1_batch_number!", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "timestamp", - "ordinal": 2, - "type_info": "Int8" - }, - { - "name": "l1_tx_count", - "ordinal": 3, - "type_info": "Int4" - }, - { - "name": "l2_tx_count", - "ordinal": 4, - "type_info": "Int4" - }, - { - "name": "root_hash?", - "ordinal": 5, - "type_info": "Bytea" - }, - { - "name": "commit_tx_hash?", - "ordinal": 6, - "type_info": "Text" - }, - { - "name": "committed_at?", - "ordinal": 7, - "type_info": "Timestamp" - }, - { - "name": "prove_tx_hash?", - "ordinal": 8, - "type_info": "Text" - }, - { - "name": "proven_at?", - "ordinal": 9, - "type_info": "Timestamp" - }, - { - "name": "execute_tx_hash?", - "ordinal": 10, - "type_info": "Text" - }, - { - "name": "executed_at?", - "ordinal": 11, - "type_info": "Timestamp" - }, - { - "name": "l1_gas_price", - "ordinal": 12, - "type_info": "Int8" - }, - { - "name": "l2_fair_gas_price", - "ordinal": 13, - "type_info": "Int8" - }, - { - "name": "bootloader_code_hash", - "ordinal": 14, - "type_info": "Bytea" - }, - { - "name": "default_aa_code_hash", - "ordinal": 15, - "type_info": "Bytea" - }, - { - "name": "protocol_version", - "ordinal": 16, - "type_info": "Int4" - }, - { - "name": "fee_account_address?", - "ordinal": 17, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - null, - false, - false, - false, - false, - false, - true, - false, - true, - false, - true, - false, - false, - true, - true, - true, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n miniblocks.number,\n COALESCE(\n miniblocks.l1_batch_number,\n (\n SELECT\n (MAX(number) + 1)\n FROM\n l1_batches\n )\n ) AS \"l1_batch_number!\",\n miniblocks.timestamp,\n miniblocks.l1_tx_count,\n miniblocks.l2_tx_count,\n miniblocks.hash AS \"root_hash?\",\n commit_tx.tx_hash AS \"commit_tx_hash?\",\n commit_tx.confirmed_at AS \"committed_at?\",\n prove_tx.tx_hash AS \"prove_tx_hash?\",\n prove_tx.confirmed_at AS \"proven_at?\",\n execute_tx.tx_hash AS \"execute_tx_hash?\",\n execute_tx.confirmed_at AS \"executed_at?\",\n miniblocks.l1_gas_price,\n miniblocks.l2_fair_gas_price,\n miniblocks.bootloader_code_hash,\n miniblocks.default_aa_code_hash,\n miniblocks.protocol_version,\n l1_batches.fee_account_address AS \"fee_account_address?\"\n FROM\n miniblocks\n LEFT JOIN l1_batches ON miniblocks.l1_batch_number = l1_batches.number\n LEFT JOIN eth_txs_history AS commit_tx ON (\n l1_batches.eth_commit_tx_id = commit_tx.eth_tx_id\n AND commit_tx.confirmed_at IS NOT NULL\n )\n LEFT JOIN eth_txs_history AS prove_tx ON (\n l1_batches.eth_prove_tx_id = prove_tx.eth_tx_id\n AND prove_tx.confirmed_at IS NOT NULL\n )\n LEFT JOIN eth_txs_history AS execute_tx ON (\n l1_batches.eth_execute_tx_id = execute_tx.eth_tx_id\n AND execute_tx.confirmed_at IS NOT NULL\n )\n WHERE\n miniblocks.number = $1\n " - }, - "26cb272c2a46a267c47681e0f1f07997b7e24682da56f84d812da2b9aeb14ca2": { - "describe": { - "columns": [ - { - "name": "miniblock_number!", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "hash", - "ordinal": 1, - "type_info": "Bytea" - }, - { - "name": "index_in_block!", - "ordinal": 2, - "type_info": "Int4" - }, - { - "name": "l1_batch_tx_index!", - "ordinal": 3, - "type_info": "Int4" - } - ], - "nullable": [ - true, - false, - true, - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n miniblock_number AS \"miniblock_number!\",\n hash,\n index_in_block AS \"index_in_block!\",\n l1_batch_tx_index AS \"l1_batch_tx_index!\"\n FROM\n transactions\n WHERE\n l1_batch_number = $1\n ORDER BY\n miniblock_number,\n index_in_block\n " - }, - "26e0b7eb1871d94ddc98254fece6381a9c4165e2727542eaeef3bbedd13a4f20": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text", - "Int8" - ] - } - }, - "query": "\n UPDATE proof_generation_details\n SET\n status = $1,\n updated_at = NOW()\n WHERE\n l1_batch_number = $2\n " - }, - "2737fea02599cdc163854b1395c42d4ef93ca238fd2fbc9155e6d012d0d1e113": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Varchar", - "Bytea" - ] - } - }, - "query": "\n UPDATE transactions\n SET\n error = $1,\n updated_at = NOW()\n WHERE\n hash = $2\n " - }, - "2757b30c4641a346eb0226c706223efc18e51e6d4092188e081f4fafe92fe0ef": { - "describe": { - "columns": [ - { - "name": "bootloader_code_hash", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "default_account_code_hash", - "ordinal": 1, - "type_info": "Bytea" - }, - { - "name": "id", - "ordinal": 2, - "type_info": "Int4" - } - ], - "nullable": [ - false, - false, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n bootloader_code_hash,\n default_account_code_hash,\n id\n FROM\n protocol_versions\n WHERE\n timestamp <= $1\n ORDER BY\n id DESC\n LIMIT\n 1\n " - }, - "280cf015e40353e2833c0a70b77095596297be0d728a0aa2d9b180fb72de222b": { - "describe": { - "columns": [ - { - "name": "attempts", - "ordinal": 0, - "type_info": "Int2" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n attempts\n FROM\n basic_witness_input_producer_jobs\n WHERE\n l1_batch_number = $1\n " - }, - "293258ecb299be5f5e81696d14883f115cd97586bd795ee31f58fc14e56d58cb": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n DELETE FROM events\n WHERE\n miniblock_number > $1\n " - }, - "2955e976281f9cbd98b7378c5ab52964b268b93c32fd280c49bf9f932884300d": { - "describe": { - "columns": [ - { - "name": "timestamp", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n timestamp\n FROM\n l1_batches\n WHERE\n eth_prove_tx_id IS NULL\n AND number > 0\n ORDER BY\n number\n LIMIT\n 1\n " - }, - "2a2469109033ba08591db3647b73595fe783b7b894748d07fed9735c58fb28fb": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n number\n FROM\n miniblocks\n WHERE\n consensus IS NOT NULL\n ORDER BY\n number DESC\n LIMIT\n 1\n " - }, - "2b626262c8003817ee02978f77452554ccfb5b83f00efdc12bed0f60ef439785": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8", - "Int2", - "Int2", - "Int4" - ] - } - }, - "query": "\n SELECT\n id\n FROM\n prover_jobs_fri\n WHERE\n l1_batch_number = $1\n AND circuit_id = $2\n AND aggregation_round = $3\n AND depth = $4\n AND status = 'successful'\n ORDER BY\n sequence_number ASC;\n " - }, - "2c827c1c3cfa3552b90d4746c5df45d57f1f8b2558fdb374bf02e84d3c825a23": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n MAX(number) AS \"number\"\n FROM\n miniblocks\n " - }, - "2d0c2e9ec4187641baef8a33229bffc78d92adb3c1e3ca60b12163e38c67047e": { - "describe": { - "columns": [ - { - "name": "count!", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [ - "Bytea" - ] - } - }, - "query": "\n SELECT\n COUNT(*) AS \"count!\"\n FROM\n contracts_verification_info\n WHERE\n address = $1\n " - }, - "2d1e0f2e043c193052c9cc20f9efeb5f094160627bc09db4bda2dda9a8c11c44": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Bytea", - "Jsonb" - ] - } - }, - "query": "\n INSERT INTO\n contracts_verification_info (address, verification_info)\n VALUES\n ($1, $2)\n ON CONFLICT (address) DO\n UPDATE\n SET\n verification_info = $2\n " - }, - "2d31fcce581975a82d6156b52e35fb7a093b73727f75e0cb7db9cea480c95f5c": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "status", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "attempts", - "ordinal": 2, - "type_info": "Int2" - } - ], - "nullable": [ - false, - false, - false - ], - "parameters": { - "Left": [ - "Interval", - "Int2" - ] - } - }, - "query": "\n UPDATE prover_jobs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n id IN (\n SELECT\n id\n FROM\n prover_jobs_fri\n WHERE\n (\n status = 'in_progress'\n AND processing_started_at <= NOW() - $1::INTERVAL\n AND attempts < $2\n )\n OR (\n status = 'in_gpu_proof'\n AND processing_started_at <= NOW() - $1::INTERVAL\n AND attempts < $2\n )\n OR (\n status = 'failed'\n AND attempts < $2\n )\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n id,\n status,\n attempts\n " - }, - "2d862097cfae49a1fb28ec0a05176085385c3a79d72f49669b4215a9454323c2": { - "describe": { - "columns": [ - { - "name": "index", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n INDEX\n FROM\n initial_writes\n WHERE\n l1_batch_number <= $1\n ORDER BY\n l1_batch_number DESC,\n INDEX DESC\n LIMIT\n 1;\n " - }, - "2d87b294817859e42258136b1cb78f42a877039094c3d6354928a03dad29451a": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Int4Array" - ] - } - }, - "query": "\n DELETE FROM storage_logs\n WHERE\n miniblock_number = $1\n AND operation_number != ALL ($2)\n " - }, - "2dd7dbaeb2572404451e78a96f540e73a2778633bbf9d8e591ec912634639af9": { - "describe": { - "columns": [ - { - "name": "hash", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "is_priority", - "ordinal": 1, - "type_info": "Bool" - }, - { - "name": "full_fee", - "ordinal": 2, - "type_info": "Numeric" - }, - { - "name": "layer_2_tip_fee", - "ordinal": 3, - "type_info": "Numeric" - }, - { - "name": "initiator_address", - "ordinal": 4, - "type_info": "Bytea" - }, - { - "name": "nonce", - "ordinal": 5, - "type_info": "Int8" - }, - { - "name": "signature", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "input", - "ordinal": 7, - "type_info": "Bytea" - }, - { - "name": "data", - "ordinal": 8, - "type_info": "Jsonb" - }, - { - "name": "received_at", - "ordinal": 9, - "type_info": "Timestamp" - }, - { - "name": "priority_op_id", - "ordinal": 10, - "type_info": "Int8" - }, - { - "name": "l1_batch_number", - "ordinal": 11, - "type_info": "Int8" - }, - { - "name": "index_in_block", - "ordinal": 12, - "type_info": "Int4" - }, - { - "name": "error", - "ordinal": 13, - "type_info": "Varchar" - }, - { - "name": "gas_limit", - "ordinal": 14, - "type_info": "Numeric" - }, - { - "name": "gas_per_storage_limit", - "ordinal": 15, - "type_info": "Numeric" - }, - { - "name": "gas_per_pubdata_limit", - "ordinal": 16, - "type_info": "Numeric" - }, - { - "name": "tx_format", - "ordinal": 17, - "type_info": "Int4" - }, - { - "name": "created_at", - "ordinal": 18, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 19, - "type_info": "Timestamp" - }, - { - "name": "execution_info", - "ordinal": 20, - "type_info": "Jsonb" - }, - { - "name": "contract_address", - "ordinal": 21, - "type_info": "Bytea" - }, - { - "name": "in_mempool", - "ordinal": 22, - "type_info": "Bool" - }, - { - "name": "l1_block_number", - "ordinal": 23, - "type_info": "Int4" - }, - { - "name": "value", - "ordinal": 24, - "type_info": "Numeric" - }, - { - "name": "paymaster", - "ordinal": 25, - "type_info": "Bytea" - }, - { - "name": "paymaster_input", - "ordinal": 26, - "type_info": "Bytea" - }, - { - "name": "max_fee_per_gas", - "ordinal": 27, - "type_info": "Numeric" - }, - { - "name": "max_priority_fee_per_gas", - "ordinal": 28, - "type_info": "Numeric" - }, - { - "name": "effective_gas_price", - "ordinal": 29, - "type_info": "Numeric" - }, - { - "name": "miniblock_number", - "ordinal": 30, - "type_info": "Int8" - }, - { - "name": "l1_batch_tx_index", - "ordinal": 31, - "type_info": "Int4" - }, - { - "name": "refunded_gas", - "ordinal": 32, - "type_info": "Int8" - }, - { - "name": "l1_tx_mint", - "ordinal": 33, - "type_info": "Numeric" - }, - { - "name": "l1_tx_refund_recipient", - "ordinal": 34, - "type_info": "Bytea" - }, - { - "name": "upgrade_id", - "ordinal": 35, - "type_info": "Int4" - } - ], - "nullable": [ - false, - false, - true, - true, - false, - true, - true, - true, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - true, - false, - true, - false, - false, - false, - true, - true, - true, - true, - true, - false, - true, - true, - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n *\n FROM\n transactions\n WHERE\n miniblock_number = $1\n ORDER BY\n index_in_block\n " - }, - "2ddba807ac8ec5260bf92c77073eb89c728357c0744f209090824695a5d35fa3": { - "describe": { - "columns": [ - { - "name": "hash", - "ordinal": 0, - "type_info": "Bytea" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n UPDATE transactions\n SET\n l1_batch_number = NULL,\n miniblock_number = NULL,\n error = NULL,\n index_in_block = NULL,\n execution_info = '{}'\n WHERE\n miniblock_number > $1\n RETURNING\n hash\n " - }, - "2e0ea9434195270cc65cdca1f674d6b3b1d15b818974e4e403f4ac418ed40c2c": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int4" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int4", - "Int8", - "Int8", - "Text", - "Bytea" - ] - } - }, - "query": "\n INSERT INTO\n eth_txs_history (\n eth_tx_id,\n base_fee_per_gas,\n priority_fee_per_gas,\n tx_hash,\n signed_raw_tx,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, $4, $5, NOW(), NOW())\n ON CONFLICT (tx_hash) DO NOTHING\n RETURNING\n id\n " - }, - "2e5b9ae1b81b0abfe7a962c93b3119a0a60dc9804175b2baf8b45939c74bd583": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "TextArray", - "Text" - ] - } - }, - "query": "\n INSERT INTO\n compiler_versions (VERSION, compiler, created_at, updated_at)\n SELECT\n u.version,\n $2,\n NOW(),\n NOW()\n FROM\n UNNEST($1::TEXT[]) AS u (VERSION)\n ON CONFLICT (VERSION, compiler) DO NOTHING\n " - }, - "2eb25bfcfc1114de825dc4eeb0605d7d1c9e649663f6e9444c4425821d0a5b71": { - "describe": { - "columns": [ - { - "name": "eth_commit_tx_id", - "ordinal": 0, - "type_info": "Int4" - } - ], - "nullable": [ - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n eth_commit_tx_id\n FROM\n l1_batches\n WHERE\n number = $1\n " - }, - "2eb617f3e34ac5b21f925053a45da2b4afc314a3b3e78b041b44c8a020a0ee12": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "ByteaArray" - ] - } - }, - "query": "\n UPDATE transactions\n SET\n in_mempool = FALSE\n FROM\n UNNEST($1::bytea[]) AS s (address)\n WHERE\n transactions.in_mempool = TRUE\n AND transactions.initiator_address = s.address\n " - }, - "314f7e619a34efa89255a58c89f85d4402ff6005446bbded68c8d3dbca510f37": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Int8", - "Bytea", - "Int4", - "Int4", - "Numeric", - "Int8", - "Int8", - "Int8", - "Bytea", - "Bytea", - "Int4", - "Int8" - ] - } - }, - "query": "\n INSERT INTO\n miniblocks (\n number,\n timestamp,\n hash,\n l1_tx_count,\n l2_tx_count,\n base_fee_per_gas,\n l1_gas_price,\n l2_fair_gas_price,\n gas_per_pubdata_limit,\n bootloader_code_hash,\n default_aa_code_hash,\n protocol_version,\n virtual_blocks,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, NOW(), NOW())\n " - }, - "31f12a8c44124bb2ce31889ac5295f3823926f69cb1d54874878e6d6c301bfd8": { - "describe": { - "columns": [ - { - "name": "count!", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n COUNT(*) AS \"count!\"\n FROM\n l1_batches\n " - }, - "322d919ff1ef4675623a58af2b0e9ebdda648667d48d6b27ddf155f2fe01d77a": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Bytea", - "Bytea" - ] - } - }, - "query": "\n UPDATE l1_batches\n SET\n commitment = $2,\n aux_data_hash = $3,\n updated_at = NOW()\n WHERE\n number = $1\n " - }, - "3263423b6097fac01eadd978b826b831321c10f91b87cea38dc8a7377da9385e": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "circuit_input_blob_url", - "ordinal": 1, - "type_info": "Text" - } - ], - "nullable": [ - false, - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n id,\n circuit_input_blob_url\n FROM\n prover_jobs\n WHERE\n status = 'successful'\n AND circuit_input_blob_url IS NOT NULL\n AND updated_at < NOW() - INTERVAL '30 days'\n LIMIT\n $1;\n " - }, - "32792c6aee69cb8c8b928a209a3b04ba5868d1897553df85aac15b169ebb0732": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - { - "Custom": { - "kind": { - "Enum": [ - "Queued", - "ManuallySkipped", - "InProgress", - "Successful", - "Failed" - ] - }, - "name": "basic_witness_input_producer_job_status" - } - } - ] - } - }, - "query": "\n INSERT INTO\n basic_witness_input_producer_jobs (l1_batch_number, status, created_at, updated_at)\n VALUES\n ($1, $2, NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO NOTHING\n " - }, - "33d6be45b246523ad76f9ae512322ff6372f63ecadb504a329499b02e7d3550e": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "circuit_id", - "ordinal": 1, - "type_info": "Int2" - } - ], - "nullable": [ - false, - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n UPDATE leaf_aggregation_witness_jobs_fri\n SET\n status = 'queued'\n WHERE\n (l1_batch_number, circuit_id) IN (\n SELECT\n prover_jobs_fri.l1_batch_number,\n prover_jobs_fri.circuit_id\n FROM\n prover_jobs_fri\n JOIN leaf_aggregation_witness_jobs_fri lawj ON prover_jobs_fri.l1_batch_number = lawj.l1_batch_number\n AND prover_jobs_fri.circuit_id = lawj.circuit_id\n WHERE\n lawj.status = 'waiting_for_proofs'\n AND prover_jobs_fri.status = 'successful'\n AND prover_jobs_fri.aggregation_round = 0\n GROUP BY\n prover_jobs_fri.l1_batch_number,\n prover_jobs_fri.circuit_id,\n lawj.number_of_basic_circuits\n HAVING\n COUNT(*) = lawj.number_of_basic_circuits\n )\n RETURNING\n l1_batch_number,\n circuit_id;\n " - }, - "3490fe0b778a03c73111bf8cbf426b0b3185a231bbf0b8b132a1a95bc157e827": { - "describe": { - "columns": [ - { - "name": "hashed_key", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "l1_batch_number", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "index", - "ordinal": 2, - "type_info": "Int8" - } - ], - "nullable": [ - false, - false, - false - ], - "parameters": { - "Left": [ - "ByteaArray" - ] - } - }, - "query": "\n SELECT\n hashed_key,\n l1_batch_number,\n INDEX\n FROM\n initial_writes\n WHERE\n hashed_key = ANY ($1::bytea[])\n " - }, - "3502a673e04b57bfde096303d7643092702c835069cc055e01f382bc56681401": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Time", - "Bytea", - "Text", - "Int8" - ] - } - }, - "query": "\n UPDATE prover_jobs\n SET\n status = 'successful',\n updated_at = NOW(),\n time_taken = $1,\n result = $2,\n proccesed_by = $3\n WHERE\n id = $4\n " - }, - "35b87a3b7db0af87c6a95e9fe7ef9044ae85b579c7051301b40bd5f94df1f530": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text", - "Int8" - ] - } - }, - "query": "\n UPDATE prover_jobs_fri\n SET\n status = 'failed',\n error = $1,\n updated_at = NOW()\n WHERE\n id = $2\n " - }, - "3671f23665664b8d6acf97e4f697e5afa28d855d87ea2f8c93e79c436749068a": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "timestamp", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "is_finished", - "ordinal": 2, - "type_info": "Bool" - }, - { - "name": "l1_tx_count", - "ordinal": 3, - "type_info": "Int4" - }, - { - "name": "l2_tx_count", - "ordinal": 4, - "type_info": "Int4" - }, - { - "name": "fee_account_address", - "ordinal": 5, - "type_info": "Bytea" - }, - { - "name": "bloom", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "priority_ops_onchain_data", - "ordinal": 7, - "type_info": "ByteaArray" - }, - { - "name": "hash", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "parent_hash", - "ordinal": 9, - "type_info": "Bytea" - }, - { - "name": "commitment", - "ordinal": 10, - "type_info": "Bytea" - }, - { - "name": "compressed_write_logs", - "ordinal": 11, - "type_info": "Bytea" - }, - { - "name": "compressed_contracts", - "ordinal": 12, - "type_info": "Bytea" - }, - { - "name": "eth_prove_tx_id", - "ordinal": 13, - "type_info": "Int4" - }, - { - "name": "eth_commit_tx_id", - "ordinal": 14, - "type_info": "Int4" - }, - { - "name": "eth_execute_tx_id", - "ordinal": 15, - "type_info": "Int4" - }, - { - "name": "merkle_root_hash", - "ordinal": 16, - "type_info": "Bytea" - }, - { - "name": "l2_to_l1_logs", - "ordinal": 17, - "type_info": "ByteaArray" - }, - { - "name": "l2_to_l1_messages", - "ordinal": 18, - "type_info": "ByteaArray" - }, - { - "name": "used_contract_hashes", - "ordinal": 19, - "type_info": "Jsonb" - }, - { - "name": "compressed_initial_writes", - "ordinal": 20, - "type_info": "Bytea" - }, - { - "name": "compressed_repeated_writes", - "ordinal": 21, - "type_info": "Bytea" - }, - { - "name": "l2_l1_compressed_messages", - "ordinal": 22, - "type_info": "Bytea" - }, - { - "name": "l2_l1_merkle_root", - "ordinal": 23, - "type_info": "Bytea" - }, - { - "name": "l1_gas_price", - "ordinal": 24, - "type_info": "Int8" - }, - { - "name": "l2_fair_gas_price", - "ordinal": 25, - "type_info": "Int8" - }, - { - "name": "rollup_last_leaf_index", - "ordinal": 26, - "type_info": "Int8" - }, - { - "name": "zkporter_is_available", - "ordinal": 27, - "type_info": "Bool" - }, - { - "name": "bootloader_code_hash", - "ordinal": 28, - "type_info": "Bytea" - }, - { - "name": "default_aa_code_hash", - "ordinal": 29, - "type_info": "Bytea" - }, - { - "name": "base_fee_per_gas", - "ordinal": 30, - "type_info": "Numeric" - }, - { - "name": "aux_data_hash", - "ordinal": 31, - "type_info": "Bytea" - }, - { - "name": "pass_through_data_hash", - "ordinal": 32, - "type_info": "Bytea" - }, - { - "name": "meta_parameters_hash", - "ordinal": 33, - "type_info": "Bytea" - }, - { - "name": "protocol_version", - "ordinal": 34, - "type_info": "Int4" - }, - { - "name": "compressed_state_diffs", - "ordinal": 35, - "type_info": "Bytea" - }, - { - "name": "system_logs", - "ordinal": 36, - "type_info": "ByteaArray" - }, - { - "name": "events_queue_commitment", - "ordinal": 37, - "type_info": "Bytea" - }, - { - "name": "bootloader_initial_content_commitment", - "ordinal": 38, - "type_info": "Bytea" - }, - { - "name": "pubdata_input", - "ordinal": 39, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - true, - true, - true, - true, - false, - false, - true, - true, - true, - true, - false, - true, - true, - true, - true, - true, - false, - true, - true, - true - ], - "parameters": { - "Left": [ - "Int8", - "Int8", - "Int8" - ] - } - }, - "query": "\n SELECT\n number,\n timestamp,\n is_finished,\n l1_tx_count,\n l2_tx_count,\n fee_account_address,\n bloom,\n priority_ops_onchain_data,\n hash,\n parent_hash,\n commitment,\n compressed_write_logs,\n compressed_contracts,\n eth_prove_tx_id,\n eth_commit_tx_id,\n eth_execute_tx_id,\n merkle_root_hash,\n l2_to_l1_logs,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_compressed_messages,\n l2_l1_merkle_root,\n l1_gas_price,\n l2_fair_gas_price,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n base_fee_per_gas,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n WHERE\n number BETWEEN $1 AND $2\n ORDER BY\n number\n LIMIT\n $3\n " - }, - "367ca58514762ffc26fd906c4c441a21691357494c2f9919bfcbcbb0e42315c2": { - "describe": { - "columns": [ - { - "name": "count!", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n COUNT(*) AS \"count!\"\n FROM\n miniblocks\n WHERE\n number = $1\n AND consensus IS NOT NULL\n " - }, - "373f6339a61c6ac74080f855fcc25dab33355eefdce69255bc7106675b0e5641": { - "describe": { - "columns": [ - { - "name": "count!", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [ - "Int4" - ] - } - }, - "query": "\n SELECT\n COUNT(*) AS \"count!\"\n FROM\n prover_protocol_versions\n WHERE\n id = $1\n " - }, - "38a8b00e320b16e99f6ea0e5954e2f7e49cd6600bd3d56cf41795c2c9e082e4c": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n MAX(number) AS \"number\"\n FROM\n l1_batches\n " - }, - "3b0af308b0ce95a13a4eed40834279601234a489f73d843f2f314252ed4cb8b0": { - "describe": { - "columns": [ - { - "name": "hashed_key", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "value!", - "ordinal": 1, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false - ], - "parameters": { - "Left": [ - "ByteaArray" - ] - } - }, - "query": "\n SELECT\n hashed_key,\n value AS \"value!\"\n FROM\n storage\n WHERE\n hashed_key = ANY ($1)\n " - }, - "3b3fbcffd2702047045c2f358e8ac77b63879ab97a32eed8392b48cc46116a28": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "ByteaArray" - ] - } - }, - "query": "\n DELETE FROM call_traces\n WHERE\n tx_hash = ANY ($1)\n " - }, - "3b4d5009ec22f54cc7d305aa11d96ec397767a063dc21aa3add974cb9b070361": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "ByteaArray", - "ByteaArray", - "Int8" - ] - } - }, - "query": "\n INSERT INTO\n factory_deps (bytecode_hash, bytecode, miniblock_number, created_at, updated_at)\n SELECT\n u.bytecode_hash,\n u.bytecode,\n $3,\n NOW(),\n NOW()\n FROM\n UNNEST($1::bytea[], $2::bytea[]) AS u (bytecode_hash, bytecode)\n ON CONFLICT (bytecode_hash) DO NOTHING\n " - }, - "3c1d5f985be7e378211aa339c2c6387f2f3eda07a630503324bd6576dbdf8231": { - "describe": { - "columns": [ - { - "name": "trace", - "ordinal": 0, - "type_info": "Jsonb" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Bytea" - ] - } - }, - "query": "\n SELECT\n trace\n FROM\n transaction_traces\n WHERE\n tx_hash = $1\n " - }, - "3c3abbf689fa64c6da7de69fd916769dbb04d3a61cf232892236c974660ffe64": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "status", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "attempts", - "ordinal": 2, - "type_info": "Int2" - } - ], - "nullable": [ - false, - false, - false - ], - "parameters": { - "Left": [ - "Interval", - "Int2" - ] - } - }, - "query": "\n UPDATE scheduler_witness_jobs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n (\n status = 'in_progress'\n AND processing_started_at <= NOW() - $1::INTERVAL\n AND attempts < $2\n )\n OR (\n status = 'failed'\n AND attempts < $2\n )\n RETURNING\n l1_batch_number,\n status,\n attempts\n " - }, - "3e170eea3a5ea5c7389c15f76c6489745438eae73a07b577aa25bd08adf95354": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Bytea", - "Int8", - "Bytea" - ] - } - }, - "query": "\n DELETE FROM tokens\n WHERE\n l2_address IN (\n SELECT\n SUBSTRING(key, 12, 20)\n FROM\n storage_logs\n WHERE\n storage_logs.address = $1\n AND miniblock_number > $2\n AND NOT EXISTS (\n SELECT\n 1\n FROM\n storage_logs AS s\n WHERE\n s.hashed_key = storage_logs.hashed_key\n AND (s.miniblock_number, s.operation_number) >= (storage_logs.miniblock_number, storage_logs.operation_number)\n AND s.value = $3\n )\n )\n " - }, - "3ec365c5c81f4678a905ae5bbd48b87ead36f593488437c6f67da629ca81e4fa": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n UPDATE scheduler_witness_jobs_fri\n SET\n status = 'queued'\n WHERE\n l1_batch_number = $1\n AND status != 'successful'\n AND status != 'in_progress'\n " - }, - "40c82325e05572db9c3a4ca8cc347617ed18495ef147b3ecfacdd89f54957b6a": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int4", - "Int8", - "Bytea", - "Bytea", - "Bytea", - "Bytea", - "Bytea" - ] - } - }, - "query": "\n INSERT INTO\n prover_protocol_versions (\n id,\n timestamp,\n recursion_scheduler_level_vk_hash,\n recursion_node_level_vk_hash,\n recursion_leaf_level_vk_hash,\n recursion_circuits_set_vks_hash,\n verifier_address,\n created_at\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, NOW())\n " - }, - "41c9f45d6eb727aafad0d8c18024cee5c602d275bb812022cc8fdabf0a60e151": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int4" - }, - { - "name": "eth_tx_id", - "ordinal": 1, - "type_info": "Int4" - }, - { - "name": "tx_hash", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "base_fee_per_gas", - "ordinal": 3, - "type_info": "Int8" - }, - { - "name": "priority_fee_per_gas", - "ordinal": 4, - "type_info": "Int8" - }, - { - "name": "signed_raw_tx", - "ordinal": 5, - "type_info": "Bytea" - }, - { - "name": "nonce", - "ordinal": 6, - "type_info": "Int8" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - true, - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n eth_txs_history.id,\n eth_txs_history.eth_tx_id,\n eth_txs_history.tx_hash,\n eth_txs_history.base_fee_per_gas,\n eth_txs_history.priority_fee_per_gas,\n eth_txs_history.signed_raw_tx,\n eth_txs.nonce\n FROM\n eth_txs_history\n JOIN eth_txs ON eth_txs.id = eth_txs_history.eth_tx_id\n WHERE\n eth_txs_history.sent_at_block IS NULL\n AND eth_txs.confirmed_eth_tx_history_id IS NULL\n ORDER BY\n eth_txs_history.id DESC\n " - }, - "43c7e352d09f69de1a182196aea4de79b67833f17d252b5b0e8e00cd6e75b5c1": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n MIN(number) AS \"number\"\n FROM\n l1_batches\n " - }, - "46c4696fff5a4b8cc5cb46b05645da82065836fe17687ffad04126a6a8b2b27c": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Time", - "Int8" - ] - } - }, - "query": "\n UPDATE leaf_aggregation_witness_jobs_fri\n SET\n status = 'successful',\n updated_at = NOW(),\n time_taken = $1\n WHERE\n id = $2\n " - }, - "47c2f23d9209d155f3f32fd21ef7931a02fe5ffaf2c4dc2f1e7a48c0e932c060": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "l1_batch_root_hash", - "ordinal": 1, - "type_info": "Bytea" - }, - { - "name": "miniblock_number", - "ordinal": 2, - "type_info": "Int8" - }, - { - "name": "miniblock_root_hash", - "ordinal": 3, - "type_info": "Bytea" - }, - { - "name": "last_finished_chunk_id", - "ordinal": 4, - "type_info": "Int4" - }, - { - "name": "total_chunk_count", - "ordinal": 5, - "type_info": "Int4" - } - ], - "nullable": [ - false, - false, - false, - false, - true, - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n l1_batch_number,\n l1_batch_root_hash,\n miniblock_number,\n miniblock_root_hash,\n last_finished_chunk_id,\n total_chunk_count\n FROM\n snapshot_recovery\n " - }, - "481d3cdb6c9a90843b240dba84377cb8f1340b483faedbbc2b71055aa5451cae": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n MAX(number) AS \"number\"\n FROM\n l1_batches\n WHERE\n is_finished = TRUE\n " - }, - "4cdc90ed409b37b3c1c57bbcca9f82918afa1b0ac410325e4d00cd1c4fdd1e8b": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "l1_tx_count", - "ordinal": 1, - "type_info": "Int4" - }, - { - "name": "l2_tx_count", - "ordinal": 2, - "type_info": "Int4" - }, - { - "name": "timestamp", - "ordinal": 3, - "type_info": "Int8" - }, - { - "name": "is_finished", - "ordinal": 4, - "type_info": "Bool" - }, - { - "name": "fee_account_address", - "ordinal": 5, - "type_info": "Bytea" - }, - { - "name": "l2_to_l1_logs", - "ordinal": 6, - "type_info": "ByteaArray" - }, - { - "name": "l2_to_l1_messages", - "ordinal": 7, - "type_info": "ByteaArray" - }, - { - "name": "bloom", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "priority_ops_onchain_data", - "ordinal": 9, - "type_info": "ByteaArray" - }, - { - "name": "used_contract_hashes", - "ordinal": 10, - "type_info": "Jsonb" - }, - { - "name": "base_fee_per_gas", - "ordinal": 11, - "type_info": "Numeric" - }, - { - "name": "l1_gas_price", - "ordinal": 12, - "type_info": "Int8" - }, - { - "name": "l2_fair_gas_price", - "ordinal": 13, - "type_info": "Int8" - }, - { - "name": "bootloader_code_hash", - "ordinal": 14, - "type_info": "Bytea" - }, - { - "name": "default_aa_code_hash", - "ordinal": 15, - "type_info": "Bytea" - }, - { - "name": "protocol_version", - "ordinal": 16, - "type_info": "Int4" - }, - { - "name": "compressed_state_diffs", - "ordinal": 17, - "type_info": "Bytea" - }, - { - "name": "system_logs", - "ordinal": 18, - "type_info": "ByteaArray" - }, - { - "name": "pubdata_input", - "ordinal": 19, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - true - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n number,\n l1_tx_count,\n l2_tx_count,\n timestamp,\n is_finished,\n fee_account_address,\n l2_to_l1_logs,\n l2_to_l1_messages,\n bloom,\n priority_ops_onchain_data,\n used_contract_hashes,\n base_fee_per_gas,\n l1_gas_price,\n l2_fair_gas_price,\n bootloader_code_hash,\n default_aa_code_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n pubdata_input\n FROM\n l1_batches\n ORDER BY\n number DESC\n LIMIT\n 1\n " - }, - "4d263992ed6d5abbd7d3ca43af9d772d8801b0ae673b7173ae08a1fa6cbf67b2": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "l1_batch_number", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "circuit_id", - "ordinal": 2, - "type_info": "Int2" - }, - { - "name": "aggregation_round", - "ordinal": 3, - "type_info": "Int2" - }, - { - "name": "sequence_number", - "ordinal": 4, - "type_info": "Int4" - }, - { - "name": "depth", - "ordinal": 5, - "type_info": "Int4" - }, - { - "name": "is_node_final_proof", - "ordinal": 6, - "type_info": "Bool" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false - ], - "parameters": { - "Left": [ - "Int4Array", - "Text" - ] - } - }, - "query": "\n UPDATE prover_jobs_fri\n SET\n status = 'in_progress',\n attempts = attempts + 1,\n updated_at = NOW(),\n processing_started_at = NOW(),\n picked_by = $2\n WHERE\n id = (\n SELECT\n id\n FROM\n prover_jobs_fri\n WHERE\n status = 'queued'\n AND protocol_version = ANY ($1)\n ORDER BY\n aggregation_round DESC,\n l1_batch_number ASC,\n id ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n prover_jobs_fri.id,\n prover_jobs_fri.l1_batch_number,\n prover_jobs_fri.circuit_id,\n prover_jobs_fri.aggregation_round,\n prover_jobs_fri.sequence_number,\n prover_jobs_fri.depth,\n prover_jobs_fri.is_node_final_proof\n " - }, - "4d50dabc25d392e6b9d0dbe0e386ea7ef2c1178b1b0394a17442185b79f2d77d": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int4" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Text" - ] - } - }, - "query": "SELECT eth_txs.id FROM eth_txs_history JOIN eth_txs ON eth_txs.confirmed_eth_tx_history_id = eth_txs_history.id WHERE eth_txs_history.tx_hash = $1" - }, - "4d84bb4e180b7267bee5e3c1f83c6d47e8e1b4b5124c82c1f35d405204fcf783": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int4" - }, - { - "name": "eth_tx_id", - "ordinal": 1, - "type_info": "Int4" - }, - { - "name": "tx_hash", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "created_at", - "ordinal": 3, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 4, - "type_info": "Timestamp" - }, - { - "name": "base_fee_per_gas", - "ordinal": 5, - "type_info": "Int8" - }, - { - "name": "priority_fee_per_gas", - "ordinal": 6, - "type_info": "Int8" - }, - { - "name": "confirmed_at", - "ordinal": 7, - "type_info": "Timestamp" - }, - { - "name": "signed_raw_tx", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "sent_at_block", - "ordinal": 9, - "type_info": "Int4" - }, - { - "name": "sent_at", - "ordinal": 10, - "type_info": "Timestamp" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true - ], - "parameters": { - "Left": [ - "Int4" - ] - } - }, - "query": "\n SELECT\n *\n FROM\n eth_txs_history\n WHERE\n eth_tx_id = $1\n ORDER BY\n created_at DESC\n " - }, - "4d92a133a36afd682a84fbfd75aafca34d61347e0e2e29fb07ca3d1b8b1f309c": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int4", - "Bytea", - "Bytea", - "Bytea", - "Bytea" - ] - } - }, - "query": "\n INSERT INTO\n prover_fri_protocol_versions (\n id,\n recursion_scheduler_level_vk_hash,\n recursion_node_level_vk_hash,\n recursion_leaf_level_vk_hash,\n recursion_circuits_set_vks_hash,\n created_at\n )\n VALUES\n ($1, $2, $3, $4, $5, NOW())\n ON CONFLICT (id) DO NOTHING\n " - }, - "4e2cb66131a524d1bd628424d0c0735d7f9b0b5820ae3a07467d2e76cd6280f9": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "factory_deps_filepath", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "storage_logs_filepaths", - "ordinal": 2, - "type_info": "TextArray" - } - ], - "nullable": [ - false, - false, - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n l1_batch_number,\n factory_deps_filepath,\n storage_logs_filepaths\n FROM\n snapshots\n " - }, - "4f9b84e4ee54902edb3738ec111268d1266a05f4d931dd874baceedf5444efa4": { - "describe": { - "columns": [ - { - "name": "l1_batch_number!", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "aggregation_round", - "ordinal": 1, - "type_info": "Int4" - } - ], - "nullable": [ - null, - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n MAX(l1_batch_number) AS \"l1_batch_number!\",\n aggregation_round\n FROM\n prover_jobs\n WHERE\n status = 'successful'\n GROUP BY\n aggregation_round\n " - }, - "525123d4ec2b427f1c171f30d0937d8d542b4f14cf560972c005ab3cc13d1f63": { - "describe": { - "columns": [ - { - "name": "hash", - "ordinal": 0, - "type_info": "Bytea" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8", - "Int8" - ] - } - }, - "query": "\n SELECT\n hash\n FROM\n miniblocks\n WHERE\n number BETWEEN $1 AND $2\n ORDER BY\n number\n " - }, - "532a80b0873871896dd318beba5ec427a099492905a1feee512dc43f39d10047": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int4", - "Int4" - ] - } - }, - "query": "\n UPDATE eth_txs_history\n SET\n sent_at_block = $2,\n sent_at = NOW()\n WHERE\n id = $1\n AND sent_at_block IS NULL\n " - }, - "534822a226068cde83ad8c30b569a8f447824a5ab466bb6eea1710e8aeaa2c56": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text", - "Int8" - ] - } - }, - "query": "\n UPDATE proof_compression_jobs_fri\n SET\n status = $1,\n updated_at = NOW()\n WHERE\n l1_batch_number = $2\n " - }, - "53c04fd528752c0e0ef7ffa1f68a7ea81d8d10c76bbae540013667e13230e2ea": { - "describe": { - "columns": [ - { - "name": "fee_account_address", - "ordinal": 0, - "type_info": "Bytea" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n fee_account_address\n FROM\n l1_batches\n WHERE\n number = $1\n " - }, - "53f78fdee39b113d2f55f6f951bd94f28b7b2b60d551d552a9b0bab1f1791e39": { - "describe": { - "columns": [ - { - "name": "attempts", - "ordinal": 0, - "type_info": "Int2" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n attempts\n FROM\n leaf_aggregation_witness_jobs_fri\n WHERE\n id = $1\n " - }, - "5503575d9377785894de6cf6139a8d4768c6a803a1a90889e5a1b8254c315231": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int4" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Text" - ] - } - }, - "query": "INSERT INTO eth_txs (raw_tx, nonce, tx_type, contract_address, predicted_gas_cost, created_at, updated_at) VALUES ('\\x00', 0, $1, '', 0, now(), now()) RETURNING id" - }, - "556f9b9e82d3a9399660dfa4bbf252f26335699a4e7f0347d7e894320245271d": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Jsonb" - ] - } - }, - "query": "\n INSERT INTO\n events_queue (l1_batch_number, serialized_events_queue)\n VALUES\n ($1, $2)\n " - }, - "55b0b4c569c0aaf9741afc85400ecd50a04799ffd36be0e17c56f47fcdbc8f60": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n DELETE FROM l1_batches\n WHERE\n number > $1\n " - }, - "5659480e5d79dab3399e35539b240e7eb9f598999c28015a504605f88bf84b33": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int4" - }, - { - "name": "nonce", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "raw_tx", - "ordinal": 2, - "type_info": "Bytea" - }, - { - "name": "contract_address", - "ordinal": 3, - "type_info": "Text" - }, - { - "name": "tx_type", - "ordinal": 4, - "type_info": "Text" - }, - { - "name": "gas_used", - "ordinal": 5, - "type_info": "Int8" - }, - { - "name": "created_at", - "ordinal": 6, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 7, - "type_info": "Timestamp" - }, - { - "name": "has_failed", - "ordinal": 8, - "type_info": "Bool" - }, - { - "name": "sent_at_block", - "ordinal": 9, - "type_info": "Int4" - }, - { - "name": "confirmed_eth_tx_history_id", - "ordinal": 10, - "type_info": "Int4" - }, - { - "name": "predicted_gas_cost", - "ordinal": 11, - "type_info": "Int8" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - true, - false, - false, - false, - true, - true, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n *\n FROM\n eth_txs\n WHERE\n id > (\n SELECT\n COALESCE(MAX(eth_tx_id), 0)\n FROM\n eth_txs_history\n )\n ORDER BY\n id\n LIMIT\n $1\n " - }, - "5821f1446983260168cec366af26009503182c300877e74a8539f231050e6f85": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text", - "Int8" - ] - } - }, - "query": "\n UPDATE witness_inputs_fri\n SET\n status = $1,\n updated_at = NOW()\n WHERE\n l1_batch_number = $2\n " - }, - "58aed39245c72d231b268ce83105bb2036d21f60d4c6934f9145730ac35c04de": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n l1_batch_number\n FROM\n proof_generation_details\n WHERE\n status = 'ready_to_be_proven'\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n " - }, - "59cb0dd78fadc121e2b1ebbc8a063f089c91aead2bc9abb284697e65840f1e8f": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Bytea", - "Numeric", - "Timestamp" - ] - } - }, - "query": "\n UPDATE tokens\n SET\n usd_price = $2,\n usd_price_updated_at = $3,\n updated_at = NOW()\n WHERE\n l1_address = $1\n " - }, - "5aaed2a975042cc9b7b9d88e5fd5db07667280abef27cc73159d2fd9c95b209b": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "timestamp", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "is_finished", - "ordinal": 2, - "type_info": "Bool" - }, - { - "name": "l1_tx_count", - "ordinal": 3, - "type_info": "Int4" - }, - { - "name": "l2_tx_count", - "ordinal": 4, - "type_info": "Int4" - }, - { - "name": "fee_account_address", - "ordinal": 5, - "type_info": "Bytea" - }, - { - "name": "bloom", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "priority_ops_onchain_data", - "ordinal": 7, - "type_info": "ByteaArray" - }, - { - "name": "hash", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "parent_hash", - "ordinal": 9, - "type_info": "Bytea" - }, - { - "name": "commitment", - "ordinal": 10, - "type_info": "Bytea" - }, - { - "name": "compressed_write_logs", - "ordinal": 11, - "type_info": "Bytea" - }, - { - "name": "compressed_contracts", - "ordinal": 12, - "type_info": "Bytea" - }, - { - "name": "eth_prove_tx_id", - "ordinal": 13, - "type_info": "Int4" - }, - { - "name": "eth_commit_tx_id", - "ordinal": 14, - "type_info": "Int4" - }, - { - "name": "eth_execute_tx_id", - "ordinal": 15, - "type_info": "Int4" - }, - { - "name": "merkle_root_hash", - "ordinal": 16, - "type_info": "Bytea" - }, - { - "name": "l2_to_l1_logs", - "ordinal": 17, - "type_info": "ByteaArray" - }, - { - "name": "l2_to_l1_messages", - "ordinal": 18, - "type_info": "ByteaArray" - }, - { - "name": "used_contract_hashes", - "ordinal": 19, - "type_info": "Jsonb" - }, - { - "name": "compressed_initial_writes", - "ordinal": 20, - "type_info": "Bytea" - }, - { - "name": "compressed_repeated_writes", - "ordinal": 21, - "type_info": "Bytea" - }, - { - "name": "l2_l1_compressed_messages", - "ordinal": 22, - "type_info": "Bytea" - }, - { - "name": "l2_l1_merkle_root", - "ordinal": 23, - "type_info": "Bytea" - }, - { - "name": "l1_gas_price", - "ordinal": 24, - "type_info": "Int8" - }, - { - "name": "l2_fair_gas_price", - "ordinal": 25, - "type_info": "Int8" - }, - { - "name": "rollup_last_leaf_index", - "ordinal": 26, - "type_info": "Int8" - }, - { - "name": "zkporter_is_available", - "ordinal": 27, - "type_info": "Bool" - }, - { - "name": "bootloader_code_hash", - "ordinal": 28, - "type_info": "Bytea" - }, - { - "name": "default_aa_code_hash", - "ordinal": 29, - "type_info": "Bytea" - }, - { - "name": "base_fee_per_gas", - "ordinal": 30, - "type_info": "Numeric" - }, - { - "name": "aux_data_hash", - "ordinal": 31, - "type_info": "Bytea" - }, - { - "name": "pass_through_data_hash", - "ordinal": 32, - "type_info": "Bytea" - }, - { - "name": "meta_parameters_hash", - "ordinal": 33, - "type_info": "Bytea" - }, - { - "name": "protocol_version", - "ordinal": 34, - "type_info": "Int4" - }, - { - "name": "compressed_state_diffs", - "ordinal": 35, - "type_info": "Bytea" - }, - { - "name": "system_logs", - "ordinal": 36, - "type_info": "ByteaArray" - }, - { - "name": "events_queue_commitment", - "ordinal": 37, - "type_info": "Bytea" - }, - { - "name": "bootloader_initial_content_commitment", - "ordinal": 38, - "type_info": "Bytea" - }, - { - "name": "pubdata_input", - "ordinal": 39, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - true, - true, - true, - true, - false, - false, - true, - true, - true, - true, - false, - true, - true, - true, - true, - true, - false, - true, - true, - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n number,\n timestamp,\n is_finished,\n l1_tx_count,\n l2_tx_count,\n fee_account_address,\n bloom,\n priority_ops_onchain_data,\n hash,\n parent_hash,\n commitment,\n compressed_write_logs,\n compressed_contracts,\n eth_prove_tx_id,\n eth_commit_tx_id,\n eth_execute_tx_id,\n merkle_root_hash,\n l2_to_l1_logs,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_compressed_messages,\n l2_l1_merkle_root,\n l1_gas_price,\n l2_fair_gas_price,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n base_fee_per_gas,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n WHERE\n eth_prove_tx_id IS NOT NULL\n AND eth_execute_tx_id IS NULL\n ORDER BY\n number\n LIMIT\n $1\n " - }, - "5c39f043c9b36693b0a845eb36549374a2d931e62615bc7e6ecd0af957b42a13": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "timestamp", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "hash", - "ordinal": 2, - "type_info": "Bytea" - }, - { - "name": "l1_tx_count", - "ordinal": 3, - "type_info": "Int4" - }, - { - "name": "l2_tx_count", - "ordinal": 4, - "type_info": "Int4" - }, - { - "name": "base_fee_per_gas", - "ordinal": 5, - "type_info": "Numeric" - }, - { - "name": "l1_gas_price", - "ordinal": 6, - "type_info": "Int8" - }, - { - "name": "l2_fair_gas_price", - "ordinal": 7, - "type_info": "Int8" - }, - { - "name": "bootloader_code_hash", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "default_aa_code_hash", - "ordinal": 9, - "type_info": "Bytea" - }, - { - "name": "protocol_version", - "ordinal": 10, - "type_info": "Int4" - }, - { - "name": "virtual_blocks", - "ordinal": 11, - "type_info": "Int8" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n number,\n timestamp,\n hash,\n l1_tx_count,\n l2_tx_count,\n base_fee_per_gas,\n l1_gas_price,\n l2_fair_gas_price,\n bootloader_code_hash,\n default_aa_code_hash,\n protocol_version,\n virtual_blocks\n FROM\n miniblocks\n WHERE\n number = $1\n " - }, - "5d493cbce749cc5b56d4069423597b16599abaf51df0f19effe1a536376cf6a6": { - "describe": { - "columns": [ - { - "name": "bootloader_code_hash", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "default_account_code_hash", - "ordinal": 1, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false - ], - "parameters": { - "Left": [ - "Int4" - ] - } - }, - "query": "\n SELECT\n bootloader_code_hash,\n default_account_code_hash\n FROM\n protocol_versions\n WHERE\n id = $1\n " - }, - "5e781f84ec41edd0941fa84de837effac442434c6e734d977e6682a7484abe7f": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "status", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "attempts", - "ordinal": 2, - "type_info": "Int2" - } - ], - "nullable": [ - false, - false, - false - ], - "parameters": { - "Left": [ - "Interval", - "Int2" - ] - } - }, - "query": "\n UPDATE proof_compression_jobs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n (\n status = 'in_progress'\n AND processing_started_at <= NOW() - $1::INTERVAL\n AND attempts < $2\n )\n OR (\n status = 'failed'\n AND attempts < $2\n )\n RETURNING\n l1_batch_number,\n status,\n attempts\n " - }, - "5f6885b5457aaa78e10917ae5b8cd0bc0e8923a6bae64f22f09242766835ee0c": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "contract_address", - "ordinal": 1, - "type_info": "Bytea" - }, - { - "name": "source_code", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "contract_name", - "ordinal": 3, - "type_info": "Text" - }, - { - "name": "zk_compiler_version", - "ordinal": 4, - "type_info": "Text" - }, - { - "name": "compiler_version", - "ordinal": 5, - "type_info": "Text" - }, - { - "name": "optimization_used", - "ordinal": 6, - "type_info": "Bool" - }, - { - "name": "optimizer_mode", - "ordinal": 7, - "type_info": "Text" - }, - { - "name": "constructor_arguments", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "is_system", - "ordinal": 9, - "type_info": "Bool" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - true, - false, - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n id,\n contract_address,\n source_code,\n contract_name,\n zk_compiler_version,\n compiler_version,\n optimization_used,\n optimizer_mode,\n constructor_arguments,\n is_system\n FROM\n contract_verification_requests\n WHERE\n status = 'successful'\n ORDER BY\n id\n " - }, - "5f8fc05ae782846898295d210dd3d55ff2b1510868dfe80d14fffa3f5ff07b83": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Int8" - ] - } - }, - "query": "\n UPDATE l1_batches\n SET\n predicted_commit_gas_cost = $2,\n updated_at = NOW()\n WHERE\n number = $1\n " - }, - "61b2b858d4636809c21838635aa52aeb5f06c26f68d131dd242f6ed68816c513": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int2" - ] - } - }, - "query": "\n SELECT\n l1_batch_number\n FROM\n prover_jobs_fri\n WHERE\n status <> 'skipped'\n AND status <> 'successful'\n AND aggregation_round = $1\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n " - }, - "61bc330d6d1b5fddec78342c1b0f00e82b0b3ad9ae36bf4fe44d7e85b74c6f49": { - "describe": { - "columns": [ - { - "name": "op_id", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n MAX(priority_op_id) AS \"op_id\"\n FROM\n transactions\n WHERE\n is_priority = TRUE\n AND miniblock_number IS NOT NULL\n " - }, - "6692ff6c0fbb2fc94f5cd2837a43ce80f9b2b27758651ccfc09df61a4ae8a363": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int4" - }, - { - "name": "nonce", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "raw_tx", - "ordinal": 2, - "type_info": "Bytea" - }, - { - "name": "contract_address", - "ordinal": 3, - "type_info": "Text" - }, - { - "name": "tx_type", - "ordinal": 4, - "type_info": "Text" - }, - { - "name": "gas_used", - "ordinal": 5, - "type_info": "Int8" - }, - { - "name": "created_at", - "ordinal": 6, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 7, - "type_info": "Timestamp" - }, - { - "name": "has_failed", - "ordinal": 8, - "type_info": "Bool" - }, - { - "name": "sent_at_block", - "ordinal": 9, - "type_info": "Int4" - }, - { - "name": "confirmed_eth_tx_history_id", - "ordinal": 10, - "type_info": "Int4" - }, - { - "name": "predicted_gas_cost", - "ordinal": 11, - "type_info": "Int8" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - true, - false, - false, - false, - true, - true, - false - ], - "parameters": { - "Left": [ - "Int4" - ] - } - }, - "query": "\n SELECT\n *\n FROM\n eth_txs\n WHERE\n id = $1\n " - }, - "66e012ce974c38d9fe84cfc7eb28927f9e976319a305e0928ff366d535a97104": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int4" - }, - { - "name": "nonce", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "raw_tx", - "ordinal": 2, - "type_info": "Bytea" - }, - { - "name": "contract_address", - "ordinal": 3, - "type_info": "Text" - }, - { - "name": "tx_type", - "ordinal": 4, - "type_info": "Text" - }, - { - "name": "gas_used", - "ordinal": 5, - "type_info": "Int8" - }, - { - "name": "created_at", - "ordinal": 6, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 7, - "type_info": "Timestamp" - }, - { - "name": "has_failed", - "ordinal": 8, - "type_info": "Bool" - }, - { - "name": "sent_at_block", - "ordinal": 9, - "type_info": "Int4" - }, - { - "name": "confirmed_eth_tx_history_id", - "ordinal": 10, - "type_info": "Int4" - }, - { - "name": "predicted_gas_cost", - "ordinal": 11, - "type_info": "Int8" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - true, - false, - false, - false, - true, - true, - false - ], - "parameters": { - "Left": [ - "Bytea", - "Int8", - "Text", - "Text", - "Int8" - ] - } - }, - "query": "\n INSERT INTO\n eth_txs (\n raw_tx,\n nonce,\n tx_type,\n contract_address,\n predicted_gas_cost,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, $4, $5, NOW(), NOW())\n RETURNING\n *\n " - }, - "684775aaed3d7f3f5580363e5180a04e7a1af1057995805cb6fd35d0b810e734": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text", - "Text", - "Int4", - "Int4", - "Text", - "Text" - ] - } - }, - "query": "\n UPDATE gpu_prover_queue\n SET\n instance_status = $1,\n updated_at = NOW(),\n queue_free_slots = $4\n WHERE\n instance_host = $2::TEXT::inet\n AND instance_port = $3\n AND region = $5\n AND zone = $6\n " - }, - "68936a53e5b80576f3f341523e6843eb48b5e26ee92cd8476f50251e8c32610d": { - "describe": { - "columns": [ - { - "name": "count!", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [ - "Int8", - "Bytea", - "Bytea", - "Bytea", - "Bytea" - ] - } - }, - "query": "\n SELECT\n COUNT(*) AS \"count!\"\n FROM\n l1_batches\n WHERE\n number = $1\n AND hash = $2\n AND merkle_root_hash = $3\n AND parent_hash = $4\n AND l2_l1_merkle_root = $5\n " - }, - "68a937c42e280690a7a63eeec6883d30eeb6e614ca75edf582b44378c0a698ed": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "l1_batch_number", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "circuit_type", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "prover_input", - "ordinal": 3, - "type_info": "Bytea" - }, - { - "name": "status", - "ordinal": 4, - "type_info": "Text" - }, - { - "name": "error", - "ordinal": 5, - "type_info": "Text" - }, - { - "name": "processing_started_at", - "ordinal": 6, - "type_info": "Timestamp" - }, - { - "name": "created_at", - "ordinal": 7, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 8, - "type_info": "Timestamp" - }, - { - "name": "time_taken", - "ordinal": 9, - "type_info": "Time" - }, - { - "name": "aggregation_round", - "ordinal": 10, - "type_info": "Int4" - }, - { - "name": "result", - "ordinal": 11, - "type_info": "Bytea" - }, - { - "name": "sequence_number", - "ordinal": 12, - "type_info": "Int4" - }, - { - "name": "attempts", - "ordinal": 13, - "type_info": "Int4" - }, - { - "name": "circuit_input_blob_url", - "ordinal": 14, - "type_info": "Text" - }, - { - "name": "proccesed_by", - "ordinal": 15, - "type_info": "Text" - }, - { - "name": "is_blob_cleaned", - "ordinal": 16, - "type_info": "Bool" - }, - { - "name": "protocol_version", - "ordinal": 17, - "type_info": "Int4" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - true, - false, - false, - true, - true, - false, - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n *\n FROM\n prover_jobs\n WHERE\n id = $1\n " - }, - "68c891ee9d71cffe709731f2804b734d5d255e36e48668b3bfc25a0f86ea52e7": { - "describe": { - "columns": [ - { - "name": "is_replaced!", - "ordinal": 0, - "type_info": "Bool" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [ - "Bytea", - "Bytea", - "Int8", - "Bytea", - "Numeric", - "Numeric", - "Numeric", - "Numeric", - "Bytea", - "Jsonb", - "Int4", - "Bytea", - "Numeric", - "Bytea", - "Bytea", - "Int8", - "Int4", - "Int4", - "Timestamp" - ] - } - }, - "query": "\n INSERT INTO\n transactions (\n hash,\n is_priority,\n initiator_address,\n nonce,\n signature,\n gas_limit,\n max_fee_per_gas,\n max_priority_fee_per_gas,\n gas_per_pubdata_limit,\n input,\n data,\n tx_format,\n contract_address,\n value,\n paymaster,\n paymaster_input,\n execution_info,\n received_at,\n created_at,\n updated_at\n )\n VALUES\n (\n $1,\n FALSE,\n $2,\n $3,\n $4,\n $5,\n $6,\n $7,\n $8,\n $9,\n $10,\n $11,\n $12,\n $13,\n $14,\n $15,\n JSONB_BUILD_OBJECT('gas_used', $16::BIGINT, 'storage_writes', $17::INT, 'contracts_used', $18::INT),\n $19,\n NOW(),\n NOW()\n )\n ON CONFLICT (initiator_address, nonce) DO\n UPDATE\n SET\n hash = $1,\n signature = $4,\n gas_limit = $5,\n max_fee_per_gas = $6,\n max_priority_fee_per_gas = $7,\n gas_per_pubdata_limit = $8,\n input = $9,\n data = $10,\n tx_format = $11,\n contract_address = $12,\n value = $13,\n paymaster = $14,\n paymaster_input = $15,\n execution_info = JSONB_BUILD_OBJECT('gas_used', $16::BIGINT, 'storage_writes', $17::INT, 'contracts_used', $18::INT),\n in_mempool = FALSE,\n received_at = $19,\n created_at = NOW(),\n updated_at = NOW(),\n error = NULL\n WHERE\n transactions.is_priority = FALSE\n AND transactions.miniblock_number IS NULL\n RETURNING\n (\n SELECT\n hash\n FROM\n transactions\n WHERE\n transactions.initiator_address = $2\n AND transactions.nonce = $3\n ) IS NOT NULL AS \"is_replaced!\"\n " - }, - "6ae2ed34230beae0e86c584e293e7ee767e4c98706246eb113498c0f817f5f38": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text", - "Int4", - "Int2", - "Text" - ] - } - }, - "query": "\n INSERT INTO\n gpu_prover_queue_fri (\n instance_host,\n instance_port,\n instance_status,\n specialized_prover_group_id,\n zone,\n created_at,\n updated_at\n )\n VALUES\n (CAST($1::TEXT AS inet), $2, 'available', $3, $4, NOW(), NOW())\n ON CONFLICT (instance_host, instance_port, zone) DO\n UPDATE\n SET\n instance_status = 'available',\n specialized_prover_group_id = $3,\n zone = $4,\n updated_at = NOW()\n " - }, - "6b327df84d2b3b31d02db35fd5d91a8d67abcdb743a619ed0d1b9c16206a3c20": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [] - } - }, - "query": "\n DELETE FROM eth_txs\n WHERE\n id >= (\n SELECT\n MIN(id)\n FROM\n eth_txs\n WHERE\n has_failed = TRUE\n )\n " - }, - "6bd3094be764e6378fe52b5bb533260b49ce42daaf9dbe8075daf0a8e0ad9914": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [] - } - }, - "query": "\n DELETE FROM basic_witness_input_producer_jobs\n " - }, - "6c0d03b1fbe6f47546bc34c6b2eab01cb2c55bf86d2c8c99abb1b7ca21cf75c0": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int4" - ] - } - }, - "query": "\n UPDATE miniblocks\n SET\n protocol_version = $1\n WHERE\n l1_batch_number IS NULL\n " - }, - "6ccb3beec0624153ef2e7bff61ba896e34b757421fca9682aecb3a98b54695a6": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "timestamp", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "hash", - "ordinal": 2, - "type_info": "Bytea" - }, - { - "name": "l1_tx_count", - "ordinal": 3, - "type_info": "Int4" - }, - { - "name": "l2_tx_count", - "ordinal": 4, - "type_info": "Int4" - }, - { - "name": "base_fee_per_gas", - "ordinal": 5, - "type_info": "Numeric" - }, - { - "name": "l1_gas_price", - "ordinal": 6, - "type_info": "Int8" - }, - { - "name": "l2_fair_gas_price", - "ordinal": 7, - "type_info": "Int8" - }, - { - "name": "bootloader_code_hash", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "default_aa_code_hash", - "ordinal": 9, - "type_info": "Bytea" - }, - { - "name": "protocol_version", - "ordinal": 10, - "type_info": "Int4" - }, - { - "name": "virtual_blocks", - "ordinal": 11, - "type_info": "Int8" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n number,\n timestamp,\n hash,\n l1_tx_count,\n l2_tx_count,\n base_fee_per_gas,\n l1_gas_price,\n l2_fair_gas_price,\n bootloader_code_hash,\n default_aa_code_hash,\n protocol_version,\n virtual_blocks\n FROM\n miniblocks\n ORDER BY\n number DESC\n LIMIT\n 1\n " - }, - "6f6f60e7139fc789ca420d8610985a918e90b4e7087a98356ab19e22783c88cd": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "instance_host", - "ordinal": 1, - "type_info": "Inet" - }, - { - "name": "instance_port", - "ordinal": 2, - "type_info": "Int4" - }, - { - "name": "instance_status", - "ordinal": 3, - "type_info": "Text" - }, - { - "name": "created_at", - "ordinal": 4, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 5, - "type_info": "Timestamp" - }, - { - "name": "processing_started_at", - "ordinal": 6, - "type_info": "Timestamp" - }, - { - "name": "queue_free_slots", - "ordinal": 7, - "type_info": "Int4" - }, - { - "name": "queue_capacity", - "ordinal": 8, - "type_info": "Int4" - }, - { - "name": "specialized_prover_group_id", - "ordinal": 9, - "type_info": "Int2" - }, - { - "name": "region", - "ordinal": 10, - "type_info": "Text" - }, - { - "name": "zone", - "ordinal": 11, - "type_info": "Text" - }, - { - "name": "num_gpu", - "ordinal": 12, - "type_info": "Int2" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - true - ], - "parameters": { - "Left": [ - "Interval", - "Int2", - "Text", - "Text" - ] - } - }, - "query": "\n UPDATE gpu_prover_queue\n SET\n instance_status = 'reserved',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n id IN (\n SELECT\n id\n FROM\n gpu_prover_queue\n WHERE\n specialized_prover_group_id = $2\n AND region = $3\n AND zone = $4\n AND (\n instance_status = 'available'\n OR (\n instance_status = 'reserved'\n AND processing_started_at < NOW() - $1::INTERVAL\n )\n )\n ORDER BY\n updated_at ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n gpu_prover_queue.*\n " - }, - "708b2b3e40887e6d8d2d7aa20448a58479487686d774e6b2b1391347bdafe06d": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "hash", - "ordinal": 1, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false - ], - "parameters": { - "Left": [ - "Int8", - "Int8" - ] - } - }, - "query": "\n SELECT\n number,\n hash\n FROM\n miniblocks\n WHERE\n number >= $1\n ORDER BY\n number ASC\n LIMIT\n $2\n " - }, - "72a4f50355324cce85ebaef9fa32826095e9290f0c1157094bd0c44e06012e42": { - "describe": { - "columns": [ - { - "name": "hash", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "is_priority", - "ordinal": 1, - "type_info": "Bool" - }, - { - "name": "full_fee", - "ordinal": 2, - "type_info": "Numeric" - }, - { - "name": "layer_2_tip_fee", - "ordinal": 3, - "type_info": "Numeric" - }, - { - "name": "initiator_address", - "ordinal": 4, - "type_info": "Bytea" - }, - { - "name": "nonce", - "ordinal": 5, - "type_info": "Int8" - }, - { - "name": "signature", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "input", - "ordinal": 7, - "type_info": "Bytea" - }, - { - "name": "data", - "ordinal": 8, - "type_info": "Jsonb" - }, - { - "name": "received_at", - "ordinal": 9, - "type_info": "Timestamp" - }, - { - "name": "priority_op_id", - "ordinal": 10, - "type_info": "Int8" - }, - { - "name": "l1_batch_number", - "ordinal": 11, - "type_info": "Int8" - }, - { - "name": "index_in_block", - "ordinal": 12, - "type_info": "Int4" - }, - { - "name": "error", - "ordinal": 13, - "type_info": "Varchar" - }, - { - "name": "gas_limit", - "ordinal": 14, - "type_info": "Numeric" - }, - { - "name": "gas_per_storage_limit", - "ordinal": 15, - "type_info": "Numeric" - }, - { - "name": "gas_per_pubdata_limit", - "ordinal": 16, - "type_info": "Numeric" - }, - { - "name": "tx_format", - "ordinal": 17, - "type_info": "Int4" - }, - { - "name": "created_at", - "ordinal": 18, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 19, - "type_info": "Timestamp" - }, - { - "name": "execution_info", - "ordinal": 20, - "type_info": "Jsonb" - }, - { - "name": "contract_address", - "ordinal": 21, - "type_info": "Bytea" - }, - { - "name": "in_mempool", - "ordinal": 22, - "type_info": "Bool" - }, - { - "name": "l1_block_number", - "ordinal": 23, - "type_info": "Int4" - }, - { - "name": "value", - "ordinal": 24, - "type_info": "Numeric" - }, - { - "name": "paymaster", - "ordinal": 25, - "type_info": "Bytea" - }, - { - "name": "paymaster_input", - "ordinal": 26, - "type_info": "Bytea" - }, - { - "name": "max_fee_per_gas", - "ordinal": 27, - "type_info": "Numeric" - }, - { - "name": "max_priority_fee_per_gas", - "ordinal": 28, - "type_info": "Numeric" - }, - { - "name": "effective_gas_price", - "ordinal": 29, - "type_info": "Numeric" - }, - { - "name": "miniblock_number", - "ordinal": 30, - "type_info": "Int8" - }, - { - "name": "l1_batch_tx_index", - "ordinal": 31, - "type_info": "Int4" - }, - { - "name": "refunded_gas", - "ordinal": 32, - "type_info": "Int8" - }, - { - "name": "l1_tx_mint", - "ordinal": 33, - "type_info": "Numeric" - }, - { - "name": "l1_tx_refund_recipient", - "ordinal": 34, - "type_info": "Bytea" - }, - { - "name": "upgrade_id", - "ordinal": 35, - "type_info": "Int4" - } - ], - "nullable": [ - false, - false, - true, - true, - false, - true, - true, - true, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - true, - false, - true, - false, - false, - false, - true, - true, - true, - true, - true, - false, - true, - true, - true - ], - "parameters": { - "Left": [ - "Bytea" - ] - } - }, - "query": "\n SELECT\n *\n FROM\n transactions\n WHERE\n hash = $1\n " - }, - "72ff9df79e78129cb96d14ece0198129b44534062f524823666ed432d2fcd345": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [] - } - }, - "query": "\n VACUUM storage_logs\n " - }, - "73c4bf1e35d49faaab9f7828e80f396f9d193615d70184d4327378a7fc8a5665": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - { - "Custom": { - "kind": { - "Enum": [ - "Queued", - "ManuallySkipped", - "InProgress", - "Successful", - "Failed" - ] - }, - "name": "basic_witness_input_producer_job_status" - } - }, - "Int8", - "Time", - "Text" - ] - } - }, - "query": "\n UPDATE basic_witness_input_producer_jobs\n SET\n status = $1,\n updated_at = NOW(),\n time_taken = $3,\n input_blob_url = $4\n WHERE\n l1_batch_number = $2\n " - }, - "7560ba61643a8ec8eeefbe6034226313c255ce356a9a4e25c098484d3129c914": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int4" - ] - } - }, - "query": "\n DELETE FROM eth_txs_history\n WHERE\n id = $1\n " - }, - "759b80414b5bcbfe03a0e1e15b37f92c4cfad9313b1461e12242d9becb59e0b0": { - "describe": { - "columns": [ - { - "name": "max?", - "ordinal": 0, - "type_info": "Int4" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n MAX(operation_number) AS \"max?\"\n FROM\n storage_logs\n WHERE\n miniblock_number = $1\n " - }, - "75a3cf6f502ebb1a0e92b672dc6ce56b53cc4ca0a8c6ee7cac1b9a5863000be3": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "timestamp", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "is_finished", - "ordinal": 2, - "type_info": "Bool" - }, - { - "name": "l1_tx_count", - "ordinal": 3, - "type_info": "Int4" - }, - { - "name": "l2_tx_count", - "ordinal": 4, - "type_info": "Int4" - }, - { - "name": "fee_account_address", - "ordinal": 5, - "type_info": "Bytea" - }, - { - "name": "bloom", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "priority_ops_onchain_data", - "ordinal": 7, - "type_info": "ByteaArray" - }, - { - "name": "hash", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "parent_hash", - "ordinal": 9, - "type_info": "Bytea" - }, - { - "name": "commitment", - "ordinal": 10, - "type_info": "Bytea" - }, - { - "name": "compressed_write_logs", - "ordinal": 11, - "type_info": "Bytea" - }, - { - "name": "compressed_contracts", - "ordinal": 12, - "type_info": "Bytea" - }, - { - "name": "eth_prove_tx_id", - "ordinal": 13, - "type_info": "Int4" - }, - { - "name": "eth_commit_tx_id", - "ordinal": 14, - "type_info": "Int4" - }, - { - "name": "eth_execute_tx_id", - "ordinal": 15, - "type_info": "Int4" - }, - { - "name": "merkle_root_hash", - "ordinal": 16, - "type_info": "Bytea" - }, - { - "name": "l2_to_l1_logs", - "ordinal": 17, - "type_info": "ByteaArray" - }, - { - "name": "l2_to_l1_messages", - "ordinal": 18, - "type_info": "ByteaArray" - }, - { - "name": "used_contract_hashes", - "ordinal": 19, - "type_info": "Jsonb" - }, - { - "name": "compressed_initial_writes", - "ordinal": 20, - "type_info": "Bytea" - }, - { - "name": "compressed_repeated_writes", - "ordinal": 21, - "type_info": "Bytea" - }, - { - "name": "l2_l1_compressed_messages", - "ordinal": 22, - "type_info": "Bytea" - }, - { - "name": "l2_l1_merkle_root", - "ordinal": 23, - "type_info": "Bytea" - }, - { - "name": "l1_gas_price", - "ordinal": 24, - "type_info": "Int8" - }, - { - "name": "l2_fair_gas_price", - "ordinal": 25, - "type_info": "Int8" - }, - { - "name": "rollup_last_leaf_index", - "ordinal": 26, - "type_info": "Int8" - }, - { - "name": "zkporter_is_available", - "ordinal": 27, - "type_info": "Bool" - }, - { - "name": "bootloader_code_hash", - "ordinal": 28, - "type_info": "Bytea" - }, - { - "name": "default_aa_code_hash", - "ordinal": 29, - "type_info": "Bytea" - }, - { - "name": "base_fee_per_gas", - "ordinal": 30, - "type_info": "Numeric" - }, - { - "name": "aux_data_hash", - "ordinal": 31, - "type_info": "Bytea" - }, - { - "name": "pass_through_data_hash", - "ordinal": 32, - "type_info": "Bytea" - }, - { - "name": "meta_parameters_hash", - "ordinal": 33, - "type_info": "Bytea" - }, - { - "name": "protocol_version", - "ordinal": 34, - "type_info": "Int4" - }, - { - "name": "compressed_state_diffs", - "ordinal": 35, - "type_info": "Bytea" - }, - { - "name": "system_logs", - "ordinal": 36, - "type_info": "ByteaArray" - }, - { - "name": "events_queue_commitment", - "ordinal": 37, - "type_info": "Bytea" - }, - { - "name": "bootloader_initial_content_commitment", - "ordinal": 38, - "type_info": "Bytea" - }, - { - "name": "pubdata_input", - "ordinal": 39, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - true, - true, - true, - true, - false, - false, - true, - true, - true, - true, - false, - true, - true, - true, - true, - true, - false, - true, - true, - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n number,\n timestamp,\n is_finished,\n l1_tx_count,\n l2_tx_count,\n fee_account_address,\n bloom,\n priority_ops_onchain_data,\n hash,\n parent_hash,\n commitment,\n compressed_write_logs,\n compressed_contracts,\n eth_prove_tx_id,\n eth_commit_tx_id,\n eth_execute_tx_id,\n merkle_root_hash,\n l2_to_l1_logs,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_compressed_messages,\n l2_l1_merkle_root,\n l1_gas_price,\n l2_fair_gas_price,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n base_fee_per_gas,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n WHERE\n eth_commit_tx_id IS NOT NULL\n AND eth_prove_tx_id IS NULL\n ORDER BY\n number\n LIMIT\n $1\n " - }, - "75f6eaa518e7840374c4e44b0788bf92c7f2c55386c8208e3a82b30456abd5b4": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "merkle_tree_paths_blob_url", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "attempts", - "ordinal": 2, - "type_info": "Int2" - }, - { - "name": "status", - "ordinal": 3, - "type_info": "Text" - }, - { - "name": "error", - "ordinal": 4, - "type_info": "Text" - }, - { - "name": "created_at", - "ordinal": 5, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 6, - "type_info": "Timestamp" - }, - { - "name": "processing_started_at", - "ordinal": 7, - "type_info": "Timestamp" - }, - { - "name": "time_taken", - "ordinal": 8, - "type_info": "Time" - }, - { - "name": "is_blob_cleaned", - "ordinal": 9, - "type_info": "Bool" - }, - { - "name": "protocol_version", - "ordinal": 10, - "type_info": "Int4" - }, - { - "name": "picked_by", - "ordinal": 11, - "type_info": "Text" - } - ], - "nullable": [ - false, - true, - false, - false, - true, - false, - false, - true, - true, - true, - true, - true - ], - "parameters": { - "Left": [ - "Int8", - "Int4Array", - "Text" - ] - } - }, - "query": "\n UPDATE witness_inputs_fri\n SET\n status = 'in_progress',\n attempts = attempts + 1,\n updated_at = NOW(),\n processing_started_at = NOW(),\n picked_by = $3\n WHERE\n l1_batch_number = (\n SELECT\n l1_batch_number\n FROM\n witness_inputs_fri\n WHERE\n l1_batch_number <= $1\n AND status = 'queued'\n AND protocol_version = ANY ($2)\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n witness_inputs_fri.*\n " - }, - "75fa24c29dc312cbfa89bf1f4a04a42b4ead6964edd17bfcacb4a828492bba60": { - "describe": { - "columns": [ - { - "name": "state!", - "ordinal": 0, - "type_info": "Jsonb" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n state AS \"state!\"\n FROM\n consensus_replica_state\n WHERE\n fake_key\n " - }, - "76cb9ad97b70d584b19af194576dcf2324f380932698386aa8f9751b1fa24a7b": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "ByteaArray", - "ByteaArray" - ] - } - }, - "query": "\n INSERT INTO\n call_traces (tx_hash, call_trace)\n SELECT\n u.tx_hash,\n u.call_trace\n FROM\n UNNEST($1::bytea[], $2::bytea[]) AS u (tx_hash, call_trace)\n " - }, - "77a43830ca31eac85a3c03d87696bf94a013e49bf50ce23f4de4968781df0796": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Bytea", - "Int8" - ] - } - }, - "query": "\n UPDATE l1_batches\n SET\n hash = $1\n WHERE\n number = $2\n " - }, - "77b35855fbb989f6314469b419726dc7bb98e0f7feaf14656307e20bd2bb0b6c": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Jsonb" - ] - } - }, - "query": "\n INSERT INTO\n consensus_replica_state (fake_key, state)\n VALUES\n (TRUE, $1)\n ON CONFLICT (fake_key) DO\n UPDATE\n SET\n state = excluded.state\n " - }, - "78978c19282961c5b3dc06352b41caa4cca66d6ad74b2cd1a34ea5f7bc1e6909": { - "describe": { - "columns": [ - { - "name": "tx_hash", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "call_trace", - "ordinal": 1, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false - ], - "parameters": { - "Left": [ - "Bytea" - ] - } - }, - "query": "\n SELECT\n *\n FROM\n call_traces\n WHERE\n tx_hash = $1\n " - }, - "7a2145e2234a7896031bbc1ce82715e903f3b399886c2c73e838bd924fed6776": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text", - "Int8", - "Int2", - "Int4", - "Int4" - ] - } - }, - "query": "\n UPDATE node_aggregation_witness_jobs_fri\n SET\n aggregations_url = $1,\n number_of_dependent_jobs = $5,\n updated_at = NOW()\n WHERE\n l1_batch_number = $2\n AND circuit_id = $3\n AND depth = $4\n " - }, - "7a8fffe8d4e3085e00c98f770d250d625f057acf1440b6550375ce5509a816a6": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "l1_batch_number", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "circuit_id", - "ordinal": 2, - "type_info": "Int2" - }, - { - "name": "closed_form_inputs_blob_url", - "ordinal": 3, - "type_info": "Text" - }, - { - "name": "attempts", - "ordinal": 4, - "type_info": "Int2" - }, - { - "name": "status", - "ordinal": 5, - "type_info": "Text" - }, - { - "name": "error", - "ordinal": 6, - "type_info": "Text" - }, - { - "name": "created_at", - "ordinal": 7, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 8, - "type_info": "Timestamp" - }, - { - "name": "processing_started_at", - "ordinal": 9, - "type_info": "Timestamp" - }, - { - "name": "time_taken", - "ordinal": 10, - "type_info": "Time" - }, - { - "name": "is_blob_cleaned", - "ordinal": 11, - "type_info": "Bool" - }, - { - "name": "number_of_basic_circuits", - "ordinal": 12, - "type_info": "Int4" - }, - { - "name": "protocol_version", - "ordinal": 13, - "type_info": "Int4" - }, - { - "name": "picked_by", - "ordinal": 14, - "type_info": "Text" - } - ], - "nullable": [ - false, - false, - false, - true, - false, - false, - true, - false, - false, - true, - true, - true, - true, - true, - true - ], - "parameters": { - "Left": [ - "Int4Array", - "Text" - ] - } - }, - "query": "\n UPDATE leaf_aggregation_witness_jobs_fri\n SET\n status = 'in_progress',\n attempts = attempts + 1,\n updated_at = NOW(),\n processing_started_at = NOW(),\n picked_by = $2\n WHERE\n id = (\n SELECT\n id\n FROM\n leaf_aggregation_witness_jobs_fri\n WHERE\n status = 'queued'\n AND protocol_version = ANY ($1)\n ORDER BY\n l1_batch_number ASC,\n id ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n leaf_aggregation_witness_jobs_fri.*\n " - }, - "7fccc28bd829bce334f37197ee6b139e943f3ad2a41387b610606a42b7f03283": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Bytea", - "Bytea", - "Numeric", - "Numeric", - "Numeric", - "Jsonb", - "Int4", - "Bytea", - "Int4", - "Numeric", - "Bytea", - "Bytea", - "Int4", - "Numeric", - "Bytea", - "Timestamp" - ] - } - }, - "query": "\n INSERT INTO\n transactions (\n hash,\n is_priority,\n initiator_address,\n gas_limit,\n max_fee_per_gas,\n gas_per_pubdata_limit,\n data,\n upgrade_id,\n contract_address,\n l1_block_number,\n value,\n paymaster,\n paymaster_input,\n tx_format,\n l1_tx_mint,\n l1_tx_refund_recipient,\n received_at,\n created_at,\n updated_at\n )\n VALUES\n (\n $1,\n TRUE,\n $2,\n $3,\n $4,\n $5,\n $6,\n $7,\n $8,\n $9,\n $10,\n $11,\n $12,\n $13,\n $14,\n $15,\n $16,\n NOW(),\n NOW()\n )\n ON CONFLICT (hash) DO NOTHING\n " - }, - "806b82a9effd885ba537a2a1c7d7227120a8279db1875d26ccae5ee0785f46a9": { - "describe": { - "columns": [ - { - "name": "attempts", - "ordinal": 0, - "type_info": "Int2" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n attempts\n FROM\n node_aggregation_witness_jobs_fri\n WHERE\n id = $1\n " - }, - "8182690d0326b820d23fba49d391578db18c29cdca85b8b6aad86fe2a9bf6bbe": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "circuit_id", - "ordinal": 1, - "type_info": "Int2" - }, - { - "name": "depth", - "ordinal": 2, - "type_info": "Int4" - } - ], - "nullable": [ - false, - false, - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n UPDATE node_aggregation_witness_jobs_fri\n SET\n status = 'queued'\n WHERE\n (l1_batch_number, circuit_id, depth) IN (\n SELECT\n prover_jobs_fri.l1_batch_number,\n prover_jobs_fri.circuit_id,\n prover_jobs_fri.depth\n FROM\n prover_jobs_fri\n JOIN node_aggregation_witness_jobs_fri nawj ON prover_jobs_fri.l1_batch_number = nawj.l1_batch_number\n AND prover_jobs_fri.circuit_id = nawj.circuit_id\n AND prover_jobs_fri.depth = nawj.depth\n WHERE\n nawj.status = 'waiting_for_proofs'\n AND prover_jobs_fri.status = 'successful'\n AND prover_jobs_fri.aggregation_round = 2\n GROUP BY\n prover_jobs_fri.l1_batch_number,\n prover_jobs_fri.circuit_id,\n prover_jobs_fri.depth,\n nawj.number_of_dependent_jobs\n HAVING\n COUNT(*) = nawj.number_of_dependent_jobs\n )\n RETURNING\n l1_batch_number,\n circuit_id,\n depth;\n " - }, - "81869cb392e9fcbb71ceaa857af77b39429d56072f63b3530c576fb31d7a56f9": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "ByteaArray", - "ByteaArray", - "ByteaArray", - "ByteaArray", - "ByteaArray" - ] - } - }, - "query": "\n INSERT INTO\n storage (hashed_key, address, key, value, tx_hash, created_at, updated_at)\n SELECT\n u.hashed_key,\n u.address,\n u.key,\n u.value,\n u.tx_hash,\n NOW(),\n NOW()\n FROM\n UNNEST($1::bytea[], $2::bytea[], $3::bytea[], $4::bytea[], $5::bytea[]) AS u (hashed_key, address, key, value, tx_hash)\n ON CONFLICT (hashed_key) DO\n UPDATE\n SET\n tx_hash = excluded.tx_hash,\n value = excluded.value,\n updated_at = NOW()\n " - }, - "83134807aee4b6154a1aee4f76dd989d5b4637a97f815b84ace70587acc95e7c": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "TextArray", - "Text" - ] - } - }, - "query": "\n INSERT INTO\n snapshots (\n l1_batch_number,\n storage_logs_filepaths,\n factory_deps_filepath,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, NOW(), NOW())\n " - }, - "831f7bec105541bd3ff9bcf6940d6b6b9d558224ad2d8ed079a68c7e339ded6b": { - "describe": { - "columns": [ - { - "name": "l1_batch_number?", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n MIN(l1_batch_number) AS \"l1_batch_number?\"\n FROM\n (\n SELECT\n MIN(l1_batch_number) AS \"l1_batch_number\"\n FROM\n prover_jobs\n WHERE\n status = 'successful'\n OR aggregation_round < 3\n GROUP BY\n l1_batch_number\n HAVING\n MAX(aggregation_round) < 3\n ) AS inn\n " - }, - "83a931ceddf34e1c760649d613f534014b9ab9ca7725e14fb17aa050d9f35eb8": { - "describe": { - "columns": [ - { - "name": "base_fee_per_gas", - "ordinal": 0, - "type_info": "Numeric" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8", - "Int8" - ] - } - }, - "query": "\n SELECT\n base_fee_per_gas\n FROM\n miniblocks\n WHERE\n number <= $1\n ORDER BY\n number DESC\n LIMIT\n $2\n " - }, - "84c804db9d60a4c1ebbce5e3dcdf03c0aad3ac30d85176e0a4e35f72bbb21b12": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "timestamp", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "is_finished", - "ordinal": 2, - "type_info": "Bool" - }, - { - "name": "l1_tx_count", - "ordinal": 3, - "type_info": "Int4" - }, - { - "name": "l2_tx_count", - "ordinal": 4, - "type_info": "Int4" - }, - { - "name": "fee_account_address", - "ordinal": 5, - "type_info": "Bytea" - }, - { - "name": "bloom", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "priority_ops_onchain_data", - "ordinal": 7, - "type_info": "ByteaArray" - }, - { - "name": "hash", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "parent_hash", - "ordinal": 9, - "type_info": "Bytea" - }, - { - "name": "commitment", - "ordinal": 10, - "type_info": "Bytea" - }, - { - "name": "compressed_write_logs", - "ordinal": 11, - "type_info": "Bytea" - }, - { - "name": "compressed_contracts", - "ordinal": 12, - "type_info": "Bytea" - }, - { - "name": "eth_prove_tx_id", - "ordinal": 13, - "type_info": "Int4" - }, - { - "name": "eth_commit_tx_id", - "ordinal": 14, - "type_info": "Int4" - }, - { - "name": "eth_execute_tx_id", - "ordinal": 15, - "type_info": "Int4" - }, - { - "name": "merkle_root_hash", - "ordinal": 16, - "type_info": "Bytea" - }, - { - "name": "l2_to_l1_logs", - "ordinal": 17, - "type_info": "ByteaArray" - }, - { - "name": "l2_to_l1_messages", - "ordinal": 18, - "type_info": "ByteaArray" - }, - { - "name": "used_contract_hashes", - "ordinal": 19, - "type_info": "Jsonb" - }, - { - "name": "compressed_initial_writes", - "ordinal": 20, - "type_info": "Bytea" - }, - { - "name": "compressed_repeated_writes", - "ordinal": 21, - "type_info": "Bytea" - }, - { - "name": "l2_l1_compressed_messages", - "ordinal": 22, - "type_info": "Bytea" - }, - { - "name": "l2_l1_merkle_root", - "ordinal": 23, - "type_info": "Bytea" - }, - { - "name": "l1_gas_price", - "ordinal": 24, - "type_info": "Int8" - }, - { - "name": "l2_fair_gas_price", - "ordinal": 25, - "type_info": "Int8" - }, - { - "name": "rollup_last_leaf_index", - "ordinal": 26, - "type_info": "Int8" - }, - { - "name": "zkporter_is_available", - "ordinal": 27, - "type_info": "Bool" - }, - { - "name": "bootloader_code_hash", - "ordinal": 28, - "type_info": "Bytea" - }, - { - "name": "default_aa_code_hash", - "ordinal": 29, - "type_info": "Bytea" - }, - { - "name": "base_fee_per_gas", - "ordinal": 30, - "type_info": "Numeric" - }, - { - "name": "aux_data_hash", - "ordinal": 31, - "type_info": "Bytea" - }, - { - "name": "pass_through_data_hash", - "ordinal": 32, - "type_info": "Bytea" - }, - { - "name": "meta_parameters_hash", - "ordinal": 33, - "type_info": "Bytea" - }, - { - "name": "protocol_version", - "ordinal": 34, - "type_info": "Int4" - }, - { - "name": "system_logs", - "ordinal": 35, - "type_info": "ByteaArray" - }, - { - "name": "compressed_state_diffs", - "ordinal": 36, - "type_info": "Bytea" - }, - { - "name": "events_queue_commitment", - "ordinal": 37, - "type_info": "Bytea" - }, - { - "name": "bootloader_initial_content_commitment", - "ordinal": 38, - "type_info": "Bytea" - }, - { - "name": "pubdata_input", - "ordinal": 39, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - true, - true, - true, - true, - false, - false, - true, - true, - true, - true, - false, - true, - true, - true, - true, - false, - true, - true, - true, - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n number,\n timestamp,\n is_finished,\n l1_tx_count,\n l2_tx_count,\n fee_account_address,\n bloom,\n priority_ops_onchain_data,\n hash,\n parent_hash,\n commitment,\n compressed_write_logs,\n compressed_contracts,\n eth_prove_tx_id,\n eth_commit_tx_id,\n eth_execute_tx_id,\n merkle_root_hash,\n l2_to_l1_logs,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_compressed_messages,\n l2_l1_merkle_root,\n l1_gas_price,\n l2_fair_gas_price,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n base_fee_per_gas,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n system_logs,\n compressed_state_diffs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n WHERE\n number = $1\n " - }, - "852aa5fe1c3b2dfe875cd4adf0d19a00c170cf7725d95dd6eb8b753fa5facec8": { - "describe": { - "columns": [ - { - "name": "hash", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "is_priority", - "ordinal": 1, - "type_info": "Bool" - }, - { - "name": "full_fee", - "ordinal": 2, - "type_info": "Numeric" - }, - { - "name": "layer_2_tip_fee", - "ordinal": 3, - "type_info": "Numeric" - }, - { - "name": "initiator_address", - "ordinal": 4, - "type_info": "Bytea" - }, - { - "name": "nonce", - "ordinal": 5, - "type_info": "Int8" - }, - { - "name": "signature", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "input", - "ordinal": 7, - "type_info": "Bytea" - }, - { - "name": "data", - "ordinal": 8, - "type_info": "Jsonb" - }, - { - "name": "received_at", - "ordinal": 9, - "type_info": "Timestamp" - }, - { - "name": "priority_op_id", - "ordinal": 10, - "type_info": "Int8" - }, - { - "name": "l1_batch_number", - "ordinal": 11, - "type_info": "Int8" - }, - { - "name": "index_in_block", - "ordinal": 12, - "type_info": "Int4" - }, - { - "name": "error", - "ordinal": 13, - "type_info": "Varchar" - }, - { - "name": "gas_limit", - "ordinal": 14, - "type_info": "Numeric" - }, - { - "name": "gas_per_storage_limit", - "ordinal": 15, - "type_info": "Numeric" - }, - { - "name": "gas_per_pubdata_limit", - "ordinal": 16, - "type_info": "Numeric" - }, - { - "name": "tx_format", - "ordinal": 17, - "type_info": "Int4" - }, - { - "name": "created_at", - "ordinal": 18, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 19, - "type_info": "Timestamp" - }, - { - "name": "execution_info", - "ordinal": 20, - "type_info": "Jsonb" - }, - { - "name": "contract_address", - "ordinal": 21, - "type_info": "Bytea" - }, - { - "name": "in_mempool", - "ordinal": 22, - "type_info": "Bool" - }, - { - "name": "l1_block_number", - "ordinal": 23, - "type_info": "Int4" - }, - { - "name": "value", - "ordinal": 24, - "type_info": "Numeric" - }, - { - "name": "paymaster", - "ordinal": 25, - "type_info": "Bytea" - }, - { - "name": "paymaster_input", - "ordinal": 26, - "type_info": "Bytea" - }, - { - "name": "max_fee_per_gas", - "ordinal": 27, - "type_info": "Numeric" - }, - { - "name": "max_priority_fee_per_gas", - "ordinal": 28, - "type_info": "Numeric" - }, - { - "name": "effective_gas_price", - "ordinal": 29, - "type_info": "Numeric" - }, - { - "name": "miniblock_number", - "ordinal": 30, - "type_info": "Int8" - }, - { - "name": "l1_batch_tx_index", - "ordinal": 31, - "type_info": "Int4" - }, - { - "name": "refunded_gas", - "ordinal": 32, - "type_info": "Int8" - }, - { - "name": "l1_tx_mint", - "ordinal": 33, - "type_info": "Numeric" - }, - { - "name": "l1_tx_refund_recipient", - "ordinal": 34, - "type_info": "Bytea" - }, - { - "name": "upgrade_id", - "ordinal": 35, - "type_info": "Int4" - } - ], - "nullable": [ - false, - false, - true, - true, - false, - true, - true, - true, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - true, - false, - true, - false, - false, - false, - true, - true, - true, - true, - true, - false, - true, - true, - true - ], - "parameters": { - "Left": [ - "Int8", - "Numeric", - "Numeric", - "Int4" - ] - } - }, - "query": "\n UPDATE transactions\n SET\n in_mempool = TRUE\n FROM\n (\n SELECT\n hash\n FROM\n (\n SELECT\n hash\n FROM\n transactions\n WHERE\n miniblock_number IS NULL\n AND in_mempool = FALSE\n AND error IS NULL\n AND (\n is_priority = TRUE\n OR (\n max_fee_per_gas >= $2\n AND gas_per_pubdata_limit >= $3\n )\n )\n AND tx_format != $4\n ORDER BY\n is_priority DESC,\n priority_op_id,\n received_at\n LIMIT\n $1\n ) AS subquery1\n ORDER BY\n hash\n ) AS subquery2\n WHERE\n transactions.hash = subquery2.hash\n RETURNING\n transactions.*\n " - }, - "8625ca45ce76b8c8633d390e35e0c5f885240d99ea69140a4636b00469d08497": { - "describe": { - "columns": [ - { - "name": "tx_hash", - "ordinal": 0, - "type_info": "Text" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int4" - ] - } - }, - "query": "\n SELECT\n tx_hash\n FROM\n eth_txs_history\n WHERE\n eth_tx_id = $1\n AND confirmed_at IS NOT NULL\n " - }, - "877d20634068170326ab5801b69c70aff49e60b7def3d93b9206e650c259168b": { - "describe": { - "columns": [ - { - "name": "timestamp", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n timestamp\n FROM\n l1_batches\n WHERE\n eth_execute_tx_id IS NULL\n AND number > 0\n ORDER BY\n number\n LIMIT\n 1\n " - }, - "878c9cdfd69ad8988d049041edd63595237a0c54f67b8c669dfbb4fca32757e4": { - "describe": { - "columns": [ - { - "name": "l2_address", - "ordinal": 0, - "type_info": "Bytea" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n l2_address\n FROM\n tokens\n " - }, - "88c629334e30bb9f5c81c858aa51af63b86e8da6d908d48998012231e1d66a60": { - "describe": { - "columns": [ - { - "name": "timestamp", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "virtual_blocks", - "ordinal": 1, - "type_info": "Int8" - } - ], - "nullable": [ - false, - false - ], - "parameters": { - "Left": [ - "Int8", - "Int8" - ] - } - }, - "query": "\n SELECT\n timestamp,\n virtual_blocks\n FROM\n miniblocks\n WHERE\n number BETWEEN $1 AND $2\n ORDER BY\n number\n " - }, - "8903ba5db3f87851c12da133573b4207b69cc48b4ba648e797211631be612b69": { - "describe": { - "columns": [ - { - "name": "bytecode_hash", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "bytecode", - "ordinal": 1, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n bytecode_hash,\n bytecode\n FROM\n factory_deps\n INNER JOIN miniblocks ON miniblocks.number = factory_deps.miniblock_number\n WHERE\n miniblocks.l1_batch_number = $1\n " - }, - "894665c2c467bd1aaeb331b112c567e2667c63a033baa6b427bd8a0898c08bf2": { - "describe": { - "columns": [ - { - "name": "protocol_version", - "ordinal": 0, - "type_info": "Int4" - } - ], - "nullable": [ - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n protocol_version\n FROM\n miniblocks\n WHERE\n number = $1\n " - }, - "8a773618c9df11217467222c9117d6868fbf88ee21d8868a7d133e7cebb3d20e": { - "describe": { - "columns": [ - { - "name": "successful_limit!", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "queued_limit!", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "max_block!", - "ordinal": 2, - "type_info": "Int8" - } - ], - "nullable": [ - null, - null, - null - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n (\n SELECT\n l1_batch_number\n FROM\n prover_jobs\n WHERE\n status NOT IN ('successful', 'skipped')\n ORDER BY\n l1_batch_number\n LIMIT\n 1\n ) AS \"successful_limit!\",\n (\n SELECT\n l1_batch_number\n FROM\n prover_jobs\n WHERE\n status <> 'queued'\n ORDER BY\n l1_batch_number DESC\n LIMIT\n 1\n ) AS \"queued_limit!\",\n (\n SELECT\n MAX(l1_batch_number) AS \"max!\"\n FROM\n prover_jobs\n ) AS \"max_block!\"\n " - }, - "8a7a57ca3d4d65da3e0877c003902c690c33686c889d318b1d64bdd7fa6374db": { - "describe": { - "columns": [ - { - "name": "l1_block_number", - "ordinal": 0, - "type_info": "Int4" - } - ], - "nullable": [ - true - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n l1_block_number\n FROM\n transactions\n WHERE\n priority_op_id IS NOT NULL\n ORDER BY\n priority_op_id DESC\n LIMIT\n 1\n " - }, - "8b9e5d525c026de97c0a732b1adc8dc4bd57e32dfefe1017acba9a15fc14b895": { - "describe": { - "columns": [ - { - "name": "hashed_key", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "value", - "ordinal": 1, - "type_info": "Bytea" - }, - { - "name": "index", - "ordinal": 2, - "type_info": "Int8" - } - ], - "nullable": [ - false, - false, - false - ], - "parameters": { - "Left": [ - "Int8", - "Bytea", - "Bytea" - ] - } - }, - "query": "\n SELECT\n storage_logs.hashed_key,\n storage_logs.value,\n initial_writes.index\n FROM\n storage_logs\n INNER JOIN initial_writes ON storage_logs.hashed_key = initial_writes.hashed_key\n WHERE\n storage_logs.miniblock_number = $1\n AND storage_logs.hashed_key >= $2::bytea\n AND storage_logs.hashed_key <= $3::bytea\n ORDER BY\n storage_logs.hashed_key\n " - }, - "8f5e89ccadd4ea1da7bfe9793a1cbb724af0f0216433a70f19d784e3f2afbc9f": { - "describe": { - "columns": [ - { - "name": "protocol_version", - "ordinal": 0, - "type_info": "Int4" - } - ], - "nullable": [ - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n protocol_version\n FROM\n witness_inputs_fri\n WHERE\n l1_batch_number = $1\n " - }, - "90f7657bae05c4bad6902c6bfb1b8ba0b771cb45573aca81db254f6bcfc17c77": { - "describe": { - "columns": [ - { - "name": "nonce", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n nonce\n FROM\n eth_txs\n ORDER BY\n id DESC\n LIMIT\n 1\n " - }, - "9334df89c9562d4b35611b8e5ffb17305343df99ebc55f240278b5c4e63f89f5": { - "describe": { - "columns": [ - { - "name": "value", - "ordinal": 0, - "type_info": "Bytea" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Bytea" - ] - } - }, - "query": "\n SELECT\n value\n FROM\n storage\n WHERE\n hashed_key = $1\n " - }, - "95ea0522a3eff6c0d2d0b1c58fd2767e112b95f4d103c27acd6f7ede108bd300": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Int4", - "Int4" - ] - } - }, - "query": "\n UPDATE eth_txs\n SET\n gas_used = $1,\n confirmed_eth_tx_history_id = $2\n WHERE\n id = $3\n " - }, - "966dddc881bfe6fd94b56f587424125a2633ddb6abaa129f2b12389140d83c3f": { - "describe": { - "columns": [ - { - "name": "recursion_scheduler_level_vk_hash", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "recursion_node_level_vk_hash", - "ordinal": 1, - "type_info": "Bytea" - }, - { - "name": "recursion_leaf_level_vk_hash", - "ordinal": 2, - "type_info": "Bytea" - }, - { - "name": "recursion_circuits_set_vks_hash", - "ordinal": 3, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false, - false, - false - ], - "parameters": { - "Left": [ - "Int4" - ] - } - }, - "query": "\n SELECT\n recursion_scheduler_level_vk_hash,\n recursion_node_level_vk_hash,\n recursion_leaf_level_vk_hash,\n recursion_circuits_set_vks_hash\n FROM\n protocol_versions\n WHERE\n id = $1\n " - }, - "9955b9215096f781442153518c4f0a9676e26f422506545ccc90b7e8a36c8d47": { - "describe": { - "columns": [ - { - "name": "bytecode", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "data?", - "ordinal": 1, - "type_info": "Jsonb" - }, - { - "name": "contract_address?", - "ordinal": 2, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false, - true - ], - "parameters": { - "Left": [ - "Bytea", - "Bytea" - ] - } - }, - "query": "\n SELECT\n factory_deps.bytecode,\n transactions.data AS \"data?\",\n transactions.contract_address AS \"contract_address?\"\n FROM\n (\n SELECT\n *\n FROM\n storage_logs\n WHERE\n storage_logs.hashed_key = $1\n ORDER BY\n miniblock_number DESC,\n operation_number DESC\n LIMIT\n 1\n ) storage_logs\n JOIN factory_deps ON factory_deps.bytecode_hash = storage_logs.value\n LEFT JOIN transactions ON transactions.hash = storage_logs.tx_hash\n WHERE\n storage_logs.value != $2\n " - }, - "99acb091650478fe0feb367b1d64561347b81f8931cc2addefa907c9aa9355e6": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int4" - }, - { - "name": "timestamp", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "recursion_scheduler_level_vk_hash", - "ordinal": 2, - "type_info": "Bytea" - }, - { - "name": "recursion_node_level_vk_hash", - "ordinal": 3, - "type_info": "Bytea" - }, - { - "name": "recursion_leaf_level_vk_hash", - "ordinal": 4, - "type_info": "Bytea" - }, - { - "name": "recursion_circuits_set_vks_hash", - "ordinal": 5, - "type_info": "Bytea" - }, - { - "name": "bootloader_code_hash", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "default_account_code_hash", - "ordinal": 7, - "type_info": "Bytea" - }, - { - "name": "verifier_address", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "upgrade_tx_hash", - "ordinal": 9, - "type_info": "Bytea" - }, - { - "name": "created_at", - "ordinal": 10, - "type_info": "Timestamp" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - false - ], - "parameters": { - "Left": [ - "Int4" - ] - } - }, - "query": "\n SELECT\n *\n FROM\n protocol_versions\n WHERE\n id < $1\n ORDER BY\n id DESC\n LIMIT\n 1\n " - }, - "99d9ee2a0d0450acefa0d9b6c031e30606fddf6631c859ab03819ec476bcf005": { - "describe": { - "columns": [ - { - "name": "hashed_key", - "ordinal": 0, - "type_info": "Bytea" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "ByteaArray" - ] - } - }, - "query": "\n SELECT\n hashed_key\n FROM\n initial_writes\n WHERE\n hashed_key = ANY ($1)\n " - }, - "99dd6f04e82585d81ac23bc4871578179e6269c6ff36877cedee264067ccdafc": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - { - "Custom": { - "kind": { - "Enum": [ - "Queued", - "ManuallySkipped", - "InProgress", - "Successful", - "Failed" - ] - }, - "name": "basic_witness_input_producer_job_status" - } - }, - { - "Custom": { - "kind": { - "Enum": [ - "Queued", - "ManuallySkipped", - "InProgress", - "Successful", - "Failed" - ] - }, - "name": "basic_witness_input_producer_job_status" - } - }, - { - "Custom": { - "kind": { - "Enum": [ - "Queued", - "ManuallySkipped", - "InProgress", - "Successful", - "Failed" - ] - }, - "name": "basic_witness_input_producer_job_status" - } - }, - "Interval", - "Int2" - ] - } - }, - "query": "\n UPDATE basic_witness_input_producer_jobs\n SET\n status = $1,\n attempts = attempts + 1,\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n l1_batch_number = (\n SELECT\n l1_batch_number\n FROM\n basic_witness_input_producer_jobs\n WHERE\n status = $2\n OR (\n status = $1\n AND processing_started_at < NOW() - $4::INTERVAL\n )\n OR (\n status = $3\n AND attempts < $5\n )\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n basic_witness_input_producer_jobs.l1_batch_number\n " - }, - "9b90f7a7ffee3cd8439f90a6f79693831e2ab6d6d3c1805df5aa51d76994ec19": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Text", - "Int4" - ] - } - }, - "query": "\n INSERT INTO\n witness_inputs_fri (\n l1_batch_number,\n merkle_tree_paths_blob_url,\n protocol_version,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, 'queued', NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO NOTHING\n " - }, - "9c0c3e5edce083804f49137eb3b01c0b73dfb30bdb9e11fcbf370d599344f20e": { - "describe": { - "columns": [ - { - "name": "count!", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "circuit_type!", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "status!", - "ordinal": 2, - "type_info": "Text" - } - ], - "nullable": [ - null, - false, - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n COUNT(*) AS \"count!\",\n circuit_type AS \"circuit_type!\",\n status AS \"status!\"\n FROM\n prover_jobs\n WHERE\n status <> 'skipped'\n AND status <> 'successful'\n GROUP BY\n circuit_type,\n status\n " - }, - "9c2a5f32c627d3a5c6f1e87b31ce3b0fd67aa1f5f7ea0de673a2fbe1f742db86": { - "describe": { - "columns": [ - { - "name": "timestamp", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n timestamp\n FROM\n miniblocks\n WHERE\n number = $1\n " - }, - "9cfcde703a48b110791d2ae1103c9317c01d6e35db3b07d0a31f436e7e3c7c40": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n UPDATE contract_verification_requests\n SET\n status = 'successful',\n updated_at = NOW()\n WHERE\n id = $1\n " - }, - "9ef2f43e6201cc00a0e1425a666a36532fee1450733849852dfd20e18ded1f03": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text", - "Int8" - ] - } - }, - "query": "\n UPDATE scheduler_witness_jobs_fri\n SET\n status = 'failed',\n error = $1,\n updated_at = NOW()\n WHERE\n l1_batch_number = $2\n " - }, - "a0e2b2c034cc5f668f0b3d43b94d2e2326d7ace079b095def52723a45b65d3f3": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text", - "Int8" - ] - } - }, - "query": "\n UPDATE witness_inputs_fri\n SET\n status = 'failed',\n error = $1,\n updated_at = NOW()\n WHERE\n l1_batch_number = $2\n " - }, - "a2d02b71e3dcc29a2c0c20b44392cfbaf09164aecfa5eed8d7142518ad96abea": { - "describe": { - "columns": [ - { - "name": "initial_bootloader_heap_content", - "ordinal": 0, - "type_info": "Jsonb" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n initial_bootloader_heap_content\n FROM\n l1_batches\n WHERE\n number = $1\n " - }, - "a4861c931e84d897c27f666de1c5ca679a0459a012899a373c67393d30d12601": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8Array" - ] - } - }, - "query": "\n UPDATE scheduler_dependency_tracker_fri\n SET\n status = 'queued'\n WHERE\n l1_batch_number = ANY ($1)\n " - }, - "a48c92f557e5e3a2674ce0dee9cd92f5a547150590b8c221c4065eab11175c7a": { - "describe": { - "columns": [ - { - "name": "max?", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n MAX(INDEX) AS \"max?\"\n FROM\n initial_writes\n " - }, - "a4a4b0bfbe05eac100c42a717e8d7cbb0bc526ebe61a07f735d4ab587058b22c": { - "describe": { - "columns": [ - { - "name": "hash", - "ordinal": 0, - "type_info": "Bytea" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n hash\n FROM\n miniblocks\n WHERE\n number = $1\n " - }, - "a4fcd075b68467bb119e49e6b20a69138206dfeb41f3daff4a3eef1de0bed4e4": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "ByteaArray", - "Int8Array", - "Int8" - ] - } - }, - "query": "\n INSERT INTO\n initial_writes (hashed_key, INDEX, l1_batch_number, created_at, updated_at)\n SELECT\n u.hashed_key,\n u.index,\n $3,\n NOW(),\n NOW()\n FROM\n UNNEST($1::bytea[], $2::BIGINT[]) AS u (hashed_key, INDEX)\n " - }, - "a74d029f58801ec05d8d14a3b065d93e391600ab9da2e5fd4e8b139ab3d77583": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text", - "Int8" - ] - } - }, - "query": "\n UPDATE proof_generation_details\n SET\n status = 'generated',\n proof_blob_url = $1,\n updated_at = NOW()\n WHERE\n l1_batch_number = $2\n " - }, - "a83f853b1d63365e88975a926816c6e7b4595f3e7c3dca1d1590de5437187733": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Bytea", - "Bytea", - "Bytea", - "Bytea", - "Bytea", - "Bytea", - "Bytea", - "Bytea", - "Bool", - "Bytea", - "Int8", - "Bytea", - "Bytea", - "Bytea", - "Bytea", - "Int8" - ] - } - }, - "query": "\n UPDATE l1_batches\n SET\n hash = $1,\n merkle_root_hash = $2,\n commitment = $3,\n default_aa_code_hash = $4,\n compressed_repeated_writes = $5,\n compressed_initial_writes = $6,\n l2_l1_compressed_messages = $7,\n l2_l1_merkle_root = $8,\n zkporter_is_available = $9,\n bootloader_code_hash = $10,\n rollup_last_leaf_index = $11,\n aux_data_hash = $12,\n pass_through_data_hash = $13,\n meta_parameters_hash = $14,\n compressed_state_diffs = $15,\n updated_at = NOW()\n WHERE\n number = $16\n " - }, - "a84ee70bec8c03bd51e1c6bad44c9a64904026506914abae2946e5d353d6a604": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8", - "Int2" - ] - } - }, - "query": "\n SELECT\n id\n FROM\n prover_jobs_fri\n WHERE\n l1_batch_number = $1\n AND status = 'successful'\n AND aggregation_round = $2\n " - }, - "a91c23c4d33771122cec2589c6fe2757dbc13be6b30f5840744e5e0569adc66e": { - "describe": { - "columns": [ - { - "name": "upgrade_tx_hash", - "ordinal": 0, - "type_info": "Bytea" - } - ], - "nullable": [ - true - ], - "parameters": { - "Left": [ - "Int4" - ] - } - }, - "query": "\n SELECT\n upgrade_tx_hash\n FROM\n protocol_versions\n WHERE\n id = $1\n " - }, - "aa8e569cf406cd0975a6ffaeeafa92f632186181ba8b93518e549e0643f58da8": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Int4", - "Int4", - "Int8", - "Bool", - "Bytea", - "ByteaArray", - "ByteaArray", - "Bytea", - "ByteaArray", - "Int8", - "Int8", - "Int8", - "Jsonb", - "Jsonb", - "Numeric", - "Int8", - "Int8", - "Bytea", - "Bytea", - "Int4", - "ByteaArray", - "Int8Array", - "Bytea" - ] - } - }, - "query": "\n INSERT INTO\n l1_batches (\n number,\n l1_tx_count,\n l2_tx_count,\n timestamp,\n is_finished,\n fee_account_address,\n l2_to_l1_logs,\n l2_to_l1_messages,\n bloom,\n priority_ops_onchain_data,\n predicted_commit_gas_cost,\n predicted_prove_gas_cost,\n predicted_execute_gas_cost,\n initial_bootloader_heap_content,\n used_contract_hashes,\n base_fee_per_gas,\n l1_gas_price,\n l2_fair_gas_price,\n bootloader_code_hash,\n default_aa_code_hash,\n protocol_version,\n system_logs,\n storage_refunds,\n pubdata_input,\n created_at,\n updated_at\n )\n VALUES\n (\n $1,\n $2,\n $3,\n $4,\n $5,\n $6,\n $7,\n $8,\n $9,\n $10,\n $11,\n $12,\n $13,\n $14,\n $15,\n $16,\n $17,\n $18,\n $19,\n $20,\n $21,\n $22,\n $23,\n $24,\n NOW(),\n NOW()\n )\n " - }, - "aa91697157517322b0dbb53dca99f41220c51f58a03c61d6b7789eab0504e320": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "circuit_id", - "ordinal": 1, - "type_info": "Int2" - }, - { - "name": "depth", - "ordinal": 2, - "type_info": "Int4" - } - ], - "nullable": [ - false, - false, - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n UPDATE node_aggregation_witness_jobs_fri\n SET\n status = 'queued'\n WHERE\n (l1_batch_number, circuit_id, depth) IN (\n SELECT\n prover_jobs_fri.l1_batch_number,\n prover_jobs_fri.circuit_id,\n prover_jobs_fri.depth\n FROM\n prover_jobs_fri\n JOIN node_aggregation_witness_jobs_fri nawj ON prover_jobs_fri.l1_batch_number = nawj.l1_batch_number\n AND prover_jobs_fri.circuit_id = nawj.circuit_id\n AND prover_jobs_fri.depth = nawj.depth\n WHERE\n nawj.status = 'waiting_for_proofs'\n AND prover_jobs_fri.status = 'successful'\n AND prover_jobs_fri.aggregation_round = 1\n AND prover_jobs_fri.depth = 0\n GROUP BY\n prover_jobs_fri.l1_batch_number,\n prover_jobs_fri.circuit_id,\n prover_jobs_fri.depth,\n nawj.number_of_dependent_jobs\n HAVING\n COUNT(*) = nawj.number_of_dependent_jobs\n )\n RETURNING\n l1_batch_number,\n circuit_id,\n depth;\n " - }, - "aaf4fb97c95a5290fb1620cd868477dcf21955e0921ba648ba2e751dbfc3cb45": { - "describe": { - "columns": [ - { - "name": "count!", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "circuit_id!", - "ordinal": 1, - "type_info": "Int2" - }, - { - "name": "aggregation_round!", - "ordinal": 2, - "type_info": "Int2" - }, - { - "name": "status!", - "ordinal": 3, - "type_info": "Text" - } - ], - "nullable": [ - null, - false, - false, - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n COUNT(*) AS \"count!\",\n circuit_id AS \"circuit_id!\",\n aggregation_round AS \"aggregation_round!\",\n status AS \"status!\"\n FROM\n prover_jobs_fri\n WHERE\n status <> 'skipped'\n AND status <> 'successful'\n GROUP BY\n circuit_id,\n aggregation_round,\n status\n " - }, - "ac505ae6cfc744b07b52997db789bdc9efc6b89fc0444caf8271edd7dfe4a3bc": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int4" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n id\n FROM\n protocol_versions\n " - }, - "ac673a122962b57b0272df2d82a1788feea2fbb5682de09120dd109899510820": { - "describe": { - "columns": [ - { - "name": "block_batch?", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "max_batch?", - "ordinal": 1, - "type_info": "Int8" - } - ], - "nullable": [ - null, - null - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n (\n SELECT\n l1_batch_number\n FROM\n miniblocks\n WHERE\n number = $1\n ) AS \"block_batch?\",\n (\n SELECT\n MAX(number) + 1\n FROM\n l1_batches\n ) AS \"max_batch?\"\n " - }, - "ad53e912e68d81628089ae68aaa4154b988ce8ed67af02f4254717a1cdd3da7e": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text", - "Int4", - "Int4", - "Text", - "Text" - ] - } - }, - "query": "\n UPDATE gpu_prover_queue\n SET\n instance_status = 'available',\n updated_at = NOW(),\n queue_free_slots = $3\n WHERE\n instance_host = $1::TEXT::inet\n AND instance_port = $2\n AND instance_status = 'full'\n AND region = $4\n AND zone = $5\n " - }, - "ada54322a28012b1b761f3631c4cd6ca26aa2fa565fcf208b6985f461c1868f2": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int4" - }, - { - "name": "eth_tx_id", - "ordinal": 1, - "type_info": "Int4" - } - ], - "nullable": [ - false, - false - ], - "parameters": { - "Left": [ - "Text" - ] - } - }, - "query": "\n UPDATE eth_txs_history\n SET\n updated_at = NOW(),\n confirmed_at = NOW()\n WHERE\n tx_hash = $1\n RETURNING\n id,\n eth_tx_id\n " - }, - "aeda34b1beadca72e3e600ea9ae63f436a4f16dbeb784d0d28be392ad96b1c49": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int4" - ] - } - }, - "query": "\n UPDATE eth_txs\n SET\n has_failed = TRUE\n WHERE\n id = $1\n " - }, - "aefea1f3e87f28791cc547f193a895006e23ec73018f4b4e0a364a741f5c9781": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n l1_batch_number\n FROM\n miniblocks\n WHERE\n number = $1\n " - }, - "af72fabd90eb43fb315f46d7fe9f724216807ffd481cd6f7f19968e42e52b284": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n UPDATE prover_jobs_fri\n SET\n status = 'sent_to_server',\n updated_at = NOW()\n WHERE\n l1_batch_number = $1\n " - }, - "afc24bd1407dba82cd3dc9e7ee71ac4ab2d73bda6022700aeb0a630a2563a4b4": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text", - "Int8" - ] - } - }, - "query": "\n UPDATE leaf_aggregation_witness_jobs_fri\n SET\n status = 'failed',\n error = $1,\n updated_at = NOW()\n WHERE\n id = $2\n " - }, - "b17c71983da060f08616e001b42f8dcbcb014b4f808c6232abd9a83354c995ac": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "status", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "attempts", - "ordinal": 2, - "type_info": "Int2" - } - ], - "nullable": [ - false, - false, - false - ], - "parameters": { - "Left": [ - "Interval", - "Int2" - ] - } - }, - "query": "\n UPDATE node_aggregation_witness_jobs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n (\n status = 'in_progress'\n AND processing_started_at <= NOW() - $1::INTERVAL\n AND attempts < $2\n )\n OR (\n status = 'failed'\n AND attempts < $2\n )\n RETURNING\n id,\n status,\n attempts\n " - }, - "b23ddb16513d69331056b94d466663a9c5ea62ea7c99a77941eb8f05d4454125": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Int2", - "Text", - "Int4", - "Int4" - ] - } - }, - "query": "\n INSERT INTO\n leaf_aggregation_witness_jobs_fri (\n l1_batch_number,\n circuit_id,\n closed_form_inputs_blob_url,\n number_of_basic_circuits,\n protocol_version,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, $4, $5, 'waiting_for_proofs', NOW(), NOW())\n ON CONFLICT (l1_batch_number, circuit_id) DO\n UPDATE\n SET\n updated_at = NOW()\n " - }, - "b321c5ba22358cbb1fd9c627f1e7b56187686173327498ac75424593547c19c5": { - "describe": { - "columns": [ - { - "name": "attempts", - "ordinal": 0, - "type_info": "Int2" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n attempts\n FROM\n scheduler_witness_jobs_fri\n WHERE\n l1_batch_number = $1\n " - }, - "b33e8da69281efe7750043e409d9871731c41cef01da3d6aaf2c53f7b17c47b2": { - "describe": { - "columns": [ - { - "name": "value", - "ordinal": 0, - "type_info": "Bytea" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Bytea", - "Int8" - ] - } - }, - "query": "\n SELECT\n value\n FROM\n storage_logs\n WHERE\n storage_logs.hashed_key = $1\n AND storage_logs.miniblock_number <= $2\n ORDER BY\n storage_logs.miniblock_number DESC,\n storage_logs.operation_number DESC\n LIMIT\n 1\n " - }, - "b367ecb1ebee86ec598c4079591f8c12deeca6b8843fe3869cc2b02b30da5de6": { - "describe": { - "columns": [ - { - "name": "attempts", - "ordinal": 0, - "type_info": "Int2" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n attempts\n FROM\n proof_compression_jobs_fri\n WHERE\n l1_batch_number = $1\n " - }, - "b3d71dbe14bcd94131b29b64dcb49b6370c211a7fc24ad03a5f0e327f9d18040": { - "describe": { - "columns": [ - { - "name": "attempts", - "ordinal": 0, - "type_info": "Int2" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n attempts\n FROM\n witness_inputs_fri\n WHERE\n l1_batch_number = $1\n " - }, - "b4304b9afb9f838eee1fe95af5fd964d4bb39b9dcd18fb03bc11ce2fb32b7fb3": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "scheduler_partial_input_blob_url", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "status", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "processing_started_at", - "ordinal": 3, - "type_info": "Timestamp" - }, - { - "name": "time_taken", - "ordinal": 4, - "type_info": "Time" - }, - { - "name": "error", - "ordinal": 5, - "type_info": "Text" - }, - { - "name": "created_at", - "ordinal": 6, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 7, - "type_info": "Timestamp" - }, - { - "name": "attempts", - "ordinal": 8, - "type_info": "Int2" - }, - { - "name": "protocol_version", - "ordinal": 9, - "type_info": "Int4" - }, - { - "name": "picked_by", - "ordinal": 10, - "type_info": "Text" - } - ], - "nullable": [ - false, - false, - false, - true, - true, - true, - false, - false, - false, - true, - true - ], - "parameters": { - "Left": [ - "Int4Array", - "Text" - ] - } - }, - "query": "\n UPDATE scheduler_witness_jobs_fri\n SET\n status = 'in_progress',\n attempts = attempts + 1,\n updated_at = NOW(),\n processing_started_at = NOW(),\n picked_by = $2\n WHERE\n l1_batch_number = (\n SELECT\n l1_batch_number\n FROM\n scheduler_witness_jobs_fri\n WHERE\n status = 'queued'\n AND protocol_version = ANY ($1)\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n scheduler_witness_jobs_fri.*\n " - }, - "b452354c888bfc19b5f4012582061b86b1abd915739533f9982fea9d8e21b9e9": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n DELETE FROM factory_deps\n WHERE\n miniblock_number > $1\n " - }, - "b4794e6a0c2366d5d95ab373c310103263af3ff5cb6c9dc5df59d3cd2a5e56b4": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text", - "Text", - "Int4", - "Text" - ] - } - }, - "query": "\n UPDATE gpu_prover_queue_fri\n SET\n instance_status = $1,\n updated_at = NOW()\n WHERE\n instance_host = $2::TEXT::inet\n AND instance_port = $3\n AND zone = $4\n " - }, - "b49478150dbc8731c531ef3eddc0c2cfff08e6fef3c3824d20dfdf2d0f73e671": { - "describe": { - "columns": [ - { - "name": "hash", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "number", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "timestamp", - "ordinal": 2, - "type_info": "Int8" - } - ], - "nullable": [ - false, - false, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n hash,\n number,\n timestamp\n FROM\n miniblocks\n WHERE\n number > $1\n ORDER BY\n number ASC\n " - }, - "b4a0444897b60c7061363a48b2b5386a2fd53492f3df05545edbfb0ec0f059d2": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int4", - "Int4" - ] - } - }, - "query": "\n UPDATE eth_txs\n SET\n confirmed_eth_tx_history_id = $1\n WHERE\n id = $2\n " - }, - "b5fd77f515fe168908cc90e44d0697e36b3c2a997038c30553f7727cdfa17361": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "ByteaArray", - "Int4Array", - "VarcharArray", - "JsonbArray", - "Int8Array", - "NumericArray" - ] - } - }, - "query": "\n UPDATE transactions\n SET\n miniblock_number = $1,\n index_in_block = data_table.index_in_block,\n error = NULLIF(data_table.error, ''),\n in_mempool = FALSE,\n execution_info = execution_info || data_table.new_execution_info,\n refunded_gas = data_table.refunded_gas,\n effective_gas_price = data_table.effective_gas_price,\n updated_at = NOW()\n FROM\n (\n SELECT\n UNNEST($2::bytea[]) AS hash,\n UNNEST($3::INTEGER[]) AS index_in_block,\n UNNEST($4::VARCHAR[]) AS error,\n UNNEST($5::jsonb[]) AS new_execution_info,\n UNNEST($6::BIGINT[]) AS refunded_gas,\n UNNEST($7::NUMERIC[]) AS effective_gas_price\n ) AS data_table\n WHERE\n transactions.hash = data_table.hash\n " - }, - "b678edd9f6ea97b8f086566811f651aa072f030c70a5e6de38843a1d9afdf329": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Bytea", - "Bytea" - ] - } - }, - "query": "\n INSERT INTO\n commitments (l1_batch_number, events_queue_commitment, bootloader_initial_content_commitment)\n VALUES\n ($1, $2, $3)\n ON CONFLICT (l1_batch_number) DO NOTHING\n " - }, - "b75e3d2fecbf5d85e93848b7a35180abbd76956e073432af8d8500327b74e488": { - "describe": { - "columns": [ - { - "name": "version", - "ordinal": 0, - "type_info": "Text" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Text" - ] - } - }, - "query": "\n SELECT\n VERSION\n FROM\n compiler_versions\n WHERE\n compiler = $1\n ORDER BY\n VERSION\n " - }, - "b7bf6999002dd89dc1224468ca79c9a85e3c24fca1bf87905f7fc68fe2ce3276": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int4Array", - "ByteaArray", - "Int8" - ] - } - }, - "query": "\n UPDATE transactions\n SET\n l1_batch_number = $3,\n l1_batch_tx_index = data_table.l1_batch_tx_index,\n updated_at = NOW()\n FROM\n (\n SELECT\n UNNEST($1::INT[]) AS l1_batch_tx_index,\n UNNEST($2::bytea[]) AS hash\n ) AS data_table\n WHERE\n transactions.hash = data_table.hash\n " - }, - "bb1904a01a3860b5440ae23763d6d5ee4341edadb8a86b459a07427b7e265e98": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "l1_tx_count", - "ordinal": 1, - "type_info": "Int4" - }, - { - "name": "l2_tx_count", - "ordinal": 2, - "type_info": "Int4" - }, - { - "name": "timestamp", - "ordinal": 3, - "type_info": "Int8" - }, - { - "name": "is_finished", - "ordinal": 4, - "type_info": "Bool" - }, - { - "name": "fee_account_address", - "ordinal": 5, - "type_info": "Bytea" - }, - { - "name": "l2_to_l1_logs", - "ordinal": 6, - "type_info": "ByteaArray" - }, - { - "name": "l2_to_l1_messages", - "ordinal": 7, - "type_info": "ByteaArray" - }, - { - "name": "bloom", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "priority_ops_onchain_data", - "ordinal": 9, - "type_info": "ByteaArray" - }, - { - "name": "used_contract_hashes", - "ordinal": 10, - "type_info": "Jsonb" - }, - { - "name": "base_fee_per_gas", - "ordinal": 11, - "type_info": "Numeric" - }, - { - "name": "l1_gas_price", - "ordinal": 12, - "type_info": "Int8" - }, - { - "name": "l2_fair_gas_price", - "ordinal": 13, - "type_info": "Int8" - }, - { - "name": "bootloader_code_hash", - "ordinal": 14, - "type_info": "Bytea" - }, - { - "name": "default_aa_code_hash", - "ordinal": 15, - "type_info": "Bytea" - }, - { - "name": "protocol_version", - "ordinal": 16, - "type_info": "Int4" - }, - { - "name": "compressed_state_diffs", - "ordinal": 17, - "type_info": "Bytea" - }, - { - "name": "system_logs", - "ordinal": 18, - "type_info": "ByteaArray" - }, - { - "name": "pubdata_input", - "ordinal": 19, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n number,\n l1_tx_count,\n l2_tx_count,\n timestamp,\n is_finished,\n fee_account_address,\n l2_to_l1_logs,\n l2_to_l1_messages,\n bloom,\n priority_ops_onchain_data,\n used_contract_hashes,\n base_fee_per_gas,\n l1_gas_price,\n l2_fair_gas_price,\n bootloader_code_hash,\n default_aa_code_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n pubdata_input\n FROM\n l1_batches\n WHERE\n number = $1\n " - }, - "bd51c9d93b103292f5acbdb266ba4b4e2af48907fa9321064ddb24ac02ab17cd": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n number\n FROM\n l1_batches\n LEFT JOIN eth_txs_history AS commit_tx ON (l1_batches.eth_commit_tx_id = commit_tx.eth_tx_id)\n WHERE\n commit_tx.confirmed_at IS NOT NULL\n ORDER BY\n number DESC\n LIMIT\n 1\n " - }, - "bd74435dc6dba3f4173858682ee5661d1df4ec053797d75cfd32272be4f485e7": { - "describe": { - "columns": [ - { - "name": "key!", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "value!", - "ordinal": 1, - "type_info": "Bytea" - }, - { - "name": "address!", - "ordinal": 2, - "type_info": "Bytea" - }, - { - "name": "miniblock_number!", - "ordinal": 3, - "type_info": "Int8" - }, - { - "name": "l1_batch_number!", - "ordinal": 4, - "type_info": "Int8" - }, - { - "name": "index", - "ordinal": 5, - "type_info": "Int8" - } - ], - "nullable": [ - true, - true, - true, - true, - true, - true - ], - "parameters": { - "Left": [ - "Int8", - "Bytea", - "Bytea" - ] - } - }, - "query": "\n SELECT\n storage_logs.key AS \"key!\",\n storage_logs.value AS \"value!\",\n storage_logs.address AS \"address!\",\n storage_logs.miniblock_number AS \"miniblock_number!\",\n initial_writes.l1_batch_number AS \"l1_batch_number!\",\n initial_writes.index\n FROM\n (\n SELECT\n hashed_key,\n MAX(ARRAY[miniblock_number, operation_number]::INT[]) AS op\n FROM\n storage_logs\n WHERE\n miniblock_number <= $1\n AND hashed_key >= $2\n AND hashed_key < $3\n GROUP BY\n hashed_key\n ORDER BY\n hashed_key\n ) AS keys\n INNER JOIN storage_logs ON keys.hashed_key = storage_logs.hashed_key\n AND storage_logs.miniblock_number = keys.op[1]\n AND storage_logs.operation_number = keys.op[2]\n INNER JOIN initial_writes ON keys.hashed_key = initial_writes.hashed_key;\n " - }, - "be16d820c124dba9f4a272f54f0b742349e78e6e4ce3e7c9a0dcf6447eedc6d8": { - "describe": { - "columns": [ - { - "name": "miniblock_number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "log_index_in_miniblock", - "ordinal": 1, - "type_info": "Int4" - }, - { - "name": "log_index_in_tx", - "ordinal": 2, - "type_info": "Int4" - }, - { - "name": "tx_hash", - "ordinal": 3, - "type_info": "Bytea" - }, - { - "name": "block_hash", - "ordinal": 4, - "type_info": "Bytea" - }, - { - "name": "l1_batch_number?", - "ordinal": 5, - "type_info": "Int8" - }, - { - "name": "shard_id", - "ordinal": 6, - "type_info": "Int4" - }, - { - "name": "is_service", - "ordinal": 7, - "type_info": "Bool" - }, - { - "name": "tx_index_in_miniblock", - "ordinal": 8, - "type_info": "Int4" - }, - { - "name": "tx_index_in_l1_batch", - "ordinal": 9, - "type_info": "Int4" - }, - { - "name": "sender", - "ordinal": 10, - "type_info": "Bytea" - }, - { - "name": "key", - "ordinal": 11, - "type_info": "Bytea" - }, - { - "name": "value", - "ordinal": 12, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false, - false, - false, - null, - null, - false, - false, - false, - false, - false, - false, - false - ], - "parameters": { - "Left": [ - "Bytea" - ] - } - }, - "query": "\n SELECT\n miniblock_number,\n log_index_in_miniblock,\n log_index_in_tx,\n tx_hash,\n NULL::bytea AS \"block_hash\",\n NULL::BIGINT AS \"l1_batch_number?\",\n shard_id,\n is_service,\n tx_index_in_miniblock,\n tx_index_in_l1_batch,\n sender,\n key,\n value\n FROM\n l2_to_l1_logs\n WHERE\n tx_hash = $1\n ORDER BY\n log_index_in_tx ASC\n " - }, - "bfb80956a18eabf266f5b5a9d62912d57f8eb2a38bdb7884fc812a2897a3a660": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "status", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "attempts", - "ordinal": 2, - "type_info": "Int2" - } - ], - "nullable": [ - false, - false, - false - ], - "parameters": { - "Left": [ - "Interval", - "Int2" - ] - } - }, - "query": "\n UPDATE witness_inputs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n (\n status = 'in_progress'\n AND processing_started_at <= NOW() - $1::INTERVAL\n AND attempts < $2\n )\n OR (\n status = 'in_gpu_proof'\n AND processing_started_at <= NOW() - $1::INTERVAL\n AND attempts < $2\n )\n OR (\n status = 'failed'\n AND attempts < $2\n )\n RETURNING\n l1_batch_number,\n status,\n attempts\n " - }, - "bfc84bcf0985446b337467dd1da709dbee508ad6d1cae43e477cf1bef8cb4aa9": { - "describe": { - "columns": [ - { - "name": "hashed_key", - "ordinal": 0, - "type_info": "Bytea" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8", - "Int8" - ] - } - }, - "query": "\n SELECT DISTINCT\n hashed_key\n FROM\n storage_logs\n WHERE\n miniblock_number BETWEEN $1 AND $2\n " - }, - "c038cecd8184e5e8d9f498116bff995b654adfe328cb825a44ad36b4bf9ec8f2": { - "describe": { - "columns": [ - { - "name": "address", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "topic1", - "ordinal": 1, - "type_info": "Bytea" - }, - { - "name": "topic2", - "ordinal": 2, - "type_info": "Bytea" - }, - { - "name": "topic3", - "ordinal": 3, - "type_info": "Bytea" - }, - { - "name": "topic4", - "ordinal": 4, - "type_info": "Bytea" - }, - { - "name": "value", - "ordinal": 5, - "type_info": "Bytea" - }, - { - "name": "block_hash", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "l1_batch_number?", - "ordinal": 7, - "type_info": "Int8" - }, - { - "name": "miniblock_number", - "ordinal": 8, - "type_info": "Int8" - }, - { - "name": "tx_hash", - "ordinal": 9, - "type_info": "Bytea" - }, - { - "name": "tx_index_in_block", - "ordinal": 10, - "type_info": "Int4" - }, - { - "name": "event_index_in_block", - "ordinal": 11, - "type_info": "Int4" - }, - { - "name": "event_index_in_tx", - "ordinal": 12, - "type_info": "Int4" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - null, - null, - false, - false, - false, - false, - false - ], - "parameters": { - "Left": [ - "Bytea" - ] - } - }, - "query": "\n SELECT\n address,\n topic1,\n topic2,\n topic3,\n topic4,\n value,\n NULL::bytea AS \"block_hash\",\n NULL::BIGINT AS \"l1_batch_number?\",\n miniblock_number,\n tx_hash,\n tx_index_in_block,\n event_index_in_block,\n event_index_in_tx\n FROM\n events\n WHERE\n tx_hash = $1\n ORDER BY\n miniblock_number ASC,\n event_index_in_block ASC\n " - }, - "c03df29f4661fa47c1412bd82ba379f3b2e9ff1bc6e8e38f473fb4950c8e4b77": { - "describe": { - "columns": [ - { - "name": "count!", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n COUNT(*) AS \"count!\"\n FROM\n contract_verification_requests\n WHERE\n status = 'queued'\n " - }, - "c10cf20825de4d24300c7ec50d4a653852f7e43670076eb2ebcd49542a870539": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n INSERT INTO\n scheduler_dependency_tracker_fri (l1_batch_number, status, created_at, updated_at)\n VALUES\n ($1, 'waiting_for_proofs', NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO\n UPDATE\n SET\n updated_at = NOW()\n " - }, - "c139df45a977290d1c2c7987fb9c1d66aeaeb6e2d36fddcf96775f01716a8a74": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n DELETE FROM storage_logs\n WHERE\n miniblock_number > $1\n " - }, - "c14837e92dbb02f2fde7109f524432d865852afe0c60e11a2c1800d30599aa61": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text" - ] - } - }, - "query": "\n DELETE FROM compiler_versions\n WHERE\n compiler = $1\n " - }, - "c192377c08abab9306c5b0844368aa0f8525832cb4075e831c0d4b23c5675b99": { - "describe": { - "columns": [ - { - "name": "bytecode", - "ordinal": 0, - "type_info": "Bytea" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Bytea", - "Int8", - "Bytea" - ] - } - }, - "query": "\n SELECT\n bytecode\n FROM\n (\n SELECT\n *\n FROM\n storage_logs\n WHERE\n storage_logs.hashed_key = $1\n AND storage_logs.miniblock_number <= $2\n ORDER BY\n storage_logs.miniblock_number DESC,\n storage_logs.operation_number DESC\n LIMIT\n 1\n ) t\n JOIN factory_deps ON value = factory_deps.bytecode_hash\n WHERE\n value != $3\n " - }, - "c23d5ff919ade5898c6a912780ae899e360650afccb34f5cc301b5cbac4a3d36": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text", - "Int8" - ] - } - }, - "query": "\n UPDATE prover_jobs_fri\n SET\n status = $1,\n updated_at = NOW()\n WHERE\n id = $2\n " - }, - "c36abacc705a2244d423599779e38d60d6e93bcb34fd20422e227714fccbf6b7": { - "describe": { - "columns": [ - { - "name": "address", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "key", - "ordinal": 1, - "type_info": "Bytea" - }, - { - "name": "value", - "ordinal": 2, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n address,\n key,\n value\n FROM\n storage_logs\n WHERE\n miniblock_number BETWEEN (\n SELECT\n MIN(number)\n FROM\n miniblocks\n WHERE\n l1_batch_number = $1\n ) AND (\n SELECT\n MAX(number)\n FROM\n miniblocks\n WHERE\n l1_batch_number = $1\n )\n ORDER BY\n miniblock_number,\n operation_number\n " - }, - "c3b76b8030d4b5266242619f091c5cffe6869add3e43c71390a9a921b8ff48c5": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int4" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Bytea", - "Bytea", - "Bytea", - "Bytea" - ] - } - }, - "query": "\n SELECT\n id\n FROM\n prover_protocol_versions\n WHERE\n recursion_circuits_set_vks_hash = $1\n AND recursion_leaf_level_vk_hash = $2\n AND recursion_node_level_vk_hash = $3\n AND recursion_scheduler_level_vk_hash = $4\n " - }, - "c41312e01aa66897552e8be9acc8d43c31ec7441a7f6c5040e120810ebbb72f7": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Int2", - "Text", - "Int2", - "Int4", - "Int4", - "Bool", - "Int4" - ] - } - }, - "query": "\n INSERT INTO\n prover_jobs_fri (\n l1_batch_number,\n circuit_id,\n circuit_blob_url,\n aggregation_round,\n sequence_number,\n depth,\n is_node_final_proof,\n protocol_version,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, $8, 'queued', NOW(), NOW())\n ON CONFLICT (l1_batch_number, aggregation_round, circuit_id, depth, sequence_number) DO\n UPDATE\n SET\n updated_at = NOW()\n " - }, - "c4ea7812861a283448095acbb1164420a25eef488de2b67e91ed39657667bd4a": { - "describe": { - "columns": [ - { - "name": "l1_address", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "l2_address", - "ordinal": 1, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n l1_address,\n l2_address\n FROM\n tokens\n " - }, - "c5656667e5610ffb33e7b977ac92b7c4d79cbd404e0267794ec203df0cbb169d": { - "describe": { - "columns": [ - { - "name": "number!", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n COALESCE(MAX(number), 0) AS \"number!\"\n FROM\n l1_batches\n WHERE\n eth_prove_tx_id IS NOT NULL\n " - }, - "c5d6e1d5d834409bd793c8ce1fb2c212918b31dabebf08a84efdfe1feee85765": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n UPDATE scheduler_dependency_tracker_fri\n SET\n status = 'queuing'\n WHERE\n l1_batch_number IN (\n SELECT\n l1_batch_number\n FROM\n scheduler_dependency_tracker_fri\n WHERE\n status != 'queued'\n AND circuit_1_final_prover_job_id IS NOT NULL\n AND circuit_2_final_prover_job_id IS NOT NULL\n AND circuit_3_final_prover_job_id IS NOT NULL\n AND circuit_4_final_prover_job_id IS NOT NULL\n AND circuit_5_final_prover_job_id IS NOT NULL\n AND circuit_6_final_prover_job_id IS NOT NULL\n AND circuit_7_final_prover_job_id IS NOT NULL\n AND circuit_8_final_prover_job_id IS NOT NULL\n AND circuit_9_final_prover_job_id IS NOT NULL\n AND circuit_10_final_prover_job_id IS NOT NULL\n AND circuit_11_final_prover_job_id IS NOT NULL\n AND circuit_12_final_prover_job_id IS NOT NULL\n AND circuit_13_final_prover_job_id IS NOT NULL\n )\n RETURNING\n l1_batch_number;\n " - }, - "c689a86a40c882a0d990a17ecc32290b2a47043fc88d4a2232461434a3f4a57d": { - "describe": { - "columns": [ - { - "name": "count!", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "status!", - "ordinal": 1, - "type_info": "Text" - } - ], - "nullable": [ - null, - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n COUNT(*) AS \"count!\",\n status AS \"status!\"\n FROM\n prover_jobs\n GROUP BY\n status\n " - }, - "c6d523c6ae857022318350a2f210d7eaeeb4549ed59b58f8d984be2a22a80355": { - "describe": { - "columns": [ - { - "name": "max", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [ - "Numeric" - ] - } - }, - "query": "\n SELECT\n MAX(l1_batches.number)\n FROM\n l1_batches\n JOIN eth_txs ON (l1_batches.eth_commit_tx_id = eth_txs.id)\n JOIN eth_txs_history AS commit_tx ON (eth_txs.confirmed_eth_tx_history_id = commit_tx.id)\n WHERE\n commit_tx.confirmed_at IS NOT NULL\n AND eth_prove_tx_id IS NOT NULL\n AND eth_execute_tx_id IS NULL\n AND EXTRACT(\n epoch\n FROM\n commit_tx.confirmed_at\n ) < $1\n " - }, - "c706a49ff54f6b424e24d061fe7ac429aac3c030f7e226a1264243d8cdae038d": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text", - "Time", - "Text", - "Int8" - ] - } - }, - "query": "\n UPDATE proof_compression_jobs_fri\n SET\n status = $1,\n updated_at = NOW(),\n time_taken = $2,\n l1_proof_blob_url = $3\n WHERE\n l1_batch_number = $4\n " - }, - "c809f42a221b18a767e9dd0286503d8bd356f2f9cc249cd8b90caa5a8b5918e3": { - "describe": { - "columns": [ - { - "name": "count!", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [ - "Bytea", - "Bytea" - ] - } - }, - "query": "\n SELECT\n COUNT(*) AS \"count!\"\n FROM\n (\n SELECT\n *\n FROM\n storage_logs\n WHERE\n storage_logs.hashed_key = $1\n ORDER BY\n storage_logs.miniblock_number DESC,\n storage_logs.operation_number DESC\n LIMIT\n 1\n ) sl\n WHERE\n sl.value != $2\n " - }, - "ca9d06141265b8524ee28c55569cb21a635037d89ce24dd3ad58ffaadb59594a": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n l1_batch_number\n FROM\n proof_compression_jobs_fri\n WHERE\n status <> 'successful'\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n " - }, - "cb98d84fc34af1e4a4c2f427c5bb4afd384063ae394a847b26304dd18d490ab4": { - "describe": { - "columns": [ - { - "name": "timestamp", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "hash", - "ordinal": 1, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n timestamp,\n hash\n FROM\n l1_batches\n WHERE\n number = $1\n " - }, - "cd76f54e1b9b4c0cf3044d3b767714e290f88ea1f20092a0278718fecda63caf": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "l1_batch_number", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "circuit_type", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "prover_input", - "ordinal": 3, - "type_info": "Bytea" - }, - { - "name": "status", - "ordinal": 4, - "type_info": "Text" - }, - { - "name": "error", - "ordinal": 5, - "type_info": "Text" - }, - { - "name": "processing_started_at", - "ordinal": 6, - "type_info": "Timestamp" - }, - { - "name": "created_at", - "ordinal": 7, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 8, - "type_info": "Timestamp" - }, - { - "name": "time_taken", - "ordinal": 9, - "type_info": "Time" - }, - { - "name": "aggregation_round", - "ordinal": 10, - "type_info": "Int4" - }, - { - "name": "result", - "ordinal": 11, - "type_info": "Bytea" - }, - { - "name": "sequence_number", - "ordinal": 12, - "type_info": "Int4" - }, - { - "name": "attempts", - "ordinal": 13, - "type_info": "Int4" - }, - { - "name": "circuit_input_blob_url", - "ordinal": 14, - "type_info": "Text" - }, - { - "name": "proccesed_by", - "ordinal": 15, - "type_info": "Text" - }, - { - "name": "is_blob_cleaned", - "ordinal": 16, - "type_info": "Bool" - }, - { - "name": "protocol_version", - "ordinal": 17, - "type_info": "Int4" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - true, - false, - false, - true, - true, - false, - true - ], - "parameters": { - "Left": [ - "TextArray", - "Int4Array" - ] - } - }, - "query": "\n UPDATE prover_jobs\n SET\n status = 'in_progress',\n attempts = attempts + 1,\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n id = (\n SELECT\n id\n FROM\n prover_jobs\n WHERE\n circuit_type = ANY ($1)\n AND status = 'queued'\n AND protocol_version = ANY ($2)\n ORDER BY\n aggregation_round DESC,\n l1_batch_number ASC,\n id ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n prover_jobs.*\n " - }, - "cddf48514aa2aa249d0530d44c741368993009bb4bd90c2ad177ce56317aa04c": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "timestamp", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "is_finished", - "ordinal": 2, - "type_info": "Bool" - }, - { - "name": "l1_tx_count", - "ordinal": 3, - "type_info": "Int4" - }, - { - "name": "l2_tx_count", - "ordinal": 4, - "type_info": "Int4" - }, - { - "name": "fee_account_address", - "ordinal": 5, - "type_info": "Bytea" - }, - { - "name": "bloom", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "priority_ops_onchain_data", - "ordinal": 7, - "type_info": "ByteaArray" - }, - { - "name": "hash", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "parent_hash", - "ordinal": 9, - "type_info": "Bytea" - }, - { - "name": "commitment", - "ordinal": 10, - "type_info": "Bytea" - }, - { - "name": "compressed_write_logs", - "ordinal": 11, - "type_info": "Bytea" - }, - { - "name": "compressed_contracts", - "ordinal": 12, - "type_info": "Bytea" - }, - { - "name": "eth_prove_tx_id", - "ordinal": 13, - "type_info": "Int4" - }, - { - "name": "eth_commit_tx_id", - "ordinal": 14, - "type_info": "Int4" - }, - { - "name": "eth_execute_tx_id", - "ordinal": 15, - "type_info": "Int4" - }, - { - "name": "merkle_root_hash", - "ordinal": 16, - "type_info": "Bytea" - }, - { - "name": "l2_to_l1_logs", - "ordinal": 17, - "type_info": "ByteaArray" - }, - { - "name": "l2_to_l1_messages", - "ordinal": 18, - "type_info": "ByteaArray" - }, - { - "name": "used_contract_hashes", - "ordinal": 19, - "type_info": "Jsonb" - }, - { - "name": "compressed_initial_writes", - "ordinal": 20, - "type_info": "Bytea" - }, - { - "name": "compressed_repeated_writes", - "ordinal": 21, - "type_info": "Bytea" - }, - { - "name": "l2_l1_compressed_messages", - "ordinal": 22, - "type_info": "Bytea" - }, - { - "name": "l2_l1_merkle_root", - "ordinal": 23, - "type_info": "Bytea" - }, - { - "name": "l1_gas_price", - "ordinal": 24, - "type_info": "Int8" - }, - { - "name": "l2_fair_gas_price", - "ordinal": 25, - "type_info": "Int8" - }, - { - "name": "rollup_last_leaf_index", - "ordinal": 26, - "type_info": "Int8" - }, - { - "name": "zkporter_is_available", - "ordinal": 27, - "type_info": "Bool" - }, - { - "name": "bootloader_code_hash", - "ordinal": 28, - "type_info": "Bytea" - }, - { - "name": "default_aa_code_hash", - "ordinal": 29, - "type_info": "Bytea" - }, - { - "name": "base_fee_per_gas", - "ordinal": 30, - "type_info": "Numeric" - }, - { - "name": "aux_data_hash", - "ordinal": 31, - "type_info": "Bytea" - }, - { - "name": "pass_through_data_hash", - "ordinal": 32, - "type_info": "Bytea" - }, - { - "name": "meta_parameters_hash", - "ordinal": 33, - "type_info": "Bytea" - }, - { - "name": "system_logs", - "ordinal": 34, - "type_info": "ByteaArray" - }, - { - "name": "compressed_state_diffs", - "ordinal": 35, - "type_info": "Bytea" - }, - { - "name": "protocol_version", - "ordinal": 36, - "type_info": "Int4" - }, - { - "name": "events_queue_commitment", - "ordinal": 37, - "type_info": "Bytea" - }, - { - "name": "bootloader_initial_content_commitment", - "ordinal": 38, - "type_info": "Bytea" - }, - { - "name": "pubdata_input", - "ordinal": 39, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - true, - true, - true, - true, - false, - false, - true, - true, - true, - true, - false, - true, - true, - true, - false, - true, - true, - true, - true, - true - ], - "parameters": { - "Left": [ - "Int8", - "Int8" - ] - } - }, - "query": "\n SELECT\n number,\n timestamp,\n is_finished,\n l1_tx_count,\n l2_tx_count,\n fee_account_address,\n bloom,\n priority_ops_onchain_data,\n hash,\n parent_hash,\n commitment,\n compressed_write_logs,\n compressed_contracts,\n eth_prove_tx_id,\n eth_commit_tx_id,\n eth_execute_tx_id,\n merkle_root_hash,\n l2_to_l1_logs,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_compressed_messages,\n l2_l1_merkle_root,\n l1_gas_price,\n l2_fair_gas_price,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n base_fee_per_gas,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n system_logs,\n compressed_state_diffs,\n protocol_version,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n (\n SELECT\n l1_batches.*,\n ROW_NUMBER() OVER (\n ORDER BY\n number ASC\n ) AS ROW_NUMBER\n FROM\n l1_batches\n WHERE\n eth_commit_tx_id IS NOT NULL\n AND l1_batches.skip_proof = TRUE\n AND l1_batches.number > $1\n ORDER BY\n number\n LIMIT\n $2\n ) inn\n LEFT JOIN commitments ON commitments.l1_batch_number = inn.number\n WHERE\n number - ROW_NUMBER = $1\n " - }, - "ce5779092feb8a3d3e2c5e395783e67f08f2ead5f55bfb6594e50346bf9cf2ef": { - "describe": { - "columns": [ - { - "name": "l1_batch_number!", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "circuit_id", - "ordinal": 1, - "type_info": "Int2" - }, - { - "name": "aggregation_round", - "ordinal": 2, - "type_info": "Int2" - } - ], - "nullable": [ - null, - false, - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n MIN(l1_batch_number) AS \"l1_batch_number!\",\n circuit_id,\n aggregation_round\n FROM\n prover_jobs_fri\n WHERE\n status IN ('queued', 'in_gpu_proof', 'in_progress', 'failed')\n GROUP BY\n circuit_id,\n aggregation_round\n " - }, - "cea9fe027a6a0ada827f23b48ac32432295b2f7ee40bf13522a6edbd236f1970": { - "describe": { - "columns": [ - { - "name": "hashed_key!", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "value?", - "ordinal": 1, - "type_info": "Bytea" - } - ], - "nullable": [ - null, - null - ], - "parameters": { - "Left": [ - "ByteaArray", - "Int8" - ] - } - }, - "query": "\n SELECT\n u.hashed_key AS \"hashed_key!\",\n (\n SELECT\n value\n FROM\n storage_logs\n WHERE\n hashed_key = u.hashed_key\n AND miniblock_number <= $2\n ORDER BY\n miniblock_number DESC,\n operation_number DESC\n LIMIT\n 1\n ) AS \"value?\"\n FROM\n UNNEST($1::bytea[]) AS u (hashed_key)\n " - }, - "d14b52df2cd9f9e484c60ba00383b438f14b68535111cf2cedd363fc646aac99": { - "describe": { - "columns": [ - { - "name": "timestamp", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n timestamp\n FROM\n l1_batches\n WHERE\n eth_commit_tx_id IS NULL\n AND number > 0\n ORDER BY\n number\n LIMIT\n 1\n " - }, - "d17221312e645b0287ff9238954512b528e7928087351a32c96b44d538dfb9ee": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "l1_batch_number", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "circuit_type", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "prover_input", - "ordinal": 3, - "type_info": "Bytea" - }, - { - "name": "status", - "ordinal": 4, - "type_info": "Text" - }, - { - "name": "error", - "ordinal": 5, - "type_info": "Text" - }, - { - "name": "processing_started_at", - "ordinal": 6, - "type_info": "Timestamp" - }, - { - "name": "created_at", - "ordinal": 7, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 8, - "type_info": "Timestamp" - }, - { - "name": "time_taken", - "ordinal": 9, - "type_info": "Time" - }, - { - "name": "aggregation_round", - "ordinal": 10, - "type_info": "Int4" - }, - { - "name": "result", - "ordinal": 11, - "type_info": "Bytea" - }, - { - "name": "sequence_number", - "ordinal": 12, - "type_info": "Int4" - }, - { - "name": "attempts", - "ordinal": 13, - "type_info": "Int4" - }, - { - "name": "circuit_input_blob_url", - "ordinal": 14, - "type_info": "Text" - }, - { - "name": "proccesed_by", - "ordinal": 15, - "type_info": "Text" - }, - { - "name": "is_blob_cleaned", - "ordinal": 16, - "type_info": "Bool" - }, - { - "name": "protocol_version", - "ordinal": 17, - "type_info": "Int4" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - true, - false, - false, - true, - true, - false, - true - ], - "parameters": { - "Left": [ - "Int4Array" - ] - } - }, - "query": "\n UPDATE prover_jobs\n SET\n status = 'in_progress',\n attempts = attempts + 1,\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n id = (\n SELECT\n id\n FROM\n prover_jobs\n WHERE\n status = 'queued'\n AND protocol_version = ANY ($1)\n ORDER BY\n aggregation_round DESC,\n l1_batch_number ASC,\n id ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n prover_jobs.*\n " - }, - "d1b261f4057e4113b96eb87c9e20015eeb3ef2643ceda3024504a471b24d1283": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "timestamp", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "is_finished", - "ordinal": 2, - "type_info": "Bool" - }, - { - "name": "l1_tx_count", - "ordinal": 3, - "type_info": "Int4" - }, - { - "name": "l2_tx_count", - "ordinal": 4, - "type_info": "Int4" - }, - { - "name": "fee_account_address", - "ordinal": 5, - "type_info": "Bytea" - }, - { - "name": "bloom", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "priority_ops_onchain_data", - "ordinal": 7, - "type_info": "ByteaArray" - }, - { - "name": "hash", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "parent_hash", - "ordinal": 9, - "type_info": "Bytea" - }, - { - "name": "commitment", - "ordinal": 10, - "type_info": "Bytea" - }, - { - "name": "compressed_write_logs", - "ordinal": 11, - "type_info": "Bytea" - }, - { - "name": "compressed_contracts", - "ordinal": 12, - "type_info": "Bytea" - }, - { - "name": "eth_prove_tx_id", - "ordinal": 13, - "type_info": "Int4" - }, - { - "name": "eth_commit_tx_id", - "ordinal": 14, - "type_info": "Int4" - }, - { - "name": "eth_execute_tx_id", - "ordinal": 15, - "type_info": "Int4" - }, - { - "name": "merkle_root_hash", - "ordinal": 16, - "type_info": "Bytea" - }, - { - "name": "l2_to_l1_logs", - "ordinal": 17, - "type_info": "ByteaArray" - }, - { - "name": "l2_to_l1_messages", - "ordinal": 18, - "type_info": "ByteaArray" - }, - { - "name": "used_contract_hashes", - "ordinal": 19, - "type_info": "Jsonb" - }, - { - "name": "compressed_initial_writes", - "ordinal": 20, - "type_info": "Bytea" - }, - { - "name": "compressed_repeated_writes", - "ordinal": 21, - "type_info": "Bytea" - }, - { - "name": "l2_l1_compressed_messages", - "ordinal": 22, - "type_info": "Bytea" - }, - { - "name": "l2_l1_merkle_root", - "ordinal": 23, - "type_info": "Bytea" - }, - { - "name": "l1_gas_price", - "ordinal": 24, - "type_info": "Int8" - }, - { - "name": "l2_fair_gas_price", - "ordinal": 25, - "type_info": "Int8" - }, - { - "name": "rollup_last_leaf_index", - "ordinal": 26, - "type_info": "Int8" - }, - { - "name": "zkporter_is_available", - "ordinal": 27, - "type_info": "Bool" - }, - { - "name": "bootloader_code_hash", - "ordinal": 28, - "type_info": "Bytea" - }, - { - "name": "default_aa_code_hash", - "ordinal": 29, - "type_info": "Bytea" - }, - { - "name": "base_fee_per_gas", - "ordinal": 30, - "type_info": "Numeric" - }, - { - "name": "aux_data_hash", - "ordinal": 31, - "type_info": "Bytea" - }, - { - "name": "pass_through_data_hash", - "ordinal": 32, - "type_info": "Bytea" - }, - { - "name": "meta_parameters_hash", - "ordinal": 33, - "type_info": "Bytea" - }, - { - "name": "protocol_version", - "ordinal": 34, - "type_info": "Int4" - }, - { - "name": "compressed_state_diffs", - "ordinal": 35, - "type_info": "Bytea" - }, - { - "name": "system_logs", - "ordinal": 36, - "type_info": "ByteaArray" - }, - { - "name": "events_queue_commitment", - "ordinal": 37, - "type_info": "Bytea" - }, - { - "name": "bootloader_initial_content_commitment", - "ordinal": 38, - "type_info": "Bytea" - }, - { - "name": "pubdata_input", - "ordinal": 39, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - true, - true, - true, - true, - false, - false, - true, - true, - true, - true, - false, - true, - true, - true, - true, - true, - false, - true, - true, - true - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n number,\n timestamp,\n is_finished,\n l1_tx_count,\n l2_tx_count,\n fee_account_address,\n bloom,\n priority_ops_onchain_data,\n hash,\n parent_hash,\n commitment,\n compressed_write_logs,\n compressed_contracts,\n eth_prove_tx_id,\n eth_commit_tx_id,\n eth_execute_tx_id,\n merkle_root_hash,\n l2_to_l1_logs,\n l2_to_l1_messages,\n used_contract_hashes,\n compressed_initial_writes,\n compressed_repeated_writes,\n l2_l1_compressed_messages,\n l2_l1_merkle_root,\n l1_gas_price,\n l2_fair_gas_price,\n rollup_last_leaf_index,\n zkporter_is_available,\n bootloader_code_hash,\n default_aa_code_hash,\n base_fee_per_gas,\n aux_data_hash,\n pass_through_data_hash,\n meta_parameters_hash,\n protocol_version,\n compressed_state_diffs,\n system_logs,\n events_queue_commitment,\n bootloader_initial_content_commitment,\n pubdata_input\n FROM\n l1_batches\n LEFT JOIN commitments ON commitments.l1_batch_number = l1_batches.number\n WHERE\n number = 0\n OR eth_commit_tx_id IS NOT NULL\n AND commitment IS NOT NULL\n ORDER BY\n number DESC\n LIMIT\n 1\n " - }, - "d3b09cbcddf6238b358d32d57678242aad3e9a47400f6d6837a35f4c54a216b9": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n number\n FROM\n l1_batches\n LEFT JOIN eth_txs_history AS execute_tx ON (l1_batches.eth_execute_tx_id = execute_tx.eth_tx_id)\n WHERE\n execute_tx.confirmed_at IS NOT NULL\n ORDER BY\n number DESC\n LIMIT\n 1\n " - }, - "d70cfc158e31dd2d5c942d24f81fd17f833fb15b58b0110c7cc566946db98e76": { - "describe": { - "columns": [ - { - "name": "block_hash?", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "address!", - "ordinal": 1, - "type_info": "Bytea" - }, - { - "name": "topic1!", - "ordinal": 2, - "type_info": "Bytea" - }, - { - "name": "topic2!", - "ordinal": 3, - "type_info": "Bytea" - }, - { - "name": "topic3!", - "ordinal": 4, - "type_info": "Bytea" - }, - { - "name": "topic4!", - "ordinal": 5, - "type_info": "Bytea" - }, - { - "name": "value!", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "miniblock_number!", - "ordinal": 7, - "type_info": "Int8" - }, - { - "name": "l1_batch_number?", - "ordinal": 8, - "type_info": "Int8" - }, - { - "name": "tx_hash!", - "ordinal": 9, - "type_info": "Bytea" - }, - { - "name": "tx_index_in_block!", - "ordinal": 10, - "type_info": "Int4" - }, - { - "name": "event_index_in_block!", - "ordinal": 11, - "type_info": "Int4" - }, - { - "name": "event_index_in_tx!", - "ordinal": 12, - "type_info": "Int4" - } - ], - "nullable": [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n WITH\n events_select AS (\n SELECT\n address,\n topic1,\n topic2,\n topic3,\n topic4,\n value,\n miniblock_number,\n tx_hash,\n tx_index_in_block,\n event_index_in_block,\n event_index_in_tx\n FROM\n events\n WHERE\n miniblock_number > $1\n ORDER BY\n miniblock_number ASC,\n event_index_in_block ASC\n )\n SELECT\n miniblocks.hash AS \"block_hash?\",\n address AS \"address!\",\n topic1 AS \"topic1!\",\n topic2 AS \"topic2!\",\n topic3 AS \"topic3!\",\n topic4 AS \"topic4!\",\n value AS \"value!\",\n miniblock_number AS \"miniblock_number!\",\n miniblocks.l1_batch_number AS \"l1_batch_number?\",\n tx_hash AS \"tx_hash!\",\n tx_index_in_block AS \"tx_index_in_block!\",\n event_index_in_block AS \"event_index_in_block!\",\n event_index_in_tx AS \"event_index_in_tx!\"\n FROM\n events_select\n INNER JOIN miniblocks ON events_select.miniblock_number = miniblocks.number\n ORDER BY\n miniblock_number ASC,\n event_index_in_block ASC\n " - }, - "d712707e47e143c52330ea6e0513d2839f0f928c06b8020eecec38e895f99b42": { - "describe": { - "columns": [ - { - "name": "address", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "key", - "ordinal": 1, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n address,\n key\n FROM\n protective_reads\n WHERE\n l1_batch_number = $1\n " - }, - "d7e8eabd7b43ff62838fbc847e4813d2b2d411bd5faf8306cd48db500532b711": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "status", - "ordinal": 1, - "type_info": "Text" - } - ], - "nullable": [ - false, - false - ], - "parameters": { - "Left": [ - "Text", - "Text" - ] - } - }, - "query": "\n SELECT\n l1_batch_number,\n status\n FROM\n proof_compression_jobs_fri\n WHERE\n l1_batch_number = (\n SELECT\n MIN(l1_batch_number)\n FROM\n proof_compression_jobs_fri\n WHERE\n status = $1\n OR status = $2\n )\n " - }, - "d7ed82f0d012f72374edb2ebcec33c83477d65a6f8cb2673f67b3148cd95b436": { - "describe": { - "columns": [ - { - "name": "count", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n COUNT(*)\n FROM\n eth_txs\n WHERE\n has_failed = TRUE\n " - }, - "d8e0f98a67ffb53a1caa6820f8475da2787332deca5708d1d08730cdbfc73541": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "l1_tx_count", - "ordinal": 1, - "type_info": "Int4" - }, - { - "name": "l2_tx_count", - "ordinal": 2, - "type_info": "Int4" - }, - { - "name": "timestamp", - "ordinal": 3, - "type_info": "Int8" - }, - { - "name": "is_finished", - "ordinal": 4, - "type_info": "Bool" - }, - { - "name": "fee_account_address", - "ordinal": 5, - "type_info": "Bytea" - }, - { - "name": "l2_to_l1_logs", - "ordinal": 6, - "type_info": "ByteaArray" - }, - { - "name": "l2_to_l1_messages", - "ordinal": 7, - "type_info": "ByteaArray" - }, - { - "name": "bloom", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "priority_ops_onchain_data", - "ordinal": 9, - "type_info": "ByteaArray" - }, - { - "name": "used_contract_hashes", - "ordinal": 10, - "type_info": "Jsonb" - }, - { - "name": "base_fee_per_gas", - "ordinal": 11, - "type_info": "Numeric" - }, - { - "name": "l1_gas_price", - "ordinal": 12, - "type_info": "Int8" - }, - { - "name": "l2_fair_gas_price", - "ordinal": 13, - "type_info": "Int8" - }, - { - "name": "bootloader_code_hash", - "ordinal": 14, - "type_info": "Bytea" - }, - { - "name": "default_aa_code_hash", - "ordinal": 15, - "type_info": "Bytea" - }, - { - "name": "protocol_version", - "ordinal": 16, - "type_info": "Int4" - }, - { - "name": "system_logs", - "ordinal": 17, - "type_info": "ByteaArray" - }, - { - "name": "compressed_state_diffs", - "ordinal": 18, - "type_info": "Bytea" - }, - { - "name": "pubdata_input", - "ordinal": 19, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - false, - true, - true - ], - "parameters": { - "Left": [ - "Int4" - ] - } - }, - "query": "\n SELECT\n number,\n l1_tx_count,\n l2_tx_count,\n timestamp,\n is_finished,\n fee_account_address,\n l2_to_l1_logs,\n l2_to_l1_messages,\n bloom,\n priority_ops_onchain_data,\n used_contract_hashes,\n base_fee_per_gas,\n l1_gas_price,\n l2_fair_gas_price,\n bootloader_code_hash,\n default_aa_code_hash,\n protocol_version,\n system_logs,\n compressed_state_diffs,\n pubdata_input\n FROM\n l1_batches\n WHERE\n eth_commit_tx_id = $1\n OR eth_prove_tx_id = $1\n OR eth_execute_tx_id = $1\n " - }, - "d8e3ee346375e4b6a8b2c73a3827e88abd0f8164c2413dc83c91c29665ca645e": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "status", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "attempts", - "ordinal": 2, - "type_info": "Int2" - } - ], - "nullable": [ - false, - false, - false - ], - "parameters": { - "Left": [ - "Interval", - "Int2" - ] - } - }, - "query": "\n UPDATE leaf_aggregation_witness_jobs_fri\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n (\n status = 'in_progress'\n AND processing_started_at <= NOW() - $1::INTERVAL\n AND attempts < $2\n )\n OR (\n status = 'failed'\n AND attempts < $2\n )\n RETURNING\n id,\n status,\n attempts\n " - }, - "d90ed4c0f67c1826f9be90bb5566aba34bfab67494fee578613b03ef7255324d": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Jsonb" - ] - } - }, - "query": "\n UPDATE miniblocks\n SET\n consensus = $2\n WHERE\n number = $1\n " - }, - "da51a5220c2b964303292592c34e8ee5e54b170de9da863bbdbc79e3f206640b": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "ByteaArray" - ] - } - }, - "query": "\n DELETE FROM storage\n WHERE\n hashed_key = ANY ($1)\n " - }, - "db3e74f0e83ffbf84a6d61e560f2060fbea775dc185f639139fbfd23e4d5f3c6": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Time", - "Int8" - ] - } - }, - "query": "\n UPDATE node_aggregation_witness_jobs_fri\n SET\n status = 'successful',\n updated_at = NOW(),\n time_taken = $1\n WHERE\n id = $2\n " - }, - "dc16d0fac093a52480b66dfcb5976fb01e6629e8c982c265f2af1d5000090572": { - "describe": { - "columns": [ - { - "name": "count", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [] - } - }, - "query": "SELECT COUNT(miniblocks.number) FROM miniblocks WHERE l1_batch_number IS NULL" - }, - "dc481f59aae632ff6f5fa23f5c5c82627a936f7ea9f6c354eca4bea76fac6b10": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n MAX(number) AS \"number\"\n FROM\n l1_batches\n WHERE\n hash IS NOT NULL\n " - }, - "dc764e1636c4e958753c1fd54562e2ca92fdfdf01cfd0b11f5ce24f0458a5e48": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Bytea", - "Bytea", - "Bytea", - "Bytea", - "Bytea", - "Bytea", - "Bool", - "Bytea", - "Int8", - "Bytea", - "Bytea", - "Bytea", - "Int8" - ] - } - }, - "query": "\n UPDATE l1_batches\n SET\n hash = $1,\n merkle_root_hash = $2,\n compressed_repeated_writes = $3,\n compressed_initial_writes = $4,\n l2_l1_compressed_messages = $5,\n l2_l1_merkle_root = $6,\n zkporter_is_available = $7,\n parent_hash = $8,\n rollup_last_leaf_index = $9,\n pass_through_data_hash = $10,\n meta_parameters_hash = $11,\n compressed_state_diffs = $12,\n updated_at = NOW()\n WHERE\n number = $13\n AND hash IS NULL\n " - }, - "dd55e46dfa5ba3692d9620088a3550b8db817630d1a9341db4a1f453f12e64fb": { - "describe": { - "columns": [ - { - "name": "status", - "ordinal": 0, - "type_info": "Text" - }, - { - "name": "error", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "compilation_errors", - "ordinal": 2, - "type_info": "Jsonb" - } - ], - "nullable": [ - false, - true, - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n status,\n error,\n compilation_errors\n FROM\n contract_verification_requests\n WHERE\n id = $1\n " - }, - "dea22358feed1418430505767d03aa4239d3a8be71b47178b4b8fb11fe898b31": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int4", - "Int8", - "Int8" - ] - } - }, - "query": "\n UPDATE l1_batches\n SET\n eth_execute_tx_id = $1,\n updated_at = NOW()\n WHERE\n number BETWEEN $2 AND $3\n " - }, - "df00e33809768120e395d8f740770a4e629b2a1cde641e74e4e55bb100df809f": { - "describe": { - "columns": [ - { - "name": "attempts", - "ordinal": 0, - "type_info": "Int2" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n attempts\n FROM\n prover_jobs_fri\n WHERE\n id = $1\n " - }, - "df3b08549a11729fb475341b8f38f8af02aa297d85a2695c5f448ed14b2d7386": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Bytea", - "Int8", - "Bytea", - "Int4", - "Int4" - ] - } - }, - "query": "\n INSERT INTO\n snapshot_recovery (\n l1_batch_number,\n l1_batch_root_hash,\n miniblock_number,\n miniblock_root_hash,\n last_finished_chunk_id,\n total_chunk_count,\n updated_at,\n created_at\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO\n UPDATE\n SET\n l1_batch_number = excluded.l1_batch_number,\n l1_batch_root_hash = excluded.l1_batch_root_hash,\n miniblock_number = excluded.miniblock_number,\n miniblock_root_hash = excluded.miniblock_root_hash,\n last_finished_chunk_id = excluded.last_finished_chunk_id,\n total_chunk_count = excluded.total_chunk_count,\n updated_at = excluded.updated_at\n " - }, - "e073cfdc7a00559994ce04eca15f35d55901fb1e6805f23413ea43e3637540a0": { - "describe": { - "columns": [ - { - "name": "bytecode", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "bytecode_hash", - "ordinal": 1, - "type_info": "Bytea" - } - ], - "nullable": [ - false, - false - ], - "parameters": { - "Left": [ - "ByteaArray" - ] - } - }, - "query": "\n SELECT\n bytecode,\n bytecode_hash\n FROM\n factory_deps\n WHERE\n bytecode_hash = ANY ($1)\n " - }, - "e3479d12d9dc97001cf03dc42d9b957e92cd375ec33fe16f855f319ffc0b208e": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "status", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "circuit_1_final_prover_job_id", - "ordinal": 2, - "type_info": "Int8" - }, - { - "name": "circuit_2_final_prover_job_id", - "ordinal": 3, - "type_info": "Int8" - }, - { - "name": "circuit_3_final_prover_job_id", - "ordinal": 4, - "type_info": "Int8" - }, - { - "name": "circuit_4_final_prover_job_id", - "ordinal": 5, - "type_info": "Int8" - }, - { - "name": "circuit_5_final_prover_job_id", - "ordinal": 6, - "type_info": "Int8" - }, - { - "name": "circuit_6_final_prover_job_id", - "ordinal": 7, - "type_info": "Int8" - }, - { - "name": "circuit_7_final_prover_job_id", - "ordinal": 8, - "type_info": "Int8" - }, - { - "name": "circuit_8_final_prover_job_id", - "ordinal": 9, - "type_info": "Int8" - }, - { - "name": "circuit_9_final_prover_job_id", - "ordinal": 10, - "type_info": "Int8" - }, - { - "name": "circuit_10_final_prover_job_id", - "ordinal": 11, - "type_info": "Int8" - }, - { - "name": "circuit_11_final_prover_job_id", - "ordinal": 12, - "type_info": "Int8" - }, - { - "name": "circuit_12_final_prover_job_id", - "ordinal": 13, - "type_info": "Int8" - }, - { - "name": "circuit_13_final_prover_job_id", - "ordinal": 14, - "type_info": "Int8" - }, - { - "name": "created_at", - "ordinal": 15, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 16, - "type_info": "Timestamp" - } - ], - "nullable": [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n *\n FROM\n scheduler_dependency_tracker_fri\n WHERE\n l1_batch_number = $1\n " - }, - "e5a90d17b2c25744df4585b53678c7ffd9a04eae27afbdf37a6ba8ff7ac85f3b": { - "describe": { - "columns": [ - { - "name": "serialized_events_queue", - "ordinal": 0, - "type_info": "Jsonb" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n serialized_events_queue\n FROM\n events_queue\n WHERE\n l1_batch_number = $1\n " - }, - "e63cc86a8d527dae2905b2af6a66bc6419ba51514519652e055c769b096015f6": { - "describe": { - "columns": [ - { - "name": "hash", - "ordinal": 0, - "type_info": "Bytea" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Interval" - ] - } - }, - "query": "\n DELETE FROM transactions\n WHERE\n miniblock_number IS NULL\n AND received_at < NOW() - $1::INTERVAL\n AND is_priority = FALSE\n AND error IS NULL\n RETURNING\n hash\n " - }, - "e6a3efeffe1b3520cc9b1751e2c842c27546b3fd41f7d8a784ca58579856621b": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "attempts", - "ordinal": 1, - "type_info": "Int4" - } - ], - "nullable": [ - false, - false - ], - "parameters": { - "Left": [ - "Text", - "Int8" - ] - } - }, - "query": "\n UPDATE prover_jobs\n SET\n status = 'failed',\n error = $1,\n updated_at = NOW()\n WHERE\n id = $2\n RETURNING\n l1_batch_number,\n attempts\n " - }, - "e71c39b93ceba5416ff3d988290cb35d4d07d47f33fe1a5b9e9fe1f0ae09b705": { - "describe": { - "columns": [ - { - "name": "usd_price", - "ordinal": 0, - "type_info": "Numeric" - }, - { - "name": "usd_price_updated_at", - "ordinal": 1, - "type_info": "Timestamp" - } - ], - "nullable": [ - true, - true - ], - "parameters": { - "Left": [ - "Bytea" - ] - } - }, - "query": "\n SELECT\n usd_price,\n usd_price_updated_at\n FROM\n tokens\n WHERE\n l2_address = $1\n " - }, - "e74a34a59e6afda689b0ec9e19071ababa66e4a443fbefbfffca72b7540b075b": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Text" - ] - } - }, - "query": "\n INSERT INTO\n proof_compression_jobs_fri (l1_batch_number, status, created_at, updated_at)\n VALUES\n ($1, $2, NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO NOTHING\n " - }, - "e76217231b4d896118e9630de9485b19e1294b3aa6e084d2051bb532408672be": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [] - } - }, - "query": "\n UPDATE transactions\n SET\n in_mempool = FALSE\n WHERE\n in_mempool = TRUE\n " - }, - "e9adf5b5a1ab84c20a514a7775f91a9984685eaaaa0a8b223410d560a15a3034": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "l1_batch_number", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "circuit_id", - "ordinal": 2, - "type_info": "Int2" - }, - { - "name": "aggregation_round", - "ordinal": 3, - "type_info": "Int2" - }, - { - "name": "sequence_number", - "ordinal": 4, - "type_info": "Int4" - }, - { - "name": "depth", - "ordinal": 5, - "type_info": "Int4" - }, - { - "name": "is_node_final_proof", - "ordinal": 6, - "type_info": "Bool" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false - ], - "parameters": { - "Left": [ - "Int2Array", - "Int2Array", - "Int4Array", - "Text" - ] - } - }, - "query": "\n UPDATE prover_jobs_fri\n SET\n status = 'in_progress',\n attempts = attempts + 1,\n processing_started_at = NOW(),\n updated_at = NOW(),\n picked_by = $4\n WHERE\n id = (\n SELECT\n pj.id\n FROM\n (\n SELECT\n *\n FROM\n UNNEST($1::SMALLINT[], $2::SMALLINT[])\n ) AS tuple (circuit_id, ROUND)\n JOIN LATERAL (\n SELECT\n *\n FROM\n prover_jobs_fri AS pj\n WHERE\n pj.status = 'queued'\n AND pj.protocol_version = ANY ($3)\n AND pj.circuit_id = tuple.circuit_id\n AND pj.aggregation_round = tuple.round\n ORDER BY\n pj.l1_batch_number ASC,\n pj.id ASC\n LIMIT\n 1\n ) AS pj ON TRUE\n ORDER BY\n pj.l1_batch_number ASC,\n pj.aggregation_round DESC,\n pj.id ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n prover_jobs_fri.id,\n prover_jobs_fri.l1_batch_number,\n prover_jobs_fri.circuit_id,\n prover_jobs_fri.aggregation_round,\n prover_jobs_fri.sequence_number,\n prover_jobs_fri.depth,\n prover_jobs_fri.is_node_final_proof\n " - }, - "e9ca863d6e77edd39a9fc55700a6686e655206601854799139c22c017a214744": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Int2", - "Int4", - "Text", - "Int4", - "Int4" - ] - } - }, - "query": "\n INSERT INTO\n node_aggregation_witness_jobs_fri (\n l1_batch_number,\n circuit_id,\n depth,\n aggregations_url,\n number_of_dependent_jobs,\n protocol_version,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, 'waiting_for_proofs', NOW(), NOW())\n ON CONFLICT (l1_batch_number, circuit_id, depth) DO\n UPDATE\n SET\n updated_at = NOW()\n " - }, - "ea904aa930d602d33b6fbc1bf1178a8a0ec739f4ddec8ffeb3a87253aeb18d30": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n DELETE FROM miniblocks\n WHERE\n number > $1\n " - }, - "ec04b89218111a5dc8d5ade506ac3465e2211ef3013386feb12d4cc04e0eade9": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "l1_batch_number", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "circuit_id", - "ordinal": 2, - "type_info": "Int2" - }, - { - "name": "aggregation_round", - "ordinal": 3, - "type_info": "Int2" - }, - { - "name": "sequence_number", - "ordinal": 4, - "type_info": "Int4" - }, - { - "name": "depth", - "ordinal": 5, - "type_info": "Int4" - }, - { - "name": "is_node_final_proof", - "ordinal": 6, - "type_info": "Bool" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false - ], - "parameters": { - "Left": [ - "Time", - "Text", - "Int8" - ] - } - }, - "query": "\n UPDATE prover_jobs_fri\n SET\n status = 'successful',\n updated_at = NOW(),\n time_taken = $1,\n proof_blob_url = $2\n WHERE\n id = $3\n RETURNING\n prover_jobs_fri.id,\n prover_jobs_fri.l1_batch_number,\n prover_jobs_fri.circuit_id,\n prover_jobs_fri.aggregation_round,\n prover_jobs_fri.sequence_number,\n prover_jobs_fri.depth,\n prover_jobs_fri.is_node_final_proof\n " - }, - "edc61e1285bf6d3837acc67af4f15aaade450980719933089824eb8c494d64a4": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Time", - "Int8" - ] - } - }, - "query": "\n UPDATE witness_inputs_fri\n SET\n status = 'successful',\n updated_at = NOW(),\n time_taken = $1\n WHERE\n l1_batch_number = $2\n " - }, - "ee17d2b3edfe705d14811e3938d4312b2b780563a9fde48bae5e51650475670f": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int4" - }, - { - "name": "eth_tx_id", - "ordinal": 1, - "type_info": "Int4" - }, - { - "name": "tx_hash", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "created_at", - "ordinal": 3, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 4, - "type_info": "Timestamp" - }, - { - "name": "base_fee_per_gas", - "ordinal": 5, - "type_info": "Int8" - }, - { - "name": "priority_fee_per_gas", - "ordinal": 6, - "type_info": "Int8" - }, - { - "name": "confirmed_at", - "ordinal": 7, - "type_info": "Timestamp" - }, - { - "name": "signed_raw_tx", - "ordinal": 8, - "type_info": "Bytea" - }, - { - "name": "sent_at_block", - "ordinal": 9, - "type_info": "Int4" - }, - { - "name": "sent_at", - "ordinal": 10, - "type_info": "Timestamp" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true - ], - "parameters": { - "Left": [ - "Int4" - ] - } - }, - "query": "\n SELECT\n *\n FROM\n eth_txs_history\n WHERE\n eth_tx_id = $1\n ORDER BY\n created_at DESC\n LIMIT\n 1\n " - }, - "ef331469f78c6ff68a254a15b55d056cc9bae25bc070c5de8424f88fab20e5ea": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "l1_batch_tx_index", - "ordinal": 1, - "type_info": "Int4" - } - ], - "nullable": [ - true, - true - ], - "parameters": { - "Left": [ - "Bytea" - ] - } - }, - "query": "\n SELECT\n l1_batch_number,\n l1_batch_tx_index\n FROM\n transactions\n WHERE\n hash = $1\n " - }, - "ef687be83e496d6647e4dfef9eabae63443c51deb818dd0affd1a0949b161737": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8", - "Text", - "Text" - ] - } - }, - "query": "\n INSERT INTO\n proof_compression_jobs_fri (l1_batch_number, fri_proof_blob_url, status, created_at, updated_at)\n VALUES\n ($1, $2, $3, NOW(), NOW())\n ON CONFLICT (l1_batch_number) DO NOTHING\n " - }, - "efe2a4ce4ba09e40ac7401f19ac5a42a0d521ffa33594c7861d786741d303f30": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text", - "Int4", - "Int4", - "Int2", - "Text", - "Text", - "Int2" - ] - } - }, - "query": "\n INSERT INTO\n gpu_prover_queue (\n instance_host,\n instance_port,\n queue_capacity,\n queue_free_slots,\n instance_status,\n specialized_prover_group_id,\n region,\n zone,\n num_gpu,\n created_at,\n updated_at\n )\n VALUES\n (CAST($1::TEXT AS inet), $2, $3, $3, 'available', $4, $5, $6, $7, NOW(), NOW())\n ON CONFLICT (instance_host, instance_port, region, zone) DO\n UPDATE\n SET\n instance_status = 'available',\n queue_capacity = $3,\n queue_free_slots = $3,\n specialized_prover_group_id = $4,\n region = $5,\n zone = $6,\n num_gpu = $7,\n updated_at = NOW()\n " - }, - "f012d0922265269746396dac8f25ff66f2c3b2b83d45360818a8782e56aa3d66": { - "describe": { - "columns": [ - { - "name": "hashed_key?", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "value?", - "ordinal": 1, - "type_info": "Bytea" - }, - { - "name": "index", - "ordinal": 2, - "type_info": "Int8" - } - ], - "nullable": [ - null, - null, - true - ], - "parameters": { - "Left": [ - "Int8", - "ByteaArray", - "ByteaArray" - ] - } - }, - "query": "\n WITH\n sl AS (\n SELECT\n (\n SELECT\n ARRAY[hashed_key, value] AS kv\n FROM\n storage_logs\n WHERE\n storage_logs.miniblock_number = $1\n AND storage_logs.hashed_key >= u.start_key\n AND storage_logs.hashed_key <= u.end_key\n ORDER BY\n storage_logs.hashed_key\n LIMIT\n 1\n )\n FROM\n UNNEST($2::bytea[], $3::bytea[]) AS u (start_key, end_key)\n )\n SELECT\n sl.kv[1] AS \"hashed_key?\",\n sl.kv[2] AS \"value?\",\n initial_writes.index\n FROM\n sl\n LEFT OUTER JOIN initial_writes ON initial_writes.hashed_key = sl.kv[1]\n " - }, - "f1478830e5f95cbcd0da01d3457cbb9cb8da439c7ab28fa865f53908621dc4c5": { - "describe": { - "columns": [ - { - "name": "region", - "ordinal": 0, - "type_info": "Text" - }, - { - "name": "zone", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "total_gpus", - "ordinal": 2, - "type_info": "Int8" - } - ], - "nullable": [ - false, - false, - null - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n region,\n zone,\n SUM(num_gpu) AS total_gpus\n FROM\n gpu_prover_queue\n GROUP BY\n region,\n zone\n " - }, - "f1a90090c192d68367e799188356efe8d41759bbdcdd6d39db93208f2664f03a": { - "describe": { - "columns": [ - { - "name": "index", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Bytea" - ] - } - }, - "query": "\n SELECT\n INDEX\n FROM\n initial_writes\n WHERE\n hashed_key = $1\n " - }, - "f22c5d136fe68bbfcee60beb304cfdc050b85e6d773b13f9699f15c335d42593": { - "describe": { - "columns": [ - { - "name": "l1_address", - "ordinal": 0, - "type_info": "Bytea" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Numeric" - ] - } - }, - "query": "\n SELECT\n l1_address\n FROM\n tokens\n WHERE\n market_volume > $1\n " - }, - "f303c53843a58fac4fcdedbfe2b2b33ad609b7df8e55a0cf214ea1ec6421e57a": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "status", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "attempts", - "ordinal": 2, - "type_info": "Int4" - } - ], - "nullable": [ - false, - false, - false - ], - "parameters": { - "Left": [ - "Interval", - "Int4" - ] - } - }, - "query": "\n UPDATE prover_jobs\n SET\n status = 'queued',\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n (\n status = 'in_progress'\n AND processing_started_at <= NOW() - $1::INTERVAL\n AND attempts < $2\n )\n OR (\n status = 'in_gpu_proof'\n AND processing_started_at <= NOW() - $1::INTERVAL\n AND attempts < $2\n )\n OR (\n status = 'failed'\n AND attempts < $2\n )\n RETURNING\n id,\n status,\n attempts\n " - }, - "f39372e37160df4897f62a800694867ed765dcb9dc60754df9df8700d4244bfb": { - "describe": { - "columns": [ - { - "name": "l1_address", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "l2_address", - "ordinal": 1, - "type_info": "Bytea" - }, - { - "name": "name", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "symbol", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "decimals", - "ordinal": 4, - "type_info": "Int4" - } - ], - "nullable": [ - false, - false, - false, - false, - false - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n l1_address,\n l2_address,\n NAME,\n symbol,\n decimals\n FROM\n tokens\n WHERE\n well_known = TRUE\n ORDER BY\n symbol\n " - }, - "f4362a61ab05af3d71a3232d2f017db60405a887f9f7fa0ca60aa7fc879ce630": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text", - "Text", - "Int8" - ] - } - }, - "query": "\n UPDATE proof_compression_jobs_fri\n SET\n status = $1,\n error = $2,\n updated_at = NOW()\n WHERE\n l1_batch_number = $3\n " - }, - "f63586d59264eab7388ad1de823227ecaa45d76d1ba260074898fe57c059a15a": { - "describe": { - "columns": [ - { - "name": "hash", - "ordinal": 0, - "type_info": "Bytea" - }, - { - "name": "is_priority", - "ordinal": 1, - "type_info": "Bool" - }, - { - "name": "full_fee", - "ordinal": 2, - "type_info": "Numeric" - }, - { - "name": "layer_2_tip_fee", - "ordinal": 3, - "type_info": "Numeric" - }, - { - "name": "initiator_address", - "ordinal": 4, - "type_info": "Bytea" - }, - { - "name": "nonce", - "ordinal": 5, - "type_info": "Int8" - }, - { - "name": "signature", - "ordinal": 6, - "type_info": "Bytea" - }, - { - "name": "input", - "ordinal": 7, - "type_info": "Bytea" - }, - { - "name": "data", - "ordinal": 8, - "type_info": "Jsonb" - }, - { - "name": "received_at", - "ordinal": 9, - "type_info": "Timestamp" - }, - { - "name": "priority_op_id", - "ordinal": 10, - "type_info": "Int8" - }, - { - "name": "l1_batch_number", - "ordinal": 11, - "type_info": "Int8" - }, - { - "name": "index_in_block", - "ordinal": 12, - "type_info": "Int4" - }, - { - "name": "error", - "ordinal": 13, - "type_info": "Varchar" - }, - { - "name": "gas_limit", - "ordinal": 14, - "type_info": "Numeric" - }, - { - "name": "gas_per_storage_limit", - "ordinal": 15, - "type_info": "Numeric" - }, - { - "name": "gas_per_pubdata_limit", - "ordinal": 16, - "type_info": "Numeric" - }, - { - "name": "tx_format", - "ordinal": 17, - "type_info": "Int4" - }, - { - "name": "created_at", - "ordinal": 18, - "type_info": "Timestamp" - }, - { - "name": "updated_at", - "ordinal": 19, - "type_info": "Timestamp" - }, - { - "name": "execution_info", - "ordinal": 20, - "type_info": "Jsonb" - }, - { - "name": "contract_address", - "ordinal": 21, - "type_info": "Bytea" - }, - { - "name": "in_mempool", - "ordinal": 22, - "type_info": "Bool" - }, - { - "name": "l1_block_number", - "ordinal": 23, - "type_info": "Int4" - }, - { - "name": "value", - "ordinal": 24, - "type_info": "Numeric" - }, - { - "name": "paymaster", - "ordinal": 25, - "type_info": "Bytea" - }, - { - "name": "paymaster_input", - "ordinal": 26, - "type_info": "Bytea" - }, - { - "name": "max_fee_per_gas", - "ordinal": 27, - "type_info": "Numeric" - }, - { - "name": "max_priority_fee_per_gas", - "ordinal": 28, - "type_info": "Numeric" - }, - { - "name": "effective_gas_price", - "ordinal": 29, - "type_info": "Numeric" - }, - { - "name": "miniblock_number", - "ordinal": 30, - "type_info": "Int8" - }, - { - "name": "l1_batch_tx_index", - "ordinal": 31, - "type_info": "Int4" - }, - { - "name": "refunded_gas", - "ordinal": 32, - "type_info": "Int8" - }, - { - "name": "l1_tx_mint", - "ordinal": 33, - "type_info": "Numeric" - }, - { - "name": "l1_tx_refund_recipient", - "ordinal": 34, - "type_info": "Bytea" - }, - { - "name": "upgrade_id", - "ordinal": 35, - "type_info": "Int4" - } - ], - "nullable": [ - false, - false, - true, - true, - false, - true, - true, - true, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - true, - false, - true, - false, - false, - false, - true, - true, - true, - true, - true, - false, - true, - true, - true - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n *\n FROM\n transactions\n WHERE\n l1_batch_number = $1\n ORDER BY\n miniblock_number,\n index_in_block\n " - }, - "f717ca5d0890759496739a678955e6f8b7f88a0894a7f9e27fc26f93997d37c7": { - "describe": { - "columns": [ - { - "name": "l1_batch_number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Text", - "Text", - "Text" - ] - } - }, - "query": "\n UPDATE proof_compression_jobs_fri\n SET\n status = $1,\n attempts = attempts + 1,\n updated_at = NOW(),\n processing_started_at = NOW(),\n picked_by = $3\n WHERE\n l1_batch_number = (\n SELECT\n l1_batch_number\n FROM\n proof_compression_jobs_fri\n WHERE\n status = $2\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n proof_compression_jobs_fri.l1_batch_number\n " - }, - "f91790ae5cc4b087bf942ba52dd63a1e89945f8d5e0f4da42ecf6313c4f5967e": { - "describe": { - "columns": [ - { - "name": "number", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n MIN(number) AS \"number\"\n FROM\n l1_batches\n WHERE\n hash IS NOT NULL\n " - }, - "f922c0718c9dda2f285f09cbabad425bac8ed3d2780c60c9b63afbcea131f9a0": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Bytea", - "Jsonb" - ] - } - }, - "query": "\n INSERT INTO\n transaction_traces (tx_hash, trace, created_at, updated_at)\n VALUES\n ($1, $2, NOW(), NOW())\n " - }, - "fcc108fd59203644ff86ded0505c7dfb7aad7261e5fc402d845aedc3b91a4e99": { - "describe": { - "columns": [ - { - "name": "nonce!", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - true - ], - "parameters": { - "Left": [ - "Bytea", - "Int8" - ] - } - }, - "query": "\n SELECT\n nonce AS \"nonce!\"\n FROM\n transactions\n WHERE\n initiator_address = $1\n AND nonce >= $2\n AND is_priority = FALSE\n AND (\n miniblock_number IS NOT NULL\n OR error IS NULL\n )\n ORDER BY\n nonce\n " - }, - "fcddeb96dcd1611dedb2091c1be304e8a35fd65bf37e976b7106f57c57e70b9b": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Text", - "Int4", - "Text" - ] - } - }, - "query": "\n UPDATE gpu_prover_queue_fri\n SET\n instance_status = 'available',\n updated_at = NOW()\n WHERE\n instance_host = $1::TEXT::inet\n AND instance_port = $2\n AND instance_status = 'full'\n AND zone = $3\n " - }, - "fde16cd2d3de03f4b61625fa453a58f82acd817932415f04bcbd05442ad80c2b": { - "describe": { - "columns": [ - { - "name": "bytecode", - "ordinal": 0, - "type_info": "Bytea" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Bytea", - "Int8" - ] - } - }, - "query": "\n SELECT\n bytecode\n FROM\n factory_deps\n WHERE\n bytecode_hash = $1\n AND miniblock_number <= $2\n " - }, - "fdffa5841554286a924b217b5885d9ec9b3f628c3a4cf5e10580ea6e5e3a2429": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n UPDATE miniblocks\n SET\n l1_batch_number = $1\n WHERE\n l1_batch_number IS NULL\n " - }, - "fe501f86f4bf6c5b8ccc2e039a4eb09b538a67d1c39fda052c4f4ddb23ce0084": { - "describe": { - "columns": [ - { - "name": "l2_to_l1_logs", - "ordinal": 0, - "type_info": "ByteaArray" - } - ], - "nullable": [ - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT\n l2_to_l1_logs\n FROM\n l1_batches\n WHERE\n number = $1\n " - } -} \ No newline at end of file diff --git a/core/lib/dal/src/blocks_dal.rs b/core/lib/dal/src/blocks_dal.rs index ba3c314a135b..ee7598d6ed30 100644 --- a/core/lib/dal/src/blocks_dal.rs +++ b/core/lib/dal/src/blocks_dal.rs @@ -10,12 +10,12 @@ use sqlx::Row; use zksync_types::{ aggregated_operations::AggregatedActionType, block::{BlockGasCount, L1BatchHeader, MiniblockHeader}, + circuit::CircuitStatistic, commitment::{L1BatchMetadata, L1BatchWithMetadata}, - Address, L1BatchNumber, LogQuery, MiniblockNumber, ProtocolVersionId, H256, - MAX_GAS_PER_PUBDATA_BYTE, U256, + zk_evm_types::LogQuery, + Address, L1BatchNumber, MiniblockNumber, ProtocolVersionId, H256, U256, }; -pub use crate::models::storage_sync::ConsensusBlockFields; use crate::{ instrument::InstrumentExt, models::storage_block::{StorageL1Batch, StorageL1BatchHeader, StorageMiniblockHeader}, @@ -43,29 +43,25 @@ impl BlocksDal<'_, '_> { Ok(count == 0) } - pub async fn get_sealed_l1_batch_number(&mut self) -> anyhow::Result { - let number = sqlx::query!( + pub async fn get_sealed_l1_batch_number(&mut self) -> sqlx::Result> { + let row = sqlx::query!( r#" SELECT MAX(number) AS "number" FROM l1_batches - WHERE - is_finished = TRUE "# ) .instrument("get_sealed_block_number") .report_latency() .fetch_one(self.storage.conn()) - .await? - .number - .context("DAL invocation before genesis")?; + .await?; - Ok(L1BatchNumber(number as u32)) + Ok(row.number.map(|num| L1BatchNumber(num as u32))) } - pub async fn get_sealed_miniblock_number(&mut self) -> sqlx::Result { - let number: i64 = sqlx::query!( + pub async fn get_sealed_miniblock_number(&mut self) -> sqlx::Result> { + let row = sqlx::query!( r#" SELECT MAX(number) AS "number" @@ -76,10 +72,9 @@ impl BlocksDal<'_, '_> { .instrument("get_sealed_miniblock_number") .report_latency() .fetch_one(self.storage.conn()) - .await? - .number - .unwrap_or(0); - Ok(MiniblockNumber(number as u32)) + .await?; + + Ok(row.number.map(|number| MiniblockNumber(number as u32))) } /// Returns the number of the earliest L1 batch present in the DB, or `None` if there are no L1 batches. @@ -156,16 +151,11 @@ impl BlocksDal<'_, '_> { l1_tx_count, l2_tx_count, timestamp, - is_finished, - fee_account_address, l2_to_l1_logs, l2_to_l1_messages, bloom, priority_ops_onchain_data, used_contract_hashes, - base_fee_per_gas, - l1_gas_price, - l2_fair_gas_price, bootloader_code_hash, default_aa_code_hash, protocol_version, @@ -199,10 +189,8 @@ impl BlocksDal<'_, '_> { SELECT number, timestamp, - is_finished, l1_tx_count, l2_tx_count, - fee_account_address, bloom, priority_ops_onchain_data, hash, @@ -221,13 +209,10 @@ impl BlocksDal<'_, '_> { compressed_repeated_writes, l2_l1_compressed_messages, l2_l1_merkle_root, - l1_gas_price, - l2_fair_gas_price, rollup_last_leaf_index, zkporter_is_available, bootloader_code_hash, default_aa_code_hash, - base_fee_per_gas, aux_data_hash, pass_through_data_hash, meta_parameters_hash, @@ -263,16 +248,11 @@ impl BlocksDal<'_, '_> { l1_tx_count, l2_tx_count, timestamp, - is_finished, - fee_account_address, l2_to_l1_logs, l2_to_l1_messages, bloom, priority_ops_onchain_data, used_contract_hashes, - base_fee_per_gas, - l1_gas_price, - l2_fair_gas_price, bootloader_code_hash, default_aa_code_hash, protocol_version, @@ -452,6 +432,7 @@ impl BlocksDal<'_, '_> { predicted_block_gas: BlockGasCount, events_queue: &[LogQuery], storage_refunds: &[u32], + predicted_circuits_by_type: CircuitStatistic, // predicted number of circuits for each circuit type ) -> anyhow::Result<()> { let priority_onchain_data: Vec> = header .priority_ops_onchain_data @@ -478,8 +459,6 @@ impl BlocksDal<'_, '_> { // Serialization should always succeed. let used_contract_hashes = serde_json::to_value(&header.used_contract_hashes) .expect("failed to serialize used_contract_hashes to JSON value"); - let base_fee_per_gas = BigDecimal::from_u64(header.base_fee_per_gas) - .context("block.base_fee_per_gas should fit in u64")?; let storage_refunds: Vec<_> = storage_refunds.iter().map(|n| *n as i64).collect(); let mut transaction = self.storage.start_transaction().await?; @@ -491,8 +470,6 @@ impl BlocksDal<'_, '_> { l1_tx_count, l2_tx_count, timestamp, - is_finished, - fee_account_address, l2_to_l1_logs, l2_to_l1_messages, bloom, @@ -502,15 +479,13 @@ impl BlocksDal<'_, '_> { predicted_execute_gas_cost, initial_bootloader_heap_content, used_contract_hashes, - base_fee_per_gas, - l1_gas_price, - l2_fair_gas_price, bootloader_code_hash, default_aa_code_hash, protocol_version, system_logs, storage_refunds, pubdata_input, + predicted_circuits_by_type, created_at, updated_at ) @@ -536,10 +511,6 @@ impl BlocksDal<'_, '_> { $18, $19, $20, - $21, - $22, - $23, - $24, NOW(), NOW() ) @@ -548,8 +519,6 @@ impl BlocksDal<'_, '_> { header.l1_tx_count as i32, header.l2_tx_count as i32, header.timestamp as i64, - header.is_finished, - header.fee_account_address.as_bytes(), &l2_to_l1_logs, &header.l2_to_l1_messages, header.bloom.as_bytes(), @@ -559,15 +528,13 @@ impl BlocksDal<'_, '_> { predicted_block_gas.execute as i64, initial_bootloader_contents, used_contract_hashes, - base_fee_per_gas, - header.l1_gas_price as i64, - header.l2_fair_gas_price as i64, header.base_system_contracts_hashes.bootloader.as_bytes(), header.base_system_contracts_hashes.default_aa.as_bytes(), header.protocol_version.map(|v| v as i32), &system_logs, &storage_refunds, pubdata_input, + serde_json::to_value(predicted_circuits_by_type).unwrap(), ) .execute(transaction.conn()) .await?; @@ -595,6 +562,7 @@ impl BlocksDal<'_, '_> { ) -> anyhow::Result<()> { let base_fee_per_gas = BigDecimal::from_u64(miniblock_header.base_fee_per_gas) .context("base_fee_per_gas should fit in u64")?; + sqlx::query!( r#" INSERT INTO @@ -604,6 +572,7 @@ impl BlocksDal<'_, '_> { hash, l1_tx_count, l2_tx_count, + fee_account_address, base_fee_per_gas, l1_gas_price, l2_fair_gas_price, @@ -612,21 +581,23 @@ impl BlocksDal<'_, '_> { default_aa_code_hash, protocol_version, virtual_blocks, + fair_pubdata_price, created_at, updated_at ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, NOW(), NOW()) + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, NOW(), NOW()) "#, miniblock_header.number.0 as i64, miniblock_header.timestamp as i64, miniblock_header.hash.as_bytes(), miniblock_header.l1_tx_count as i32, miniblock_header.l2_tx_count as i32, + miniblock_header.fee_account_address.as_bytes(), base_fee_per_gas, - miniblock_header.l1_gas_price as i64, - miniblock_header.l2_fair_gas_price as i64, - MAX_GAS_PER_PUBDATA_BYTE as i64, + miniblock_header.batch_fee_input.l1_gas_price() as i64, + miniblock_header.batch_fee_input.fair_l2_gas_price() as i64, + miniblock_header.gas_per_pubdata_limit as i64, miniblock_header .base_system_contracts_hashes .bootloader @@ -637,94 +608,17 @@ impl BlocksDal<'_, '_> { .as_bytes(), miniblock_header.protocol_version.map(|v| v as i32), miniblock_header.virtual_blocks as i64, + miniblock_header.batch_fee_input.fair_pubdata_price() as i64, ) .execute(self.storage.conn()) .await?; Ok(()) } - /// Fetches the number of the last miniblock with consensus fields set. - /// Miniblocks with Consensus fields set constitute a prefix of sealed miniblocks, - /// so it is enough to traverse the miniblocks in descending order to find the last - /// with consensus fields. - /// - /// If better efficiency is needed we can add an index on "miniblocks without consensus fields". - pub async fn get_last_miniblock_number_with_consensus_fields( - &mut self, - ) -> anyhow::Result> { - let Some(row) = sqlx::query!( - r#" - SELECT - number - FROM - miniblocks - WHERE - consensus IS NOT NULL - ORDER BY - number DESC - LIMIT - 1 - "# - ) - .fetch_optional(self.storage.conn()) - .await? - else { - return Ok(None); - }; - Ok(Some(MiniblockNumber(row.number.try_into()?))) - } - - /// Checks whether the specified miniblock has consensus field set. - pub async fn has_consensus_fields(&mut self, number: MiniblockNumber) -> sqlx::Result { - Ok(sqlx::query!( - r#" - SELECT - COUNT(*) AS "count!" - FROM - miniblocks - WHERE - number = $1 - AND consensus IS NOT NULL - "#, - number.0 as i64 - ) - .fetch_one(self.storage.conn()) - .await? - .count - > 0) - } - - /// Sets consensus-related fields for the specified miniblock. - pub async fn set_miniblock_consensus_fields( - &mut self, - miniblock_number: MiniblockNumber, - consensus: &ConsensusBlockFields, - ) -> anyhow::Result<()> { - let result = sqlx::query!( - r#" - UPDATE miniblocks - SET - consensus = $2 - WHERE - number = $1 - "#, - miniblock_number.0 as i64, - zksync_protobuf::serde::serialize(consensus, serde_json::value::Serializer).unwrap(), - ) - .execute(self.storage.conn()) - .await?; - - anyhow::ensure!( - result.rows_affected() == 1, - "Miniblock #{miniblock_number} is not present in Postgres" - ); - Ok(()) - } - pub async fn get_last_sealed_miniblock_header( &mut self, ) -> sqlx::Result> { - Ok(sqlx::query_as!( + let header = sqlx::query_as!( StorageMiniblockHeader, r#" SELECT @@ -733,13 +627,16 @@ impl BlocksDal<'_, '_> { hash, l1_tx_count, l2_tx_count, + fee_account_address AS "fee_account_address!", base_fee_per_gas, l1_gas_price, l2_fair_gas_price, + gas_per_pubdata_limit, bootloader_code_hash, default_aa_code_hash, protocol_version, - virtual_blocks + virtual_blocks, + fair_pubdata_price FROM miniblocks ORDER BY @@ -749,15 +646,25 @@ impl BlocksDal<'_, '_> { "#, ) .fetch_optional(self.storage.conn()) - .await? - .map(Into::into)) + .await?; + + let Some(header) = header else { + return Ok(None); + }; + let mut header = MiniblockHeader::from(header); + // FIXME (PLA-728): remove after 2nd phase of `fee_account_address` migration + #[allow(deprecated)] + self.maybe_load_fee_address(&mut header.fee_account_address, header.number) + .await?; + + Ok(Some(header)) } pub async fn get_miniblock_header( &mut self, miniblock_number: MiniblockNumber, ) -> sqlx::Result> { - Ok(sqlx::query_as!( + let header = sqlx::query_as!( StorageMiniblockHeader, r#" SELECT @@ -766,13 +673,16 @@ impl BlocksDal<'_, '_> { hash, l1_tx_count, l2_tx_count, + fee_account_address AS "fee_account_address!", base_fee_per_gas, l1_gas_price, l2_fair_gas_price, + gas_per_pubdata_limit, bootloader_code_hash, default_aa_code_hash, protocol_version, - virtual_blocks + virtual_blocks, + fair_pubdata_price FROM miniblocks WHERE @@ -781,8 +691,18 @@ impl BlocksDal<'_, '_> { miniblock_number.0 as i64, ) .fetch_optional(self.storage.conn()) - .await? - .map(Into::into)) + .await?; + + let Some(header) = header else { + return Ok(None); + }; + let mut header = MiniblockHeader::from(header); + // FIXME (PLA-728): remove after 2nd phase of `fee_account_address` migration + #[allow(deprecated)] + self.maybe_load_fee_address(&mut header.fee_account_address, header.number) + .await?; + + Ok(Some(header)) } pub async fn mark_miniblocks_as_executed_in_l1_batch( @@ -1007,10 +927,8 @@ impl BlocksDal<'_, '_> { SELECT number, timestamp, - is_finished, l1_tx_count, l2_tx_count, - fee_account_address, bloom, priority_ops_onchain_data, hash, @@ -1029,13 +947,10 @@ impl BlocksDal<'_, '_> { compressed_repeated_writes, l2_l1_compressed_messages, l2_l1_merkle_root, - l1_gas_price, - l2_fair_gas_price, rollup_last_leaf_index, zkporter_is_available, bootloader_code_hash, default_aa_code_hash, - base_fee_per_gas, aux_data_hash, pass_through_data_hash, meta_parameters_hash, @@ -1193,10 +1108,8 @@ impl BlocksDal<'_, '_> { SELECT number, timestamp, - is_finished, l1_tx_count, l2_tx_count, - fee_account_address, bloom, priority_ops_onchain_data, hash, @@ -1215,13 +1128,10 @@ impl BlocksDal<'_, '_> { compressed_repeated_writes, l2_l1_compressed_messages, l2_l1_merkle_root, - l1_gas_price, - l2_fair_gas_price, rollup_last_leaf_index, zkporter_is_available, bootloader_code_hash, default_aa_code_hash, - base_fee_per_gas, aux_data_hash, pass_through_data_hash, meta_parameters_hash, @@ -1306,10 +1216,8 @@ impl BlocksDal<'_, '_> { SELECT number, timestamp, - is_finished, l1_tx_count, l2_tx_count, - fee_account_address, bloom, priority_ops_onchain_data, hash, @@ -1328,13 +1236,10 @@ impl BlocksDal<'_, '_> { compressed_repeated_writes, l2_l1_compressed_messages, l2_l1_merkle_root, - l1_gas_price, - l2_fair_gas_price, rollup_last_leaf_index, zkporter_is_available, bootloader_code_hash, default_aa_code_hash, - base_fee_per_gas, aux_data_hash, pass_through_data_hash, meta_parameters_hash, @@ -1393,10 +1298,8 @@ impl BlocksDal<'_, '_> { SELECT number, timestamp, - is_finished, l1_tx_count, l2_tx_count, - fee_account_address, bloom, priority_ops_onchain_data, hash, @@ -1415,13 +1318,10 @@ impl BlocksDal<'_, '_> { compressed_repeated_writes, l2_l1_compressed_messages, l2_l1_merkle_root, - l1_gas_price, - l2_fair_gas_price, rollup_last_leaf_index, zkporter_is_available, bootloader_code_hash, default_aa_code_hash, - base_fee_per_gas, aux_data_hash, pass_through_data_hash, meta_parameters_hash, @@ -1532,10 +1432,8 @@ impl BlocksDal<'_, '_> { SELECT number, timestamp, - is_finished, l1_tx_count, l2_tx_count, - fee_account_address, bloom, priority_ops_onchain_data, hash, @@ -1554,13 +1452,10 @@ impl BlocksDal<'_, '_> { compressed_repeated_writes, l2_l1_compressed_messages, l2_l1_merkle_root, - l1_gas_price, - l2_fair_gas_price, rollup_last_leaf_index, zkporter_is_available, bootloader_code_hash, default_aa_code_hash, - base_fee_per_gas, aux_data_hash, pass_through_data_hash, meta_parameters_hash, @@ -1610,10 +1505,8 @@ impl BlocksDal<'_, '_> { SELECT number, l1_batches.timestamp, - is_finished, l1_tx_count, l2_tx_count, - fee_account_address, bloom, priority_ops_onchain_data, hash, @@ -1632,13 +1525,10 @@ impl BlocksDal<'_, '_> { compressed_repeated_writes, l2_l1_compressed_messages, l2_l1_merkle_root, - l1_gas_price, - l2_fair_gas_price, rollup_last_leaf_index, zkporter_is_available, l1_batches.bootloader_code_hash, l1_batches.default_aa_code_hash, - base_fee_per_gas, aux_data_hash, pass_through_data_hash, meta_parameters_hash, @@ -1698,10 +1588,8 @@ impl BlocksDal<'_, '_> { SELECT number, l1_batches.timestamp, - is_finished, l1_tx_count, l2_tx_count, - fee_account_address, bloom, priority_ops_onchain_data, hash, @@ -1720,13 +1608,10 @@ impl BlocksDal<'_, '_> { compressed_repeated_writes, l2_l1_compressed_messages, l2_l1_merkle_root, - l1_gas_price, - l2_fair_gas_price, rollup_last_leaf_index, zkporter_is_available, l1_batches.bootloader_code_hash, l1_batches.default_aa_code_hash, - base_fee_per_gas, aux_data_hash, pass_through_data_hash, meta_parameters_hash, @@ -1823,46 +1708,6 @@ impl BlocksDal<'_, '_> { Ok(Some((H256::from_slice(&hash), row.timestamp as u64))) } - pub async fn get_newest_l1_batch_header(&mut self) -> sqlx::Result { - let last_l1_batch = sqlx::query_as!( - StorageL1BatchHeader, - r#" - SELECT - number, - l1_tx_count, - l2_tx_count, - timestamp, - is_finished, - fee_account_address, - l2_to_l1_logs, - l2_to_l1_messages, - bloom, - priority_ops_onchain_data, - used_contract_hashes, - base_fee_per_gas, - l1_gas_price, - l2_fair_gas_price, - bootloader_code_hash, - default_aa_code_hash, - protocol_version, - compressed_state_diffs, - system_logs, - pubdata_input - FROM - l1_batches - ORDER BY - number DESC - LIMIT - 1 - "# - ) - .instrument("get_newest_l1_batch_header") - .fetch_one(self.storage.conn()) - .await?; - - Ok(last_l1_batch.into()) - } - pub async fn get_l1_batch_metadata( &mut self, number: L1BatchNumber, @@ -1923,6 +1768,31 @@ impl BlocksDal<'_, '_> { .collect()) } + pub async fn delete_initial_writes( + &mut self, + last_batch_to_keep: L1BatchNumber, + ) -> sqlx::Result<()> { + self.delete_initial_writes_inner(Some(last_batch_to_keep)) + .await + } + + pub async fn delete_initial_writes_inner( + &mut self, + last_batch_to_keep: Option, + ) -> sqlx::Result<()> { + let block_number = last_batch_to_keep.map_or(-1, |number| number.0 as i64); + sqlx::query!( + r#" + DELETE FROM initial_writes + WHERE + l1_batch_number > $1 + "#, + block_number + ) + .execute(self.storage.conn()) + .await?; + Ok(()) + } /// Deletes all L1 batches from the storage so that the specified batch number is the last one left. pub async fn delete_l1_batches( &mut self, @@ -2219,24 +2089,44 @@ impl BlocksDal<'_, '_> { Ok(()) } - pub async fn get_fee_address_for_l1_batch( + pub async fn get_fee_address_for_miniblock( &mut self, - l1_batch_number: L1BatchNumber, + number: MiniblockNumber, ) -> sqlx::Result> { - Ok(sqlx::query!( + let Some(mut fee_account_address) = self.raw_fee_address_for_miniblock(number).await? + else { + return Ok(None); + }; + + // FIXME (PLA-728): remove after 2nd phase of `fee_account_address` migration + #[allow(deprecated)] + self.maybe_load_fee_address(&mut fee_account_address, number) + .await?; + Ok(Some(fee_account_address)) + } + + async fn raw_fee_address_for_miniblock( + &mut self, + number: MiniblockNumber, + ) -> sqlx::Result> { + let Some(row) = sqlx::query!( r#" SELECT fee_account_address FROM - l1_batches + miniblocks WHERE number = $1 "#, - l1_batch_number.0 as u32 + number.0 as i32 ) .fetch_optional(self.storage.conn()) .await? - .map(|row| Address::from_slice(&row.fee_account_address))) + else { + return Ok(None); + }; + + Ok(Some(Address::from_slice(&row.fee_account_address))) } pub async fn get_virtual_blocks_for_miniblock( @@ -2252,7 +2142,7 @@ impl BlocksDal<'_, '_> { WHERE number = $1 "#, - miniblock_number.0 as u32 + miniblock_number.0 as i32 ) .fetch_optional(self.storage.conn()) .await? @@ -2260,7 +2150,149 @@ impl BlocksDal<'_, '_> { } } -/// These functions should only be used for tests. +/// Temporary methods for migrating `fee_account_address`. +#[deprecated(note = "will be removed after the fee address migration is complete")] +impl BlocksDal<'_, '_> { + pub(crate) async fn maybe_load_fee_address( + &mut self, + fee_address: &mut Address, + miniblock_number: MiniblockNumber, + ) -> sqlx::Result<()> { + if *fee_address != Address::default() { + return Ok(()); + } + + // This clause should be triggered only for non-migrated miniblock rows. After `fee_account_address` + // is filled for all miniblocks, it won't be called; thus, `fee_account_address` column could be removed + // from `l1_batches` even with this code present. + let Some(row) = sqlx::query!( + r#" + SELECT + l1_batches.fee_account_address + FROM + l1_batches + INNER JOIN miniblocks ON miniblocks.l1_batch_number = l1_batches.number + WHERE + miniblocks.number = $1 + "#, + miniblock_number.0 as i32 + ) + .fetch_optional(self.storage.conn()) + .await? + else { + return Ok(()); + }; + + *fee_address = Address::from_slice(&row.fee_account_address); + Ok(()) + } + + /// Checks whether `fee_account_address` is migrated for the specified miniblock. Returns + /// `Ok(None)` if the miniblock doesn't exist. + pub async fn is_fee_address_migrated( + &mut self, + number: MiniblockNumber, + ) -> sqlx::Result> { + Ok(self + .raw_fee_address_for_miniblock(number) + .await? + .map(|address| address != Address::default())) + } + + /// Copies `fee_account_address` for pending miniblocks (ones without an associated L1 batch) + /// from the last L1 batch. Returns the number of affected rows. + pub async fn copy_fee_account_address_for_pending_miniblocks(&mut self) -> sqlx::Result { + let execution_result = sqlx::query!( + r#" + UPDATE miniblocks + SET + fee_account_address = ( + SELECT + l1_batches.fee_account_address + FROM + l1_batches + ORDER BY + l1_batches.number DESC + LIMIT + 1 + ) + WHERE + l1_batch_number IS NULL + AND fee_account_address = '\x0000000000000000000000000000000000000000'::bytea + "# + ) + .execute(self.storage.conn()) + .await?; + + Ok(execution_result.rows_affected()) + } + + pub async fn check_l1_batches_have_fee_account_address(&mut self) -> sqlx::Result { + let count = sqlx::query_scalar!( + r#" + SELECT COUNT(*) + FROM information_schema.columns + WHERE table_name = 'l1_batches' AND column_name = 'fee_account_address' + "# + ) + .fetch_one(self.storage.conn()) + .await? + .unwrap_or(0); + + Ok(count > 0) + } + + /// Copies `fee_account_address` for miniblocks in the given range from the L1 batch they belong to. + /// Returns the number of affected rows. + pub async fn copy_fee_account_address_for_miniblocks( + &mut self, + numbers: ops::RangeInclusive, + ) -> sqlx::Result { + let execution_result = sqlx::query!( + r#" + UPDATE miniblocks + SET + fee_account_address = l1_batches.fee_account_address + FROM + l1_batches + WHERE + l1_batches.number = miniblocks.l1_batch_number + AND miniblocks.number BETWEEN $1 AND $2 + AND miniblocks.fee_account_address = '\x0000000000000000000000000000000000000000'::bytea + "#, + numbers.start().0 as i64, + numbers.end().0 as i64 + ) + .execute(self.storage.conn()) + .await?; + + Ok(execution_result.rows_affected()) + } + + /// Sets `fee_account_address` for an L1 batch. Should only be used in tests. + pub async fn set_l1_batch_fee_address( + &mut self, + l1_batch: L1BatchNumber, + fee_account_address: Address, + ) -> sqlx::Result<()> { + sqlx::query!( + r#" + UPDATE l1_batches + SET + fee_account_address = $1::bytea + WHERE + number = $2 + "#, + fee_account_address.as_bytes(), + l1_batch.0 as i64 + ) + .execute(self.storage.conn()) + .await?; + Ok(()) + } +} + +/// These methods should only be used for tests. impl BlocksDal<'_, '_> { // The actual l1 batch hash is only set by the metadata calculator. pub async fn set_l1_batch_hash( @@ -2284,6 +2316,18 @@ impl BlocksDal<'_, '_> { Ok(()) } + pub async fn insert_mock_l1_batch(&mut self, header: &L1BatchHeader) -> anyhow::Result<()> { + self.insert_l1_batch( + header, + &[], + Default::default(), + &[], + &[], + Default::default(), + ) + .await + } + /// Deletes all miniblocks and L1 batches, including the genesis ones. Should only be used in tests. pub async fn delete_genesis(&mut self) -> anyhow::Result<()> { self.delete_miniblocks_inner(None) @@ -2292,6 +2336,9 @@ impl BlocksDal<'_, '_> { self.delete_l1_batches_inner(None) .await .context("delete_l1_batches_inner()")?; + self.delete_initial_writes_inner(None) + .await + .context("delete_initial_writes_inner()")?; Ok(()) } } @@ -2305,16 +2352,12 @@ mod tests { }; use super::*; - use crate::ConnectionPool; + use crate::{tests::create_miniblock_header, ConnectionPool}; #[tokio::test] async fn loading_l1_batch_header() { let pool = ConnectionPool::test_pool().await; let mut conn = pool.access_storage().await.unwrap(); - conn.blocks_dal() - .delete_l1_batches(L1BatchNumber(0)) - .await - .unwrap(); conn.protocol_versions_dal() .save_protocol_version_with_tx(ProtocolVersion::default()) .await; @@ -2322,7 +2365,6 @@ mod tests { let mut header = L1BatchHeader::new( L1BatchNumber(1), 100, - Address::default(), BaseSystemContractsHashes { bootloader: H256::repeat_byte(1), default_aa: H256::repeat_byte(42), @@ -2343,7 +2385,7 @@ mod tests { header.l2_to_l1_messages.push(vec![33; 33]); conn.blocks_dal() - .insert_l1_batch(&header, &[], BlockGasCount::default(), &[], &[]) + .insert_mock_l1_batch(&header) .await .unwrap(); @@ -2372,17 +2414,12 @@ mod tests { async fn getting_predicted_gas() { let pool = ConnectionPool::test_pool().await; let mut conn = pool.access_storage().await.unwrap(); - conn.blocks_dal() - .delete_l1_batches(L1BatchNumber(0)) - .await - .unwrap(); conn.protocol_versions_dal() .save_protocol_version_with_tx(ProtocolVersion::default()) .await; let mut header = L1BatchHeader::new( L1BatchNumber(1), 100, - Address::default(), BaseSystemContractsHashes::default(), ProtocolVersionId::default(), ); @@ -2392,7 +2429,7 @@ mod tests { execute: 10, }; conn.blocks_dal() - .insert_l1_batch(&header, &[], predicted_gas, &[], &[]) + .insert_l1_batch(&header, &[], predicted_gas, &[], &[], Default::default()) .await .unwrap(); @@ -2400,7 +2437,7 @@ mod tests { header.timestamp += 100; predicted_gas += predicted_gas; conn.blocks_dal() - .insert_l1_batch(&header, &[], predicted_gas, &[], &[]) + .insert_l1_batch(&header, &[], predicted_gas, &[], &[], Default::default()) .await .unwrap(); @@ -2432,4 +2469,144 @@ mod tests { assert_eq!(gas, 3 * expected_gas); } } + + #[allow(deprecated)] // that's the whole point + #[tokio::test] + async fn checking_fee_account_address_in_l1_batches() { + let pool = ConnectionPool::test_pool().await; + let mut conn = pool.access_storage().await.unwrap(); + assert!(conn + .blocks_dal() + .check_l1_batches_have_fee_account_address() + .await + .unwrap()); + } + + #[allow(deprecated)] // that's the whole point + #[tokio::test] + async fn ensuring_fee_account_address_for_miniblocks() { + let pool = ConnectionPool::test_pool().await; + let mut conn = pool.access_storage().await.unwrap(); + conn.protocol_versions_dal() + .save_protocol_version_with_tx(ProtocolVersion::default()) + .await; + + for number in [1, 2] { + let l1_batch = L1BatchHeader::new( + L1BatchNumber(number), + 100, + BaseSystemContractsHashes { + bootloader: H256::repeat_byte(1), + default_aa: H256::repeat_byte(42), + }, + ProtocolVersionId::latest(), + ); + let miniblock = MiniblockHeader { + fee_account_address: Address::default(), + ..create_miniblock_header(number) + }; + conn.blocks_dal() + .insert_miniblock(&miniblock) + .await + .unwrap(); + conn.blocks_dal() + .insert_mock_l1_batch(&l1_batch) + .await + .unwrap(); + conn.blocks_dal() + .mark_miniblocks_as_executed_in_l1_batch(L1BatchNumber(number)) + .await + .unwrap(); + + assert_eq!( + conn.blocks_dal() + .is_fee_address_migrated(miniblock.number) + .await + .unwrap(), + Some(false) + ); + } + + // Manually set `fee_account_address` for the inserted L1 batches. + conn.blocks_dal() + .set_l1_batch_fee_address(L1BatchNumber(1), Address::repeat_byte(0x23)) + .await + .unwrap(); + conn.blocks_dal() + .set_l1_batch_fee_address(L1BatchNumber(2), Address::repeat_byte(0x42)) + .await + .unwrap(); + + // Add a pending miniblock. + let miniblock = MiniblockHeader { + fee_account_address: Address::default(), + ..create_miniblock_header(3) + }; + conn.blocks_dal() + .insert_miniblock(&miniblock) + .await + .unwrap(); + + let rows_affected = conn + .blocks_dal() + .copy_fee_account_address_for_miniblocks(MiniblockNumber(0)..=MiniblockNumber(100)) + .await + .unwrap(); + + assert_eq!(rows_affected, 2); + let first_miniblock_addr = conn + .blocks_dal() + .raw_fee_address_for_miniblock(MiniblockNumber(1)) + .await + .unwrap() + .expect("No fee address for block #1"); + assert_eq!(first_miniblock_addr, Address::repeat_byte(0x23)); + let second_miniblock_addr = conn + .blocks_dal() + .raw_fee_address_for_miniblock(MiniblockNumber(2)) + .await + .unwrap() + .expect("No fee address for block #1"); + assert_eq!(second_miniblock_addr, Address::repeat_byte(0x42)); + // The pending miniblock should not be affected. + let pending_miniblock_addr = conn + .blocks_dal() + .raw_fee_address_for_miniblock(MiniblockNumber(3)) + .await + .unwrap() + .expect("No fee address for block #3"); + assert_eq!(pending_miniblock_addr, Address::default()); + assert_eq!( + conn.blocks_dal() + .is_fee_address_migrated(MiniblockNumber(3)) + .await + .unwrap(), + Some(false) + ); + + let rows_affected = conn + .blocks_dal() + .copy_fee_account_address_for_pending_miniblocks() + .await + .unwrap(); + assert_eq!(rows_affected, 1); + + let pending_miniblock_addr = conn + .blocks_dal() + .raw_fee_address_for_miniblock(MiniblockNumber(3)) + .await + .unwrap() + .expect("No fee address for block #3"); + assert_eq!(pending_miniblock_addr, Address::repeat_byte(0x42)); + + for number in 1..=3 { + assert_eq!( + conn.blocks_dal() + .is_fee_address_migrated(MiniblockNumber(number)) + .await + .unwrap(), + Some(true) + ); + } + } } diff --git a/core/lib/dal/src/blocks_web3_dal.rs b/core/lib/dal/src/blocks_web3_dal.rs index 4be51e07240f..c03352937d22 100644 --- a/core/lib/dal/src/blocks_web3_dal.rs +++ b/core/lib/dal/src/blocks_web3_dal.rs @@ -3,11 +3,9 @@ use sqlx::Row; use zksync_system_constants::EMPTY_UNCLES_HASH; use zksync_types::{ api, - ethabi::Address, l2_to_l1_log::L2ToL1Log, vm_trace::Call, web3::types::{BlockHeader, U64}, - zkevm_test_harness::zk_evm::zkevm_opcode_defs::system_params, Bytes, L1BatchNumber, L2ChainId, MiniblockNumber, H160, H2048, H256, U256, }; use zksync_utils::bigdecimal_to_u256; @@ -17,14 +15,14 @@ use crate::{ models::{ storage_block::{ bind_block_where_sql_params, web3_block_number_to_sql, web3_block_where_sql, - StorageBlockDetails, StorageL1BatchDetails, + ResolvedL1BatchForMiniblock, StorageBlockDetails, StorageL1BatchDetails, }, storage_transaction::{extract_web3_transaction, web3_transaction_select_sql, CallTrace}, }, StorageProcessor, }; -const BLOCK_GAS_LIMIT: u32 = system_params::VM_INITIAL_FRAME_ERGS; +const BLOCK_GAS_LIMIT: u32 = u32::MAX; #[derive(Debug)] pub struct BlocksWeb3Dal<'a, 'c> { @@ -32,42 +30,6 @@ pub struct BlocksWeb3Dal<'a, 'c> { } impl BlocksWeb3Dal<'_, '_> { - pub async fn get_sealed_miniblock_number(&mut self) -> sqlx::Result { - let number = sqlx::query!( - r#" - SELECT - MAX(number) AS "number" - FROM - miniblocks - "# - ) - .instrument("get_sealed_block_number") - .report_latency() - .fetch_one(self.storage.conn()) - .await? - .number - .expect("DAL invocation before genesis"); - Ok(MiniblockNumber(number as u32)) - } - - pub async fn get_sealed_l1_batch_number(&mut self) -> sqlx::Result { - let number = sqlx::query!( - r#" - SELECT - MAX(number) AS "number" - FROM - l1_batches - "# - ) - .instrument("get_sealed_block_number") - .report_latency() - .fetch_one(self.storage.conn()) - .await? - .number - .expect("DAL invocation before genesis"); - Ok(L1BatchNumber(number as u32)) - } - pub async fn get_block_by_web3_block_id( &mut self, block_id: api::BlockId, @@ -99,7 +61,8 @@ impl BlocksWeb3Dal<'_, '_> { ON l1_batches.number = miniblocks.l1_batch_number LEFT JOIN transactions ON transactions.miniblock_number = miniblocks.number - WHERE {}", + WHERE {} + ORDER BY transactions.index_in_block ASC", transactions_sql, web3_block_where_sql(block_id, 1) ); @@ -258,21 +221,26 @@ impl BlocksWeb3Dal<'_, '_> { &mut self, block_id: api::BlockId, ) -> sqlx::Result> { - let query_string = match block_id { - api::BlockId::Hash(_) => "SELECT number FROM miniblocks WHERE hash = $1".to_owned(), + let query_string; + let query_str = match block_id { + api::BlockId::Hash(_) => "SELECT number FROM miniblocks WHERE hash = $1", api::BlockId::Number(api::BlockNumber::Number(_)) => { // The reason why instead of returning the `block_number` directly we use query is - // to handle numbers of blocks that are not created yet. - // the `SELECT number FROM miniblocks WHERE number=block_number` for - // non-existing block number will returns zero. - "SELECT number FROM miniblocks WHERE number = $1".to_owned() + // to handle numbers of blocks that are not created yet or were pruned. + // The query below will return NULL for non-existing block numbers. + "SELECT number FROM miniblocks WHERE number = $1" } api::BlockId::Number(api::BlockNumber::Earliest) => { - return Ok(Some(MiniblockNumber(0))); + // Similarly to `BlockNumber::Number`, we may be missing the earliest block + // if the storage was recovered from a snapshot. + "SELECT number FROM miniblocks WHERE number = 0" + } + api::BlockId::Number(block_number) => { + query_string = web3_block_number_to_sql(block_number); + &query_string } - api::BlockId::Number(block_number) => web3_block_number_to_sql(block_number), }; - let row = bind_block_where_sql_params(&block_id, sqlx::query(&query_string)) + let row = bind_block_where_sql_params(&block_id, sqlx::query(query_str)) .fetch_optional(self.storage.conn()) .await?; @@ -283,36 +251,74 @@ impl BlocksWeb3Dal<'_, '_> { } /// Returns L1 batch timestamp for either sealed or pending L1 batch. + /// + /// The correctness of the current implementation depends on the timestamp of an L1 batch always + /// being equal to the timestamp of the first miniblock in the batch. pub async fn get_expected_l1_batch_timestamp( &mut self, - l1_batch_number: L1BatchNumber, + l1_batch_number: &ResolvedL1BatchForMiniblock, ) -> sqlx::Result> { - let first_miniblock_of_batch = if l1_batch_number.0 == 0 { - MiniblockNumber(0) + if let Some(miniblock_l1_batch) = l1_batch_number.miniblock_l1_batch { + Ok(sqlx::query!( + r#" + SELECT + timestamp + FROM + miniblocks + WHERE + l1_batch_number = $1 + ORDER BY + number + LIMIT + 1 + "#, + i64::from(miniblock_l1_batch.0) + ) + .fetch_optional(self.storage.conn()) + .await? + .map(|row| row.timestamp as u64)) } else { - match self - .get_miniblock_range_of_l1_batch(l1_batch_number - 1) - .await? - { - Some((_, miniblock_number)) => miniblock_number + 1, - None => return Ok(None), - } - }; - let timestamp = sqlx::query!( - r#" - SELECT - timestamp - FROM - miniblocks - WHERE - number = $1 - "#, - first_miniblock_of_batch.0 as i64 - ) - .fetch_optional(self.storage.conn()) - .await? - .map(|row| row.timestamp as u64); - Ok(timestamp) + // Got a pending miniblock. Searching the timestamp of the first pending miniblock using + // `WHERE l1_batch_number IS NULL` is slow since it potentially locks the `miniblocks` table. + // Instead, we determine its number using the previous L1 batch, taking into the account that + // it may be stored in the `snapshot_recovery` table. + let prev_l1_batch_number = if l1_batch_number.pending_l1_batch == L1BatchNumber(0) { + return Ok(None); // We haven't created the genesis miniblock yet + } else { + l1_batch_number.pending_l1_batch - 1 + }; + Ok(sqlx::query!( + r#" + SELECT + timestamp + FROM + miniblocks + WHERE + number = COALESCE( + ( + SELECT + MAX(number) + 1 + FROM + miniblocks + WHERE + l1_batch_number = $1 + ), + ( + SELECT + MAX(miniblock_number) + 1 + FROM + snapshot_recovery + WHERE + l1_batch_number = $1 + ) + ) + "#, + i64::from(prev_l1_batch_number.0) + ) + .fetch_optional(self.storage.conn()) + .await? + .map(|row| row.timestamp as u64)) + } } pub async fn get_miniblock_hash( @@ -441,7 +447,8 @@ impl BlocksWeb3Dal<'_, '_> { Ok(result) } - pub async fn get_trace_for_miniblock( + /// Returns call traces for all transactions in the specified miniblock in the order of their execution. + pub async fn get_traces_for_miniblock( &mut self, block_number: MiniblockNumber, ) -> sqlx::Result> { @@ -449,18 +456,14 @@ impl BlocksWeb3Dal<'_, '_> { CallTrace, r#" SELECT - * + call_trace FROM call_traces + INNER JOIN transactions ON tx_hash = transactions.hash WHERE - tx_hash IN ( - SELECT - hash - FROM - transactions - WHERE - miniblock_number = $1 - ) + transactions.miniblock_number = $1 + ORDER BY + transactions.index_in_block "#, block_number.0 as i64 ) @@ -506,122 +509,139 @@ impl BlocksWeb3Dal<'_, '_> { pub async fn get_block_details( &mut self, block_number: MiniblockNumber, - current_operator_address: Address, ) -> sqlx::Result> { - { - let storage_block_details = sqlx::query_as!( - StorageBlockDetails, - r#" - SELECT - miniblocks.number, - COALESCE( - miniblocks.l1_batch_number, - ( - SELECT - (MAX(number) + 1) - FROM - l1_batches - ) - ) AS "l1_batch_number!", - miniblocks.timestamp, - miniblocks.l1_tx_count, - miniblocks.l2_tx_count, - miniblocks.hash AS "root_hash?", - commit_tx.tx_hash AS "commit_tx_hash?", - commit_tx.confirmed_at AS "committed_at?", - prove_tx.tx_hash AS "prove_tx_hash?", - prove_tx.confirmed_at AS "proven_at?", - execute_tx.tx_hash AS "execute_tx_hash?", - execute_tx.confirmed_at AS "executed_at?", - miniblocks.l1_gas_price, - miniblocks.l2_fair_gas_price, - miniblocks.bootloader_code_hash, - miniblocks.default_aa_code_hash, - miniblocks.protocol_version, - l1_batches.fee_account_address AS "fee_account_address?" - FROM - miniblocks - LEFT JOIN l1_batches ON miniblocks.l1_batch_number = l1_batches.number - LEFT JOIN eth_txs_history AS commit_tx ON ( - l1_batches.eth_commit_tx_id = commit_tx.eth_tx_id - AND commit_tx.confirmed_at IS NOT NULL - ) - LEFT JOIN eth_txs_history AS prove_tx ON ( - l1_batches.eth_prove_tx_id = prove_tx.eth_tx_id - AND prove_tx.confirmed_at IS NOT NULL - ) - LEFT JOIN eth_txs_history AS execute_tx ON ( - l1_batches.eth_execute_tx_id = execute_tx.eth_tx_id - AND execute_tx.confirmed_at IS NOT NULL + let storage_block_details = sqlx::query_as!( + StorageBlockDetails, + r#" + SELECT + miniblocks.number, + COALESCE( + miniblocks.l1_batch_number, + ( + SELECT + (MAX(number) + 1) + FROM + l1_batches ) - WHERE - miniblocks.number = $1 - "#, - block_number.0 as i64 - ) - .instrument("get_block_details") - .with_arg("block_number", &block_number) - .report_latency() - .fetch_optional(self.storage.conn()) - .await?; + ) AS "l1_batch_number!", + miniblocks.timestamp, + miniblocks.l1_tx_count, + miniblocks.l2_tx_count, + miniblocks.hash AS "root_hash?", + commit_tx.tx_hash AS "commit_tx_hash?", + commit_tx.confirmed_at AS "committed_at?", + prove_tx.tx_hash AS "prove_tx_hash?", + prove_tx.confirmed_at AS "proven_at?", + execute_tx.tx_hash AS "execute_tx_hash?", + execute_tx.confirmed_at AS "executed_at?", + miniblocks.l1_gas_price, + miniblocks.l2_fair_gas_price, + miniblocks.bootloader_code_hash, + miniblocks.default_aa_code_hash, + miniblocks.protocol_version, + miniblocks.fee_account_address + FROM + miniblocks + LEFT JOIN l1_batches ON miniblocks.l1_batch_number = l1_batches.number + LEFT JOIN eth_txs_history AS commit_tx ON ( + l1_batches.eth_commit_tx_id = commit_tx.eth_tx_id + AND commit_tx.confirmed_at IS NOT NULL + ) + LEFT JOIN eth_txs_history AS prove_tx ON ( + l1_batches.eth_prove_tx_id = prove_tx.eth_tx_id + AND prove_tx.confirmed_at IS NOT NULL + ) + LEFT JOIN eth_txs_history AS execute_tx ON ( + l1_batches.eth_execute_tx_id = execute_tx.eth_tx_id + AND execute_tx.confirmed_at IS NOT NULL + ) + WHERE + miniblocks.number = $1 + "#, + block_number.0 as i64 + ) + .instrument("get_block_details") + .with_arg("block_number", &block_number) + .report_latency() + .fetch_optional(self.storage.conn()) + .await?; - Ok(storage_block_details.map(|storage_block_details| { - storage_block_details.into_block_details(current_operator_address) - })) - } + let Some(storage_block_details) = storage_block_details else { + return Ok(None); + }; + let mut details = api::BlockDetails::from(storage_block_details); + + // FIXME (PLA-728): remove after 2nd phase of `fee_account_address` migration + #[allow(deprecated)] + self.storage + .blocks_dal() + .maybe_load_fee_address(&mut details.operator_address, details.number) + .await?; + Ok(Some(details)) } pub async fn get_l1_batch_details( &mut self, l1_batch_number: L1BatchNumber, ) -> sqlx::Result> { - { - let l1_batch_details: Option = sqlx::query_as!( - StorageL1BatchDetails, - r#" - SELECT - l1_batches.number, - l1_batches.timestamp, - l1_batches.l1_tx_count, - l1_batches.l2_tx_count, - l1_batches.hash AS "root_hash?", - commit_tx.tx_hash AS "commit_tx_hash?", - commit_tx.confirmed_at AS "committed_at?", - prove_tx.tx_hash AS "prove_tx_hash?", - prove_tx.confirmed_at AS "proven_at?", - execute_tx.tx_hash AS "execute_tx_hash?", - execute_tx.confirmed_at AS "executed_at?", - l1_batches.l1_gas_price, - l1_batches.l2_fair_gas_price, - l1_batches.bootloader_code_hash, - l1_batches.default_aa_code_hash - FROM - l1_batches - LEFT JOIN eth_txs_history AS commit_tx ON ( - l1_batches.eth_commit_tx_id = commit_tx.eth_tx_id - AND commit_tx.confirmed_at IS NOT NULL - ) - LEFT JOIN eth_txs_history AS prove_tx ON ( - l1_batches.eth_prove_tx_id = prove_tx.eth_tx_id - AND prove_tx.confirmed_at IS NOT NULL - ) - LEFT JOIN eth_txs_history AS execute_tx ON ( - l1_batches.eth_execute_tx_id = execute_tx.eth_tx_id - AND execute_tx.confirmed_at IS NOT NULL - ) - WHERE - l1_batches.number = $1 - "#, - l1_batch_number.0 as i64 - ) - .instrument("get_l1_batch_details") - .with_arg("l1_batch_number", &l1_batch_number) - .report_latency() - .fetch_optional(self.storage.conn()) - .await?; + let l1_batch_details: Option = sqlx::query_as!( + StorageL1BatchDetails, + r#" + WITH + mb AS ( + SELECT + l1_gas_price, + l2_fair_gas_price + FROM + miniblocks + WHERE + l1_batch_number = $1 + LIMIT + 1 + ) + SELECT + l1_batches.number, + l1_batches.timestamp, + l1_batches.l1_tx_count, + l1_batches.l2_tx_count, + l1_batches.hash AS "root_hash?", + commit_tx.tx_hash AS "commit_tx_hash?", + commit_tx.confirmed_at AS "committed_at?", + prove_tx.tx_hash AS "prove_tx_hash?", + prove_tx.confirmed_at AS "proven_at?", + execute_tx.tx_hash AS "execute_tx_hash?", + execute_tx.confirmed_at AS "executed_at?", + mb.l1_gas_price, + mb.l2_fair_gas_price, + l1_batches.bootloader_code_hash, + l1_batches.default_aa_code_hash + FROM + l1_batches + INNER JOIN mb ON TRUE + LEFT JOIN eth_txs_history AS commit_tx ON ( + l1_batches.eth_commit_tx_id = commit_tx.eth_tx_id + AND commit_tx.confirmed_at IS NOT NULL + ) + LEFT JOIN eth_txs_history AS prove_tx ON ( + l1_batches.eth_prove_tx_id = prove_tx.eth_tx_id + AND prove_tx.confirmed_at IS NOT NULL + ) + LEFT JOIN eth_txs_history AS execute_tx ON ( + l1_batches.eth_execute_tx_id = execute_tx.eth_tx_id + AND execute_tx.confirmed_at IS NOT NULL + ) + WHERE + l1_batches.number = $1 + "#, + l1_batch_number.0 as i64 + ) + .instrument("get_l1_batch_details") + .with_arg("l1_batch_number", &l1_batch_number) + .report_latency() + .fetch_optional(self.storage.conn()) + .await?; - Ok(l1_batch_details.map(api::L1BatchDetails::from)) - } + Ok(l1_batch_details.map(Into::into)) } } @@ -629,11 +649,16 @@ impl BlocksWeb3Dal<'_, '_> { mod tests { use zksync_types::{ block::{MiniblockHasher, MiniblockHeader}, - MiniblockNumber, ProtocolVersion, ProtocolVersionId, + fee::TransactionExecutionMetrics, + snapshots::SnapshotRecoveryStatus, + Address, MiniblockNumber, ProtocolVersion, ProtocolVersionId, }; use super::*; - use crate::{tests::create_miniblock_header, ConnectionPool}; + use crate::{ + tests::{create_miniblock_header, mock_execution_result, mock_l2_transaction}, + ConnectionPool, + }; #[tokio::test] async fn getting_web3_block_and_tx_count() { @@ -698,8 +723,18 @@ mod tests { async fn resolving_earliest_block_id() { let connection_pool = ConnectionPool::test_pool().await; let mut conn = connection_pool.access_storage().await.unwrap(); + + let miniblock_number = conn + .blocks_web3_dal() + .resolve_block_id(api::BlockId::Number(api::BlockNumber::Earliest)) + .await; + assert_eq!(miniblock_number.unwrap(), None); + + conn.protocol_versions_dal() + .save_protocol_version_with_tx(ProtocolVersion::default()) + .await; conn.blocks_dal() - .delete_miniblocks(MiniblockNumber(0)) + .insert_miniblock(&create_miniblock_header(0)) .await .unwrap(); @@ -714,13 +749,23 @@ mod tests { async fn resolving_latest_block_id() { let connection_pool = ConnectionPool::test_pool().await; let mut conn = connection_pool.access_storage().await.unwrap(); - conn.blocks_dal() - .delete_miniblocks(MiniblockNumber(0)) - .await - .unwrap(); conn.protocol_versions_dal() .save_protocol_version_with_tx(ProtocolVersion::default()) .await; + + let miniblock_number = conn + .blocks_web3_dal() + .resolve_block_id(api::BlockId::Number(api::BlockNumber::Latest)) + .await + .unwrap(); + assert_eq!(miniblock_number, None); + let miniblock_number = conn + .blocks_web3_dal() + .resolve_block_id(api::BlockId::Number(api::BlockNumber::Pending)) + .await + .unwrap(); + assert_eq!(miniblock_number, Some(MiniblockNumber(0))); + conn.blocks_dal() .insert_miniblock(&create_miniblock_header(0)) .await @@ -767,13 +812,33 @@ mod tests { } #[tokio::test] - async fn resolving_block_by_hash() { + async fn resolving_pending_block_id_for_snapshot_recovery() { let connection_pool = ConnectionPool::test_pool().await; let mut conn = connection_pool.access_storage().await.unwrap(); - conn.blocks_dal() - .delete_miniblocks(MiniblockNumber(0)) + let snapshot_recovery = SnapshotRecoveryStatus { + l1_batch_number: L1BatchNumber(23), + l1_batch_root_hash: H256::zero(), + miniblock_number: MiniblockNumber(42), + miniblock_root_hash: H256::zero(), + storage_logs_chunks_processed: vec![true; 100], + }; + conn.snapshot_recovery_dal() + .insert_initial_recovery_status(&snapshot_recovery) + .await + .unwrap(); + + let miniblock_number = conn + .blocks_web3_dal() + .resolve_block_id(api::BlockId::Number(api::BlockNumber::Pending)) .await .unwrap(); + assert_eq!(miniblock_number, Some(MiniblockNumber(43))); + } + + #[tokio::test] + async fn resolving_block_by_hash() { + let connection_pool = ConnectionPool::test_pool().await; + let mut conn = connection_pool.access_storage().await.unwrap(); conn.protocol_versions_dal() .save_protocol_version_with_tx(ProtocolVersion::default()) .await; @@ -798,4 +863,47 @@ mod tests { .await; assert_eq!(miniblock_number.unwrap(), None); } + + #[tokio::test] + async fn getting_traces_for_block() { + let connection_pool = ConnectionPool::test_pool().await; + let mut conn = connection_pool.access_storage().await.unwrap(); + conn.protocol_versions_dal() + .save_protocol_version_with_tx(ProtocolVersion::default()) + .await; + conn.blocks_dal() + .insert_miniblock(&create_miniblock_header(1)) + .await + .unwrap(); + + let transactions = [mock_l2_transaction(), mock_l2_transaction()]; + let mut tx_results = vec![]; + for (i, tx) in transactions.into_iter().enumerate() { + conn.transactions_dal() + .insert_transaction_l2(tx.clone(), TransactionExecutionMetrics::default()) + .await; + let mut tx_result = mock_execution_result(tx); + tx_result.call_traces.push(Call { + from: Address::from_low_u64_be(i as u64), + to: Address::from_low_u64_be(i as u64 + 1), + value: i.into(), + ..Call::default() + }); + tx_results.push(tx_result); + } + conn.transactions_dal() + .mark_txs_as_executed_in_miniblock(MiniblockNumber(1), &tx_results, 1.into()) + .await; + + let traces = conn + .blocks_web3_dal() + .get_traces_for_miniblock(MiniblockNumber(1)) + .await + .unwrap(); + assert_eq!(traces.len(), 2); + for (trace, tx_result) in traces.iter().zip(&tx_results) { + let expected_trace = tx_result.call_trace().unwrap(); + assert_eq!(*trace, expected_trace); + } + } } diff --git a/core/lib/dal/src/connection/mod.rs b/core/lib/dal/src/connection/mod.rs index 0e833625bf3e..c689ddf8bc18 100644 --- a/core/lib/dal/src/connection/mod.rs +++ b/core/lib/dal/src/connection/mod.rs @@ -10,15 +10,8 @@ use crate::{metrics::CONNECTION_METRICS, StorageProcessor}; pub mod holder; -/// Obtains the test database URL from the environment variable. -fn get_test_database_url() -> anyhow::Result { - env::var("TEST_DATABASE_URL").context( - "TEST_DATABASE_URL must be set. Normally, this is done by the 'zk' tool. \ - Make sure that you are running the tests with 'zk test rust' command or equivalent.", - ) -} - /// Builder for [`ConnectionPool`]s. +#[derive(Clone)] pub struct ConnectionPoolBuilder { database_url: String, max_size: u32, @@ -68,66 +61,33 @@ impl ConnectionPoolBuilder { statement_timeout = self.statement_timeout ); Ok(ConnectionPool { + database_url: self.database_url.clone(), inner: pool, max_size: self.max_size, }) } -} -/// Constructs a new temporary database (with a randomized name) -/// by cloning the database template pointed by TEST_DATABASE_URL env var. -/// The template is expected to have all migrations from dal/migrations applied. -/// For efficiency, the Postgres container of TEST_DATABASE_URL should be -/// configured with option "fsync=off" - it disables waiting for disk synchronization -/// whenever you write to the DBs, therefore making it as fast as an in-memory Postgres instance. -/// The database is not cleaned up automatically, but rather the whole Postgres -/// container is recreated whenever you call "zk test rust". -pub(super) async fn create_test_db() -> anyhow::Result { - use rand::Rng as _; - use sqlx::{Connection as _, Executor as _}; - - const PREFIX: &str = "test-"; - - let db_url = get_test_database_url().unwrap(); - let mut db_url = url::Url::parse(&db_url) - .with_context(|| format!("{} is not a valid database address", db_url))?; - let db_name = db_url - .path() - .strip_prefix('/') - .with_context(|| format!("{} is not a valid database address", db_url.as_ref()))? - .to_string(); - let db_copy_name = format!("{PREFIX}{}", rand::thread_rng().gen::()); - db_url.set_path(""); - let mut attempts = 10; - let mut conn = loop { - match sqlx::PgConnection::connect(db_url.as_ref()).await { - Ok(conn) => break conn, - Err(err) => { - attempts -= 1; - if attempts == 0 { - return Err(err).context("sqlx::PgConnection::connect()"); - } - } - } - tokio::time::sleep(std::time::Duration::from_millis(100)).await; - }; - conn.execute( - format!("CREATE DATABASE \"{db_copy_name}\" WITH TEMPLATE \"{db_name}\"").as_str(), - ) - .await - .context("failed to create a temporary database")?; - db_url.set_path(&db_copy_name); - Ok(db_url) + /// Builds a connection pool that has a single connection. + pub async fn build_singleton(&self) -> anyhow::Result { + let singleton_builder = Self { + max_size: 1, + ..self.clone() + }; + singleton_builder.build().await + } } #[derive(Clone)] pub struct ConnectionPool { pub(crate) inner: PgPool, + database_url: String, max_size: u32, } impl fmt::Debug for ConnectionPool { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + // We don't print the `database_url`, as is may contain + // sensitive information (e.g. database password). formatter .debug_struct("ConnectionPool") .field("max_size", &self.max_size) @@ -135,18 +95,92 @@ impl fmt::Debug for ConnectionPool { } } -impl ConnectionPool { - pub async fn test_pool() -> ConnectionPool { - let db_url = create_test_db() +pub struct TestTemplate(url::Url); + +impl TestTemplate { + fn db_name(&self) -> &str { + self.0.path().strip_prefix('/').unwrap() + } + + fn url(&self, db_name: &str) -> url::Url { + let mut url = self.0.clone(); + url.set_path(db_name); + url + } + + async fn connect_to(db_url: &url::Url) -> sqlx::Result { + use sqlx::Connection as _; + let mut attempts = 10; + loop { + match sqlx::PgConnection::connect(db_url.as_ref()).await { + Ok(conn) => return Ok(conn), + Err(err) => { + attempts -= 1; + if attempts == 0 { + return Err(err); + } + } + } + tokio::time::sleep(std::time::Duration::from_millis(100)).await; + } + } + + /// Obtains the test database URL from the environment variable. + pub fn empty() -> anyhow::Result { + let db_url = env::var("TEST_DATABASE_URL").context( + "TEST_DATABASE_URL must be set. Normally, this is done by the 'zk' tool. \ + Make sure that you are running the tests with 'zk test rust' command or equivalent.", + )?; + Ok(Self(db_url.parse()?)) + } + + /// Closes the connection pool, disallows connecting to the underlying db, + /// so that the db can be used as a template. + pub async fn freeze(pool: ConnectionPool) -> anyhow::Result { + use sqlx::Executor as _; + let mut conn = pool.acquire_connection_retried().await?; + conn.execute( + "UPDATE pg_database SET datallowconn = false WHERE datname = current_database()", + ) + .await + .context("SET dataallowconn = false")?; + drop(conn); + pool.inner.close().await; + Ok(Self(pool.database_url.parse()?)) + } + + /// Constructs a new temporary database (with a randomized name) + /// by cloning the database template pointed by TEST_DATABASE_URL env var. + /// The template is expected to have all migrations from dal/migrations applied. + /// For efficiency, the Postgres container of TEST_DATABASE_URL should be + /// configured with option "fsync=off" - it disables waiting for disk synchronization + /// whenever you write to the DBs, therefore making it as fast as an in-memory Postgres instance. + /// The database is not cleaned up automatically, but rather the whole Postgres + /// container is recreated whenever you call "zk test rust". + pub async fn create_db(&self) -> anyhow::Result { + use rand::Rng as _; + use sqlx::Executor as _; + + let mut conn = Self::connect_to(&self.url("")) .await - .expect("Unable to prepare test database") - .to_string(); + .context("connect_to()")?; + let db_old = self.db_name(); + let db_new = format!("test-{}", rand::thread_rng().gen::()); + conn.execute(format!("CREATE DATABASE \"{db_new}\" WITH TEMPLATE \"{db_old}\"").as_str()) + .await + .context("CREATE DATABASE")?; const TEST_MAX_CONNECTIONS: u32 = 50; // Expected to be enough for any unit test. - Self::builder(&db_url, TEST_MAX_CONNECTIONS) + ConnectionPool::builder(self.url(&db_new).as_ref(), TEST_MAX_CONNECTIONS) .build() .await - .unwrap() + .context("ConnectionPool::builder()") + } +} + +impl ConnectionPool { + pub async fn test_pool() -> ConnectionPool { + TestTemplate::empty().unwrap().create_db().await.unwrap() } /// Initializes a builder for connection pools. @@ -261,10 +295,12 @@ mod tests { #[tokio::test] async fn setting_statement_timeout() { - let db_url = create_test_db() + let db_url = TestTemplate::empty() + .unwrap() + .create_db() .await - .expect("Unable to prepare test database") - .to_string(); + .unwrap() + .database_url; let pool = ConnectionPool::singleton(&db_url) .set_statement_timeout(Some(Duration::from_secs(1))) diff --git a/core/lib/dal/src/consensus_dal.rs b/core/lib/dal/src/consensus_dal.rs index 152191757ba8..854e0e0871ab 100644 --- a/core/lib/dal/src/consensus_dal.rs +++ b/core/lib/dal/src/consensus_dal.rs @@ -1,13 +1,19 @@ +use anyhow::Context as _; +use zksync_consensus_roles::validator; use zksync_consensus_storage::ReplicaState; +use zksync_types::MiniblockNumber; +pub use crate::models::storage_sync::Payload; use crate::StorageProcessor; +/// Storage access methods for `zksync_core::consensus` module. #[derive(Debug)] pub struct ConsensusDal<'a, 'c> { pub storage: &'a mut StorageProcessor<'c>, } impl ConsensusDal<'_, '_> { + /// Fetches the current BFT replica state. pub async fn replica_state(&mut self) -> anyhow::Result> { let Some(row) = sqlx::query!( r#" @@ -27,7 +33,8 @@ impl ConsensusDal<'_, '_> { Ok(Some(zksync_protobuf::serde::deserialize(row.state)?)) } - pub async fn put_replica_state(&mut self, state: &ReplicaState) -> sqlx::Result<()> { + /// Sets the current BFT replica state. + pub async fn set_replica_state(&mut self, state: &ReplicaState) -> sqlx::Result<()> { let state = zksync_protobuf::serde::serialize(state, serde_json::value::Serializer).unwrap(); sqlx::query!( @@ -47,6 +54,153 @@ impl ConsensusDal<'_, '_> { .await?; Ok(()) } + + /// Fetches the first consensus certificate. + /// Note that we didn't backfill the certificates for the past miniblocks + /// when enabling consensus certificate generation, so it might NOT be the certificate + /// for the genesis miniblock. + pub async fn first_certificate(&mut self) -> anyhow::Result> { + let Some(row) = sqlx::query!( + r#" + SELECT + certificate + FROM + miniblocks_consensus + ORDER BY + number ASC + LIMIT + 1 + "# + ) + .fetch_optional(self.storage.conn()) + .await? + else { + return Ok(None); + }; + Ok(Some(zksync_protobuf::serde::deserialize(row.certificate)?)) + } + + /// Fetches the last consensus certificate. + /// Currently certificates are NOT generated synchronously with miniblocks, + /// so it might NOT be the certificate for the last miniblock. + pub async fn last_certificate(&mut self) -> anyhow::Result> { + let Some(row) = sqlx::query!( + r#" + SELECT + certificate + FROM + miniblocks_consensus + ORDER BY + number DESC + LIMIT + 1 + "# + ) + .fetch_optional(self.storage.conn()) + .await? + else { + return Ok(None); + }; + Ok(Some(zksync_protobuf::serde::deserialize(row.certificate)?)) + } + + /// Fetches the consensus certificate for the miniblock with the given `block_number`. + pub async fn certificate( + &mut self, + block_number: validator::BlockNumber, + ) -> anyhow::Result> { + let Some(row) = sqlx::query!( + r#" + SELECT + certificate + FROM + miniblocks_consensus + WHERE + number = $1 + "#, + i64::try_from(block_number.0)? + ) + .fetch_optional(self.storage.conn()) + .await? + else { + return Ok(None); + }; + Ok(Some(zksync_protobuf::serde::deserialize(row.certificate)?)) + } + + /// Converts the miniblock `block_number` into consensus payload. `Payload` is an + /// opaque format for the miniblock that consensus understands and generates a + /// certificate for it. + pub async fn block_payload( + &mut self, + block_number: validator::BlockNumber, + ) -> anyhow::Result> { + let block_number = MiniblockNumber(block_number.0.try_into()?); + let Some(block) = self + .storage + .sync_dal() + .sync_block_inner(block_number) + .await? + else { + return Ok(None); + }; + let transactions = self + .storage + .transactions_web3_dal() + .get_raw_miniblock_transactions(block_number) + .await?; + Ok(Some(block.into_payload(transactions))) + } + + /// Inserts a certificate for the miniblock `cert.header().number`. + /// It verifies that + /// * the certified payload matches the miniblock in storage + /// * the `cert.header().parent` matches the parent miniblock. + /// * the parent block already has a certificate. + /// NOTE: This is an extra secure way of storing a certificate, + /// which will help us to detect bugs in the consensus implementation + /// while it is "fresh". If it turns out to take too long, + /// we can remove the verification checks later. + pub async fn insert_certificate(&mut self, cert: &validator::CommitQC) -> anyhow::Result<()> { + let header = &cert.message.proposal; + let mut txn = self.storage.start_transaction().await?; + if let Some(last) = txn.consensus_dal().last_certificate().await? { + let last = &last.message.proposal; + anyhow::ensure!( + last.number.next() == header.number, + "expected certificate for a block after the current head block" + ); + anyhow::ensure!(last.hash() == header.parent, "parent block mismatch"); + } else { + anyhow::ensure!( + header.parent == validator::BlockHeaderHash::genesis_parent(), + "inserting first block with non-zero parent hash" + ); + } + let want_payload = txn + .consensus_dal() + .block_payload(cert.message.proposal.number) + .await? + .context("corresponding miniblock is missing")?; + anyhow::ensure!( + header.payload == want_payload.encode().hash(), + "consensus block payload doesn't match the miniblock" + ); + sqlx::query!( + r#" + INSERT INTO + miniblocks_consensus (number, certificate) + VALUES + ($1, $2) + "#, + header.number.0 as i64, + zksync_protobuf::serde::serialize(cert, serde_json::value::Serializer).unwrap(), + ) + .execute(txn.conn()) + .await?; + txn.commit().await?; + Ok(()) + } } #[cfg(test)] @@ -69,7 +223,7 @@ mod tests { let rng = &mut rand::thread_rng(); for _ in 0..10 { let want: ReplicaState = rng.gen(); - conn.consensus_dal().put_replica_state(&want).await.unwrap(); + conn.consensus_dal().set_replica_state(&want).await.unwrap(); assert_eq!( Some(want), conn.consensus_dal().replica_state().await.unwrap() diff --git a/core/lib/dal/src/eth_sender_dal.rs b/core/lib/dal/src/eth_sender_dal.rs index 797928740602..5e490e6590a2 100644 --- a/core/lib/dal/src/eth_sender_dal.rs +++ b/core/lib/dal/src/eth_sender_dal.rs @@ -211,7 +211,7 @@ impl EthSenderDal<'_, '_> { base_fee_per_gas: u64, priority_fee_per_gas: u64, tx_hash: H256, - raw_signed_tx: Vec, + raw_signed_tx: &[u8], ) -> anyhow::Result> { let priority_fee_per_gas = i64::try_from(priority_fee_per_gas).context("Can't convert u64 to i64")?; @@ -237,7 +237,7 @@ impl EthSenderDal<'_, '_> { RETURNING id "#, - eth_tx_id as u32, + eth_tx_id as i32, base_fee_per_gas, priority_fee_per_gas, tx_hash, diff --git a/core/lib/dal/src/events_dal.rs b/core/lib/dal/src/events_dal.rs index b7087985f520..9fedee444572 100644 --- a/core/lib/dal/src/events_dal.rs +++ b/core/lib/dal/src/events_dal.rs @@ -1,13 +1,17 @@ -use std::fmt; +use std::{collections::HashMap, fmt}; use sqlx::types::chrono::Utc; use zksync_types::{ + api, l2_to_l1_log::{L2ToL1Log, UserL2ToL1Log}, tx::IncludedTxLocation, MiniblockNumber, VmEvent, H256, }; -use crate::{models::storage_event::StorageL2ToL1Log, SqlxError, StorageProcessor}; +use crate::{ + models::storage_event::{StorageL2ToL1Log, StorageWeb3Log}, + SqlxError, StorageProcessor, +}; /// Wrapper around an optional event topic allowing to hex-format it for `COPY` instructions. #[derive(Debug)] @@ -182,11 +186,65 @@ impl EventsDal<'_, '_> { .unwrap(); } - pub(crate) async fn l2_to_l1_logs( + pub(crate) async fn get_logs_by_tx_hashes( &mut self, - tx_hash: H256, - ) -> Result, SqlxError> { - sqlx::query_as!( + hashes: &[H256], + ) -> Result>, SqlxError> { + let hashes = hashes + .iter() + .map(|hash| hash.as_bytes().to_vec()) + .collect::>(); + let logs: Vec<_> = sqlx::query_as!( + StorageWeb3Log, + r#" + SELECT + address, + topic1, + topic2, + topic3, + topic4, + value, + NULL::bytea AS "block_hash", + NULL::BIGINT AS "l1_batch_number?", + miniblock_number, + tx_hash, + tx_index_in_block, + event_index_in_block, + event_index_in_tx + FROM + events + WHERE + tx_hash = ANY ($1) + ORDER BY + miniblock_number ASC, + tx_index_in_block ASC, + event_index_in_block ASC + "#, + &hashes[..], + ) + .fetch_all(self.storage.conn()) + .await?; + + let mut result = HashMap::>::new(); + + for storage_log in logs { + let current_log = api::Log::from(storage_log); + let tx_hash = current_log.transaction_hash.unwrap(); + result.entry(tx_hash).or_default().push(current_log); + } + + Ok(result) + } + + pub(crate) async fn get_l2_to_l1_logs_by_hashes( + &mut self, + hashes: &[H256], + ) -> Result>, SqlxError> { + let hashes = &hashes + .iter() + .map(|hash| hash.as_bytes().to_vec()) + .collect::>(); + let logs: Vec<_> = sqlx::query_as!( StorageL2ToL1Log, r#" SELECT @@ -206,14 +264,27 @@ impl EventsDal<'_, '_> { FROM l2_to_l1_logs WHERE - tx_hash = $1 + tx_hash = ANY ($1) ORDER BY + tx_index_in_l1_batch ASC, log_index_in_tx ASC "#, - tx_hash.as_bytes() + &hashes[..] ) .fetch_all(self.storage.conn()) - .await + .await?; + + let mut result = HashMap::>::new(); + + for storage_log in logs { + let current_log = api::L2ToL1Log::from(storage_log); + result + .entry(current_log.transaction_hash) + .or_default() + .push(current_log); + } + + Ok(result) } } @@ -355,34 +426,41 @@ mod tests { let logs = conn .events_dal() - .l2_to_l1_logs(H256([1; 32])) + .get_l2_to_l1_logs_by_hashes(&[H256([1; 32])]) .await .unwrap(); + + let logs = logs.get(&H256([1; 32])).unwrap().clone(); + assert_eq!(logs.len(), first_logs.len()); for (i, log) in logs.iter().enumerate() { - assert_eq!(log.log_index_in_miniblock as usize, i); - assert_eq!(log.log_index_in_tx as usize, i); + assert_eq!(log.log_index.as_usize(), i); + assert_eq!(log.transaction_log_index.as_usize(), i); } for (log, expected_log) in logs.iter().zip(&first_logs) { - assert_eq!(log.key, expected_log.0.key.as_bytes()); - assert_eq!(log.value, expected_log.0.value.as_bytes()); - assert_eq!(log.sender, expected_log.0.sender.as_bytes()); + assert_eq!(log.key.as_bytes(), expected_log.0.key.as_bytes()); + assert_eq!(log.value.as_bytes(), expected_log.0.value.as_bytes()); + assert_eq!(log.sender.as_bytes(), expected_log.0.sender.as_bytes()); } let logs = conn .events_dal() - .l2_to_l1_logs(H256([2; 32])) + .get_l2_to_l1_logs_by_hashes(&[H256([2; 32])]) .await - .unwrap(); + .unwrap() + .get(&H256([2; 32])) + .unwrap() + .clone(); + assert_eq!(logs.len(), second_logs.len()); for (i, log) in logs.iter().enumerate() { - assert_eq!(log.log_index_in_miniblock as usize, i + first_logs.len()); - assert_eq!(log.log_index_in_tx as usize, i); + assert_eq!(log.log_index.as_usize(), i + first_logs.len()); + assert_eq!(log.transaction_log_index.as_usize(), i); } for (log, expected_log) in logs.iter().zip(&second_logs) { - assert_eq!(log.key, expected_log.0.key.as_bytes()); - assert_eq!(log.value, expected_log.0.value.as_bytes()); - assert_eq!(log.sender, expected_log.0.sender.as_bytes()); + assert_eq!(log.key.as_bytes(), expected_log.0.key.as_bytes()); + assert_eq!(log.value.as_bytes(), expected_log.0.value.as_bytes()); + assert_eq!(log.sender.as_bytes(), expected_log.0.sender.as_bytes()); } } } diff --git a/core/lib/dal/src/fri_gpu_prover_queue_dal.rs b/core/lib/dal/src/fri_gpu_prover_queue_dal.rs index a29298944449..56baa32ba9c8 100644 --- a/core/lib/dal/src/fri_gpu_prover_queue_dal.rs +++ b/core/lib/dal/src/fri_gpu_prover_queue_dal.rs @@ -1,8 +1,10 @@ use std::time::Duration; -use zksync_types::proofs::{GpuProverInstanceStatus, SocketAddress}; - -use crate::{time_utils::pg_interval_from_duration, StorageProcessor}; +use crate::{ + fri_prover_dal::types::{GpuProverInstanceStatus, SocketAddress}, + time_utils::pg_interval_from_duration, + StorageProcessor, +}; #[derive(Debug)] pub struct FriGpuProverQueueDal<'a, 'c> { diff --git a/core/lib/dal/src/fri_proof_compressor_dal.rs b/core/lib/dal/src/fri_proof_compressor_dal.rs index ee331204ec43..959e4304b761 100644 --- a/core/lib/dal/src/fri_proof_compressor_dal.rs +++ b/core/lib/dal/src/fri_proof_compressor_dal.rs @@ -2,12 +2,10 @@ use std::{collections::HashMap, str::FromStr, time::Duration}; use sqlx::Row; use strum::{Display, EnumString}; -use zksync_types::{ - proofs::{JobCountStatistics, StuckJobs}, - L1BatchNumber, -}; +use zksync_types::L1BatchNumber; use crate::{ + fri_prover_dal::types::{JobCountStatistics, StuckJobs}, time_utils::{duration_to_naive_time, pg_interval_from_duration}, StorageProcessor, }; diff --git a/core/lib/dal/src/fri_prover_dal.rs b/core/lib/dal/src/fri_prover_dal.rs index d9446182b7f2..f3970f08092a 100644 --- a/core/lib/dal/src/fri_prover_dal.rs +++ b/core/lib/dal/src/fri_prover_dal.rs @@ -1,12 +1,12 @@ use std::{collections::HashMap, convert::TryFrom, time::Duration}; use zksync_types::{ - basic_fri_types::CircuitIdRoundTuple, - proofs::{AggregationRound, FriProverJobMetadata, JobCountStatistics, StuckJobs}, + basic_fri_types::{AggregationRound, CircuitIdRoundTuple}, protocol_version::FriProtocolVersionId, L1BatchNumber, }; +use self::types::{FriProverJobMetadata, JobCountStatistics, StuckJobs}; use crate::{ instrument::InstrumentExt, metrics::MethodLatency, @@ -14,6 +14,223 @@ use crate::{ StorageProcessor, }; +// TODO (PLA-775): Should not be an embedded submodule in a concrete DAL file. +pub mod types { + //! Types exposed by the prover DAL for general-purpose use. + + use std::{net::IpAddr, ops::Add}; + + use sqlx::types::chrono::{DateTime, Utc}; + use zksync_types::{basic_fri_types::AggregationRound, L1BatchNumber}; + + #[derive(Debug, Clone)] + pub struct FriProverJobMetadata { + pub id: u32, + pub block_number: L1BatchNumber, + pub circuit_id: u8, + pub aggregation_round: AggregationRound, + pub sequence_number: usize, + pub depth: u16, + pub is_node_final_proof: bool, + } + + #[derive(Debug, Clone, Copy, Default)] + pub struct JobCountStatistics { + pub queued: usize, + pub in_progress: usize, + pub failed: usize, + pub successful: usize, + } + + impl Add for JobCountStatistics { + type Output = JobCountStatistics; + + fn add(self, rhs: Self) -> Self::Output { + Self { + queued: self.queued + rhs.queued, + in_progress: self.in_progress + rhs.in_progress, + failed: self.failed + rhs.failed, + successful: self.successful + rhs.successful, + } + } + } + + #[derive(Debug)] + pub struct StuckJobs { + pub id: u64, + pub status: String, + pub attempts: u64, + } + + // TODO (PLA-774): Redundant structure, should be replaced with `std::net::SocketAddr`. + #[derive(Debug, Clone)] + pub struct SocketAddress { + pub host: IpAddr, + pub port: u16, + } + + impl From for std::net::SocketAddr { + fn from(socket_address: SocketAddress) -> Self { + Self::new(socket_address.host, socket_address.port) + } + } + + impl From for SocketAddress { + fn from(socket_address: std::net::SocketAddr) -> Self { + Self { + host: socket_address.ip(), + port: socket_address.port(), + } + } + } + + #[derive(Debug, Clone)] + pub struct LeafAggregationJobMetadata { + pub id: u32, + pub block_number: L1BatchNumber, + pub circuit_id: u8, + pub prover_job_ids_for_proofs: Vec, + } + + #[derive(Debug, Clone)] + pub struct NodeAggregationJobMetadata { + pub id: u32, + pub block_number: L1BatchNumber, + pub circuit_id: u8, + pub depth: u16, + pub prover_job_ids_for_proofs: Vec, + } + + #[derive(Debug)] + pub struct JobPosition { + pub aggregation_round: AggregationRound, + pub sequence_number: usize, + } + + #[derive(Debug, Default)] + pub struct ProverJobStatusFailed { + pub started_at: DateTime, + pub error: String, + } + + #[derive(Debug)] + pub struct ProverJobStatusSuccessful { + pub started_at: DateTime, + pub time_taken: chrono::Duration, + } + + impl Default for ProverJobStatusSuccessful { + fn default() -> Self { + ProverJobStatusSuccessful { + started_at: DateTime::default(), + time_taken: chrono::Duration::zero(), + } + } + } + + #[derive(Debug, Default)] + pub struct ProverJobStatusInProgress { + pub started_at: DateTime, + } + + #[derive(Debug)] + pub struct WitnessJobStatusSuccessful { + pub started_at: DateTime, + pub time_taken: chrono::Duration, + } + + impl Default for WitnessJobStatusSuccessful { + fn default() -> Self { + WitnessJobStatusSuccessful { + started_at: DateTime::default(), + time_taken: chrono::Duration::zero(), + } + } + } + + #[derive(Debug, Default)] + pub struct WitnessJobStatusFailed { + pub started_at: DateTime, + pub error: String, + } + + #[derive(Debug, strum::Display, strum::EnumString, strum::AsRefStr)] + pub enum ProverJobStatus { + #[strum(serialize = "queued")] + Queued, + #[strum(serialize = "in_progress")] + InProgress(ProverJobStatusInProgress), + #[strum(serialize = "successful")] + Successful(ProverJobStatusSuccessful), + #[strum(serialize = "failed")] + Failed(ProverJobStatusFailed), + #[strum(serialize = "skipped")] + Skipped, + #[strum(serialize = "ignored")] + Ignored, + } + + #[derive(Debug, strum::Display, strum::EnumString, strum::AsRefStr)] + pub enum WitnessJobStatus { + #[strum(serialize = "failed")] + Failed(WitnessJobStatusFailed), + #[strum(serialize = "skipped")] + Skipped, + #[strum(serialize = "successful")] + Successful(WitnessJobStatusSuccessful), + #[strum(serialize = "waiting_for_artifacts")] + WaitingForArtifacts, + #[strum(serialize = "waiting_for_proofs")] + WaitingForProofs, + #[strum(serialize = "in_progress")] + InProgress, + #[strum(serialize = "queued")] + Queued, + } + + #[derive(Debug)] + pub struct WitnessJobInfo { + pub block_number: L1BatchNumber, + pub created_at: DateTime, + pub updated_at: DateTime, + pub status: WitnessJobStatus, + pub position: JobPosition, + } + + #[derive(Debug)] + pub struct ProverJobInfo { + pub id: u32, + pub block_number: L1BatchNumber, + pub circuit_type: String, + pub position: JobPosition, + pub input_length: u64, + pub status: ProverJobStatus, + pub attempts: u32, + pub created_at: DateTime, + pub updated_at: DateTime, + } + + #[derive(Debug)] + pub struct JobExtendedStatistics { + pub successful_padding: L1BatchNumber, + pub queued_padding: L1BatchNumber, + pub queued_padding_len: u32, + pub active_area: Vec, + } + + #[derive(Debug, Copy, Clone)] + pub enum GpuProverInstanceStatus { + // The instance is available for processing. + Available, + // The instance is running at full capacity. + Full, + // The instance is reserved by an synthesizer. + Reserved, + // The instance is not alive anymore. + Dead, + } +} + #[derive(Debug)] pub struct FriProverDal<'a, 'c> { pub(crate) storage: &'a mut StorageProcessor<'c>, diff --git a/core/lib/dal/src/fri_witness_generator_dal.rs b/core/lib/dal/src/fri_witness_generator_dal.rs index 874ad8d03689..57b45253dd76 100644 --- a/core/lib/dal/src/fri_witness_generator_dal.rs +++ b/core/lib/dal/src/fri_witness_generator_dal.rs @@ -2,15 +2,13 @@ use std::{collections::HashMap, convert::TryFrom, time::Duration}; use sqlx::Row; use zksync_types::{ - proofs::{ - AggregationRound, JobCountStatistics, LeafAggregationJobMetadata, - NodeAggregationJobMetadata, StuckJobs, - }, - protocol_version::FriProtocolVersionId, - L1BatchNumber, + basic_fri_types::AggregationRound, protocol_version::FriProtocolVersionId, L1BatchNumber, }; use crate::{ + fri_prover_dal::types::{ + JobCountStatistics, LeafAggregationJobMetadata, NodeAggregationJobMetadata, StuckJobs, + }, metrics::MethodLatency, time_utils::{duration_to_naive_time, pg_interval_from_duration}, StorageProcessor, diff --git a/core/lib/dal/src/gpu_prover_queue_dal.rs b/core/lib/dal/src/gpu_prover_queue_dal.rs deleted file mode 100644 index b424edd57456..000000000000 --- a/core/lib/dal/src/gpu_prover_queue_dal.rs +++ /dev/null @@ -1,218 +0,0 @@ -use std::{collections::HashMap, time::Duration}; - -use zksync_types::proofs::{GpuProverInstanceStatus, SocketAddress}; - -use crate::{time_utils::pg_interval_from_duration, StorageProcessor}; - -#[derive(Debug)] -pub struct GpuProverQueueDal<'a, 'c> { - pub(crate) storage: &'a mut StorageProcessor<'c>, -} - -impl GpuProverQueueDal<'_, '_> { - pub async fn lock_available_prover( - &mut self, - processing_timeout: Duration, - specialized_prover_group_id: u8, - region: String, - zone: String, - ) -> Option { - { - let processing_timeout = pg_interval_from_duration(processing_timeout); - let result: Option = sqlx::query!( - r#" - UPDATE gpu_prover_queue - SET - instance_status = 'reserved', - updated_at = NOW(), - processing_started_at = NOW() - WHERE - id IN ( - SELECT - id - FROM - gpu_prover_queue - WHERE - specialized_prover_group_id = $2 - AND region = $3 - AND zone = $4 - AND ( - instance_status = 'available' - OR ( - instance_status = 'reserved' - AND processing_started_at < NOW() - $1::INTERVAL - ) - ) - ORDER BY - updated_at ASC - LIMIT - 1 - FOR UPDATE - SKIP LOCKED - ) - RETURNING - gpu_prover_queue.* - "#, - &processing_timeout, - specialized_prover_group_id as i16, - region, - zone - ) - .fetch_optional(self.storage.conn()) - .await - .unwrap() - .map(|row| SocketAddress { - host: row.instance_host.network(), - port: row.instance_port as u16, - }); - - result - } - } - - pub async fn insert_prover_instance( - &mut self, - address: SocketAddress, - queue_capacity: usize, - specialized_prover_group_id: u8, - region: String, - zone: String, - num_gpu: u8, - ) { - { - sqlx::query!( - r#" - INSERT INTO - gpu_prover_queue ( - instance_host, - instance_port, - queue_capacity, - queue_free_slots, - instance_status, - specialized_prover_group_id, - region, - zone, - num_gpu, - created_at, - updated_at - ) - VALUES - (CAST($1::TEXT AS inet), $2, $3, $3, 'available', $4, $5, $6, $7, NOW(), NOW()) - ON CONFLICT (instance_host, instance_port, region, zone) DO - UPDATE - SET - instance_status = 'available', - queue_capacity = $3, - queue_free_slots = $3, - specialized_prover_group_id = $4, - region = $5, - zone = $6, - num_gpu = $7, - updated_at = NOW() - "#, - format!("{}",address.host), - address.port as i32, - queue_capacity as i32, - specialized_prover_group_id as i16, - region, - zone, - num_gpu as i16) - .execute(self.storage.conn()) - .await - .unwrap(); - } - } - - pub async fn update_prover_instance_status( - &mut self, - address: SocketAddress, - status: GpuProverInstanceStatus, - queue_free_slots: usize, - region: String, - zone: String, - ) { - { - sqlx::query!( - r#" - UPDATE gpu_prover_queue - SET - instance_status = $1, - updated_at = NOW(), - queue_free_slots = $4 - WHERE - instance_host = $2::TEXT::inet - AND instance_port = $3 - AND region = $5 - AND zone = $6 - "#, - format!("{:?}", status).to_lowercase(), - format!("{}", address.host), - address.port as i32, - queue_free_slots as i32, - region, - zone - ) - .execute(self.storage.conn()) - .await - .unwrap(); - } - } - - pub async fn update_prover_instance_from_full_to_available( - &mut self, - address: SocketAddress, - queue_free_slots: usize, - region: String, - zone: String, - ) { - { - sqlx::query!( - r#" - UPDATE gpu_prover_queue - SET - instance_status = 'available', - updated_at = NOW(), - queue_free_slots = $3 - WHERE - instance_host = $1::TEXT::inet - AND instance_port = $2 - AND instance_status = 'full' - AND region = $4 - AND zone = $5 - "#, - format!("{}", address.host), - address.port as i32, - queue_free_slots as i32, - region, - zone - ) - .execute(self.storage.conn()) - .await - .unwrap(); - } - } - - pub async fn get_prover_gpu_count_per_region_zone(&mut self) -> HashMap<(String, String), u64> { - { - sqlx::query!( - r#" - SELECT - region, - zone, - SUM(num_gpu) AS total_gpus - FROM - gpu_prover_queue - GROUP BY - region, - zone - "#, - ) - .fetch_all(self.storage.conn()) - .await - .unwrap() - .into_iter() - .map(|row| ((row.region, row.zone), row.total_gpus.unwrap() as u64)) - .collect() - } - } -} diff --git a/core/lib/dal/src/lib.rs b/core/lib/dal/src/lib.rs index d2e37230a373..3a5691a1c93e 100644 --- a/core/lib/dal/src/lib.rs +++ b/core/lib/dal/src/lib.rs @@ -13,9 +13,9 @@ use crate::{ fri_proof_compressor_dal::FriProofCompressorDal, fri_protocol_versions_dal::FriProtocolVersionsDal, fri_prover_dal::FriProverDal, fri_scheduler_dependency_tracker_dal::FriSchedulerDependencyTrackerDal, - fri_witness_generator_dal::FriWitnessGeneratorDal, gpu_prover_queue_dal::GpuProverQueueDal, - proof_generation_dal::ProofGenerationDal, protocol_versions_dal::ProtocolVersionsDal, - protocol_versions_web3_dal::ProtocolVersionsWeb3Dal, prover_dal::ProverDal, + fri_witness_generator_dal::FriWitnessGeneratorDal, proof_generation_dal::ProofGenerationDal, + protocol_versions_dal::ProtocolVersionsDal, + protocol_versions_web3_dal::ProtocolVersionsWeb3Dal, snapshot_recovery_dal::SnapshotRecoveryDal, snapshots_creator_dal::SnapshotsCreatorDal, snapshots_dal::SnapshotsDal, storage_dal::StorageDal, storage_logs_dal::StorageLogsDal, storage_logs_dedup_dal::StorageLogsDedupDal, storage_web3_dal::StorageWeb3Dal, @@ -42,7 +42,6 @@ pub mod fri_protocol_versions_dal; pub mod fri_prover_dal; pub mod fri_scheduler_dependency_tracker_dal; pub mod fri_witness_generator_dal; -pub mod gpu_prover_queue_dal; pub mod healthcheck; mod instrument; mod metrics; @@ -50,7 +49,6 @@ mod models; pub mod proof_generation_dal; pub mod protocol_versions_dal; pub mod protocol_versions_web3_dal; -pub mod prover_dal; pub mod snapshot_recovery_dal; pub mod snapshots_creator_dal; pub mod snapshots_dal; @@ -187,18 +185,10 @@ impl<'a> StorageProcessor<'a> { TokensWeb3Dal { storage: self } } - pub fn prover_dal(&mut self) -> ProverDal<'_, 'a> { - ProverDal { storage: self } - } - pub fn contract_verification_dal(&mut self) -> ContractVerificationDal<'_, 'a> { ContractVerificationDal { storage: self } } - pub fn gpu_prover_queue_dal(&mut self) -> GpuProverQueueDal<'_, 'a> { - GpuProverQueueDal { storage: self } - } - pub fn protocol_versions_dal(&mut self) -> ProtocolVersionsDal<'_, 'a> { ProtocolVersionsDal { storage: self } } diff --git a/core/lib/dal/src/models/proto/mod.proto b/core/lib/dal/src/models/proto/mod.proto index b817d35e0323..33e8bbb03242 100644 --- a/core/lib/dal/src/models/proto/mod.proto +++ b/core/lib/dal/src/models/proto/mod.proto @@ -2,9 +2,24 @@ syntax = "proto3"; package zksync.dal; -import "zksync/roles/validator.proto"; +message Transaction { + // Default derive(serde::Serialize) encoding of the zksync_types::Transaction. + // TODO(BFT-407): it is neither efficient, unique, nor suitable for version control. + // replace with a more robust encoding. + optional string json = 1; // required +} -message ConsensusBlockFields { - optional roles.validator.BlockHeaderHash parent = 1; - optional roles.validator.CommitQC justification = 2; +message Payload { + // zksync-era ProtocolVersionId + optional uint32 protocol_version = 9; // required; u16 + optional bytes hash = 1; // required; H256 + optional uint32 l1_batch_number = 2; // required + optional uint64 timestamp = 3; // required; seconds since UNIX epoch + optional uint64 l1_gas_price = 4; // required; gwei + optional uint64 l2_fair_gas_price = 5; // required; gwei + optional uint64 fair_pubdata_price = 11; // required since 1.4.1; gwei + optional uint32 virtual_blocks = 6; // required + optional bytes operator_address = 7; // required; H160 + repeated Transaction transactions = 8; + optional bool last_in_batch = 10; // required } diff --git a/core/lib/dal/src/models/storage_block.rs b/core/lib/dal/src/models/storage_block.rs index c48e3d8c7104..7cd96e7f676e 100644 --- a/core/lib/dal/src/models/storage_block.rs +++ b/core/lib/dal/src/models/storage_block.rs @@ -12,8 +12,9 @@ use zksync_types::{ api, block::{L1BatchHeader, MiniblockHeader}, commitment::{L1BatchMetaParameters, L1BatchMetadata}, + fee_model::{BatchFeeInput, L1PeggedBatchFeeModelInput, PubdataIndependentBatchFeeModelInput}, l2_to_l1_log::{L2ToL1Log, SystemL2ToL1Log, UserL2ToL1Log}, - Address, L1BatchNumber, MiniblockNumber, H2048, H256, + Address, L1BatchNumber, MiniblockNumber, ProtocolVersionId, H2048, H256, }; #[derive(Debug, Error)] @@ -27,18 +28,13 @@ pub enum StorageL1BatchConvertError { pub struct StorageL1BatchHeader { pub number: i64, pub timestamp: i64, - pub is_finished: bool, pub l1_tx_count: i32, pub l2_tx_count: i32, - pub fee_account_address: Vec, pub l2_to_l1_logs: Vec>, pub l2_to_l1_messages: Vec>, pub bloom: Vec, pub priority_ops_onchain_data: Vec>, pub used_contract_hashes: serde_json::Value, - pub base_fee_per_gas: BigDecimal, - pub l1_gas_price: i64, - pub l2_fair_gas_price: i64, pub bootloader_code_hash: Option>, pub default_aa_code_hash: Option>, pub protocol_version: Option, @@ -66,9 +62,7 @@ impl From for L1BatchHeader { L1BatchHeader { number: L1BatchNumber(l1_batch.number as u32), - is_finished: l1_batch.is_finished, timestamp: l1_batch.timestamp as u64, - fee_account_address: Address::from_slice(&l1_batch.fee_account_address), priority_ops_onchain_data, l1_tx_count: l1_batch.l1_tx_count as u16, l2_tx_count: l1_batch.l2_tx_count as u16, @@ -78,16 +72,10 @@ impl From for L1BatchHeader { bloom: H2048::from_slice(&l1_batch.bloom), used_contract_hashes: serde_json::from_value(l1_batch.used_contract_hashes) .expect("invalid value for used_contract_hashes in the DB"), - base_fee_per_gas: l1_batch - .base_fee_per_gas - .to_u64() - .expect("base_fee_per_gas should fit in u64"), base_system_contracts_hashes: convert_base_system_contracts_hashes( l1_batch.bootloader_code_hash, l1_batch.default_aa_code_hash, ), - l1_gas_price: l1_batch.l1_gas_price as u64, - l2_fair_gas_price: l1_batch.l2_fair_gas_price as u64, system_logs: system_logs.into_iter().map(SystemL2ToL1Log).collect(), protocol_version: l1_batch .protocol_version @@ -125,10 +113,8 @@ fn convert_base_system_contracts_hashes( pub struct StorageL1Batch { pub number: i64, pub timestamp: i64, - pub is_finished: bool, pub l1_tx_count: i32, pub l2_tx_count: i32, - pub fee_account_address: Vec, pub bloom: Vec, pub l2_to_l1_logs: Vec>, pub priority_ops_onchain_data: Vec>, @@ -160,10 +146,6 @@ pub struct StorageL1Batch { pub used_contract_hashes: serde_json::Value, - pub base_fee_per_gas: BigDecimal, - pub l1_gas_price: i64, - pub l2_fair_gas_price: i64, - pub system_logs: Vec>, pub compressed_state_diffs: Option>, @@ -187,9 +169,7 @@ impl From for L1BatchHeader { L1BatchHeader { number: L1BatchNumber(l1_batch.number as u32), - is_finished: l1_batch.is_finished, timestamp: l1_batch.timestamp as u64, - fee_account_address: Address::from_slice(&l1_batch.fee_account_address), priority_ops_onchain_data, l1_tx_count: l1_batch.l1_tx_count as u16, l2_tx_count: l1_batch.l2_tx_count as u16, @@ -199,16 +179,10 @@ impl From for L1BatchHeader { bloom: H2048::from_slice(&l1_batch.bloom), used_contract_hashes: serde_json::from_value(l1_batch.used_contract_hashes) .expect("invalid value for used_contract_hashes in the DB"), - base_fee_per_gas: l1_batch - .base_fee_per_gas - .to_u64() - .expect("base_fee_per_gas should fit in u64"), base_system_contracts_hashes: convert_base_system_contracts_hashes( l1_batch.bootloader_code_hash, l1_batch.default_aa_code_hash, ), - l1_gas_price: l1_batch.l1_gas_price as u64, - l2_fair_gas_price: l1_batch.l2_fair_gas_price as u64, system_logs: system_logs.into_iter().map(SystemL2ToL1Log).collect(), protocol_version: l1_batch .protocol_version @@ -296,27 +270,32 @@ pub fn web3_block_number_to_sql(block_number: api::BlockNumber) -> String { match block_number { api::BlockNumber::Number(number) => number.to_string(), api::BlockNumber::Earliest => 0.to_string(), - api::BlockNumber::Pending => { - "(SELECT (MAX(number) + 1) as number FROM miniblocks)".to_string() - } + api::BlockNumber::Pending => " + (SELECT COALESCE( + (SELECT (MAX(number) + 1) AS number FROM miniblocks), + (SELECT (MAX(miniblock_number) + 1) AS number FROM snapshot_recovery), + 0 + ) AS number) + " + .to_string(), api::BlockNumber::Latest | api::BlockNumber::Committed => { - "(SELECT MAX(number) as number FROM miniblocks)".to_string() + "(SELECT MAX(number) AS number FROM miniblocks)".to_string() } api::BlockNumber::Finalized => " - (SELECT COALESCE( - ( - SELECT MAX(number) FROM miniblocks - WHERE l1_batch_number = ( - SELECT MAX(number) FROM l1_batches - JOIN eth_txs ON - l1_batches.eth_execute_tx_id = eth_txs.id - WHERE - eth_txs.confirmed_eth_tx_history_id IS NOT NULL - ) - ), - 0 - ) as number) - " + (SELECT COALESCE( + ( + SELECT MAX(number) FROM miniblocks + WHERE l1_batch_number = ( + SELECT MAX(number) FROM l1_batches + JOIN eth_txs ON + l1_batches.eth_execute_tx_id = eth_txs.id + WHERE + eth_txs.confirmed_eth_tx_history_id IS NOT NULL + ) + ), + 0 + ) AS number) + " .to_string(), } } @@ -339,7 +318,7 @@ pub fn bind_block_where_sql_params<'q>( query: Query<'q, Postgres, PgArguments>, ) -> Query<'q, Postgres, PgArguments> { match block_id { - // these block_id types result in `$1` in the query string, which we have to `bind` + // these `block_id` types result in `$1` in the query string, which we have to `bind` api::BlockId::Hash(block_hash) => query.bind(block_hash.as_bytes()), api::BlockId::Number(api::BlockNumber::Number(number)) => { query.bind(number.as_u64() as i64) @@ -369,61 +348,58 @@ pub struct StorageBlockDetails { pub l2_fair_gas_price: i64, pub bootloader_code_hash: Option>, pub default_aa_code_hash: Option>, - pub fee_account_address: Option>, // May be None if the block is not yet sealed + pub fee_account_address: Vec, pub protocol_version: Option, } -impl StorageBlockDetails { - pub(crate) fn into_block_details(self, current_operator_address: Address) -> api::BlockDetails { - let status = if self.number == 0 || self.execute_tx_hash.is_some() { +impl From for api::BlockDetails { + fn from(details: StorageBlockDetails) -> Self { + let status = if details.number == 0 || details.execute_tx_hash.is_some() { api::BlockStatus::Verified } else { api::BlockStatus::Sealed }; let base = api::BlockDetailsBase { - timestamp: self.timestamp as u64, - l1_tx_count: self.l1_tx_count as usize, - l2_tx_count: self.l2_tx_count as usize, + timestamp: details.timestamp as u64, + l1_tx_count: details.l1_tx_count as usize, + l2_tx_count: details.l2_tx_count as usize, status, - root_hash: self.root_hash.as_deref().map(H256::from_slice), - commit_tx_hash: self + root_hash: details.root_hash.as_deref().map(H256::from_slice), + commit_tx_hash: details .commit_tx_hash .as_deref() .map(|hash| H256::from_str(hash).expect("Incorrect commit_tx hash")), - committed_at: self + committed_at: details .committed_at .map(|committed_at| DateTime::from_naive_utc_and_offset(committed_at, Utc)), - prove_tx_hash: self + prove_tx_hash: details .prove_tx_hash .as_deref() .map(|hash| H256::from_str(hash).expect("Incorrect prove_tx hash")), - proven_at: self + proven_at: details .proven_at .map(|proven_at| DateTime::::from_naive_utc_and_offset(proven_at, Utc)), - execute_tx_hash: self + execute_tx_hash: details .execute_tx_hash .as_deref() .map(|hash| H256::from_str(hash).expect("Incorrect execute_tx hash")), - executed_at: self + executed_at: details .executed_at .map(|executed_at| DateTime::::from_naive_utc_and_offset(executed_at, Utc)), - l1_gas_price: self.l1_gas_price as u64, - l2_fair_gas_price: self.l2_fair_gas_price as u64, + l1_gas_price: details.l1_gas_price as u64, + l2_fair_gas_price: details.l2_fair_gas_price as u64, base_system_contracts_hashes: convert_base_system_contracts_hashes( - self.bootloader_code_hash, - self.default_aa_code_hash, + details.bootloader_code_hash, + details.default_aa_code_hash, ), }; api::BlockDetails { base, - number: MiniblockNumber(self.number as u32), - l1_batch_number: L1BatchNumber(self.l1_batch_number as u32), - operator_address: self - .fee_account_address - .map(|fee_account_address| Address::from_slice(&fee_account_address)) - .unwrap_or(current_operator_address), - protocol_version: self + number: MiniblockNumber(details.number as u32), + l1_batch_number: L1BatchNumber(details.l1_batch_number as u32), + operator_address: Address::from_slice(&details.fee_account_address), + protocol_version: details .protocol_version .map(|v| (v as u16).try_into().unwrap()), } @@ -504,6 +480,7 @@ pub struct StorageMiniblockHeader { pub hash: Vec, pub l1_tx_count: i32, pub l2_tx_count: i32, + pub fee_account_address: Vec, pub base_fee_per_gas: BigDecimal, pub l1_gas_price: i64, // L1 gas price assumed in the corresponding batch @@ -513,29 +490,55 @@ pub struct StorageMiniblockHeader { pub default_aa_code_hash: Option>, pub protocol_version: Option, + pub fair_pubdata_price: Option, + + pub gas_per_pubdata_limit: i64, + // The maximal number of virtual blocks that can be created with this miniblock. // If this value is greater than zero, then at least 1 will be created, but no more than - // min(virtual_blocks, miniblock_number - virtual_block_number), i.e. making sure that virtual blocks + // `min(virtual_blocks`, `miniblock_number - virtual_block_number`), i.e. making sure that virtual blocks // never go beyond the miniblock they are based on. pub virtual_blocks: i64, } impl From for MiniblockHeader { fn from(row: StorageMiniblockHeader) -> Self { + let protocol_version = row.protocol_version.map(|v| (v as u16).try_into().unwrap()); + + let fee_input = protocol_version + .filter(|version: &ProtocolVersionId| version.is_post_1_4_1()) + .map(|_| { + BatchFeeInput::PubdataIndependent(PubdataIndependentBatchFeeModelInput { + fair_pubdata_price: row + .fair_pubdata_price + .expect("No fair pubdata price for 1.4.1 miniblock") + as u64, + fair_l2_gas_price: row.l2_fair_gas_price as u64, + l1_gas_price: row.l1_gas_price as u64, + }) + }) + .unwrap_or_else(|| { + BatchFeeInput::L1Pegged(L1PeggedBatchFeeModelInput { + fair_l2_gas_price: row.l2_fair_gas_price as u64, + l1_gas_price: row.l1_gas_price as u64, + }) + }); + MiniblockHeader { number: MiniblockNumber(row.number as u32), timestamp: row.timestamp as u64, hash: H256::from_slice(&row.hash), l1_tx_count: row.l1_tx_count as u16, l2_tx_count: row.l2_tx_count as u16, + fee_account_address: Address::from_slice(&row.fee_account_address), base_fee_per_gas: row.base_fee_per_gas.to_u64().unwrap(), - l1_gas_price: row.l1_gas_price as u64, - l2_fair_gas_price: row.l2_fair_gas_price as u64, + batch_fee_input: fee_input, base_system_contracts_hashes: convert_base_system_contracts_hashes( row.bootloader_code_hash, row.default_aa_code_hash, ), - protocol_version: row.protocol_version.map(|v| (v as u16).try_into().unwrap()), + gas_per_pubdata_limit: row.gas_per_pubdata_limit as u64, + protocol_version, virtual_blocks: row.virtual_blocks as u32, } } @@ -558,65 +561,3 @@ impl ResolvedL1BatchForMiniblock { self.miniblock_l1_batch.unwrap_or(self.pending_l1_batch) } } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_web3_block_number_to_sql_earliest() { - let sql = web3_block_number_to_sql(api::BlockNumber::Earliest); - assert_eq!(sql, 0.to_string()); - } - - #[test] - fn test_web3_block_number_to_sql_pending() { - let sql = web3_block_number_to_sql(api::BlockNumber::Pending); - assert_eq!( - sql, - "(SELECT (MAX(number) + 1) as number FROM miniblocks)".to_string() - ); - } - - #[test] - fn test_web3_block_number_to_sql_latest() { - let sql = web3_block_number_to_sql(api::BlockNumber::Latest); - assert_eq!( - sql, - "(SELECT MAX(number) as number FROM miniblocks)".to_string() - ); - } - - #[test] - fn test_web3_block_number_to_sql_committed() { - let sql = web3_block_number_to_sql(api::BlockNumber::Committed); - assert_eq!( - sql, - "(SELECT MAX(number) as number FROM miniblocks)".to_string() - ); - } - - #[test] - fn test_web3_block_number_to_sql_finalized() { - let sql = web3_block_number_to_sql(api::BlockNumber::Finalized); - assert_eq!( - sql, - " - (SELECT COALESCE( - ( - SELECT MAX(number) FROM miniblocks - WHERE l1_batch_number = ( - SELECT MAX(number) FROM l1_batches - JOIN eth_txs ON - l1_batches.eth_execute_tx_id = eth_txs.id - WHERE - eth_txs.confirmed_eth_tx_history_id IS NOT NULL - ) - ), - 0 - ) as number) - " - .to_string() - ); - } -} diff --git a/core/lib/dal/src/models/storage_event.rs b/core/lib/dal/src/models/storage_event.rs index 001e4a2547a8..7de9dae73c04 100644 --- a/core/lib/dal/src/models/storage_event.rs +++ b/core/lib/dal/src/models/storage_event.rs @@ -43,7 +43,7 @@ impl From for Log { transaction_hash: Some(H256::from_slice(&log.tx_hash)), transaction_index: Some(Index::from(log.tx_index_in_block as u32)), log_index: Some(U256::from(log.event_index_in_block as u32)), - transaction_log_index: Some(U256::from(log.event_index_in_block as u32)), + transaction_log_index: Some(U256::from(log.event_index_in_tx as u32)), log_type: None, removed: Some(false), } diff --git a/core/lib/dal/src/models/storage_log.rs b/core/lib/dal/src/models/storage_log.rs index adca6742d095..fee544a19973 100644 --- a/core/lib/dal/src/models/storage_log.rs +++ b/core/lib/dal/src/models/storage_log.rs @@ -1,37 +1,36 @@ -use sqlx::types::chrono::NaiveDateTime; -use zksync_types::{AccountTreeId, Address, StorageKey, StorageLog, StorageLogKind, H256, U256}; +use zksync_types::{L1BatchNumber, MiniblockNumber, H160, H256, U256}; -#[derive(Debug, Clone, sqlx::FromRow)] -pub struct DBStorageLog { - pub id: i64, - pub hashed_key: Vec, - pub address: Vec, - pub key: Vec, - pub value: Vec, - pub operation_number: i32, - pub tx_hash: Vec, - pub miniblock_number: i64, - pub created_at: NaiveDateTime, - pub updated_at: NaiveDateTime, +/// Model of the initial write record from the `initial_writes` table. Should only be used in tests. +#[derive(Debug, PartialEq)] +pub struct DbInitialWrite { + pub hashed_key: H256, + pub l1_batch_number: L1BatchNumber, + pub index: u64, } -impl From for StorageLog { - fn from(log: DBStorageLog) -> StorageLog { - StorageLog { - kind: StorageLogKind::Write, - key: StorageKey::new( - AccountTreeId::new(Address::from_slice(&log.address)), - H256::from_slice(&log.key), - ), - value: H256::from_slice(&log.value), - } - } +/// Model of the storage log record from the `storage_logs` table. Should only be used in tests. +#[derive(Debug, PartialEq)] +pub struct DbStorageLog { + pub hashed_key: H256, + pub address: H160, + pub key: H256, + pub value: H256, + pub operation_number: u64, + pub tx_hash: H256, + pub miniblock_number: MiniblockNumber, } // We don't want to rely on the Merkle tree crate to import a single type, so we duplicate `TreeEntry` here. #[derive(Debug, Clone, Copy)] -pub struct StorageTreeEntry { - pub key: U256, +pub struct StorageRecoveryLogEntry { + pub key: H256, pub value: H256, pub leaf_index: u64, } + +impl StorageRecoveryLogEntry { + /// Converts `key` to the format used by the Merkle tree (little-endian [`U256`]). + pub fn tree_key(&self) -> U256 { + U256::from_little_endian(&self.key.0) + } +} diff --git a/core/lib/dal/src/models/storage_prover_job_info.rs b/core/lib/dal/src/models/storage_prover_job_info.rs index 3242953b39dd..efe6e8cb69d9 100644 --- a/core/lib/dal/src/models/storage_prover_job_info.rs +++ b/core/lib/dal/src/models/storage_prover_job_info.rs @@ -1,12 +1,11 @@ use std::{convert::TryFrom, panic, str::FromStr}; use sqlx::types::chrono::{DateTime, NaiveDateTime, NaiveTime, Utc}; -use zksync_types::{ - proofs::{ - AggregationRound, JobPosition, ProverJobInfo, ProverJobStatus, ProverJobStatusFailed, - ProverJobStatusInProgress, ProverJobStatusSuccessful, - }, - L1BatchNumber, +use zksync_types::{basic_fri_types::AggregationRound, L1BatchNumber}; + +use crate::fri_prover_dal::types::{ + JobPosition, ProverJobInfo, ProverJobStatus, ProverJobStatusFailed, ProverJobStatusInProgress, + ProverJobStatusSuccessful, }; #[derive(sqlx::FromRow)] diff --git a/core/lib/dal/src/models/storage_sync.rs b/core/lib/dal/src/models/storage_sync.rs index e816e5a72ab7..db1487a45489 100644 --- a/core/lib/dal/src/models/storage_sync.rs +++ b/core/lib/dal/src/models/storage_sync.rs @@ -1,8 +1,10 @@ use anyhow::Context as _; use zksync_consensus_roles::validator; use zksync_contracts::BaseSystemContractsHashes; -use zksync_protobuf::{read_required, ProtoFmt}; -use zksync_types::{api::en, Address, L1BatchNumber, MiniblockNumber, Transaction, H160, H256}; +use zksync_protobuf::{required, ProtoFmt}; +use zksync_types::{ + api::en, Address, L1BatchNumber, MiniblockNumber, ProtocolVersionId, Transaction, H160, H256, +}; #[derive(Debug, Clone, sqlx::FromRow)] pub(crate) struct StorageSyncBlock { @@ -14,13 +16,13 @@ pub(crate) struct StorageSyncBlock { pub l1_gas_price: i64, // L2 gas price assumed in the corresponding batch pub l2_fair_gas_price: i64, + pub fair_pubdata_price: Option, pub bootloader_code_hash: Option>, pub default_aa_code_hash: Option>, - pub fee_account_address: Option>, // May be None if the block is not yet sealed + pub fee_account_address: Vec, pub protocol_version: i32, pub virtual_blocks: i64, pub hash: Vec, - pub consensus: Option, } fn parse_h256(bytes: &[u8]) -> anyhow::Result { @@ -31,117 +33,190 @@ fn parse_h160(bytes: &[u8]) -> anyhow::Result { Ok(<[u8; 20]>::try_from(bytes).context("invalid size")?.into()) } -impl StorageSyncBlock { - pub(crate) fn into_sync_block( - self, - current_operator_address: Address, - transactions: Option>, - ) -> anyhow::Result { - Ok(en::SyncBlock { - number: MiniblockNumber(self.number.try_into().context("number")?), +pub(crate) struct SyncBlock { + pub number: MiniblockNumber, + pub l1_batch_number: L1BatchNumber, + pub last_in_batch: bool, + pub timestamp: u64, + pub l1_gas_price: u64, + pub l2_fair_gas_price: u64, + pub fair_pubdata_price: Option, + pub base_system_contracts_hashes: BaseSystemContractsHashes, + pub fee_account_address: Address, + pub virtual_blocks: u32, + pub hash: H256, + pub protocol_version: ProtocolVersionId, +} + +impl TryFrom for SyncBlock { + type Error = anyhow::Error; + fn try_from(block: StorageSyncBlock) -> anyhow::Result { + Ok(Self { + number: MiniblockNumber(block.number.try_into().context("number")?), l1_batch_number: L1BatchNumber( - self.l1_batch_number.try_into().context("l1_batch_number")?, + block + .l1_batch_number + .try_into() + .context("l1_batch_number")?, ), - last_in_batch: self - .last_batch_miniblock - .map(|n| n == self.number) - .unwrap_or(false), - timestamp: self.timestamp.try_into().context("timestamp")?, - l1_gas_price: self.l1_gas_price.try_into().context("l1_gas_price")?, - l2_fair_gas_price: self + last_in_batch: block.last_batch_miniblock == Some(block.number), + timestamp: block.timestamp.try_into().context("timestamp")?, + l1_gas_price: block.l1_gas_price.try_into().context("l1_gas_price")?, + l2_fair_gas_price: block .l2_fair_gas_price .try_into() .context("l2_fair_gas_price")?, + fair_pubdata_price: block + .fair_pubdata_price + .map(|v| v.try_into().context("fair_pubdata_price")) + .transpose()?, // TODO (SMA-1635): Make these fields non optional in database base_system_contracts_hashes: BaseSystemContractsHashes { bootloader: parse_h256( - &self + &block .bootloader_code_hash .context("bootloader_code_hash should not be none")?, ) .context("bootloader_code_hash")?, default_aa: parse_h256( - &self + &block .default_aa_code_hash .context("default_aa_code_hash should not be none")?, ) .context("default_aa_code_hash")?, }, - operator_address: match self.fee_account_address { - Some(addr) => parse_h160(&addr).context("fee_account_address")?, - None => current_operator_address, - }, - transactions, - virtual_blocks: Some(self.virtual_blocks.try_into().context("virtual_blocks")?), - hash: Some(parse_h256(&self.hash).context("hash")?), - protocol_version: u16::try_from(self.protocol_version) + fee_account_address: parse_h160(&block.fee_account_address) + .context("fee_account_address")?, + virtual_blocks: block.virtual_blocks.try_into().context("virtual_blocks")?, + hash: parse_h256(&block.hash).context("hash")?, + protocol_version: u16::try_from(block.protocol_version) .context("protocol_version")? .try_into() .context("protocol_version")?, - consensus: match self.consensus { - None => None, - Some(v) => { - let v: ConsensusBlockFields = - zksync_protobuf::serde::deserialize(v).context("consensus")?; - Some(v.encode()) - } - }, }) } } -/// Consensus-related L2 block (= miniblock) fields. -#[derive(Debug, Clone, PartialEq)] -pub struct ConsensusBlockFields { - /// Hash of the previous consensus block. - pub parent: validator::BlockHeaderHash, - /// Quorum certificate for the block. - pub justification: validator::CommitQC, -} - -impl ConsensusBlockFields { - pub fn decode(src: &en::ConsensusBlockFields) -> anyhow::Result { - zksync_protobuf::decode(&src.0 .0) +impl SyncBlock { + pub(crate) fn into_api(self, transactions: Option>) -> en::SyncBlock { + en::SyncBlock { + number: self.number, + l1_batch_number: self.l1_batch_number, + last_in_batch: self.last_in_batch, + timestamp: self.timestamp, + l1_gas_price: self.l1_gas_price, + l2_fair_gas_price: self.l2_fair_gas_price, + fair_pubdata_price: self.fair_pubdata_price, + base_system_contracts_hashes: self.base_system_contracts_hashes, + operator_address: self.fee_account_address, + transactions, + virtual_blocks: Some(self.virtual_blocks), + hash: Some(self.hash), + protocol_version: self.protocol_version, + } } - pub fn encode(&self) -> en::ConsensusBlockFields { - en::ConsensusBlockFields(zksync_protobuf::encode(self).into()) + pub(crate) fn into_payload(self, transactions: Vec) -> Payload { + Payload { + protocol_version: self.protocol_version, + hash: self.hash, + l1_batch_number: self.l1_batch_number, + timestamp: self.timestamp, + l1_gas_price: self.l1_gas_price, + l2_fair_gas_price: self.l2_fair_gas_price, + fair_pubdata_price: self.fair_pubdata_price, + virtual_blocks: self.virtual_blocks, + operator_address: self.fee_account_address, + transactions, + last_in_batch: self.last_in_batch, + } } } -impl ProtoFmt for ConsensusBlockFields { - type Proto = crate::models::proto::ConsensusBlockFields; +/// L2 block (= miniblock) payload. +#[derive(Debug, PartialEq)] +pub struct Payload { + pub protocol_version: ProtocolVersionId, + pub hash: H256, + pub l1_batch_number: L1BatchNumber, + pub timestamp: u64, + pub l1_gas_price: u64, + pub l2_fair_gas_price: u64, + pub fair_pubdata_price: Option, + pub virtual_blocks: u32, + pub operator_address: Address, + pub transactions: Vec, + pub last_in_batch: bool, +} + +impl ProtoFmt for Payload { + type Proto = super::proto::Payload; + + fn read(message: &Self::Proto) -> anyhow::Result { + let mut transactions = Vec::with_capacity(message.transactions.len()); + for (i, tx) in message.transactions.iter().enumerate() { + transactions.push( + required(&tx.json) + .and_then(|json_str| Ok(serde_json::from_str(json_str)?)) + .with_context(|| format!("transaction[{i}]"))?, + ); + } - fn read(r: &Self::Proto) -> anyhow::Result { Ok(Self { - parent: read_required(&r.parent).context("parent")?, - justification: read_required(&r.justification).context("justification")?, + protocol_version: required(&message.protocol_version) + .and_then(|x| Ok(ProtocolVersionId::try_from(u16::try_from(*x)?)?)) + .context("protocol_version")?, + hash: required(&message.hash) + .and_then(|h| parse_h256(h)) + .context("hash")?, + l1_batch_number: L1BatchNumber( + *required(&message.l1_batch_number).context("l1_batch_number")?, + ), + timestamp: *required(&message.timestamp).context("timestamp")?, + l1_gas_price: *required(&message.l1_gas_price).context("l1_gas_price")?, + l2_fair_gas_price: *required(&message.l2_fair_gas_price) + .context("l2_fair_gas_price")?, + fair_pubdata_price: message.fair_pubdata_price, + virtual_blocks: *required(&message.virtual_blocks).context("virtual_blocks")?, + operator_address: required(&message.operator_address) + .and_then(|a| parse_h160(a)) + .context("operator_address")?, + transactions, + last_in_batch: *required(&message.last_in_batch).context("last_in_batch")?, }) } fn build(&self) -> Self::Proto { Self::Proto { - parent: Some(self.parent.build()), - justification: Some(self.justification.build()), + protocol_version: Some((self.protocol_version as u16).into()), + hash: Some(self.hash.as_bytes().into()), + l1_batch_number: Some(self.l1_batch_number.0), + timestamp: Some(self.timestamp), + l1_gas_price: Some(self.l1_gas_price), + l2_fair_gas_price: Some(self.l2_fair_gas_price), + fair_pubdata_price: self.fair_pubdata_price, + virtual_blocks: Some(self.virtual_blocks), + operator_address: Some(self.operator_address.as_bytes().into()), + // Transactions are stored in execution order, therefore order is deterministic. + transactions: self + .transactions + .iter() + .map(|t| super::proto::Transaction { + // TODO: There is no guarantee that json encoding here will be deterministic. + json: Some(serde_json::to_string(t).unwrap()), + }) + .collect(), + last_in_batch: Some(self.last_in_batch), } } } -#[cfg(test)] -mod tests { - use rand::Rng; - use zksync_consensus_roles::validator; - - use super::ConsensusBlockFields; +impl Payload { + pub fn decode(payload: &validator::Payload) -> anyhow::Result { + zksync_protobuf::decode(&payload.0) + } - #[tokio::test] - async fn encode_decode() { - let rng = &mut rand::thread_rng(); - let block = rng.gen::(); - let want = ConsensusBlockFields { - parent: block.header.parent, - justification: block.justification, - }; - assert_eq!(want, ConsensusBlockFields::decode(&want.encode()).unwrap()); + pub fn encode(&self) -> validator::Payload { + validator::Payload(zksync_protobuf::encode(self)) } } diff --git a/core/lib/dal/src/models/storage_transaction.rs b/core/lib/dal/src/models/storage_transaction.rs index 8e03590dcc59..82732f5ab99b 100644 --- a/core/lib/dal/src/models/storage_transaction.rs +++ b/core/lib/dal/src/models/storage_transaction.rs @@ -9,7 +9,7 @@ use sqlx::{ }; use zksync_types::{ api, - api::{TransactionDetails, TransactionStatus}, + api::{TransactionDetails, TransactionReceipt, TransactionStatus}, fee::Fee, l1::{OpProcessingType, PriorityQueueType}, l2::TransactionType, @@ -21,7 +21,7 @@ use zksync_types::{ Nonce, PackedEthSignature, PriorityOpId, Transaction, EIP_1559_TX_TYPE, EIP_2930_TX_TYPE, EIP_712_TX_TYPE, H160, H256, PRIORITY_OPERATION_L2_TX_TYPE, PROTOCOL_UPGRADE_TX_TYPE, U256, }; -use zksync_utils::bigdecimal_to_u256; +use zksync_utils::{bigdecimal_to_u256, h256_to_account_address}; use crate::BigDecimal; @@ -119,7 +119,7 @@ impl From for L1TxCommonData { // `tx.hash` represents the transaction hash obtained from the execution results, // and it should be exactly the same as the canonical tx hash calculated from the - // transaction data, so we don't store it as a separate "canonical_tx_hash" field. + // transaction data, so we don't store it as a separate `canonical_tx_hash` field. let canonical_tx_hash = H256::from_slice(&tx.hash); L1TxCommonData { @@ -322,6 +322,83 @@ impl From for Transaction { } } +#[derive(sqlx::FromRow)] +pub(crate) struct StorageTransactionReceipt { + pub error: Option, + pub tx_format: Option, + pub index_in_block: Option, + pub block_hash: Vec, + pub tx_hash: Vec, + pub block_number: i64, + pub l1_batch_tx_index: Option, + pub l1_batch_number: Option, + pub transfer_to: Option, + pub execute_contract_address: Option, + pub refunded_gas: i64, + pub gas_limit: Option, + pub effective_gas_price: Option, + pub contract_address: Option>, + pub initiator_address: Vec, +} + +impl From for TransactionReceipt { + fn from(storage_receipt: StorageTransactionReceipt) -> Self { + let status = storage_receipt.error.map_or_else(U64::one, |_| U64::zero()); + + let tx_type = storage_receipt + .tx_format + .map_or_else(Default::default, U64::from); + let transaction_index = storage_receipt + .index_in_block + .map_or_else(Default::default, U64::from); + + let block_hash = H256::from_slice(&storage_receipt.block_hash); + TransactionReceipt { + transaction_hash: H256::from_slice(&storage_receipt.tx_hash), + transaction_index, + block_hash, + block_number: storage_receipt.block_number.into(), + l1_batch_tx_index: storage_receipt.l1_batch_tx_index.map(U64::from), + l1_batch_number: storage_receipt.l1_batch_number.map(U64::from), + from: H160::from_slice(&storage_receipt.initiator_address), + to: storage_receipt + .transfer_to + .or(storage_receipt.execute_contract_address) + .map(|addr| { + serde_json::from_value::
(addr) + .expect("invalid address value in the database") + }) + // For better compatibility with various clients, we never return null. + .or_else(|| Some(Address::default())), + cumulative_gas_used: Default::default(), // TODO: Should be actually calculated (SMA-1183). + gas_used: { + let refunded_gas: U256 = storage_receipt.refunded_gas.into(); + storage_receipt.gas_limit.map(|val| { + let gas_limit = bigdecimal_to_u256(val); + gas_limit - refunded_gas + }) + }, + effective_gas_price: Some( + storage_receipt + .effective_gas_price + .map(bigdecimal_to_u256) + .unwrap_or_default(), + ), + contract_address: storage_receipt + .contract_address + .map(|addr| h256_to_account_address(&H256::from_slice(&addr))), + logs: vec![], + l2_to_l1_logs: vec![], + status, + root: block_hash, + logs_bloom: Default::default(), + // Even though the Rust SDK recommends us to supply "None" for legacy transactions + // we always supply some number anyway to have the same behavior as most popular RPCs + transaction_type: Some(tx_type), + } + } +} + #[derive(Serialize, Deserialize)] pub struct StorageApiTransaction { #[serde(flatten)] @@ -514,8 +591,7 @@ pub fn extract_web3_transaction(db_row: PgRow, chain_id: L2ChainId) -> api::Tran } #[derive(Debug, Clone, sqlx::FromRow)] -pub struct CallTrace { - pub tx_hash: Vec, +pub(crate) struct CallTrace { pub call_trace: Vec, } diff --git a/core/lib/dal/src/models/storage_witness_job_info.rs b/core/lib/dal/src/models/storage_witness_job_info.rs index 486b9f89681b..ea8e15fb9c99 100644 --- a/core/lib/dal/src/models/storage_witness_job_info.rs +++ b/core/lib/dal/src/models/storage_witness_job_info.rs @@ -1,12 +1,11 @@ use std::{convert::TryFrom, str::FromStr}; use sqlx::types::chrono::{DateTime, NaiveDateTime, NaiveTime, Utc}; -use zksync_types::{ - proofs::{ - AggregationRound, JobPosition, WitnessJobInfo, WitnessJobStatus, WitnessJobStatusFailed, - WitnessJobStatusSuccessful, - }, - L1BatchNumber, +use zksync_types::{basic_fri_types::AggregationRound, L1BatchNumber}; + +use crate::fri_prover_dal::types::{ + JobPosition, WitnessJobInfo, WitnessJobStatus, WitnessJobStatusFailed, + WitnessJobStatusSuccessful, }; #[derive(sqlx::FromRow)] diff --git a/core/lib/dal/src/protocol_versions_dal.rs b/core/lib/dal/src/protocol_versions_dal.rs index 0f4818864dfe..8aad040221c4 100644 --- a/core/lib/dal/src/protocol_versions_dal.rs +++ b/core/lib/dal/src/protocol_versions_dal.rs @@ -1,4 +1,4 @@ -use std::convert::{TryFrom, TryInto}; +use std::convert::TryInto; use zksync_contracts::{BaseSystemContracts, BaseSystemContractsHashes}; use zksync_types::{ @@ -98,51 +98,6 @@ impl ProtocolVersionsDal<'_, '_> { db_transaction.commit().await.unwrap(); } - pub async fn save_prover_protocol_version(&mut self, version: ProtocolVersion) { - sqlx::query!( - r#" - INSERT INTO - prover_protocol_versions ( - id, - timestamp, - recursion_scheduler_level_vk_hash, - recursion_node_level_vk_hash, - recursion_leaf_level_vk_hash, - recursion_circuits_set_vks_hash, - verifier_address, - created_at - ) - VALUES - ($1, $2, $3, $4, $5, $6, $7, NOW()) - "#, - version.id as i32, - version.timestamp as i64, - version - .l1_verifier_config - .recursion_scheduler_level_vk_hash - .as_bytes(), - version - .l1_verifier_config - .params - .recursion_node_level_vk_hash - .as_bytes(), - version - .l1_verifier_config - .params - .recursion_leaf_level_vk_hash - .as_bytes(), - version - .l1_verifier_config - .params - .recursion_circuits_set_vks_hash - .as_bytes(), - version.verifier_address.as_bytes(), - ) - .execute(self.storage.conn()) - .await - .unwrap(); - } - pub async fn base_system_contracts_by_timestamp( &mut self, current_timestamp: u64, @@ -392,61 +347,4 @@ impl ProtocolVersionsDal<'_, '_> { None } } - - pub async fn protocol_version_for( - &mut self, - vk_commitments: &L1VerifierConfig, - ) -> Vec { - sqlx::query!( - r#" - SELECT - id - FROM - prover_protocol_versions - WHERE - recursion_circuits_set_vks_hash = $1 - AND recursion_leaf_level_vk_hash = $2 - AND recursion_node_level_vk_hash = $3 - AND recursion_scheduler_level_vk_hash = $4 - "#, - vk_commitments - .params - .recursion_circuits_set_vks_hash - .as_bytes(), - vk_commitments - .params - .recursion_leaf_level_vk_hash - .as_bytes(), - vk_commitments - .params - .recursion_node_level_vk_hash - .as_bytes(), - vk_commitments.recursion_scheduler_level_vk_hash.as_bytes(), - ) - .fetch_all(self.storage.conn()) - .await - .unwrap() - .into_iter() - .map(|row| ProtocolVersionId::try_from(row.id as u16).unwrap()) - .collect() - } - - pub async fn prover_protocol_version_exists(&mut self, id: ProtocolVersionId) -> bool { - sqlx::query!( - r#" - SELECT - COUNT(*) AS "count!" - FROM - prover_protocol_versions - WHERE - id = $1 - "#, - id as i32 - ) - .fetch_one(self.storage.conn()) - .await - .unwrap() - .count - > 0 - } } diff --git a/core/lib/dal/src/prover_dal.rs b/core/lib/dal/src/prover_dal.rs deleted file mode 100644 index c0a767531af3..000000000000 --- a/core/lib/dal/src/prover_dal.rs +++ /dev/null @@ -1,724 +0,0 @@ -use std::{ - collections::HashMap, - convert::{TryFrom, TryInto}, - ops::Range, - time::Duration, -}; - -use sqlx::Error; -use zksync_types::{ - proofs::{ - AggregationRound, JobCountStatistics, JobExtendedStatistics, ProverJobInfo, - ProverJobMetadata, - }, - L1BatchNumber, ProtocolVersionId, -}; - -use crate::{ - instrument::InstrumentExt, - models::storage_prover_job_info::StorageProverJobInfo, - time_utils::{duration_to_naive_time, pg_interval_from_duration}, - StorageProcessor, -}; - -#[derive(Debug)] -pub struct ProverDal<'a, 'c> { - pub(crate) storage: &'a mut StorageProcessor<'c>, -} - -impl ProverDal<'_, '_> { - pub async fn get_next_prover_job( - &mut self, - protocol_versions: &[ProtocolVersionId], - ) -> Option { - let protocol_versions: Vec = protocol_versions.iter().map(|&id| id as i32).collect(); - let result: Option = sqlx::query!( - r#" - UPDATE prover_jobs - SET - status = 'in_progress', - attempts = attempts + 1, - updated_at = NOW(), - processing_started_at = NOW() - WHERE - id = ( - SELECT - id - FROM - prover_jobs - WHERE - status = 'queued' - AND protocol_version = ANY ($1) - ORDER BY - aggregation_round DESC, - l1_batch_number ASC, - id ASC - LIMIT - 1 - FOR UPDATE - SKIP LOCKED - ) - RETURNING - prover_jobs.* - "#, - &protocol_versions[..] - ) - .fetch_optional(self.storage.conn()) - .await - .unwrap() - .map(|row| ProverJobMetadata { - id: row.id as u32, - block_number: L1BatchNumber(row.l1_batch_number as u32), - circuit_type: row.circuit_type, - aggregation_round: AggregationRound::try_from(row.aggregation_round).unwrap(), - sequence_number: row.sequence_number as usize, - }); - result - } - - pub async fn get_proven_l1_batches(&mut self) -> Vec<(L1BatchNumber, AggregationRound)> { - { - sqlx::query!( - r#" - SELECT - MAX(l1_batch_number) AS "l1_batch_number!", - aggregation_round - FROM - prover_jobs - WHERE - status = 'successful' - GROUP BY - aggregation_round - "# - ) - .fetch_all(self.storage.conn()) - .await - .unwrap() - .into_iter() - .map(|record| { - ( - L1BatchNumber(record.l1_batch_number as u32), - record.aggregation_round.try_into().unwrap(), - ) - }) - .collect() - } - } - - pub async fn get_next_prover_job_by_circuit_types( - &mut self, - circuit_types: Vec, - protocol_versions: &[ProtocolVersionId], - ) -> Option { - { - let protocol_versions: Vec = - protocol_versions.iter().map(|&id| id as i32).collect(); - let result: Option = sqlx::query!( - r#" - UPDATE prover_jobs - SET - status = 'in_progress', - attempts = attempts + 1, - updated_at = NOW(), - processing_started_at = NOW() - WHERE - id = ( - SELECT - id - FROM - prover_jobs - WHERE - circuit_type = ANY ($1) - AND status = 'queued' - AND protocol_version = ANY ($2) - ORDER BY - aggregation_round DESC, - l1_batch_number ASC, - id ASC - LIMIT - 1 - FOR UPDATE - SKIP LOCKED - ) - RETURNING - prover_jobs.* - "#, - &circuit_types[..], - &protocol_versions[..] - ) - .fetch_optional(self.storage.conn()) - .await - .unwrap() - .map(|row| ProverJobMetadata { - id: row.id as u32, - block_number: L1BatchNumber(row.l1_batch_number as u32), - circuit_type: row.circuit_type, - aggregation_round: AggregationRound::try_from(row.aggregation_round).unwrap(), - sequence_number: row.sequence_number as usize, - }); - - result - } - } - - // If making changes to this method, consider moving the serialization logic to the DAL layer. - pub async fn insert_prover_jobs( - &mut self, - l1_batch_number: L1BatchNumber, - circuit_types_and_urls: Vec<(&'static str, String)>, - aggregation_round: AggregationRound, - protocol_version: i32, - ) { - { - let it = circuit_types_and_urls.into_iter().enumerate(); - for (sequence_number, (circuit, circuit_input_blob_url)) in it { - sqlx::query!( - r#" - INSERT INTO - prover_jobs ( - l1_batch_number, - circuit_type, - sequence_number, - prover_input, - aggregation_round, - circuit_input_blob_url, - protocol_version, - status, - created_at, - updated_at - ) - VALUES - ($1, $2, $3, $4, $5, $6, $7, 'queued', NOW(), NOW()) - ON CONFLICT (l1_batch_number, aggregation_round, sequence_number) DO NOTHING - "#, - l1_batch_number.0 as i64, - circuit, - sequence_number as i64, - &[] as &[u8], - aggregation_round as i64, - circuit_input_blob_url, - protocol_version - ) - .instrument("save_witness") - .report_latency() - .with_arg("l1_batch_number", &l1_batch_number) - .with_arg("circuit", &circuit) - .with_arg("circuit_input_blob_url", &circuit_input_blob_url) - .execute(self.storage.conn()) - .await - .unwrap(); - } - } - } - - pub async fn save_proof( - &mut self, - id: u32, - time_taken: Duration, - proof: Vec, - proccesed_by: &str, - ) -> Result<(), Error> { - { - sqlx::query!( - r#" - UPDATE prover_jobs - SET - status = 'successful', - updated_at = NOW(), - time_taken = $1, - result = $2, - proccesed_by = $3 - WHERE - id = $4 - "#, - duration_to_naive_time(time_taken), - &proof, - proccesed_by, - id as i64, - ) - .instrument("save_proof") - .report_latency() - .with_arg("id", &id) - .with_arg("proof.len", &proof.len()) - .execute(self.storage.conn()) - .await?; - } - Ok(()) - } - - pub async fn save_proof_error( - &mut self, - id: u32, - error: String, - max_attempts: u32, - ) -> Result<(), Error> { - { - let mut transaction = self.storage.start_transaction().await.unwrap(); - - let row = sqlx::query!( - r#" - UPDATE prover_jobs - SET - status = 'failed', - error = $1, - updated_at = NOW() - WHERE - id = $2 - RETURNING - l1_batch_number, - attempts - "#, - error, - id as i64, - ) - .fetch_one(transaction.conn()) - .await?; - - if row.attempts as u32 >= max_attempts { - transaction - .blocks_dal() - .set_skip_proof_for_l1_batch(L1BatchNumber(row.l1_batch_number as u32)) - .await - .unwrap(); - } - - transaction.commit().await.unwrap(); - Ok(()) - } - } - - pub async fn requeue_stuck_jobs( - &mut self, - processing_timeout: Duration, - max_attempts: u32, - ) -> Vec { - let processing_timeout = pg_interval_from_duration(processing_timeout); - { - sqlx::query!( - r#" - UPDATE prover_jobs - SET - status = 'queued', - updated_at = NOW(), - processing_started_at = NOW() - WHERE - ( - status = 'in_progress' - AND processing_started_at <= NOW() - $1::INTERVAL - AND attempts < $2 - ) - OR ( - status = 'in_gpu_proof' - AND processing_started_at <= NOW() - $1::INTERVAL - AND attempts < $2 - ) - OR ( - status = 'failed' - AND attempts < $2 - ) - RETURNING - id, - status, - attempts - "#, - &processing_timeout, - max_attempts as i32, - ) - .fetch_all(self.storage.conn()) - .await - .unwrap() - .into_iter() - .map(|row| StuckProverJobs { - id: row.id as u64, - status: row.status, - attempts: row.attempts as u64, - }) - .collect() - } - } - - pub async fn get_prover_jobs_stats_per_circuit( - &mut self, - ) -> HashMap { - { - sqlx::query!( - r#" - SELECT - COUNT(*) AS "count!", - circuit_type AS "circuit_type!", - status AS "status!" - FROM - prover_jobs - WHERE - status <> 'skipped' - AND status <> 'successful' - GROUP BY - circuit_type, - status - "# - ) - .fetch_all(self.storage.conn()) - .await - .unwrap() - .into_iter() - .map(|row| (row.circuit_type, row.status, row.count as usize)) - .fold(HashMap::new(), |mut acc, (circuit_type, status, value)| { - let stats = acc.entry(circuit_type).or_insert(JobCountStatistics { - queued: 0, - in_progress: 0, - failed: 0, - successful: 0, - }); - match status.as_ref() { - "queued" => stats.queued = value, - "in_progress" => stats.in_progress = value, - "failed" => stats.failed = value, - "successful" => stats.successful = value, - _ => (), - } - acc - }) - } - } - - pub async fn get_prover_jobs_stats(&mut self) -> JobCountStatistics { - { - let mut results: HashMap = sqlx::query!( - r#" - SELECT - COUNT(*) AS "count!", - status AS "status!" - FROM - prover_jobs - GROUP BY - status - "# - ) - .fetch_all(self.storage.conn()) - .await - .unwrap() - .into_iter() - .map(|row| (row.status, row.count as usize)) - .collect::>(); - JobCountStatistics { - queued: results.remove("queued").unwrap_or(0usize), - in_progress: results.remove("in_progress").unwrap_or(0usize), - failed: results.remove("failed").unwrap_or(0usize), - successful: results.remove("successful").unwrap_or(0usize), - } - } - } - - pub async fn min_unproved_l1_batch_number(&mut self) -> Option { - { - sqlx::query!( - r#" - SELECT - MIN(l1_batch_number) AS "l1_batch_number?" - FROM - ( - SELECT - MIN(l1_batch_number) AS "l1_batch_number" - FROM - prover_jobs - WHERE - status = 'successful' - OR aggregation_round < 3 - GROUP BY - l1_batch_number - HAVING - MAX(aggregation_round) < 3 - ) AS inn - "# - ) - .fetch_one(self.storage.conn()) - .await - .unwrap() - .l1_batch_number - .map(|n| L1BatchNumber(n as u32)) - } - } - - pub async fn min_unproved_l1_batch_number_by_basic_circuit_type( - &mut self, - ) -> Vec<(String, L1BatchNumber)> { - { - sqlx::query!( - r#" - SELECT - MIN(l1_batch_number) AS "l1_batch_number!", - circuit_type - FROM - prover_jobs - WHERE - aggregation_round = 0 - AND ( - status = 'queued' - OR status = 'in_progress' - OR status = 'in_gpu_proof' - OR status = 'failed' - ) - GROUP BY - circuit_type - "# - ) - .fetch_all(self.storage.conn()) - .await - .unwrap() - .into_iter() - .map(|row| (row.circuit_type, L1BatchNumber(row.l1_batch_number as u32))) - .collect() - } - } - - pub async fn get_extended_stats(&mut self) -> anyhow::Result { - { - let limits = sqlx::query!( - r#" - SELECT - ( - SELECT - l1_batch_number - FROM - prover_jobs - WHERE - status NOT IN ('successful', 'skipped') - ORDER BY - l1_batch_number - LIMIT - 1 - ) AS "successful_limit!", - ( - SELECT - l1_batch_number - FROM - prover_jobs - WHERE - status <> 'queued' - ORDER BY - l1_batch_number DESC - LIMIT - 1 - ) AS "queued_limit!", - ( - SELECT - MAX(l1_batch_number) AS "max!" - FROM - prover_jobs - ) AS "max_block!" - "# - ) - .fetch_one(self.storage.conn()) - .await?; - - let active_area = self - .get_jobs(GetProverJobsParams::blocks( - L1BatchNumber(limits.successful_limit as u32) - ..L1BatchNumber(limits.queued_limit as u32), - )) - .await?; - - Ok(JobExtendedStatistics { - successful_padding: L1BatchNumber(limits.successful_limit as u32 - 1), - queued_padding: L1BatchNumber(limits.queued_limit as u32 + 1), - queued_padding_len: (limits.max_block - limits.queued_limit) as u32, - active_area, - }) - } - } - - pub async fn get_jobs( - &mut self, - opts: GetProverJobsParams, - ) -> Result, sqlx::Error> { - let statuses = opts - .statuses - .map(|ss| { - { - // Until statuses are enums - let whitelist = ["queued", "in_progress", "successful", "failed"]; - if !ss.iter().all(|x| whitelist.contains(&x.as_str())) { - panic!("Forbidden value in statuses list.") - } - } - - format!( - "AND status IN ({})", - ss.iter() - .map(|x| format!("'{}'", x)) - .collect::>() - .join(",") - ) - }) - .unwrap_or_default(); - - let block_range = opts - .blocks - .as_ref() - .map(|range| { - format!( - "AND l1_batch_number >= {} - AND l1_batch_number <= {}", - range.start.0, range.end.0 - ) - }) - .unwrap_or_default(); - - let round = opts - .round - .map(|round| format!("AND aggregation_round = {}", round as u32)) - .unwrap_or_default(); - - let order = match opts.desc { - true => "DESC", - false => "ASC", - }; - - let limit = opts - .limit - .map(|limit| format!("LIMIT {}", limit)) - .unwrap_or_default(); - - let sql = format!( - r#" - SELECT - id, - circuit_type, - l1_batch_number, - status, - aggregation_round, - sequence_number, - length(prover_input) as input_length, - attempts, - created_at, - updated_at, - processing_started_at, - time_taken, - error - FROM prover_jobs - WHERE 1 = 1 -- Where clause can't be empty - {statuses} - {block_range} - {round} - ORDER BY "id" {order} - {limit} - "# - ); - - let query = sqlx::query_as(&sql); - - Ok(query - .fetch_all(self.storage.conn()) - .await? - .into_iter() - .map(|x: StorageProverJobInfo| x.into()) - .collect::>()) - } - - pub async fn get_prover_job_by_id( - &mut self, - job_id: u32, - ) -> Result, Error> { - { - let row = sqlx::query!( - r#" - SELECT - * - FROM - prover_jobs - WHERE - id = $1 - "#, - job_id as i64 - ) - .fetch_optional(self.storage.conn()) - .await?; - - Ok(row.map(|row| ProverJobMetadata { - id: row.id as u32, - block_number: L1BatchNumber(row.l1_batch_number as u32), - circuit_type: row.circuit_type, - aggregation_round: AggregationRound::try_from(row.aggregation_round).unwrap(), - sequence_number: row.sequence_number as usize, - })) - } - } - - pub async fn get_circuit_input_blob_urls_to_be_cleaned( - &mut self, - limit: u8, - ) -> Vec<(i64, String)> { - { - let job_ids = sqlx::query!( - r#" - SELECT - id, - circuit_input_blob_url - FROM - prover_jobs - WHERE - status = 'successful' - AND circuit_input_blob_url IS NOT NULL - AND updated_at < NOW() - INTERVAL '30 days' - LIMIT - $1; - "#, - limit as i32 - ) - .fetch_all(self.storage.conn()) - .await - .unwrap(); - job_ids - .into_iter() - .map(|row| (row.id, row.circuit_input_blob_url.unwrap())) - .collect() - } - } - - pub async fn update_status(&mut self, id: u32, status: &str) { - { - sqlx::query!( - r#" - UPDATE prover_jobs - SET - status = $1, - updated_at = NOW() - WHERE - id = $2 - "#, - status, - id as i64, - ) - .execute(self.storage.conn()) - .await - .unwrap(); - } - } -} - -pub struct GetProverJobsParams { - pub statuses: Option>, - pub blocks: Option>, - pub limit: Option, - pub desc: bool, - pub round: Option, -} - -impl GetProverJobsParams { - pub fn blocks(range: Range) -> GetProverJobsParams { - GetProverJobsParams { - blocks: Some(range), - statuses: None, - limit: None, - desc: false, - round: None, - } - } -} - -#[derive(Debug)] -pub struct StuckProverJobs { - pub id: u64, - pub status: String, - pub attempts: u64, -} diff --git a/core/lib/dal/src/snapshot_recovery_dal.rs b/core/lib/dal/src/snapshot_recovery_dal.rs index edcf7ccf1986..af6f6a25439c 100644 --- a/core/lib/dal/src/snapshot_recovery_dal.rs +++ b/core/lib/dal/src/snapshot_recovery_dal.rs @@ -8,7 +8,7 @@ pub struct SnapshotRecoveryDal<'a, 'c> { } impl SnapshotRecoveryDal<'_, '_> { - pub async fn set_applied_snapshot_status( + pub async fn insert_initial_recovery_status( &mut self, status: &SnapshotRecoveryStatus, ) -> sqlx::Result<()> { @@ -20,36 +20,43 @@ impl SnapshotRecoveryDal<'_, '_> { l1_batch_root_hash, miniblock_number, miniblock_root_hash, - last_finished_chunk_id, - total_chunk_count, + storage_logs_chunks_processed, updated_at, created_at ) VALUES - ($1, $2, $3, $4, $5, $6, NOW(), NOW()) - ON CONFLICT (l1_batch_number) DO - UPDATE - SET - l1_batch_number = excluded.l1_batch_number, - l1_batch_root_hash = excluded.l1_batch_root_hash, - miniblock_number = excluded.miniblock_number, - miniblock_root_hash = excluded.miniblock_root_hash, - last_finished_chunk_id = excluded.last_finished_chunk_id, - total_chunk_count = excluded.total_chunk_count, - updated_at = excluded.updated_at + ($1, $2, $3, $4, $5, NOW(), NOW()) "#, status.l1_batch_number.0 as i64, status.l1_batch_root_hash.0.as_slice(), status.miniblock_number.0 as i64, status.miniblock_root_hash.0.as_slice(), - status.last_finished_chunk_id.map(|v| v as i32), - status.total_chunk_count as i64, + &status.storage_logs_chunks_processed, ) .execute(self.storage.conn()) .await?; Ok(()) } + pub async fn mark_storage_logs_chunk_as_processed( + &mut self, + chunk_id: u64, + ) -> sqlx::Result<()> { + sqlx::query!( + r#" + UPDATE snapshot_recovery + SET + storage_logs_chunks_processed[$1] = TRUE, + updated_at = NOW() + "#, + chunk_id as i32 + 1 + ) + .execute(self.storage.conn()) + .await?; + + Ok(()) + } + pub async fn get_applied_snapshot_status( &mut self, ) -> sqlx::Result> { @@ -60,8 +67,7 @@ impl SnapshotRecoveryDal<'_, '_> { l1_batch_root_hash, miniblock_number, miniblock_root_hash, - last_finished_chunk_id, - total_chunk_count + storage_logs_chunks_processed FROM snapshot_recovery "#, @@ -74,8 +80,7 @@ impl SnapshotRecoveryDal<'_, '_> { l1_batch_root_hash: H256::from_slice(&r.l1_batch_root_hash), miniblock_number: MiniblockNumber(r.miniblock_number as u32), miniblock_root_hash: H256::from_slice(&r.miniblock_root_hash), - last_finished_chunk_id: r.last_finished_chunk_id.map(|v| v as u64), - total_chunk_count: r.total_chunk_count as u64, + storage_logs_chunks_processed: r.storage_logs_chunks_processed.into_iter().collect(), })) } } @@ -87,7 +92,7 @@ mod tests { use crate::ConnectionPool; #[tokio::test] - async fn resolving_earliest_block_id() { + async fn manipulating_snapshot_recovery_table() { let connection_pool = ConnectionPool::test_pool().await; let mut conn = connection_pool.access_storage().await.unwrap(); let mut applied_status_dal = conn.snapshot_recovery_dal(); @@ -96,40 +101,37 @@ mod tests { .await .unwrap(); assert_eq!(None, empty_status); - let status = SnapshotRecoveryStatus { + let mut status = SnapshotRecoveryStatus { l1_batch_number: L1BatchNumber(123), l1_batch_root_hash: H256::random(), miniblock_number: MiniblockNumber(234), miniblock_root_hash: H256::random(), - last_finished_chunk_id: None, - total_chunk_count: 345, + storage_logs_chunks_processed: vec![false, false, true, false], }; applied_status_dal - .set_applied_snapshot_status(&status) + .insert_initial_recovery_status(&status) .await .unwrap(); let status_from_db = applied_status_dal .get_applied_snapshot_status() .await .unwrap(); - assert_eq!(Some(status), status_from_db); + assert_eq!(status, status_from_db.unwrap()); - let updated_status = SnapshotRecoveryStatus { - l1_batch_number: L1BatchNumber(123), - l1_batch_root_hash: H256::random(), - miniblock_number: MiniblockNumber(234), - miniblock_root_hash: H256::random(), - last_finished_chunk_id: Some(2345), - total_chunk_count: 345, - }; + status.storage_logs_chunks_processed = vec![false, true, true, true]; applied_status_dal - .set_applied_snapshot_status(&updated_status) + .mark_storage_logs_chunk_as_processed(1) .await .unwrap(); + applied_status_dal + .mark_storage_logs_chunk_as_processed(3) + .await + .unwrap(); + let updated_status_from_db = applied_status_dal .get_applied_snapshot_status() .await .unwrap(); - assert_eq!(Some(updated_status), updated_status_from_db); + assert_eq!(status, updated_status_from_db.unwrap()); } } diff --git a/core/lib/dal/src/snapshots_creator_dal.rs b/core/lib/dal/src/snapshots_creator_dal.rs index 15e7f0aae525..d09363592d18 100644 --- a/core/lib/dal/src/snapshots_creator_dal.rs +++ b/core/lib/dal/src/snapshots_creator_dal.rs @@ -1,6 +1,6 @@ use zksync_types::{ - snapshots::{SnapshotFactoryDependency, SnapshotStorageLog}, - AccountTreeId, Address, L1BatchNumber, MiniblockNumber, StorageKey, H256, + snapshots::SnapshotStorageLog, AccountTreeId, Address, L1BatchNumber, MiniblockNumber, + StorageKey, H256, }; use crate::{instrument::InstrumentExt, StorageProcessor}; @@ -93,19 +93,21 @@ impl SnapshotsCreatorDal<'_, '_> { ), value: H256::from_slice(&row.value), l1_batch_number_of_initial_write: L1BatchNumber(row.l1_batch_number as u32), - enumeration_index: row.index.unwrap() as u64, + enumeration_index: row.index as u64, }) .collect(); Ok(storage_logs) } + /// Returns all factory dependencies up to and including the specified `miniblock_number`. pub async fn get_all_factory_deps( &mut self, miniblock_number: MiniblockNumber, - ) -> sqlx::Result> { + ) -> sqlx::Result)>> { let rows = sqlx::query!( r#" SELECT + bytecode_hash, bytecode FROM factory_deps @@ -121,9 +123,7 @@ impl SnapshotsCreatorDal<'_, '_> { Ok(rows .into_iter() - .map(|row| SnapshotFactoryDependency { - bytecode: row.bytecode.into(), - }) + .map(|row| (H256::from_slice(&row.bytecode_hash), row.bytecode)) .collect()) } } diff --git a/core/lib/dal/src/snapshots_dal.rs b/core/lib/dal/src/snapshots_dal.rs index 9582b3a72094..3b2e62085bb6 100644 --- a/core/lib/dal/src/snapshots_dal.rs +++ b/core/lib/dal/src/snapshots_dal.rs @@ -5,6 +5,27 @@ use zksync_types::{ use crate::{instrument::InstrumentExt, StorageProcessor}; +#[derive(Debug, sqlx::FromRow)] +struct StorageSnapshotMetadata { + l1_batch_number: i64, + storage_logs_filepaths: Vec, + factory_deps_filepath: String, +} + +impl From for SnapshotMetadata { + fn from(row: StorageSnapshotMetadata) -> Self { + Self { + l1_batch_number: L1BatchNumber(row.l1_batch_number as u32), + storage_logs_filepaths: row + .storage_logs_filepaths + .into_iter() + .map(|path| (!path.is_empty()).then_some(path)) + .collect(), + factory_deps_filepath: row.factory_deps_filepath, + } + } +} + #[derive(Debug)] pub struct SnapshotsDal<'a, 'c> { pub(crate) storage: &'a mut StorageProcessor<'c>, @@ -14,9 +35,9 @@ impl SnapshotsDal<'_, '_> { pub async fn add_snapshot( &mut self, l1_batch_number: L1BatchNumber, - storage_logs_filepaths: &[String], + storage_logs_chunk_count: u64, factory_deps_filepaths: &str, - ) -> Result<(), sqlx::Error> { + ) -> sqlx::Result<()> { sqlx::query!( r#" INSERT INTO @@ -28,10 +49,10 @@ impl SnapshotsDal<'_, '_> { updated_at ) VALUES - ($1, $2, $3, NOW(), NOW()) + ($1, ARRAY_FILL(''::TEXT, ARRAY[$2::INTEGER]), $3, NOW(), NOW()) "#, l1_batch_number.0 as i32, - storage_logs_filepaths, + storage_logs_chunk_count as i32, factory_deps_filepaths, ) .instrument("add_snapshot") @@ -41,34 +62,89 @@ impl SnapshotsDal<'_, '_> { Ok(()) } - pub async fn get_all_snapshots(&mut self) -> Result { - let records: Vec = sqlx::query!( + pub async fn add_storage_logs_filepath_for_snapshot( + &mut self, + l1_batch_number: L1BatchNumber, + chunk_id: u64, + storage_logs_filepath: &str, + ) -> sqlx::Result<()> { + sqlx::query!( + r#" + UPDATE snapshots + SET + storage_logs_filepaths[$2] = $3, + updated_at = NOW() + WHERE + l1_batch_number = $1 + "#, + l1_batch_number.0 as i32, + chunk_id as i32 + 1, + storage_logs_filepath, + ) + .execute(self.storage.conn()) + .await?; + + Ok(()) + } + + pub async fn get_all_complete_snapshots(&mut self) -> sqlx::Result { + let rows = sqlx::query!( r#" SELECT - l1_batch_number, - factory_deps_filepath, - storage_logs_filepaths + l1_batch_number FROM snapshots + WHERE + NOT (''::TEXT = ANY (storage_logs_filepaths)) + ORDER BY + l1_batch_number DESC "# ) - .instrument("get_all_snapshots") + .instrument("get_all_complete_snapshots") .report_latency() .fetch_all(self.storage.conn()) - .await? - .into_iter() - .map(|r| L1BatchNumber(r.l1_batch_number as u32)) - .collect(); + .await?; + + let snapshots_l1_batch_numbers = rows + .into_iter() + .map(|row| L1BatchNumber(row.l1_batch_number as u32)) + .collect(); + Ok(AllSnapshots { - snapshots_l1_batch_numbers: records, + snapshots_l1_batch_numbers, }) } + pub async fn get_newest_snapshot_metadata(&mut self) -> sqlx::Result> { + let row = sqlx::query_as!( + StorageSnapshotMetadata, + r#" + SELECT + l1_batch_number, + factory_deps_filepath, + storage_logs_filepaths + FROM + snapshots + ORDER BY + l1_batch_number DESC + LIMIT + 1 + "# + ) + .instrument("get_newest_snapshot_metadata") + .report_latency() + .fetch_optional(self.storage.conn()) + .await?; + + Ok(row.map(Into::into)) + } + pub async fn get_snapshot_metadata( &mut self, l1_batch_number: L1BatchNumber, - ) -> Result, sqlx::Error> { - let record: Option = sqlx::query!( + ) -> sqlx::Result> { + let row = sqlx::query_as!( + StorageSnapshotMetadata, r#" SELECT l1_batch_number, @@ -84,13 +160,9 @@ impl SnapshotsDal<'_, '_> { .instrument("get_snapshot_metadata") .report_latency() .fetch_optional(self.storage.conn()) - .await? - .map(|r| SnapshotMetadata { - l1_batch_number: L1BatchNumber(r.l1_batch_number as u32), - factory_deps_filepath: r.factory_deps_filepath, - storage_logs_filepaths: r.storage_logs_filepaths, - }); - Ok(record) + .await?; + + Ok(row.map(Into::into)) } } @@ -106,29 +178,38 @@ mod tests { let mut conn = pool.access_storage().await.unwrap(); let mut dal = conn.snapshots_dal(); let l1_batch_number = L1BatchNumber(100); - dal.add_snapshot(l1_batch_number, &[], "gs:///bucket/factory_deps.bin") + dal.add_snapshot(l1_batch_number, 2, "gs:///bucket/factory_deps.bin") .await .expect("Failed to add snapshot"); let snapshots = dal - .get_all_snapshots() + .get_all_complete_snapshots() .await .expect("Failed to retrieve snapshots"); - assert_eq!(1, snapshots.snapshots_l1_batch_numbers.len()); - assert_eq!( - snapshots.snapshots_l1_batch_numbers[0], - l1_batch_number as L1BatchNumber - ); + assert_eq!(snapshots.snapshots_l1_batch_numbers, []); + + for i in 0..2 { + dal.add_storage_logs_filepath_for_snapshot( + l1_batch_number, + i, + "gs:///bucket/chunk.bin", + ) + .await + .unwrap(); + } + + let snapshots = dal + .get_all_complete_snapshots() + .await + .expect("Failed to retrieve snapshots"); + assert_eq!(snapshots.snapshots_l1_batch_numbers, [l1_batch_number]); let snapshot_metadata = dal .get_snapshot_metadata(l1_batch_number) .await .expect("Failed to retrieve snapshot") .unwrap(); - assert_eq!( - snapshot_metadata.l1_batch_number, - l1_batch_number as L1BatchNumber - ); + assert_eq!(snapshot_metadata.l1_batch_number, l1_batch_number); } #[tokio::test] @@ -137,16 +218,14 @@ mod tests { let mut conn = pool.access_storage().await.unwrap(); let mut dal = conn.snapshots_dal(); let l1_batch_number = L1BatchNumber(100); - dal.add_snapshot( - l1_batch_number, - &[ - "gs:///bucket/test_file1.bin".to_string(), - "gs:///bucket/test_file2.bin".to_string(), - ], - "gs:///bucket/factory_deps.bin", - ) - .await - .expect("Failed to add snapshot"); + dal.add_snapshot(l1_batch_number, 2, "gs:///bucket/factory_deps.bin") + .await + .expect("Failed to add snapshot"); + + let storage_log_filepaths = ["gs:///bucket/test_file1.bin", "gs:///bucket/test_file2.bin"]; + dal.add_storage_logs_filepath_for_snapshot(l1_batch_number, 1, storage_log_filepaths[1]) + .await + .unwrap(); let files = dal .get_snapshot_metadata(l1_batch_number) @@ -154,7 +233,27 @@ mod tests { .expect("Failed to retrieve snapshot") .unwrap() .storage_logs_filepaths; - assert!(files.contains(&"gs:///bucket/test_file1.bin".to_string())); - assert!(files.contains(&"gs:///bucket/test_file2.bin".to_string())); + assert_eq!( + files, + [None, Some("gs:///bucket/test_file2.bin".to_string())] + ); + + dal.add_storage_logs_filepath_for_snapshot(l1_batch_number, 0, storage_log_filepaths[0]) + .await + .unwrap(); + + let files = dal + .get_snapshot_metadata(l1_batch_number) + .await + .expect("Failed to retrieve snapshot") + .unwrap() + .storage_logs_filepaths; + assert_eq!( + files, + [ + Some("gs:///bucket/test_file1.bin".to_string()), + Some("gs:///bucket/test_file2.bin".to_string()) + ] + ); } } diff --git a/core/lib/dal/src/storage_dal.rs b/core/lib/dal/src/storage_dal.rs index 8f08f65b4405..1155cae4a3be 100644 --- a/core/lib/dal/src/storage_dal.rs +++ b/core/lib/dal/src/storage_dal.rs @@ -19,13 +19,13 @@ impl StorageDal<'_, '_> { &mut self, block_number: MiniblockNumber, factory_deps: &HashMap>, - ) { + ) -> sqlx::Result<()> { let (bytecode_hashes, bytecodes): (Vec<_>, Vec<_>) = factory_deps .iter() .map(|dep| (dep.0.as_bytes(), dep.1.as_slice())) .unzip(); - // Copy from stdin can't be used here because of 'ON CONFLICT'. + // Copy from stdin can't be used here because of `ON CONFLICT`. sqlx::query!( r#" INSERT INTO @@ -45,8 +45,9 @@ impl StorageDal<'_, '_> { block_number.0 as i64, ) .execute(self.storage.conn()) - .await - .unwrap(); + .await?; + + Ok(()) } /// Returns bytecode for a factory dependency with the specified bytecode `hash`. @@ -134,8 +135,8 @@ impl StorageDal<'_, '_> { pub async fn get_factory_deps_for_revert( &mut self, block_number: MiniblockNumber, - ) -> Vec { - sqlx::query!( + ) -> sqlx::Result> { + Ok(sqlx::query!( r#" SELECT bytecode_hash @@ -147,11 +148,10 @@ impl StorageDal<'_, '_> { block_number.0 as i64 ) .fetch_all(self.storage.conn()) - .await - .unwrap() + .await? .into_iter() .map(|row| H256::from_slice(&row.bytecode_hash)) - .collect() + .collect()) } /// Applies the specified storage logs for a miniblock. Returns the map of unique storage updates. @@ -186,7 +186,7 @@ impl StorageDal<'_, '_> { Vec<_>, ) = query_parts.multiunzip(); - // Copy from stdin can't be used here because of 'ON CONFLICT'. + // Copy from stdin can't be used here because of `ON CONFLICT`. sqlx::query!( r#" INSERT INTO @@ -222,10 +222,9 @@ impl StorageDal<'_, '_> { } /// Gets the current storage value at the specified `key`. - pub async fn get_by_key(&mut self, key: &StorageKey) -> Option { + pub async fn get_by_key(&mut self, key: &StorageKey) -> sqlx::Result> { let hashed_key = key.hashed_key(); - - sqlx::query!( + let row = sqlx::query!( r#" SELECT value @@ -240,9 +239,9 @@ impl StorageDal<'_, '_> { .report_latency() .with_arg("key", &hashed_key) .fetch_optional(self.storage.conn()) - .await - .unwrap() - .map(|row| H256::from_slice(&row.value)) + .await?; + + Ok(row.map(|row| H256::from_slice(&row.value))) } /// Removes all factory deps with a miniblock number strictly greater than the specified `block_number`. @@ -284,8 +283,8 @@ mod tests { conn.storage_dal().apply_storage_logs(&updates).await; let first_value = conn.storage_dal().get_by_key(&first_key).await.unwrap(); - assert_eq!(first_value, H256::repeat_byte(1)); + assert_eq!(first_value, Some(H256::repeat_byte(1))); let second_value = conn.storage_dal().get_by_key(&second_key).await.unwrap(); - assert_eq!(second_value, H256::repeat_byte(2)); + assert_eq!(second_value, Some(H256::repeat_byte(2))); } } diff --git a/core/lib/dal/src/storage_logs_dal.rs b/core/lib/dal/src/storage_logs_dal.rs index ff757b748e8d..fa09a15bdf34 100644 --- a/core/lib/dal/src/storage_logs_dal.rs +++ b/core/lib/dal/src/storage_logs_dal.rs @@ -2,11 +2,12 @@ use std::{collections::HashMap, ops, time::Instant}; use sqlx::{types::chrono::Utc, Row}; use zksync_types::{ - get_code_key, AccountTreeId, Address, L1BatchNumber, MiniblockNumber, StorageKey, StorageLog, - FAILED_CONTRACT_DEPLOYMENT_BYTECODE_HASH, H256, U256, + get_code_key, snapshots::SnapshotStorageLog, AccountTreeId, Address, L1BatchNumber, + MiniblockNumber, StorageKey, StorageLog, FAILED_CONTRACT_DEPLOYMENT_BYTECODE_HASH, H160, H256, }; -use crate::{instrument::InstrumentExt, models::storage_log::StorageTreeEntry, StorageProcessor}; +pub use crate::models::storage_log::{DbStorageLog, StorageRecoveryLogEntry}; +use crate::{instrument::InstrumentExt, StorageProcessor}; #[derive(Debug)] pub struct StorageLogsDal<'a, 'c> { @@ -67,6 +68,46 @@ impl StorageLogsDal<'_, '_> { copy.finish().await.unwrap(); } + pub async fn insert_storage_logs_from_snapshot( + &mut self, + miniblock_number: MiniblockNumber, + snapshot_storage_logs: &[SnapshotStorageLog], + ) -> sqlx::Result<()> { + let mut copy = self + .storage + .conn() + .copy_in_raw( + "COPY storage_logs( + hashed_key, address, key, value, operation_number, tx_hash, miniblock_number, + created_at, updated_at + ) + FROM STDIN WITH (DELIMITER '|')", + ) + .await?; + + let mut buffer = String::new(); + let now = Utc::now().naive_utc().to_string(); + for log in snapshot_storage_logs.iter() { + write_str!( + &mut buffer, + r"\\x{hashed_key:x}|\\x{address:x}|\\x{key:x}|\\x{value:x}|", + hashed_key = log.key.hashed_key(), + address = log.key.address(), + key = log.key.key(), + value = log.value + ); + writeln_str!( + &mut buffer, + r"{}|\\x{:x}|{miniblock_number}|{now}|{now}", + log.enumeration_index, + H256::zero() + ); + } + copy.send(buffer.as_bytes()).await?; + copy.finish().await?; + Ok(()) + } + pub async fn append_storage_logs( &mut self, block_number: MiniblockNumber, @@ -95,11 +136,14 @@ impl StorageLogsDal<'_, '_> { } /// Rolls back storage to the specified point in time. - pub async fn rollback_storage(&mut self, last_miniblock_to_keep: MiniblockNumber) { + pub async fn rollback_storage( + &mut self, + last_miniblock_to_keep: MiniblockNumber, + ) -> sqlx::Result<()> { let stage_start = Instant::now(); let modified_keys = self .modified_keys_since_miniblock(last_miniblock_to_keep) - .await; + .await?; tracing::info!( "Loaded {} keys changed after miniblock #{last_miniblock_to_keep} in {:?}", modified_keys.len(), @@ -109,7 +153,7 @@ impl StorageLogsDal<'_, '_> { let stage_start = Instant::now(); let prev_values = self .get_storage_values(&modified_keys, last_miniblock_to_keep) - .await; + .await?; tracing::info!( "Loaded previous storage values for modified keys in {:?}", stage_start.elapsed() @@ -144,8 +188,8 @@ impl StorageLogsDal<'_, '_> { &keys_to_delete as &[&[u8]], ) .execute(self.storage.conn()) - .await - .unwrap(); + .await?; + tracing::info!( "Removed {} keys in {:?}", keys_to_delete.len(), @@ -167,21 +211,22 @@ impl StorageLogsDal<'_, '_> { &values_to_update as &[&[u8]], ) .execute(self.storage.conn()) - .await - .unwrap(); + .await?; + tracing::info!( "Updated {} keys to previous values in {:?}", keys_to_update.len(), stage_start.elapsed() ); + Ok(()) } /// Returns all storage keys that were modified after the specified miniblock. async fn modified_keys_since_miniblock( &mut self, miniblock_number: MiniblockNumber, - ) -> Vec { - sqlx::query!( + ) -> sqlx::Result> { + Ok(sqlx::query!( r#" SELECT DISTINCT ON (hashed_key) hashed_key @@ -198,11 +243,10 @@ impl StorageLogsDal<'_, '_> { miniblock_number.0 as i64 ) .fetch_all(self.storage.conn()) - .await - .unwrap() + .await? .into_iter() .map(|row| H256::from_slice(&row.hashed_key)) - .collect() + .collect()) } /// Removes all storage logs with a miniblock number strictly greater than the specified `block_number`. @@ -258,7 +302,7 @@ impl StorageLogsDal<'_, '_> { pub async fn get_touched_slots_for_l1_batch( &mut self, l1_batch_number: L1BatchNumber, - ) -> HashMap { + ) -> sqlx::Result> { let rows = sqlx::query!( r#" SELECT @@ -290,8 +334,7 @@ impl StorageLogsDal<'_, '_> { l1_batch_number.0 as i64 ) .fetch_all(self.storage.conn()) - .await - .unwrap(); + .await?; let touched_slots = rows.into_iter().map(|row| { let key = StorageKey::new( @@ -300,7 +343,7 @@ impl StorageLogsDal<'_, '_> { ); (key, H256::from_slice(&row.value)) }); - touched_slots.collect() + Ok(touched_slots.collect()) } /// Returns (hashed) storage keys and the corresponding values that need to be applied to a storage @@ -308,19 +351,18 @@ impl StorageLogsDal<'_, '_> { pub async fn get_storage_logs_for_revert( &mut self, l1_batch_number: L1BatchNumber, - ) -> HashMap> { + ) -> sqlx::Result>> { let miniblock_range = self .storage .blocks_dal() .get_miniblock_range_of_l1_batch(l1_batch_number) - .await - .unwrap(); + .await?; let Some((_, last_miniblock)) = miniblock_range else { - return HashMap::new(); + return Ok(HashMap::new()); }; let stage_start = Instant::now(); - let mut modified_keys = self.modified_keys_since_miniblock(last_miniblock).await; + let mut modified_keys = self.modified_keys_since_miniblock(last_miniblock).await?; let modified_keys_count = modified_keys.len(); tracing::info!( "Fetched {modified_keys_count} keys changed after miniblock #{last_miniblock} in {:?}", @@ -334,7 +376,7 @@ impl StorageLogsDal<'_, '_> { let stage_start = Instant::now(); let l1_batch_and_index_by_key = self .get_l1_batches_and_indices_for_initial_writes(&modified_keys) - .await; + .await?; tracing::info!( "Loaded initial write info for modified keys in {:?}", stage_start.elapsed() @@ -372,7 +414,7 @@ impl StorageLogsDal<'_, '_> { let stage_start = Instant::now(); let prev_values_for_updated_keys = self .get_storage_values(&modified_keys, last_miniblock) - .await + .await? .into_iter() .map(|(key, value)| { let value = value.unwrap(); // We already filtered out keys that weren't touched. @@ -385,15 +427,15 @@ impl StorageLogsDal<'_, '_> { stage_start.elapsed() ); output.extend(prev_values_for_updated_keys); - output + Ok(output) } pub async fn get_l1_batches_and_indices_for_initial_writes( &mut self, hashed_keys: &[H256], - ) -> HashMap { + ) -> sqlx::Result> { if hashed_keys.is_empty() { - return HashMap::new(); // Shortcut to save time on communication with DB in the common case + return Ok(HashMap::new()); // Shortcut to save time on communication with DB in the common case } let hashed_keys: Vec<_> = hashed_keys.iter().map(H256::as_bytes).collect(); @@ -413,17 +455,17 @@ impl StorageLogsDal<'_, '_> { .instrument("get_l1_batches_and_indices_for_initial_writes") .report_latency() .fetch_all(self.storage.conn()) - .await - .unwrap(); + .await?; - rows.into_iter() + Ok(rows + .into_iter() .map(|row| { ( H256::from_slice(&row.hashed_key), (L1BatchNumber(row.l1_batch_number as u32), row.index as u64), ) }) - .collect() + .collect()) } /// Gets previous values for the specified storage keys before the specified L1 batch number. @@ -440,17 +482,16 @@ impl StorageLogsDal<'_, '_> { &mut self, hashed_keys: &[H256], next_l1_batch: L1BatchNumber, - ) -> HashMap> { + ) -> sqlx::Result>> { let (miniblock_number, _) = self .storage .blocks_dal() .get_miniblock_range_of_l1_batch(next_l1_batch) - .await - .unwrap() + .await? .unwrap(); if miniblock_number == MiniblockNumber(0) { - hashed_keys.iter().copied().map(|key| (key, None)).collect() + Ok(hashed_keys.iter().copied().map(|key| (key, None)).collect()) } else { self.get_storage_values(hashed_keys, miniblock_number - 1) .await @@ -462,7 +503,7 @@ impl StorageLogsDal<'_, '_> { &mut self, hashed_keys: &[H256], miniblock_number: MiniblockNumber, - ) -> HashMap> { + ) -> sqlx::Result>> { let hashed_keys: Vec<_> = hashed_keys.iter().map(H256::as_bytes).collect(); let rows = sqlx::query!( @@ -490,15 +531,48 @@ impl StorageLogsDal<'_, '_> { miniblock_number.0 as i64 ) .fetch_all(self.storage.conn()) - .await - .unwrap(); + .await?; - rows.into_iter() + Ok(rows + .into_iter() .map(|row| { let key = H256::from_slice(&row.hashed_key); let value = row.value.map(|value| H256::from_slice(&value)); (key, value) }) + .collect()) + } + + /// Retrieves all storage log entries for testing purposes. + pub async fn dump_all_storage_logs_for_tests(&mut self) -> Vec { + let rows = sqlx::query!( + r#" + SELECT + hashed_key, + address, + key, + value, + operation_number, + tx_hash, + miniblock_number + FROM + storage_logs + "# + ) + .fetch_all(self.storage.conn()) + .await + .expect("get_all_storage_logs_for_tests"); + + rows.into_iter() + .map(|row| DbStorageLog { + hashed_key: H256::from_slice(&row.hashed_key), + address: H160::from_slice(&row.address), + key: H256::from_slice(&row.key), + value: H256::from_slice(&row.value), + operation_number: row.operation_number as u64, + tx_hash: H256::from_slice(&row.tx_hash), + miniblock_number: MiniblockNumber(row.miniblock_number as u32), + }) .collect() } @@ -531,7 +605,7 @@ impl StorageLogsDal<'_, '_> { &mut self, miniblock_number: MiniblockNumber, key_ranges: &[ops::RangeInclusive], - ) -> sqlx::Result>> { + ) -> sqlx::Result>> { let (start_keys, end_keys): (Vec<_>, Vec<_>) = key_ranges .iter() .map(|range| (range.start().as_bytes(), range.end().as_bytes())) @@ -574,8 +648,8 @@ impl StorageLogsDal<'_, '_> { .await?; let rows = rows.into_iter().map(|row| { - Some(StorageTreeEntry { - key: U256::from_little_endian(row.hashed_key.as_ref()?), + Some(StorageRecoveryLogEntry { + key: H256::from_slice(row.hashed_key.as_ref()?), value: H256::from_slice(row.value.as_ref()?), leaf_index: row.index? as u64, }) @@ -589,7 +663,7 @@ impl StorageLogsDal<'_, '_> { &mut self, miniblock_number: MiniblockNumber, key_range: ops::RangeInclusive, - ) -> sqlx::Result> { + ) -> sqlx::Result> { let rows = sqlx::query!( r#" SELECT @@ -613,8 +687,8 @@ impl StorageLogsDal<'_, '_> { .fetch_all(self.storage.conn()) .await?; - let rows = rows.into_iter().map(|row| StorageTreeEntry { - key: U256::from_little_endian(&row.hashed_key), + let rows = rows.into_iter().map(|row| StorageRecoveryLogEntry { + key: H256::from_slice(&row.hashed_key), value: H256::from_slice(&row.value), leaf_index: row.index as u64, }); @@ -709,31 +783,20 @@ impl StorageLogsDal<'_, '_> { #[cfg(test)] mod tests { use zksync_contracts::BaseSystemContractsHashes; - use zksync_types::{ - block::{BlockGasCount, L1BatchHeader}, - ProtocolVersion, ProtocolVersionId, - }; + use zksync_types::{block::L1BatchHeader, ProtocolVersion, ProtocolVersionId}; use super::*; use crate::{tests::create_miniblock_header, ConnectionPool}; - fn u256_to_h256_reversed(value: U256) -> H256 { - let mut bytes = [0_u8; 32]; - value.to_little_endian(&mut bytes); - H256(bytes) - } - async fn insert_miniblock(conn: &mut StorageProcessor<'_>, number: u32, logs: Vec) { - let mut header = L1BatchHeader::new( + let header = L1BatchHeader::new( L1BatchNumber(number), 0, - Address::default(), BaseSystemContractsHashes::default(), ProtocolVersionId::default(), ); - header.is_finished = true; conn.blocks_dal() - .insert_l1_batch(&header, &[], BlockGasCount::default(), &[], &[]) + .insert_mock_l1_batch(&header) .await .unwrap(); conn.blocks_dal() @@ -770,7 +833,8 @@ mod tests { let touched_slots = conn .storage_logs_dal() .get_touched_slots_for_l1_batch(L1BatchNumber(1)) - .await; + .await + .unwrap(); assert_eq!(touched_slots.len(), 2); assert_eq!(touched_slots[&first_key], H256::repeat_byte(1)); assert_eq!(touched_slots[&second_key], H256::repeat_byte(2)); @@ -786,7 +850,8 @@ mod tests { let touched_slots = conn .storage_logs_dal() .get_touched_slots_for_l1_batch(L1BatchNumber(1)) - .await; + .await + .unwrap(); assert_eq!(touched_slots.len(), 2); assert_eq!(touched_slots[&first_key], H256::repeat_byte(3)); assert_eq!(touched_slots[&second_key], H256::repeat_byte(2)); @@ -808,17 +873,18 @@ mod tests { insert_miniblock(conn, 2, logs).await; let value = conn.storage_dal().get_by_key(&key).await.unwrap(); - assert_eq!(value, H256::repeat_byte(0xff)); + assert_eq!(value, Some(H256::repeat_byte(0xff))); let value = conn.storage_dal().get_by_key(&second_key).await.unwrap(); - assert_eq!(value, H256::zero()); + assert_eq!(value, Some(H256::zero())); let value = conn.storage_dal().get_by_key(&new_key).await.unwrap(); - assert_eq!(value, H256::repeat_byte(0xfe)); + assert_eq!(value, Some(H256::repeat_byte(0xfe))); let prev_keys = vec![key.hashed_key(), new_key.hashed_key(), H256::zero()]; let prev_values = conn .storage_logs_dal() .get_previous_storage_values(&prev_keys, L1BatchNumber(2)) - .await; + .await + .unwrap(); assert_eq!(prev_values.len(), 3); assert_eq!(prev_values[&prev_keys[0]], Some(H256::repeat_byte(3))); assert_eq!(prev_values[&prev_keys[1]], None); @@ -826,14 +892,15 @@ mod tests { conn.storage_logs_dal() .rollback_storage(MiniblockNumber(1)) - .await; + .await + .unwrap(); let value = conn.storage_dal().get_by_key(&key).await.unwrap(); - assert_eq!(value, H256::repeat_byte(3)); + assert_eq!(value, Some(H256::repeat_byte(3))); let value = conn.storage_dal().get_by_key(&second_key).await.unwrap(); - assert_eq!(value, H256::repeat_byte(2)); - let value = conn.storage_dal().get_by_key(&new_key).await; - assert!(value.is_none()); + assert_eq!(value, Some(H256::repeat_byte(2))); + let value = conn.storage_dal().get_by_key(&new_key).await.unwrap(); + assert_eq!(value, None); } #[tokio::test] @@ -872,7 +939,8 @@ mod tests { let logs_for_revert = conn .storage_logs_dal() .get_storage_logs_for_revert(L1BatchNumber(1)) - .await; + .await + .unwrap(); assert_eq!(logs_for_revert.len(), 15); // 5 updated + 10 new keys for log in &logs[5..] { let prev_value = logs_for_revert[&log.key.hashed_key()].unwrap().0; @@ -931,7 +999,8 @@ mod tests { let logs_for_revert = conn .storage_logs_dal() .get_storage_logs_for_revert(L1BatchNumber(1)) - .await; + .await + .unwrap(); assert_eq!(logs_for_revert.len(), 3); for (i, log) in logs.iter().enumerate() { let hashed_key = log.key.hashed_key(); @@ -974,10 +1043,7 @@ mod tests { .iter() .find(|&key| key_range.contains(key)); if let Some(chunk_start) = chunk_start { - assert_eq!( - u256_to_h256_reversed(chunk_start.key), - *expected_start_key.unwrap() - ); + assert_eq!(chunk_start.key, *expected_start_key.unwrap()); assert_ne!(chunk_start.value, H256::zero()); assert_ne!(chunk_start.leaf_index, 0); } else { @@ -1027,7 +1093,7 @@ mod tests { assert_eq!( tree_entries .iter() - .map(|entry| u256_to_h256_reversed(entry.key)) + .map(|entry| entry.key) .collect::>(), sorted_hashed_keys ); @@ -1040,7 +1106,7 @@ mod tests { .unwrap(); assert!(!tree_entries.is_empty() && tree_entries.len() < 10); for entry in &tree_entries { - assert!(key_range.contains(&u256_to_h256_reversed(entry.key))); + assert!(key_range.contains(&entry.key)); } } } diff --git a/core/lib/dal/src/storage_logs_dedup_dal.rs b/core/lib/dal/src/storage_logs_dedup_dal.rs index a7bef5aa794a..9ca17176e8b6 100644 --- a/core/lib/dal/src/storage_logs_dedup_dal.rs +++ b/core/lib/dal/src/storage_logs_dedup_dal.rs @@ -1,9 +1,13 @@ use std::collections::HashSet; use sqlx::types::chrono::Utc; -use zksync_types::{AccountTreeId, Address, L1BatchNumber, LogQuery, StorageKey, H256}; +use zksync_types::{ + snapshots::SnapshotStorageLog, zk_evm_types::LogQuery, AccountTreeId, Address, L1BatchNumber, + StorageKey, H256, +}; use zksync_utils::u256_to_h256; +pub use crate::models::storage_log::DbInitialWrite; use crate::StorageProcessor; #[derive(Debug)] @@ -44,6 +48,38 @@ impl StorageLogsDedupDal<'_, '_> { /// Insert initial writes and assigns indices to them. /// Assumes indices are already assigned for all saved initial_writes, so must be called only after the migration. + pub async fn insert_initial_writes_from_snapshot( + &mut self, + snapshot_storage_logs: &[SnapshotStorageLog], + ) -> sqlx::Result<()> { + let mut copy = self + .storage + .conn() + .copy_in_raw( + "COPY initial_writes (hashed_key, index, l1_batch_number, created_at, updated_at) \ + FROM STDIN WITH (DELIMITER '|')", + ) + .await?; + + let mut bytes: Vec = Vec::new(); + let now = Utc::now().naive_utc().to_string(); + for log in snapshot_storage_logs.iter() { + let row = format!( + "\\\\x{:x}|{}|{}|{}|{}\n", + log.key.hashed_key(), + log.enumeration_index, + log.l1_batch_number_of_initial_write, + now, + now, + ); + bytes.extend_from_slice(row.as_bytes()); + } + copy.send(bytes).await?; + copy.finish().await?; + + Ok(()) + } + pub async fn insert_initial_writes( &mut self, l1_batch_number: L1BatchNumber, @@ -191,4 +227,29 @@ impl StorageLogsDedupDal<'_, '_> { .map(|row| H256::from_slice(&row.hashed_key)) .collect() } + + /// Retrieves all initial write entries for testing purposes. + pub async fn dump_all_initial_writes_for_tests(&mut self) -> Vec { + let rows = sqlx::query!( + r#" + SELECT + hashed_key, + l1_batch_number, + INDEX + FROM + initial_writes + "# + ) + .fetch_all(self.storage.conn()) + .await + .expect("get_all_initial_writes_for_tests"); + + rows.into_iter() + .map(|row| DbInitialWrite { + hashed_key: H256::from_slice(&row.hashed_key), + l1_batch_number: L1BatchNumber(row.l1_batch_number as u32), + index: row.index as u64, + }) + .collect() + } } diff --git a/core/lib/dal/src/storage_web3_dal.rs b/core/lib/dal/src/storage_web3_dal.rs index c95d4ca73dbb..312c46acba23 100644 --- a/core/lib/dal/src/storage_web3_dal.rs +++ b/core/lib/dal/src/storage_web3_dal.rs @@ -107,12 +107,21 @@ impl StorageWeb3Dal<'_, '_> { WHERE number = $1 ) AS "block_batch?", - ( - SELECT - MAX(number) + 1 - FROM - l1_batches - ) AS "max_batch?" + COALESCE( + ( + SELECT + MAX(number) + 1 + FROM + l1_batches + ), + ( + SELECT + MAX(l1_batch_number) + 1 + FROM + snapshot_recovery + ), + 0 + ) AS "pending_batch!" "#, miniblock_number.0 as i64 ) @@ -121,7 +130,7 @@ impl StorageWeb3Dal<'_, '_> { Ok(ResolvedL1BatchForMiniblock { miniblock_l1_batch: row.block_batch.map(|n| L1BatchNumber(n as u32)), - pending_l1_batch: L1BatchNumber(row.max_batch.unwrap_or(0) as u32), + pending_l1_batch: L1BatchNumber(row.pending_batch as u32), }) } @@ -245,3 +254,159 @@ impl StorageWeb3Dal<'_, '_> { } } } + +#[cfg(test)] +mod tests { + use zksync_types::{ + block::L1BatchHeader, snapshots::SnapshotRecoveryStatus, ProtocolVersion, ProtocolVersionId, + }; + + use super::*; + use crate::{tests::create_miniblock_header, ConnectionPool}; + + #[tokio::test] + async fn resolving_l1_batch_number_of_miniblock() { + let pool = ConnectionPool::test_pool().await; + let mut conn = pool.access_storage().await.unwrap(); + conn.protocol_versions_dal() + .save_protocol_version_with_tx(ProtocolVersion::default()) + .await; + conn.blocks_dal() + .insert_miniblock(&create_miniblock_header(0)) + .await + .unwrap(); + let l1_batch_header = L1BatchHeader::new( + L1BatchNumber(0), + 0, + Default::default(), + ProtocolVersionId::latest(), + ); + conn.blocks_dal() + .insert_mock_l1_batch(&l1_batch_header) + .await + .unwrap(); + conn.blocks_dal() + .mark_miniblocks_as_executed_in_l1_batch(L1BatchNumber(0)) + .await + .unwrap(); + + let first_miniblock = create_miniblock_header(1); + conn.blocks_dal() + .insert_miniblock(&first_miniblock) + .await + .unwrap(); + + let resolved = conn + .storage_web3_dal() + .resolve_l1_batch_number_of_miniblock(MiniblockNumber(0)) + .await + .unwrap(); + assert_eq!(resolved.miniblock_l1_batch, Some(L1BatchNumber(0))); + assert_eq!(resolved.pending_l1_batch, L1BatchNumber(1)); + assert_eq!(resolved.expected_l1_batch(), L1BatchNumber(0)); + + let timestamp = conn + .blocks_web3_dal() + .get_expected_l1_batch_timestamp(&resolved) + .await + .unwrap(); + assert_eq!(timestamp, Some(0)); + + for pending_miniblock_number in [1, 2] { + let resolved = conn + .storage_web3_dal() + .resolve_l1_batch_number_of_miniblock(MiniblockNumber(pending_miniblock_number)) + .await + .unwrap(); + assert_eq!(resolved.miniblock_l1_batch, None); + assert_eq!(resolved.pending_l1_batch, L1BatchNumber(1)); + assert_eq!(resolved.expected_l1_batch(), L1BatchNumber(1)); + + let timestamp = conn + .blocks_web3_dal() + .get_expected_l1_batch_timestamp(&resolved) + .await + .unwrap(); + assert_eq!(timestamp, Some(first_miniblock.timestamp)); + } + } + + #[tokio::test] + async fn resolving_l1_batch_number_of_miniblock_with_snapshot_recovery() { + let pool = ConnectionPool::test_pool().await; + let mut conn = pool.access_storage().await.unwrap(); + conn.protocol_versions_dal() + .save_protocol_version_with_tx(ProtocolVersion::default()) + .await; + let snapshot_recovery = SnapshotRecoveryStatus { + l1_batch_number: L1BatchNumber(23), + l1_batch_root_hash: H256::zero(), + miniblock_number: MiniblockNumber(42), + miniblock_root_hash: H256::zero(), + storage_logs_chunks_processed: vec![true; 100], + }; + conn.snapshot_recovery_dal() + .insert_initial_recovery_status(&snapshot_recovery) + .await + .unwrap(); + + let first_miniblock = create_miniblock_header(snapshot_recovery.miniblock_number.0 + 1); + conn.blocks_dal() + .insert_miniblock(&first_miniblock) + .await + .unwrap(); + + let resolved = conn + .storage_web3_dal() + .resolve_l1_batch_number_of_miniblock(snapshot_recovery.miniblock_number + 1) + .await + .unwrap(); + assert_eq!(resolved.miniblock_l1_batch, None); + assert_eq!( + resolved.pending_l1_batch, + snapshot_recovery.l1_batch_number + 1 + ); + assert_eq!( + resolved.expected_l1_batch(), + snapshot_recovery.l1_batch_number + 1 + ); + + let timestamp = conn + .blocks_web3_dal() + .get_expected_l1_batch_timestamp(&resolved) + .await + .unwrap(); + assert_eq!(timestamp, Some(first_miniblock.timestamp)); + + let l1_batch_header = L1BatchHeader::new( + snapshot_recovery.l1_batch_number + 1, + 100, + Default::default(), + ProtocolVersionId::latest(), + ); + conn.blocks_dal() + .insert_mock_l1_batch(&l1_batch_header) + .await + .unwrap(); + conn.blocks_dal() + .mark_miniblocks_as_executed_in_l1_batch(l1_batch_header.number) + .await + .unwrap(); + + let resolved = conn + .storage_web3_dal() + .resolve_l1_batch_number_of_miniblock(snapshot_recovery.miniblock_number + 1) + .await + .unwrap(); + assert_eq!(resolved.miniblock_l1_batch, Some(l1_batch_header.number)); + assert_eq!(resolved.pending_l1_batch, l1_batch_header.number + 1); + assert_eq!(resolved.expected_l1_batch(), l1_batch_header.number); + + let timestamp = conn + .blocks_web3_dal() + .get_expected_l1_batch_timestamp(&resolved) + .await + .unwrap(); + assert_eq!(timestamp, Some(first_miniblock.timestamp)); + } +} diff --git a/core/lib/dal/src/sync_dal.rs b/core/lib/dal/src/sync_dal.rs index 4d50f2855bbf..284ce3175559 100644 --- a/core/lib/dal/src/sync_dal.rs +++ b/core/lib/dal/src/sync_dal.rs @@ -1,9 +1,9 @@ -use zksync_types::{api::en::SyncBlock, Address, MiniblockNumber, Transaction}; +use zksync_types::{api::en, MiniblockNumber}; use crate::{ instrument::InstrumentExt, metrics::MethodLatency, - models::{storage_sync::StorageSyncBlock, storage_transaction::StorageTransaction}, + models::storage_sync::{StorageSyncBlock, SyncBlock}, StorageProcessor, }; @@ -14,14 +14,11 @@ pub struct SyncDal<'a, 'c> { } impl SyncDal<'_, '_> { - pub async fn sync_block( + pub(super) async fn sync_block_inner( &mut self, block_number: MiniblockNumber, - current_operator_address: Address, - include_transactions: bool, ) -> anyhow::Result> { - let latency = MethodLatency::new("sync_dal_sync_block"); - let storage_block_details = sqlx::query_as!( + let Some(block) = sqlx::query_as!( StorageSyncBlock, r#" SELECT @@ -46,16 +43,15 @@ impl SyncDal<'_, '_> { miniblocks.timestamp, miniblocks.l1_gas_price, miniblocks.l2_fair_gas_price, + miniblocks.fair_pubdata_price, miniblocks.bootloader_code_hash, miniblocks.default_aa_code_hash, miniblocks.virtual_blocks, miniblocks.hash, - miniblocks.consensus, miniblocks.protocol_version AS "protocol_version!", - l1_batches.fee_account_address AS "fee_account_address?" + miniblocks.fee_account_address AS "fee_account_address!" FROM miniblocks - LEFT JOIN l1_batches ON miniblocks.l1_batch_number = l1_batches.number WHERE miniblocks.number = $1 "#, @@ -64,49 +60,50 @@ impl SyncDal<'_, '_> { .instrument("sync_dal_sync_block.block") .with_arg("block_number", &block_number) .fetch_optional(self.storage.conn()) - .await?; - - let Some(storage_block_details) = storage_block_details else { + .await? + else { return Ok(None); }; - let transactions = if include_transactions { - let transactions = sqlx::query_as!( - StorageTransaction, - r#" - SELECT - * - FROM - transactions - WHERE - miniblock_number = $1 - ORDER BY - index_in_block - "#, - block_number.0 as i64 - ) - .instrument("sync_dal_sync_block.transactions") - .with_arg("block_number", &block_number) - .fetch_all(self.storage.conn()) + + let mut block = SyncBlock::try_from(block)?; + // FIXME (PLA-728): remove after 2nd phase of `fee_account_address` migration + #[allow(deprecated)] + self.storage + .blocks_dal() + .maybe_load_fee_address(&mut block.fee_account_address, block.number) .await?; + Ok(Some(block)) + } - Some(transactions.into_iter().map(Transaction::from).collect()) + pub async fn sync_block( + &mut self, + block_number: MiniblockNumber, + include_transactions: bool, + ) -> anyhow::Result> { + let _latency = MethodLatency::new("sync_dal_sync_block"); + let Some(block) = self.sync_block_inner(block_number).await? else { + return Ok(None); + }; + let transactions = if include_transactions { + let transactions = self + .storage + .transactions_web3_dal() + .get_raw_miniblock_transactions(block_number) + .await?; + Some(transactions) } else { None }; - - let block = - storage_block_details.into_sync_block(current_operator_address, transactions)?; - drop(latency); - Ok(Some(block)) + Ok(Some(block.into_api(transactions))) } } #[cfg(test)] mod tests { use zksync_types::{ - block::{BlockGasCount, L1BatchHeader}, + block::{L1BatchHeader, MiniblockHeader}, fee::TransactionExecutionMetrics, - L1BatchNumber, ProtocolVersion, ProtocolVersionId, + Address, L1BatchNumber, ProtocolVersion, ProtocolVersionId, Transaction, }; use super::*; @@ -131,12 +128,11 @@ mod tests { let mut l1_batch_header = L1BatchHeader::new( L1BatchNumber(0), 0, - Address::repeat_byte(0x42), Default::default(), ProtocolVersionId::latest(), ); conn.blocks_dal() - .insert_l1_batch(&l1_batch_header, &[], BlockGasCount::default(), &[], &[]) + .insert_mock_l1_batch(&l1_batch_header) .await .unwrap(); conn.blocks_dal() @@ -144,16 +140,18 @@ mod tests { .await .unwrap(); - let operator_address = Address::repeat_byte(1); assert!(conn .sync_dal() - .sync_block(MiniblockNumber(1), operator_address, false) + .sync_block(MiniblockNumber(1), false) .await .unwrap() .is_none()); // Insert another block in the store. - let miniblock_header = create_miniblock_header(1); + let miniblock_header = MiniblockHeader { + fee_account_address: Address::repeat_byte(0x42), + ..create_miniblock_header(1) + }; let tx = mock_l2_transaction(); conn.transactions_dal() .insert_transaction_l2(tx.clone(), TransactionExecutionMetrics::default()) @@ -172,7 +170,7 @@ mod tests { let block = conn .sync_dal() - .sync_block(MiniblockNumber(1), operator_address, false) + .sync_block(MiniblockNumber(1), false) .await .unwrap() .expect("no sync block"); @@ -188,14 +186,20 @@ mod tests { block.virtual_blocks.unwrap(), miniblock_header.virtual_blocks ); - assert_eq!(block.l1_gas_price, miniblock_header.l1_gas_price); - assert_eq!(block.l2_fair_gas_price, miniblock_header.l2_fair_gas_price); - assert_eq!(block.operator_address, operator_address); + assert_eq!( + block.l1_gas_price, + miniblock_header.batch_fee_input.l1_gas_price() + ); + assert_eq!( + block.l2_fair_gas_price, + miniblock_header.batch_fee_input.fair_l2_gas_price() + ); + assert_eq!(block.operator_address, miniblock_header.fee_account_address); assert!(block.transactions.is_none()); let block = conn .sync_dal() - .sync_block(MiniblockNumber(1), operator_address, true) + .sync_block(MiniblockNumber(1), true) .await .unwrap() .expect("no sync block"); @@ -205,7 +209,7 @@ mod tests { l1_batch_header.number = L1BatchNumber(1); l1_batch_header.timestamp = 1; conn.blocks_dal() - .insert_l1_batch(&l1_batch_header, &[], BlockGasCount::default(), &[], &[]) + .insert_mock_l1_batch(&l1_batch_header) .await .unwrap(); conn.blocks_dal() @@ -215,12 +219,12 @@ mod tests { let block = conn .sync_dal() - .sync_block(MiniblockNumber(1), operator_address, true) + .sync_block(MiniblockNumber(1), true) .await .unwrap() .expect("no sync block"); assert_eq!(block.l1_batch_number, L1BatchNumber(1)); assert!(block.last_in_batch); - assert_eq!(block.operator_address, l1_batch_header.fee_account_address); + assert_eq!(block.operator_address, miniblock_header.fee_account_address); } } diff --git a/core/lib/dal/src/system_dal.rs b/core/lib/dal/src/system_dal.rs index e9b020943052..e5cf2cf29d4f 100644 --- a/core/lib/dal/src/system_dal.rs +++ b/core/lib/dal/src/system_dal.rs @@ -9,7 +9,7 @@ pub struct SystemDal<'a, 'c> { impl SystemDal<'_, '_> { pub async fn get_replication_lag_sec(&mut self) -> u32 { // NOTE: lag (seconds) has a special meaning here - // (it is not the same that replay_lag/write_lag/flush_lag from pg_stat_replication view) + // (it is not the same that `replay_lag/write_lag/flush_lag` from `pg_stat_replication` view) // and it is only useful when synced column is false, // because lag means how many seconds elapsed since the last action was committed. let pg_row = sqlx::query( diff --git a/core/lib/dal/src/tests/mod.rs b/core/lib/dal/src/tests/mod.rs index 6b8ae6090f9c..8094f37216c5 100644 --- a/core/lib/dal/src/tests/mod.rs +++ b/core/lib/dal/src/tests/mod.rs @@ -2,22 +2,21 @@ use std::time::Duration; use zksync_contracts::BaseSystemContractsHashes; use zksync_types::{ - block::{L1BatchHeader, MiniblockHasher, MiniblockHeader}, + block::{MiniblockHasher, MiniblockHeader}, fee::{Fee, TransactionExecutionMetrics}, + fee_model::BatchFeeInput, helpers::unix_timestamp_ms, l1::{L1Tx, OpProcessingType, PriorityQueueType}, l2::L2Tx, - proofs::AggregationRound, tx::{tx_execution_info::TxExecutionStatus, ExecutionMetrics, TransactionExecutionResult}, - Address, Execute, L1BatchNumber, L1BlockNumber, L1TxCommonData, L2ChainId, MiniblockNumber, - PriorityOpId, ProtocolVersion, ProtocolVersionId, H160, H256, MAX_GAS_PER_PUBDATA_BYTE, U256, + Address, Execute, L1BlockNumber, L1TxCommonData, L2ChainId, MiniblockNumber, PriorityOpId, + ProtocolVersionId, H160, H256, U256, }; use crate::{ blocks_dal::BlocksDal, connection::ConnectionPool, protocol_versions_dal::ProtocolVersionsDal, - prover_dal::{GetProverJobsParams, ProverDal}, transactions_dal::{L2TxSubmissionResult, TransactionsDal}, transactions_web3_dal::TransactionsWeb3Dal, }; @@ -33,13 +32,14 @@ pub(crate) fn create_miniblock_header(number: u32) -> MiniblockHeader { let protocol_version = ProtocolVersionId::default(); MiniblockHeader { number, - timestamp: 0, + timestamp: number.0.into(), hash: MiniblockHasher::new(number, 0, H256::zero()).finalize(protocol_version), l1_tx_count: 0, l2_tx_count: 0, + fee_account_address: Address::default(), + gas_per_pubdata_limit: 100, base_fee_per_gas: 100, - l1_gas_price: 100, - l2_fair_gas_price: 100, + batch_fee_input: BatchFeeInput::l1_pegged(100, 100), base_system_contracts_hashes: BaseSystemContractsHashes::default(), protocol_version: Some(protocol_version), virtual_blocks: 1, @@ -81,7 +81,7 @@ fn mock_l1_execute() -> L1Tx { full_fee: U256::zero(), gas_limit: U256::from(100_100), max_fee_per_gas: U256::from(1u32), - gas_per_pubdata_limit: MAX_GAS_PER_PUBDATA_BYTE.into(), + gas_per_pubdata_limit: 100.into(), op_processing_type: OpProcessingType::Common, priority_queue_type: PriorityQueueType::Deque, eth_hash: H256::random(), @@ -205,11 +205,11 @@ async fn remove_stuck_txs() { .await; // Get all txs - transactions_dal.reset_mempool().await; - let txs = transactions_dal - .sync_mempool(vec![], vec![], 0, 0, 1000) + transactions_dal.reset_mempool().await.unwrap(); + let (txs, _) = transactions_dal + .sync_mempool(&[], &[], 0, 0, 1000) .await - .0; + .unwrap(); assert_eq!(txs.len(), 4); let storage = transactions_dal.storage; @@ -228,172 +228,33 @@ async fn remove_stuck_txs() { .await; // Get all txs - transactions_dal.reset_mempool().await; - let txs = transactions_dal - .sync_mempool(vec![], vec![], 0, 0, 1000) + transactions_dal.reset_mempool().await.unwrap(); + let (txs, _) = transactions_dal + .sync_mempool(&[], &[], 0, 0, 1000) .await - .0; + .unwrap(); assert_eq!(txs.len(), 3); // Remove one stuck tx let removed_txs = transactions_dal .remove_stuck_txs(Duration::from_secs(500)) - .await; + .await + .unwrap(); assert_eq!(removed_txs, 1); - transactions_dal.reset_mempool().await; - let txs = transactions_dal - .sync_mempool(vec![], vec![], 0, 0, 1000) + transactions_dal.reset_mempool().await.unwrap(); + let (txs, _) = transactions_dal + .sync_mempool(&[], &[], 0, 0, 1000) .await - .0; + .unwrap(); assert_eq!(txs.len(), 2); // We shouldn't collect executed tx let storage = transactions_dal.storage; let mut transactions_web3_dal = TransactionsWeb3Dal { storage }; - transactions_web3_dal - .get_transaction_receipt(executed_tx.hash()) - .await - .unwrap() - .unwrap(); -} - -fn create_circuits() -> Vec<(&'static str, String)> { - vec![ - ("Main VM", "1_0_Main VM_BasicCircuits.bin".to_owned()), - ("SHA256", "1_1_SHA256_BasicCircuits.bin".to_owned()), - ( - "Code decommitter", - "1_2_Code decommitter_BasicCircuits.bin".to_owned(), - ), - ( - "Log demuxer", - "1_3_Log demuxer_BasicCircuits.bin".to_owned(), - ), - ] -} - -#[tokio::test] -async fn test_duplicate_insert_prover_jobs() { - let connection_pool = ConnectionPool::test_pool().await; - let storage = &mut connection_pool.access_storage().await.unwrap(); - storage - .protocol_versions_dal() - .save_protocol_version_with_tx(Default::default()) - .await; - storage - .protocol_versions_dal() - .save_prover_protocol_version(Default::default()) - .await; - let block_number = 1; - let header = L1BatchHeader::new( - L1BatchNumber(block_number), - 0, - Default::default(), - Default::default(), - Default::default(), - ); - storage - .blocks_dal() - .insert_l1_batch(&header, &[], Default::default(), &[], &[]) + let receipts = transactions_web3_dal + .get_transaction_receipts(&[executed_tx.hash()]) .await .unwrap(); - let mut prover_dal = ProverDal { storage }; - let circuits = create_circuits(); - let l1_batch_number = L1BatchNumber(block_number); - prover_dal - .insert_prover_jobs( - l1_batch_number, - circuits.clone(), - AggregationRound::BasicCircuits, - ProtocolVersionId::latest() as i32, - ) - .await; - - // try inserting the same jobs again to ensure it does not panic - prover_dal - .insert_prover_jobs( - l1_batch_number, - circuits.clone(), - AggregationRound::BasicCircuits, - ProtocolVersionId::latest() as i32, - ) - .await; - - let prover_jobs_params = GetProverJobsParams { - statuses: None, - blocks: Some(std::ops::Range { - start: l1_batch_number, - end: l1_batch_number + 1, - }), - limit: None, - desc: false, - round: None, - }; - let jobs = prover_dal.get_jobs(prover_jobs_params).await.unwrap(); - assert_eq!(circuits.len(), jobs.len()); -} - -#[tokio::test] -async fn test_requeue_prover_jobs() { - let connection_pool = ConnectionPool::test_pool().await; - let storage = &mut connection_pool.access_storage().await.unwrap(); - let protocol_version = ProtocolVersion::default(); - storage - .protocol_versions_dal() - .save_protocol_version_with_tx(protocol_version) - .await; - storage - .protocol_versions_dal() - .save_prover_protocol_version(Default::default()) - .await; - let block_number = 1; - let header = L1BatchHeader::new( - L1BatchNumber(block_number), - 0, - Default::default(), - Default::default(), - ProtocolVersionId::latest(), - ); - storage - .blocks_dal() - .insert_l1_batch(&header, &[], Default::default(), &[], &[]) - .await - .unwrap(); - - let mut prover_dal = ProverDal { storage }; - let circuits = create_circuits(); - let l1_batch_number = L1BatchNumber(block_number); - prover_dal - .insert_prover_jobs( - l1_batch_number, - circuits, - AggregationRound::BasicCircuits, - ProtocolVersionId::latest() as i32, - ) - .await; - - // take all jobs from prover_job table - for _ in 1..=4 { - let job = prover_dal - .get_next_prover_job(&[ProtocolVersionId::latest()]) - .await; - assert!(job.is_some()); - } - let job = prover_dal - .get_next_prover_job(&[ProtocolVersionId::latest()]) - .await; - assert!(job.is_none()); - // re-queue jobs - let stuck_jobs = prover_dal - .requeue_stuck_jobs(Duration::from_secs(0), 10) - .await; - assert_eq!(4, stuck_jobs.len()); - // re-check that all jobs can be taken again - for _ in 1..=4 { - let job = prover_dal - .get_next_prover_job(&[ProtocolVersionId::latest()]) - .await; - assert!(job.is_some()); - } + assert_eq!(receipts.len(), 1); } diff --git a/core/lib/dal/src/tokens_dal.rs b/core/lib/dal/src/tokens_dal.rs index 96072bc2ec4c..1910ecbe9437 100644 --- a/core/lib/dal/src/tokens_dal.rs +++ b/core/lib/dal/src/tokens_dal.rs @@ -112,25 +112,22 @@ impl TokensDal<'_, '_> { } } - pub async fn get_all_l2_token_addresses(&mut self) -> Vec
{ - { - let records = sqlx::query!( - r#" - SELECT - l2_address - FROM - tokens - "# - ) - .fetch_all(self.storage.conn()) - .await - .unwrap(); - let addresses: Vec
= records - .into_iter() - .map(|record| Address::from_slice(&record.l2_address)) - .collect(); - addresses - } + pub async fn get_all_l2_token_addresses(&mut self) -> sqlx::Result> { + let rows = sqlx::query!( + r#" + SELECT + l2_address + FROM + tokens + "# + ) + .fetch_all(self.storage.conn()) + .await?; + + Ok(rows + .into_iter() + .map(|row| Address::from_slice(&row.l2_address)) + .collect()) } pub async fn get_unknown_l1_token_addresses(&mut self) -> Vec
{ diff --git a/core/lib/dal/src/transactions_dal.rs b/core/lib/dal/src/transactions_dal.rs index 7041d4e20ac7..b084a1ba01a1 100644 --- a/core/lib/dal/src/transactions_dal.rs +++ b/core/lib/dal/src/transactions_dal.rs @@ -284,7 +284,7 @@ impl TransactionsDal<'_, '_> { // 3) WHERE clause conditions for DO UPDATE block were not met, so the transaction can't be replaced // the subquery in RETURNING clause looks into pre-UPDATE state of the table. So if the subquery will return NULL // transaction is fresh and was added to db(the second condition of RETURNING clause checks it). - // Otherwise, if the subquery won't return NULL it means that there is already tx with such nonce and initiator_address in DB + // Otherwise, if the subquery won't return NULL it means that there is already tx with such nonce and `initiator_address` in DB // and we can replace it WHERE clause conditions are met. // It is worth mentioning that if WHERE clause conditions are not met, None will be returned. let query_result = sqlx::query!( @@ -408,7 +408,7 @@ impl TransactionsDal<'_, '_> { // another tx with the same tx hash is supposed to have the same data // In this case we identify it as Duplicate // Note, this error can happen because of the race condition (tx can be taken by several - // api servers, that simultaneously start execute it and try to inserted to DB) + // API servers, that simultaneously start execute it and try to inserted to DB) if let error::Error::Database(ref error) = err { if let Some(constraint) = error.constraint() { if constraint == "transactions_pkey" { @@ -597,7 +597,7 @@ impl TransactionsDal<'_, '_> { }); if !l2_hashes.is_empty() { - // Update l2 txs + // Update L2 txs // Due to the current tx replacement model, it's possible that tx has been replaced, // but the original was executed in memory, @@ -856,184 +856,171 @@ impl TransactionsDal<'_, '_> { } } - pub async fn remove_stuck_txs(&mut self, stuck_tx_timeout: Duration) -> usize { - { - let stuck_tx_timeout = pg_interval_from_duration(stuck_tx_timeout); - sqlx::query!( - r#" - DELETE FROM transactions - WHERE - miniblock_number IS NULL - AND received_at < NOW() - $1::INTERVAL - AND is_priority = FALSE - AND error IS NULL - RETURNING - hash - "#, - stuck_tx_timeout - ) - .fetch_all(self.storage.conn()) - .await - .unwrap() - .len() - } + pub async fn remove_stuck_txs(&mut self, stuck_tx_timeout: Duration) -> sqlx::Result { + let stuck_tx_timeout = pg_interval_from_duration(stuck_tx_timeout); + let rows = sqlx::query!( + r#" + DELETE FROM transactions + WHERE + miniblock_number IS NULL + AND received_at < NOW() - $1::INTERVAL + AND is_priority = FALSE + AND error IS NULL + RETURNING + hash + "#, + stuck_tx_timeout + ) + .fetch_all(self.storage.conn()) + .await?; + + Ok(rows.len()) } - /// Fetches new updates for mempool - /// Returns new transactions and current nonces for related accounts - /// Latter is only used to bootstrap mempool for given account + /// Fetches new updates for mempool. Returns new transactions and current nonces for related accounts; + /// the latter are only used to bootstrap mempool for given account. pub async fn sync_mempool( &mut self, - stashed_accounts: Vec
, - purged_accounts: Vec
, + stashed_accounts: &[Address], + purged_accounts: &[Address], gas_per_pubdata: u32, fee_per_gas: u64, limit: usize, - ) -> (Vec, HashMap) { - { - let stashed_addresses: Vec<_> = - stashed_accounts.into_iter().map(|a| a.0.to_vec()).collect(); - sqlx::query!( - r#" - UPDATE transactions - SET - in_mempool = FALSE - FROM - UNNEST($1::bytea[]) AS s (address) - WHERE - transactions.in_mempool = TRUE - AND transactions.initiator_address = s.address - "#, - &stashed_addresses, - ) - .execute(self.storage.conn()) - .await - .unwrap(); + ) -> sqlx::Result<(Vec, HashMap)> { + let stashed_addresses: Vec<_> = stashed_accounts.iter().map(Address::as_bytes).collect(); + sqlx::query!( + r#" + UPDATE transactions + SET + in_mempool = FALSE + FROM + UNNEST($1::bytea[]) AS s (address) + WHERE + transactions.in_mempool = TRUE + AND transactions.initiator_address = s.address + "#, + &stashed_addresses as &[&[u8]], + ) + .execute(self.storage.conn()) + .await?; - let purged_addresses: Vec<_> = - purged_accounts.into_iter().map(|a| a.0.to_vec()).collect(); - sqlx::query!( - r#" - DELETE FROM transactions - WHERE - in_mempool = TRUE - AND initiator_address = ANY ($1) - "#, - &purged_addresses[..] - ) - .execute(self.storage.conn()) - .await - .unwrap(); + let purged_addresses: Vec<_> = purged_accounts.iter().map(Address::as_bytes).collect(); + sqlx::query!( + r#" + DELETE FROM transactions + WHERE + in_mempool = TRUE + AND initiator_address = ANY ($1) + "#, + &purged_addresses as &[&[u8]] + ) + .execute(self.storage.conn()) + .await?; - // Note, that transactions are updated in order of their hashes to avoid deadlocks with other UPDATE queries. - let transactions = sqlx::query_as!( - StorageTransaction, - r#" - UPDATE transactions - SET - in_mempool = TRUE - FROM - ( - SELECT - hash - FROM - ( - SELECT - hash - FROM - transactions - WHERE - miniblock_number IS NULL - AND in_mempool = FALSE - AND error IS NULL - AND ( - is_priority = TRUE - OR ( - max_fee_per_gas >= $2 - AND gas_per_pubdata_limit >= $3 - ) + // Note, that transactions are updated in order of their hashes to avoid deadlocks with other UPDATE queries. + let transactions = sqlx::query_as!( + StorageTransaction, + r#" + UPDATE transactions + SET + in_mempool = TRUE + FROM + ( + SELECT + hash + FROM + ( + SELECT + hash + FROM + transactions + WHERE + miniblock_number IS NULL + AND in_mempool = FALSE + AND error IS NULL + AND ( + is_priority = TRUE + OR ( + max_fee_per_gas >= $2 + AND gas_per_pubdata_limit >= $3 ) - AND tx_format != $4 - ORDER BY - is_priority DESC, - priority_op_id, - received_at - LIMIT - $1 - ) AS subquery1 - ORDER BY - hash - ) AS subquery2 - WHERE - transactions.hash = subquery2.hash - RETURNING - transactions.* - "#, - limit as i32, - BigDecimal::from(fee_per_gas), - BigDecimal::from(gas_per_pubdata), - PROTOCOL_UPGRADE_TX_TYPE as i32, - ) - .fetch_all(self.storage.conn()) - .await - .unwrap(); + ) + AND tx_format != $4 + ORDER BY + is_priority DESC, + priority_op_id, + received_at + LIMIT + $1 + ) AS subquery1 + ORDER BY + hash + ) AS subquery2 + WHERE + transactions.hash = subquery2.hash + RETURNING + transactions.* + "#, + limit as i32, + BigDecimal::from(fee_per_gas), + BigDecimal::from(gas_per_pubdata), + PROTOCOL_UPGRADE_TX_TYPE as i32, + ) + .fetch_all(self.storage.conn()) + .await?; - let nonce_keys: HashMap<_, _> = transactions - .iter() - .map(|tx| { - let address = Address::from_slice(&tx.initiator_address); - let nonce_key = get_nonce_key(&address).hashed_key(); - (nonce_key, address) - }) - .collect(); + let nonce_keys: HashMap<_, _> = transactions + .iter() + .map(|tx| { + let address = Address::from_slice(&tx.initiator_address); + let nonce_key = get_nonce_key(&address).hashed_key(); + (nonce_key, address) + }) + .collect(); - let storage_keys: Vec<_> = nonce_keys.keys().map(|key| key.0.to_vec()).collect(); - let nonces: HashMap<_, _> = sqlx::query!( - r#" - SELECT - hashed_key, - value AS "value!" - FROM - storage - WHERE - hashed_key = ANY ($1) - "#, - &storage_keys, - ) - .fetch_all(self.storage.conn()) - .await - .unwrap() + let storage_keys: Vec<_> = nonce_keys.keys().map(H256::as_bytes).collect(); + let nonce_rows = sqlx::query!( + r#" + SELECT + hashed_key, + value AS "value!" + FROM + storage + WHERE + hashed_key = ANY ($1) + "#, + &storage_keys as &[&[u8]], + ) + .fetch_all(self.storage.conn()) + .await?; + + let nonces = nonce_rows .into_iter() .map(|row| { let nonce_key = H256::from_slice(&row.hashed_key); let nonce = Nonce(h256_to_u32(H256::from_slice(&row.value))); - - (*nonce_keys.get(&nonce_key).unwrap(), nonce) + (nonce_keys[&nonce_key], nonce) }) .collect(); - - ( - transactions.into_iter().map(|tx| tx.into()).collect(), - nonces, - ) - } + Ok(( + transactions.into_iter().map(|tx| tx.into()).collect(), + nonces, + )) } - pub async fn reset_mempool(&mut self) { - { - sqlx::query!( - r#" - UPDATE transactions - SET - in_mempool = FALSE - WHERE - in_mempool = TRUE - "# - ) - .execute(self.storage.conn()) - .await - .unwrap(); - } + pub async fn reset_mempool(&mut self) -> sqlx::Result<()> { + sqlx::query!( + r#" + UPDATE transactions + SET + in_mempool = FALSE + WHERE + in_mempool = TRUE + "# + ) + .execute(self.storage.conn()) + .await?; + Ok(()) } pub async fn get_last_processed_l1_block(&mut self) -> Option { @@ -1329,25 +1316,22 @@ impl TransactionsDal<'_, '_> { } } - pub async fn get_call_trace(&mut self, tx_hash: H256) -> Option { - { - sqlx::query_as!( - CallTrace, - r#" - SELECT - * - FROM - call_traces - WHERE - tx_hash = $1 - "#, - tx_hash.as_bytes() - ) - .fetch_optional(self.storage.conn()) - .await - .unwrap() - .map(|trace| trace.into()) - } + pub async fn get_call_trace(&mut self, tx_hash: H256) -> sqlx::Result> { + Ok(sqlx::query_as!( + CallTrace, + r#" + SELECT + call_trace + FROM + call_traces + WHERE + tx_hash = $1 + "#, + tx_hash.as_bytes() + ) + .fetch_optional(self.storage.conn()) + .await? + .map(Into::into)) } pub(crate) async fn get_tx_by_hash(&mut self, hash: H256) -> Option { @@ -1369,3 +1353,52 @@ impl TransactionsDal<'_, '_> { .map(|tx| tx.into()) } } + +#[cfg(test)] +mod tests { + use zksync_types::ProtocolVersion; + + use super::*; + use crate::{ + tests::{create_miniblock_header, mock_execution_result, mock_l2_transaction}, + ConnectionPool, + }; + + #[tokio::test] + async fn getting_call_trace_for_transaction() { + let connection_pool = ConnectionPool::test_pool().await; + let mut conn = connection_pool.access_storage().await.unwrap(); + conn.protocol_versions_dal() + .save_protocol_version_with_tx(ProtocolVersion::default()) + .await; + conn.blocks_dal() + .insert_miniblock(&create_miniblock_header(1)) + .await + .unwrap(); + + let tx = mock_l2_transaction(); + let tx_hash = tx.hash(); + conn.transactions_dal() + .insert_transaction_l2(tx.clone(), TransactionExecutionMetrics::default()) + .await; + let mut tx_result = mock_execution_result(tx); + tx_result.call_traces.push(Call { + from: Address::from_low_u64_be(1), + to: Address::from_low_u64_be(2), + value: 100.into(), + ..Call::default() + }); + let expected_call_trace = tx_result.call_trace().unwrap(); + conn.transactions_dal() + .mark_txs_as_executed_in_miniblock(MiniblockNumber(1), &[tx_result], 1.into()) + .await; + + let call_trace = conn + .transactions_dal() + .get_call_trace(tx_hash) + .await + .unwrap() + .expect("no call trace"); + assert_eq!(call_trace, expected_call_trace); + } +} diff --git a/core/lib/dal/src/transactions_web3_dal.rs b/core/lib/dal/src/transactions_web3_dal.rs index 3eb22bf05479..251d1db7f498 100644 --- a/core/lib/dal/src/transactions_web3_dal.rs +++ b/core/lib/dal/src/transactions_web3_dal.rs @@ -1,18 +1,16 @@ use sqlx::types::chrono::NaiveDateTime; use zksync_types::{ - api, Address, L2ChainId, MiniblockNumber, Transaction, ACCOUNT_CODE_STORAGE_ADDRESS, - FAILED_CONTRACT_DEPLOYMENT_BYTECODE_HASH, H160, H256, U256, U64, + api, api::TransactionReceipt, Address, L2ChainId, MiniblockNumber, Transaction, + ACCOUNT_CODE_STORAGE_ADDRESS, FAILED_CONTRACT_DEPLOYMENT_BYTECODE_HASH, H256, U256, }; -use zksync_utils::{bigdecimal_to_u256, h256_to_account_address}; use crate::{ instrument::InstrumentExt, models::{ storage_block::{bind_block_where_sql_params, web3_block_where_sql}, - storage_event::StorageWeb3Log, storage_transaction::{ extract_web3_transaction, web3_transaction_select_sql, StorageTransaction, - StorageTransactionDetails, + StorageTransactionDetails, StorageTransactionReceipt, }, }, SqlxError, StorageProcessor, @@ -24,171 +22,106 @@ pub struct TransactionsWeb3Dal<'a, 'c> { } impl TransactionsWeb3Dal<'_, '_> { - pub async fn get_transaction_receipt( + /// Returns receipts by transactions hashes. + /// Hashes are expected to be unique. + pub async fn get_transaction_receipts( &mut self, - hash: H256, - ) -> Result, SqlxError> { - { - let receipt = sqlx::query!( - r#" - WITH - sl AS ( - SELECT - * - FROM - storage_logs - WHERE - storage_logs.address = $1 - AND storage_logs.tx_hash = $2 - ORDER BY - storage_logs.miniblock_number DESC, - storage_logs.operation_number DESC - LIMIT - 1 - ) - SELECT - transactions.hash AS tx_hash, - transactions.index_in_block AS index_in_block, - transactions.l1_batch_tx_index AS l1_batch_tx_index, - transactions.miniblock_number AS "block_number!", - transactions.error AS error, - transactions.effective_gas_price AS effective_gas_price, - transactions.initiator_address AS initiator_address, - transactions.data -> 'to' AS "transfer_to?", - transactions.data -> 'contractAddress' AS "execute_contract_address?", - transactions.tx_format AS "tx_format?", - transactions.refunded_gas AS refunded_gas, - transactions.gas_limit AS gas_limit, - miniblocks.hash AS "block_hash", - miniblocks.l1_batch_number AS "l1_batch_number?", - sl.key AS "contract_address?" - FROM - transactions - JOIN miniblocks ON miniblocks.number = transactions.miniblock_number - LEFT JOIN sl ON sl.value != $3 - WHERE - transactions.hash = $2 - "#, - ACCOUNT_CODE_STORAGE_ADDRESS.as_bytes(), - hash.as_bytes(), - FAILED_CONTRACT_DEPLOYMENT_BYTECODE_HASH.as_bytes() - ) - .instrument("get_transaction_receipt") - .with_arg("hash", &hash) - .fetch_optional(self.storage.conn()) - .await? - .map(|db_row| { - let status = db_row.error.map(|_| U64::zero()).unwrap_or_else(U64::one); - - let tx_type = db_row.tx_format.map(U64::from).unwrap_or_default(); - let transaction_index = db_row.index_in_block.map(U64::from).unwrap_or_default(); - - let block_hash = H256::from_slice(&db_row.block_hash); - api::TransactionReceipt { - transaction_hash: H256::from_slice(&db_row.tx_hash), - transaction_index, - block_hash, - block_number: db_row.block_number.into(), - l1_batch_tx_index: db_row.l1_batch_tx_index.map(U64::from), - l1_batch_number: db_row.l1_batch_number.map(U64::from), - from: H160::from_slice(&db_row.initiator_address), - to: db_row - .transfer_to - .or(db_row.execute_contract_address) - .map(|addr| { - serde_json::from_value::
(addr) - .expect("invalid address value in the database") - }) - // For better compatibility with various clients, we never return null. - .or_else(|| Some(Address::default())), - cumulative_gas_used: Default::default(), // TODO: Should be actually calculated (SMA-1183). - gas_used: { - let refunded_gas: U256 = db_row.refunded_gas.into(); - db_row.gas_limit.map(|val| { - let gas_limit = bigdecimal_to_u256(val); - gas_limit - refunded_gas - }) - }, - effective_gas_price: Some( - db_row - .effective_gas_price - .map(bigdecimal_to_u256) - .unwrap_or_default(), - ), - contract_address: db_row - .contract_address - .map(|addr| h256_to_account_address(&H256::from_slice(&addr))), - logs: vec![], - l2_to_l1_logs: vec![], - status, - root: block_hash, - logs_bloom: Default::default(), - // Even though the Rust SDK recommends us to supply "None" for legacy transactions - // we always supply some number anyway to have the same behaviour as most popular RPCs - transaction_type: Some(tx_type), - } - }); - match receipt { - Some(mut receipt) => { - let logs: Vec<_> = sqlx::query_as!( - StorageWeb3Log, - r#" - SELECT - address, - topic1, - topic2, - topic3, - topic4, - value, - NULL::bytea AS "block_hash", - NULL::BIGINT AS "l1_batch_number?", - miniblock_number, - tx_hash, - tx_index_in_block, - event_index_in_block, - event_index_in_tx - FROM - events - WHERE - tx_hash = $1 - ORDER BY - miniblock_number ASC, - event_index_in_block ASC - "#, - hash.as_bytes() - ) - .instrument("get_transaction_receipt_events") - .with_arg("hash", &hash) - .fetch_all(self.storage.conn()) - .await? + hashes: &[H256], + ) -> Result, SqlxError> { + let mut receipts: Vec = sqlx::query_as!( + StorageTransactionReceipt, + r#" + WITH + sl AS ( + SELECT DISTINCT + ON (storage_logs.tx_hash) * + FROM + storage_logs + WHERE + storage_logs.address = $1 + AND storage_logs.tx_hash = ANY ($3) + ORDER BY + storage_logs.tx_hash, + storage_logs.miniblock_number DESC, + storage_logs.operation_number DESC + ) + SELECT + transactions.hash AS tx_hash, + transactions.index_in_block AS index_in_block, + transactions.l1_batch_tx_index AS l1_batch_tx_index, + transactions.miniblock_number AS "block_number!", + transactions.error AS error, + transactions.effective_gas_price AS effective_gas_price, + transactions.initiator_address AS initiator_address, + transactions.data -> 'to' AS "transfer_to?", + transactions.data -> 'contractAddress' AS "execute_contract_address?", + transactions.tx_format AS "tx_format?", + transactions.refunded_gas AS refunded_gas, + transactions.gas_limit AS gas_limit, + miniblocks.hash AS "block_hash", + miniblocks.l1_batch_number AS "l1_batch_number?", + sl.key AS "contract_address?" + FROM + transactions + JOIN miniblocks ON miniblocks.number = transactions.miniblock_number + LEFT JOIN sl ON sl.value != $2 + AND sl.tx_hash = transactions.hash + WHERE + transactions.hash = ANY ($3) + "#, + ACCOUNT_CODE_STORAGE_ADDRESS.as_bytes(), + FAILED_CONTRACT_DEPLOYMENT_BYTECODE_HASH.as_bytes(), + &hashes + .iter() + .map(|h| h.as_bytes().to_vec()) + .collect::>()[..] + ) + .fetch_all(self.storage.conn()) + .await? + .into_iter() + .map(Into::into) + .collect(); + + let mut logs = self + .storage + .events_dal() + .get_logs_by_tx_hashes(hashes) + .await?; + + let mut l2_to_l1_logs = self + .storage + .events_dal() + .get_l2_to_l1_logs_by_hashes(hashes) + .await?; + + for receipt in &mut receipts { + let logs_for_tx = logs.remove(&receipt.transaction_hash); + + if let Some(logs) = logs_for_tx { + receipt.logs = logs .into_iter() - .map(|storage_log| { - let mut log = api::Log::from(storage_log); + .map(|mut log| { log.block_hash = Some(receipt.block_hash); log.l1_batch_number = receipt.l1_batch_number; log }) .collect(); + } - receipt.logs = logs; - - let l2_to_l1_logs = self.storage.events_dal().l2_to_l1_logs(hash).await?; - let l2_to_l1_logs: Vec<_> = l2_to_l1_logs - .into_iter() - .map(|storage_l2_to_l1_log| { - let mut l2_to_l1_log = api::L2ToL1Log::from(storage_l2_to_l1_log); - l2_to_l1_log.block_hash = Some(receipt.block_hash); - l2_to_l1_log.l1_batch_number = receipt.l1_batch_number; - l2_to_l1_log - }) - .collect(); - receipt.l2_to_l1_logs = l2_to_l1_logs; - - Ok(Some(receipt)) - } - None => Ok(None), + let l2_to_l1_logs_for_tx = l2_to_l1_logs.remove(&receipt.transaction_hash); + if let Some(l2_to_l1_logs) = l2_to_l1_logs_for_tx { + receipt.l2_to_l1_logs = l2_to_l1_logs + .into_iter() + .map(|mut log| { + log.block_hash = Some(receipt.block_hash); + log.l1_batch_number = receipt.l1_batch_number; + log + }) + .collect(); } } + + Ok(receipts) } pub async fn get_transaction( @@ -321,23 +254,12 @@ impl TransactionsWeb3Dal<'_, '_> { Ok((hashes, last_loc)) } + /// `committed_next_nonce` should equal the nonce for `initiator_address` in the storage. pub async fn next_nonce_by_initiator_account( &mut self, initiator_address: Address, + committed_next_nonce: u64, ) -> Result { - let latest_block_number = self - .storage - .blocks_web3_dal() - .resolve_block_id(api::BlockId::Number(api::BlockNumber::Latest)) - .await? - .expect("Failed to get `latest` nonce"); - let latest_nonce = self - .storage - .storage_web3_dal() - .get_address_historical_nonce(initiator_address, latest_block_number) - .await? - .as_u64(); - // Get nonces of non-rejected transactions, starting from the 'latest' nonce. // `latest` nonce is used, because it is guaranteed that there are no gaps before it. // `(miniblock_number IS NOT NULL OR error IS NULL)` is the condition that filters non-rejected transactions. @@ -361,7 +283,7 @@ impl TransactionsWeb3Dal<'_, '_> { nonce "#, initiator_address.as_bytes(), - latest_nonce as i64 + committed_next_nonce as i64 ) .fetch_all(self.storage.conn()) .await? @@ -370,7 +292,7 @@ impl TransactionsWeb3Dal<'_, '_> { .collect(); // Find pending nonce as the first "gap" in nonces. - let mut pending_nonce = latest_nonce; + let mut pending_nonce = committed_next_nonce; for nonce in non_rejected_nonces { if pending_nonce == nonce { pending_nonce += 1; @@ -387,7 +309,7 @@ impl TransactionsWeb3Dal<'_, '_> { pub async fn get_raw_miniblock_transactions( &mut self, miniblock: MiniblockNumber, - ) -> Result, SqlxError> { + ) -> sqlx::Result> { let rows = sqlx::query_as!( StorageTransaction, r#" @@ -411,8 +333,10 @@ impl TransactionsWeb3Dal<'_, '_> { #[cfg(test)] mod tests { + use std::collections::HashMap; + use zksync_types::{ - block::MiniblockHasher, fee::TransactionExecutionMetrics, l2::L2Tx, ProtocolVersion, + block::MiniblockHasher, fee::TransactionExecutionMetrics, l2::L2Tx, Nonce, ProtocolVersion, ProtocolVersionId, }; @@ -422,26 +346,33 @@ mod tests { ConnectionPool, }; - async fn prepare_transaction(conn: &mut StorageProcessor<'_>, tx: L2Tx) { + async fn prepare_transactions(conn: &mut StorageProcessor<'_>, txs: Vec) { conn.blocks_dal() .delete_miniblocks(MiniblockNumber(0)) .await .unwrap(); - conn.transactions_dal() - .insert_transaction_l2(tx.clone(), TransactionExecutionMetrics::default()) - .await; + + for tx in &txs { + conn.transactions_dal() + .insert_transaction_l2(tx.clone(), TransactionExecutionMetrics::default()) + .await; + } conn.blocks_dal() .insert_miniblock(&create_miniblock_header(0)) .await .unwrap(); let mut miniblock_header = create_miniblock_header(1); - miniblock_header.l2_tx_count = 1; + miniblock_header.l2_tx_count = txs.len() as u16; conn.blocks_dal() .insert_miniblock(&miniblock_header) .await .unwrap(); - let tx_results = [mock_execution_result(tx)]; + let tx_results = txs + .into_iter() + .map(mock_execution_result) + .collect::>(); + conn.transactions_dal() .mark_txs_as_executed_in_miniblock(MiniblockNumber(1), &tx_results, U256::from(1)) .await; @@ -456,7 +387,7 @@ mod tests { .await; let tx = mock_l2_transaction(); let tx_hash = tx.hash(); - prepare_transaction(&mut conn, tx).await; + prepare_transactions(&mut conn, vec![tx]).await; let block_hash = MiniblockHasher::new(MiniblockNumber(1), 0, H256::zero()) .finalize(ProtocolVersionId::latest()); @@ -510,6 +441,34 @@ mod tests { } } + #[tokio::test] + async fn getting_receipts() { + let connection_pool = ConnectionPool::test_pool().await; + let mut conn = connection_pool.access_storage().await.unwrap(); + conn.protocol_versions_dal() + .save_protocol_version_with_tx(ProtocolVersion::default()) + .await; + + let tx1 = mock_l2_transaction(); + let tx1_hash = tx1.hash(); + let tx2 = mock_l2_transaction(); + let tx2_hash = tx2.hash(); + + prepare_transactions(&mut conn, vec![tx1.clone(), tx2.clone()]).await; + + let mut receipts = conn + .transactions_web3_dal() + .get_transaction_receipts(&[tx1_hash, tx2_hash]) + .await + .unwrap(); + + receipts.sort_unstable_by_key(|receipt| receipt.transaction_index); + + assert_eq!(receipts.len(), 2); + assert_eq!(receipts[0].transaction_hash, tx1_hash); + assert_eq!(receipts[1].transaction_hash, tx2_hash); + } + #[tokio::test] async fn getting_miniblock_transactions() { let connection_pool = ConnectionPool::test_pool().await; @@ -519,7 +478,7 @@ mod tests { .await; let tx = mock_l2_transaction(); let tx_hash = tx.hash(); - prepare_transaction(&mut conn, tx).await; + prepare_transactions(&mut conn, vec![tx]).await; let raw_txs = conn .transactions_web3_dal() @@ -536,4 +495,102 @@ mod tests { assert_eq!(raw_txs.len(), 1); assert_eq!(raw_txs[0].hash(), tx_hash); } + + #[tokio::test] + async fn getting_next_nonce_by_initiator_account() { + let connection_pool = ConnectionPool::test_pool().await; + let mut conn = connection_pool.access_storage().await.unwrap(); + conn.protocol_versions_dal() + .save_protocol_version_with_tx(ProtocolVersion::default()) + .await; + + let initiator = Address::repeat_byte(1); + let next_nonce = conn + .transactions_web3_dal() + .next_nonce_by_initiator_account(initiator, 0) + .await + .unwrap(); + assert_eq!(next_nonce, 0.into()); + + let mut tx_by_nonce = HashMap::new(); + for nonce in [0, 1, 4] { + let mut tx = mock_l2_transaction(); + // Changing transaction fields invalidates its signature, but it's OK for test purposes + tx.common_data.nonce = Nonce(nonce); + tx.common_data.initiator_address = initiator; + tx_by_nonce.insert(nonce, tx.clone()); + conn.transactions_dal() + .insert_transaction_l2(tx, TransactionExecutionMetrics::default()) + .await; + } + + let next_nonce = conn + .transactions_web3_dal() + .next_nonce_by_initiator_account(initiator, 0) + .await + .unwrap(); + assert_eq!(next_nonce, 2.into()); + + // Reject the transaction with nonce 1, so that it'd be not taken into account. + conn.transactions_dal() + .mark_tx_as_rejected(tx_by_nonce[&1].hash(), "oops") + .await; + let next_nonce = conn + .transactions_web3_dal() + .next_nonce_by_initiator_account(initiator, 0) + .await + .unwrap(); + assert_eq!(next_nonce, 1.into()); + + // Include transactions in a miniblock (including the rejected one), so that they are taken into account again. + let mut miniblock = create_miniblock_header(1); + miniblock.l2_tx_count = 2; + conn.blocks_dal() + .insert_miniblock(&miniblock) + .await + .unwrap(); + let executed_txs = [ + mock_execution_result(tx_by_nonce[&0].clone()), + mock_execution_result(tx_by_nonce[&1].clone()), + ]; + conn.transactions_dal() + .mark_txs_as_executed_in_miniblock(miniblock.number, &executed_txs, 1.into()) + .await; + + let next_nonce = conn + .transactions_web3_dal() + .next_nonce_by_initiator_account(initiator, 0) + .await + .unwrap(); + assert_eq!(next_nonce, 2.into()); + } + + #[tokio::test] + async fn getting_next_nonce_by_initiator_account_after_snapshot_recovery() { + // Emulate snapshot recovery: no transactions with past nonces are present in the storage + let connection_pool = ConnectionPool::test_pool().await; + let mut conn = connection_pool.access_storage().await.unwrap(); + let initiator = Address::repeat_byte(1); + let next_nonce = conn + .transactions_web3_dal() + .next_nonce_by_initiator_account(initiator, 1) + .await + .unwrap(); + assert_eq!(next_nonce, 1.into()); + + let mut tx = mock_l2_transaction(); + // Changing transaction fields invalidates its signature, but it's OK for test purposes + tx.common_data.nonce = Nonce(1); + tx.common_data.initiator_address = initiator; + conn.transactions_dal() + .insert_transaction_l2(tx, TransactionExecutionMetrics::default()) + .await; + + let next_nonce = conn + .transactions_web3_dal() + .next_nonce_by_initiator_account(initiator, 1) + .await + .unwrap(); + assert_eq!(next_nonce, 2.into()); + } } diff --git a/core/lib/env_config/src/api.rs b/core/lib/env_config/src/api.rs index b5e477eda2c1..5368122437ff 100644 --- a/core/lib/env_config/src/api.rs +++ b/core/lib/env_config/src/api.rs @@ -66,9 +66,7 @@ mod tests { filters_limit: Some(10000), subscriptions_limit: Some(10000), pubsub_polling_interval: Some(200), - threads_per_server: 128, max_nonce_ahead: 5, - transactions_per_sec_limit: Some(1000), request_timeout: Some(10), account_pks: Some(vec![ hash("0x0000000000000000000000000000000000000000000000000000000000000001"), @@ -77,14 +75,13 @@ mod tests { estimate_gas_scale_factor: 1.0f64, gas_price_scale_factor: 1.2, estimate_gas_acceptable_overestimation: 1000, + l1_to_l2_transactions_compatibility_mode: true, max_tx_size: 1000000, vm_execution_cache_misses_limit: None, vm_concurrency_limit: Some(512), factory_deps_cache_size_mb: Some(128), initial_writes_cache_size_mb: Some(32), latest_values_cache_size_mb: Some(256), - http_threads: Some(128), - ws_threads: Some(256), fee_history_limit: Some(100), max_batch_request_size: Some(200), max_response_body_size_mb: Some(10), @@ -94,7 +91,6 @@ mod tests { contract_verification: ContractVerificationApiConfig { port: 3070, url: "http://127.0.0.1:3070".into(), - threads_per_server: 128, }, prometheus: PrometheusConfig { listener_port: 3312, @@ -118,27 +114,23 @@ mod tests { API_WEB3_JSON_RPC_FILTERS_LIMIT=10000 API_WEB3_JSON_RPC_SUBSCRIPTIONS_LIMIT=10000 API_WEB3_JSON_RPC_PUBSUB_POLLING_INTERVAL=200 - API_WEB3_JSON_RPC_THREADS_PER_SERVER=128 API_WEB3_JSON_RPC_MAX_NONCE_AHEAD=5 API_WEB3_JSON_RPC_GAS_PRICE_SCALE_FACTOR=1.2 - API_WEB3_JSON_RPC_TRANSACTIONS_PER_SEC_LIMIT=1000 API_WEB3_JSON_RPC_REQUEST_TIMEOUT=10 API_WEB3_JSON_RPC_ACCOUNT_PKS="0x0000000000000000000000000000000000000000000000000000000000000001,0x0000000000000000000000000000000000000000000000000000000000000002" API_WEB3_JSON_RPC_ESTIMATE_GAS_SCALE_FACTOR=1.0 API_WEB3_JSON_RPC_ESTIMATE_GAS_ACCEPTABLE_OVERESTIMATION=1000 + API_WEB3_JSON_RPC_L1_TO_L2_TRANSACTIONS_COMPATIBILITY_MODE=true API_WEB3_JSON_RPC_MAX_TX_SIZE=1000000 API_WEB3_JSON_RPC_VM_CONCURRENCY_LIMIT=512 API_WEB3_JSON_RPC_FACTORY_DEPS_CACHE_SIZE_MB=128 API_WEB3_JSON_RPC_INITIAL_WRITES_CACHE_SIZE_MB=32 API_WEB3_JSON_RPC_LATEST_VALUES_CACHE_SIZE_MB=256 - API_WEB3_JSON_RPC_HTTP_THREADS=128 - API_WEB3_JSON_RPC_WS_THREADS=256 API_WEB3_JSON_RPC_FEE_HISTORY_LIMIT=100 API_WEB3_JSON_RPC_MAX_BATCH_REQUEST_SIZE=200 API_WEB3_JSON_RPC_WEBSOCKET_REQUESTS_PER_MINUTE_LIMIT=10 API_CONTRACT_VERIFICATION_PORT="3070" API_CONTRACT_VERIFICATION_URL="http://127.0.0.1:3070" - API_CONTRACT_VERIFICATION_THREADS_PER_SERVER=128 API_WEB3_JSON_RPC_MAX_RESPONSE_BODY_SIZE_MB=10 API_PROMETHEUS_LISTENER_PORT="3312" API_PROMETHEUS_PUSHGATEWAY_URL="http://127.0.0.1:9091" diff --git a/core/lib/env_config/src/chain.rs b/core/lib/env_config/src/chain.rs index 7c2aa7e59419..c258c5092e51 100644 --- a/core/lib/env_config/src/chain.rs +++ b/core/lib/env_config/src/chain.rs @@ -1,24 +1,9 @@ -use anyhow::Context as _; use zksync_config::configs::chain::{ - ChainConfig, CircuitBreakerConfig, MempoolConfig, NetworkConfig, OperationsManagerConfig, - StateKeeperConfig, + CircuitBreakerConfig, MempoolConfig, NetworkConfig, OperationsManagerConfig, StateKeeperConfig, }; use crate::{envy_load, FromEnv}; -impl FromEnv for ChainConfig { - fn from_env() -> anyhow::Result { - Ok(Self { - network: NetworkConfig::from_env().context("NetworkConfig")?, - state_keeper: StateKeeperConfig::from_env().context("StateKeeperConfig")?, - operations_manager: OperationsManagerConfig::from_env() - .context("OperationsManagerConfig")?, - mempool: MempoolConfig::from_env().context("MempoolConfig")?, - circuit_breaker: CircuitBreakerConfig::from_env().context("CircuitBreakerConfig")?, - }) - } -} - impl FromEnv for NetworkConfig { fn from_env() -> anyhow::Result { envy_load("network", "CHAIN_ETH_") @@ -52,68 +37,70 @@ impl FromEnv for MempoolConfig { #[cfg(test)] mod tests { use zksync_basic_types::L2ChainId; + use zksync_config::configs::chain::FeeModelVersion; use super::*; use crate::test_utils::{addr, EnvMutex}; static MUTEX: EnvMutex = EnvMutex::new(); - fn expected_config() -> ChainConfig { - ChainConfig { - network: NetworkConfig { - network: "localhost".parse().unwrap(), - zksync_network: "localhost".to_string(), - zksync_network_id: L2ChainId::from(270), - }, - state_keeper: StateKeeperConfig { - transaction_slots: 50, - block_commit_deadline_ms: 2500, - miniblock_commit_deadline_ms: 1000, - miniblock_seal_queue_capacity: 10, - max_single_tx_gas: 1_000_000, - max_allowed_l2_tx_gas_limit: 2_000_000_000, - close_block_at_eth_params_percentage: 0.2, - close_block_at_gas_percentage: 0.8, - close_block_at_geometry_percentage: 0.5, - reject_tx_at_eth_params_percentage: 0.8, - reject_tx_at_geometry_percentage: 0.3, - fee_account_addr: addr("de03a0B5963f75f1C8485B355fF6D30f3093BDE7"), - reject_tx_at_gas_percentage: 0.5, - fair_l2_gas_price: 250000000, - validation_computational_gas_limit: 10_000_000, - save_call_traces: false, - virtual_blocks_interval: 1, - virtual_blocks_per_miniblock: 1, - upload_witness_inputs_to_gcs: false, - enum_index_migration_chunk_size: Some(2_000), - }, - operations_manager: OperationsManagerConfig { - delay_interval: 100, - }, - mempool: MempoolConfig { - sync_interval_ms: 10, - sync_batch_size: 1000, - capacity: 1_000_000, - stuck_tx_timeout: 10, - remove_stuck_txs: true, - delay_interval: 100, - }, - circuit_breaker: CircuitBreakerConfig { - sync_interval_ms: 1000, - http_req_max_retry_number: 5, - http_req_retry_interval_sec: 2, - replication_lag_limit_sec: Some(10), - }, + fn expected_network_config() -> NetworkConfig { + NetworkConfig { + network: "localhost".parse().unwrap(), + zksync_network: "localhost".to_string(), + zksync_network_id: L2ChainId::from(270), } } #[test] - fn from_env() { + fn network_from_env() { let mut lock = MUTEX.lock(); let config = r#" CHAIN_ETH_NETWORK="localhost" CHAIN_ETH_ZKSYNC_NETWORK="localhost" CHAIN_ETH_ZKSYNC_NETWORK_ID=270 + "#; + lock.set_env(config); + + let actual = NetworkConfig::from_env().unwrap(); + assert_eq!(actual, expected_network_config()); + } + + fn expected_state_keeper_config() -> StateKeeperConfig { + StateKeeperConfig { + transaction_slots: 50, + block_commit_deadline_ms: 2500, + miniblock_commit_deadline_ms: 1000, + miniblock_seal_queue_capacity: 10, + max_single_tx_gas: 1_000_000, + max_allowed_l2_tx_gas_limit: 2_000_000_000, + close_block_at_eth_params_percentage: 0.2, + close_block_at_gas_percentage: 0.8, + close_block_at_geometry_percentage: 0.5, + reject_tx_at_eth_params_percentage: 0.8, + reject_tx_at_geometry_percentage: 0.3, + fee_account_addr: addr("de03a0B5963f75f1C8485B355fF6D30f3093BDE7"), + reject_tx_at_gas_percentage: 0.5, + minimal_l2_gas_price: 100000000, + compute_overhead_part: 0.0, + pubdata_overhead_part: 1.0, + batch_overhead_l1_gas: 800_000, + max_gas_per_batch: 200_000_000, + max_pubdata_per_batch: 100_000, + fee_model_version: FeeModelVersion::V2, + validation_computational_gas_limit: 10_000_000, + save_call_traces: false, + virtual_blocks_interval: 1, + virtual_blocks_per_miniblock: 1, + upload_witness_inputs_to_gcs: false, + enum_index_migration_chunk_size: Some(2_000), + } + } + + #[test] + fn state_keeper_from_env() { + let mut lock = MUTEX.lock(); + let config = r#" CHAIN_STATE_KEEPER_TRANSACTION_SLOTS="50" CHAIN_STATE_KEEPER_FEE_ACCOUNT_ADDR="0xde03a0B5963f75f1C8485B355fF6D30f3093BDE7" CHAIN_STATE_KEEPER_MAX_SINGLE_TX_GAS="1000000" @@ -127,18 +114,83 @@ mod tests { CHAIN_STATE_KEEPER_BLOCK_COMMIT_DEADLINE_MS="2500" CHAIN_STATE_KEEPER_MINIBLOCK_COMMIT_DEADLINE_MS="1000" CHAIN_STATE_KEEPER_MINIBLOCK_SEAL_QUEUE_CAPACITY="10" - CHAIN_STATE_KEEPER_FAIR_L2_GAS_PRICE="250000000" + CHAIN_STATE_KEEPER_MINIMAL_L2_GAS_PRICE="100000000" + CHAIN_STATE_KEEPER_COMPUTE_OVERHEAD_PART="0.0" + CHAIN_STATE_KEEPER_PUBDATA_OVERHEAD_PART="1.0" + CHAIN_STATE_KEEPER_BATCH_OVERHEAD_L1_GAS="800000" + CHAIN_STATE_KEEPER_MAX_GAS_PER_BATCH="200000000" + CHAIN_STATE_KEEPER_MAX_PUBDATA_PER_BATCH="100000" + CHAIN_STATE_KEEPER_FEE_MODEL_VERSION="V2" CHAIN_STATE_KEEPER_VALIDATION_COMPUTATIONAL_GAS_LIMIT="10000000" CHAIN_STATE_KEEPER_SAVE_CALL_TRACES="false" CHAIN_STATE_KEEPER_UPLOAD_WITNESS_INPUTS_TO_GCS="false" CHAIN_STATE_KEEPER_ENUM_INDEX_MIGRATION_CHUNK_SIZE="2000" + "#; + lock.set_env(config); + + let actual = StateKeeperConfig::from_env().unwrap(); + assert_eq!(actual, expected_state_keeper_config()); + } + + fn expected_operations_manager_config() -> OperationsManagerConfig { + OperationsManagerConfig { + delay_interval: 100, + } + } + + #[test] + fn operations_manager_from_env() { + let mut lock = MUTEX.lock(); + let config = r#" CHAIN_OPERATIONS_MANAGER_DELAY_INTERVAL="100" + "#; + lock.set_env(config); + + let actual = OperationsManagerConfig::from_env().unwrap(); + assert_eq!(actual, expected_operations_manager_config()); + } + + fn expected_mempool_config() -> MempoolConfig { + MempoolConfig { + sync_interval_ms: 10, + sync_batch_size: 1000, + capacity: 1_000_000, + stuck_tx_timeout: 10, + remove_stuck_txs: true, + delay_interval: 100, + } + } + + #[test] + fn mempool_from_env() { + let mut lock = MUTEX.lock(); + let config = r#" CHAIN_MEMPOOL_SYNC_INTERVAL_MS="10" CHAIN_MEMPOOL_SYNC_BATCH_SIZE="1000" CHAIN_MEMPOOL_STUCK_TX_TIMEOUT="10" CHAIN_MEMPOOL_REMOVE_STUCK_TXS="true" CHAIN_MEMPOOL_DELAY_INTERVAL="100" CHAIN_MEMPOOL_CAPACITY="1000000" + "#; + lock.set_env(config); + + let actual = MempoolConfig::from_env().unwrap(); + assert_eq!(actual, expected_mempool_config()); + } + + fn expected_circuit_breaker_config() -> CircuitBreakerConfig { + CircuitBreakerConfig { + sync_interval_ms: 1000, + http_req_max_retry_number: 5, + http_req_retry_interval_sec: 2, + replication_lag_limit_sec: Some(10), + } + } + + #[test] + fn circuit_breaker_from_env() { + let mut lock = MUTEX.lock(); + let config = r#" CHAIN_CIRCUIT_BREAKER_SYNC_INTERVAL_MS="1000" CHAIN_CIRCUIT_BREAKER_HTTP_REQ_MAX_RETRY_NUMBER="5" CHAIN_CIRCUIT_BREAKER_HTTP_REQ_RETRY_INTERVAL_SEC="2" @@ -146,7 +198,7 @@ mod tests { "#; lock.set_env(config); - let actual = ChainConfig::from_env().unwrap(); - assert_eq!(actual, expected_config()); + let actual = CircuitBreakerConfig::from_env().unwrap(); + assert_eq!(actual, expected_circuit_breaker_config()); } } diff --git a/core/lib/env_config/src/circuit_synthesizer.rs b/core/lib/env_config/src/circuit_synthesizer.rs deleted file mode 100644 index a59e1adcd656..000000000000 --- a/core/lib/env_config/src/circuit_synthesizer.rs +++ /dev/null @@ -1,51 +0,0 @@ -use zksync_config::configs::CircuitSynthesizerConfig; - -use crate::{envy_load, FromEnv}; - -impl FromEnv for CircuitSynthesizerConfig { - fn from_env() -> anyhow::Result { - envy_load("circuit_synthesizer", "CIRCUIT_SYNTHESIZER_") - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::test_utils::EnvMutex; - - static MUTEX: EnvMutex = EnvMutex::new(); - - fn expected_config() -> CircuitSynthesizerConfig { - CircuitSynthesizerConfig { - generation_timeout_in_secs: 1000u16, - max_attempts: 2, - gpu_prover_queue_timeout_in_secs: 1000u16, - prover_instance_wait_timeout_in_secs: 1000u16, - prover_instance_poll_time_in_milli_secs: 250u16, - prometheus_listener_port: 3314, - prometheus_pushgateway_url: "http://127.0.0.1:9091".to_string(), - prometheus_push_interval_ms: Some(100), - prover_group_id: 0, - } - } - - #[test] - fn from_env() { - let mut lock = MUTEX.lock(); - let config = r#" - CIRCUIT_SYNTHESIZER_GENERATION_TIMEOUT_IN_SECS=1000 - CIRCUIT_SYNTHESIZER_MAX_ATTEMPTS=2 - CIRCUIT_SYNTHESIZER_GPU_PROVER_QUEUE_TIMEOUT_IN_SECS=1000 - CIRCUIT_SYNTHESIZER_PROVER_INSTANCE_WAIT_TIMEOUT_IN_SECS=1000 - CIRCUIT_SYNTHESIZER_PROVER_INSTANCE_POLL_TIME_IN_MILLI_SECS=250 - CIRCUIT_SYNTHESIZER_PROMETHEUS_LISTENER_PORT=3314 - CIRCUIT_SYNTHESIZER_PROMETHEUS_PUSHGATEWAY_URL="http://127.0.0.1:9091" - CIRCUIT_SYNTHESIZER_PROMETHEUS_PUSH_INTERVAL_MS=100 - CIRCUIT_SYNTHESIZER_PROVER_GROUP_ID=0 - "#; - lock.set_env(config); - - let actual = CircuitSynthesizerConfig::from_env().unwrap(); - assert_eq!(actual, expected_config()); - } -} diff --git a/core/lib/env_config/src/database.rs b/core/lib/env_config/src/database.rs index e6269cd23768..74f665617ce5 100644 --- a/core/lib/env_config/src/database.rs +++ b/core/lib/env_config/src/database.rs @@ -27,11 +27,11 @@ impl FromEnv for PostgresConfig { .ok() .map(|val| val.parse().context("failed to parse DATABASE_POOL_SIZE")) .transpose()?; - let statement_timeout_sec = env::var("DATABASE_STATEMENT_TIMEOUT") + let statement_timeout_sec = env::var("DATABASE_STATEMENT_TIMEOUT_SEC") .ok() .map(|val| { val.parse() - .context("failed to parse DATABASE_STATEMENT_TIMEOUT") + .context("failed to parse DATABASE_STATEMENT_TIMEOUT_SEC") }) .transpose()?; @@ -47,6 +47,8 @@ impl FromEnv for PostgresConfig { #[cfg(test)] mod tests { + use std::time::Duration; + use zksync_config::configs::database::MerkleTreeMode; use super::*; @@ -120,4 +122,26 @@ mod tests { let db_config = DBConfig::from_env().unwrap(); assert_eq!(db_config.merkle_tree.max_l1_batches_per_iter, 50); } + + #[test] + fn postgres_from_env() { + let mut lock = MUTEX.lock(); + let config = r#" + DATABASE_URL=postgres://postgres@localhost/zksync_local + DATABASE_POOL_SIZE=50 + DATABASE_STATEMENT_TIMEOUT_SEC=300 + "#; + lock.set_env(config); + + let postgres_config = PostgresConfig::from_env().unwrap(); + assert_eq!( + postgres_config.master_url().unwrap(), + "postgres://postgres@localhost/zksync_local" + ); + assert_eq!(postgres_config.max_connections().unwrap(), 50); + assert_eq!( + postgres_config.statement_timeout(), + Some(Duration::from_secs(300)) + ); + } } diff --git a/core/lib/env_config/src/fri_prover.rs b/core/lib/env_config/src/fri_prover.rs index 200f22d89b7e..7b97df50374b 100644 --- a/core/lib/env_config/src/fri_prover.rs +++ b/core/lib/env_config/src/fri_prover.rs @@ -30,6 +30,8 @@ mod tests { witness_vector_generator_thread_count: Some(5), queue_capacity: 10, witness_vector_receiver_port: 3316, + zone_read_url: "http://metadata.google.internal/computeMetadata/v1/instance/zone" + .to_string(), shall_save_to_public_bucket: true, } } @@ -49,6 +51,7 @@ mod tests { FRI_PROVER_WITNESS_VECTOR_GENERATOR_THREAD_COUNT="5" FRI_PROVER_QUEUE_CAPACITY="10" FRI_PROVER_WITNESS_VECTOR_RECEIVER_PORT="3316" + FRI_PROVER_ZONE_READ_URL="http://metadata.google.internal/computeMetadata/v1/instance/zone" FRI_PROVER_SHALL_SAVE_TO_PUBLIC_BUCKET=true "#; lock.set_env(config); diff --git a/core/lib/env_config/src/lib.rs b/core/lib/env_config/src/lib.rs index 78e6c7216dd5..5186b6e41982 100644 --- a/core/lib/env_config/src/lib.rs +++ b/core/lib/env_config/src/lib.rs @@ -4,7 +4,6 @@ use serde::de::DeserializeOwned; mod alerts; mod api; mod chain; -mod circuit_synthesizer; mod contract_verifier; mod contracts; mod database; @@ -20,8 +19,6 @@ mod fri_witness_vector_generator; mod house_keeper; pub mod object_store; mod proof_data_handler; -mod prover; -mod prover_group; mod snapshots_creator; mod utils; mod witness_generator; @@ -35,7 +32,7 @@ pub trait FromEnv: Sized { /// Convenience function that loads the structure from the environment variable given the prefix. /// Panics if the config cannot be loaded from the environment variables. -pub(crate) fn envy_load(name: &str, prefix: &str) -> anyhow::Result { +pub fn envy_load(name: &str, prefix: &str) -> anyhow::Result { envy::prefixed(prefix) .from_env() .with_context(|| format!("Cannot load config <{name}>")) diff --git a/core/lib/env_config/src/prover.rs b/core/lib/env_config/src/prover.rs deleted file mode 100644 index 700f0fffb96a..000000000000 --- a/core/lib/env_config/src/prover.rs +++ /dev/null @@ -1,197 +0,0 @@ -use zksync_config::ProverConfigs; - -use crate::{envy_load, FromEnv}; - -impl FromEnv for ProverConfigs { - fn from_env() -> anyhow::Result { - Ok(Self { - non_gpu: envy_load("non_gpu", "PROVER_NON_GPU_")?, - two_gpu_forty_gb_mem: envy_load( - "two_gpu_forty_gb_mem", - "PROVER_TWO_GPU_FORTY_GB_MEM_", - )?, - one_gpu_eighty_gb_mem: envy_load( - "one_gpu_eighty_gb_mem", - "PROVER_ONE_GPU_EIGHTY_GB_MEM_", - )?, - two_gpu_eighty_gb_mem: envy_load( - "two_gpu_eighty_gb_mem", - "PROVER_TWO_GPU_EIGHTY_GB_MEM_", - )?, - four_gpu_eighty_gb_mem: envy_load( - "four_gpu_eighty_gb_mem", - "PROVER_FOUR_GPU_EIGHTY_GB_MEM_", - )?, - }) - } -} - -#[cfg(test)] -mod tests { - use zksync_config::ProverConfig; - - use super::*; - use crate::test_utils::EnvMutex; - - static MUTEX: EnvMutex = EnvMutex::new(); - - fn expected_config() -> ProverConfigs { - ProverConfigs { - non_gpu: ProverConfig { - prometheus_port: 3313, - initial_setup_key_path: "key".to_owned(), - key_download_url: "value".to_owned(), - generation_timeout_in_secs: 2700u16, - number_of_threads: 2, - max_attempts: 4, - polling_duration_in_millis: 5, - setup_keys_path: "/usr/src/setup-keys".to_string(), - specialized_prover_group_id: 0, - number_of_setup_slots: 2, - assembly_receiver_port: 17791, - assembly_receiver_poll_time_in_millis: 250, - assembly_queue_capacity: 5, - }, - two_gpu_forty_gb_mem: ProverConfig { - prometheus_port: 3313, - initial_setup_key_path: "key".to_owned(), - key_download_url: "value".to_owned(), - generation_timeout_in_secs: 2700u16, - number_of_threads: 2, - max_attempts: 4, - polling_duration_in_millis: 5, - setup_keys_path: "/usr/src/setup-keys".to_string(), - specialized_prover_group_id: 1, - number_of_setup_slots: 5, - assembly_receiver_port: 17791, - assembly_receiver_poll_time_in_millis: 250, - assembly_queue_capacity: 5, - }, - one_gpu_eighty_gb_mem: ProverConfig { - prometheus_port: 3313, - initial_setup_key_path: "key".to_owned(), - key_download_url: "value".to_owned(), - generation_timeout_in_secs: 2700u16, - number_of_threads: 4, - max_attempts: 4, - polling_duration_in_millis: 5, - setup_keys_path: "/usr/src/setup-keys".to_string(), - specialized_prover_group_id: 2, - number_of_setup_slots: 5, - assembly_receiver_port: 17791, - assembly_receiver_poll_time_in_millis: 250, - assembly_queue_capacity: 5, - }, - two_gpu_eighty_gb_mem: ProverConfig { - prometheus_port: 3313, - initial_setup_key_path: "key".to_owned(), - key_download_url: "value".to_owned(), - generation_timeout_in_secs: 2700u16, - number_of_threads: 9, - max_attempts: 4, - polling_duration_in_millis: 5, - setup_keys_path: "/usr/src/setup-keys".to_string(), - specialized_prover_group_id: 3, - number_of_setup_slots: 9, - assembly_receiver_port: 17791, - assembly_receiver_poll_time_in_millis: 250, - assembly_queue_capacity: 5, - }, - four_gpu_eighty_gb_mem: ProverConfig { - prometheus_port: 3313, - initial_setup_key_path: "key".to_owned(), - key_download_url: "value".to_owned(), - generation_timeout_in_secs: 2700u16, - number_of_threads: 18, - max_attempts: 4, - polling_duration_in_millis: 5, - setup_keys_path: "/usr/src/setup-keys".to_string(), - specialized_prover_group_id: 4, - number_of_setup_slots: 18, - assembly_receiver_port: 17791, - assembly_receiver_poll_time_in_millis: 250, - assembly_queue_capacity: 5, - }, - } - } - - const CONFIG: &str = r#" - PROVER_NON_GPU_PROMETHEUS_PORT="3313" - PROVER_NON_GPU_INITIAL_SETUP_KEY_PATH="key" - PROVER_NON_GPU_KEY_DOWNLOAD_URL="value" - PROVER_NON_GPU_GENERATION_TIMEOUT_IN_SECS=2700 - PROVER_NON_GPU_NUMBER_OF_THREADS="2" - PROVER_NON_GPU_MAX_ATTEMPTS="4" - PROVER_NON_GPU_POLLING_DURATION_IN_MILLIS=5 - PROVER_NON_GPU_SETUP_KEYS_PATH="/usr/src/setup-keys" - PROVER_NON_GPU_NUMBER_OF_SETUP_SLOTS=2 - PROVER_NON_GPU_ASSEMBLY_RECEIVER_PORT=17791 - PROVER_NON_GPU_ASSEMBLY_RECEIVER_POLL_TIME_IN_MILLIS=250 - PROVER_NON_GPU_ASSEMBLY_QUEUE_CAPACITY=5 - PROVER_NON_GPU_SPECIALIZED_PROVER_GROUP_ID=0 - - PROVER_TWO_GPU_FORTY_GB_MEM_PROMETHEUS_PORT="3313" - PROVER_TWO_GPU_FORTY_GB_MEM_INITIAL_SETUP_KEY_PATH="key" - PROVER_TWO_GPU_FORTY_GB_MEM_KEY_DOWNLOAD_URL="value" - PROVER_TWO_GPU_FORTY_GB_MEM_GENERATION_TIMEOUT_IN_SECS=2700 - PROVER_TWO_GPU_FORTY_GB_MEM_NUMBER_OF_THREADS="2" - PROVER_TWO_GPU_FORTY_GB_MEM_MAX_ATTEMPTS="4" - PROVER_TWO_GPU_FORTY_GB_MEM_POLLING_DURATION_IN_MILLIS=5 - PROVER_TWO_GPU_FORTY_GB_MEM_SETUP_KEYS_PATH="/usr/src/setup-keys" - PROVER_TWO_GPU_FORTY_GB_MEM_NUMBER_OF_SETUP_SLOTS=5 - PROVER_TWO_GPU_FORTY_GB_MEM_ASSEMBLY_RECEIVER_PORT=17791 - PROVER_TWO_GPU_FORTY_GB_MEM_ASSEMBLY_RECEIVER_POLL_TIME_IN_MILLIS=250 - PROVER_TWO_GPU_FORTY_GB_MEM_ASSEMBLY_QUEUE_CAPACITY=5 - PROVER_TWO_GPU_FORTY_GB_MEM_SPECIALIZED_PROVER_GROUP_ID=1 - - PROVER_ONE_GPU_EIGHTY_GB_MEM_PROMETHEUS_PORT="3313" - PROVER_ONE_GPU_EIGHTY_GB_MEM_INITIAL_SETUP_KEY_PATH="key" - PROVER_ONE_GPU_EIGHTY_GB_MEM_KEY_DOWNLOAD_URL="value" - PROVER_ONE_GPU_EIGHTY_GB_MEM_GENERATION_TIMEOUT_IN_SECS=2700 - PROVER_ONE_GPU_EIGHTY_GB_MEM_NUMBER_OF_THREADS="4" - PROVER_ONE_GPU_EIGHTY_GB_MEM_MAX_ATTEMPTS="4" - PROVER_ONE_GPU_EIGHTY_GB_MEM_POLLING_DURATION_IN_MILLIS=5 - PROVER_ONE_GPU_EIGHTY_GB_MEM_SETUP_KEYS_PATH="/usr/src/setup-keys" - PROVER_ONE_GPU_EIGHTY_GB_MEM_NUMBER_OF_SETUP_SLOTS=5 - PROVER_ONE_GPU_EIGHTY_GB_MEM_ASSEMBLY_RECEIVER_PORT=17791 - PROVER_ONE_GPU_EIGHTY_GB_MEM_ASSEMBLY_RECEIVER_POLL_TIME_IN_MILLIS=250 - PROVER_ONE_GPU_EIGHTY_GB_MEM_ASSEMBLY_QUEUE_CAPACITY=5 - PROVER_ONE_GPU_EIGHTY_GB_MEM_SPECIALIZED_PROVER_GROUP_ID=2 - - PROVER_TWO_GPU_EIGHTY_GB_MEM_PROMETHEUS_PORT="3313" - PROVER_TWO_GPU_EIGHTY_GB_MEM_INITIAL_SETUP_KEY_PATH="key" - PROVER_TWO_GPU_EIGHTY_GB_MEM_KEY_DOWNLOAD_URL="value" - PROVER_TWO_GPU_EIGHTY_GB_MEM_GENERATION_TIMEOUT_IN_SECS=2700 - PROVER_TWO_GPU_EIGHTY_GB_MEM_NUMBER_OF_THREADS="9" - PROVER_TWO_GPU_EIGHTY_GB_MEM_MAX_ATTEMPTS="4" - PROVER_TWO_GPU_EIGHTY_GB_MEM_POLLING_DURATION_IN_MILLIS=5 - PROVER_TWO_GPU_EIGHTY_GB_MEM_SETUP_KEYS_PATH="/usr/src/setup-keys" - PROVER_TWO_GPU_EIGHTY_GB_MEM_NUMBER_OF_SETUP_SLOTS=9 - PROVER_TWO_GPU_EIGHTY_GB_MEM_ASSEMBLY_RECEIVER_PORT=17791 - PROVER_TWO_GPU_EIGHTY_GB_MEM_ASSEMBLY_RECEIVER_POLL_TIME_IN_MILLIS=250 - PROVER_TWO_GPU_EIGHTY_GB_MEM_ASSEMBLY_QUEUE_CAPACITY=5 - PROVER_TWO_GPU_EIGHTY_GB_MEM_SPECIALIZED_PROVER_GROUP_ID=3 - - PROVER_FOUR_GPU_EIGHTY_GB_MEM_PROMETHEUS_PORT="3313" - PROVER_FOUR_GPU_EIGHTY_GB_MEM_INITIAL_SETUP_KEY_PATH="key" - PROVER_FOUR_GPU_EIGHTY_GB_MEM_KEY_DOWNLOAD_URL="value" - PROVER_FOUR_GPU_EIGHTY_GB_MEM_GENERATION_TIMEOUT_IN_SECS=2700 - PROVER_FOUR_GPU_EIGHTY_GB_MEM_NUMBER_OF_THREADS="18" - PROVER_FOUR_GPU_EIGHTY_GB_MEM_MAX_ATTEMPTS="4" - PROVER_FOUR_GPU_EIGHTY_GB_MEM_POLLING_DURATION_IN_MILLIS=5 - PROVER_FOUR_GPU_EIGHTY_GB_MEM_SETUP_KEYS_PATH="/usr/src/setup-keys" - PROVER_FOUR_GPU_EIGHTY_GB_MEM_NUMBER_OF_SETUP_SLOTS=18 - PROVER_FOUR_GPU_EIGHTY_GB_MEM_ASSEMBLY_RECEIVER_PORT=17791 - PROVER_FOUR_GPU_EIGHTY_GB_MEM_ASSEMBLY_RECEIVER_POLL_TIME_IN_MILLIS=250 - PROVER_FOUR_GPU_EIGHTY_GB_MEM_ASSEMBLY_QUEUE_CAPACITY=5 - PROVER_FOUR_GPU_EIGHTY_GB_MEM_SPECIALIZED_PROVER_GROUP_ID=4 - "#; - - #[test] - fn from_env() { - let mut lock = MUTEX.lock(); - lock.set_env(CONFIG); - let actual = ProverConfigs::from_env().unwrap(); - assert_eq!(actual, expected_config()); - } -} diff --git a/core/lib/env_config/src/prover_group.rs b/core/lib/env_config/src/prover_group.rs deleted file mode 100644 index bdac82cbb9cc..000000000000 --- a/core/lib/env_config/src/prover_group.rs +++ /dev/null @@ -1,149 +0,0 @@ -use zksync_config::configs::ProverGroupConfig; - -use crate::{envy_load, FromEnv}; - -impl FromEnv for ProverGroupConfig { - fn from_env() -> anyhow::Result { - envy_load("prover_group", "PROVER_GROUP_") - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::test_utils::EnvMutex; - - static MUTEX: EnvMutex = EnvMutex::new(); - - fn expected_config() -> ProverGroupConfig { - ProverGroupConfig { - group_0_circuit_ids: vec![0, 18], - group_1_circuit_ids: vec![1, 4], - group_2_circuit_ids: vec![2, 5], - group_3_circuit_ids: vec![6, 7], - group_4_circuit_ids: vec![8, 9], - group_5_circuit_ids: vec![10, 11], - group_6_circuit_ids: vec![12, 13], - group_7_circuit_ids: vec![14, 15], - group_8_circuit_ids: vec![16, 17], - group_9_circuit_ids: vec![3], - region_read_url: "http://metadata.google.internal/computeMetadata/v1/instance/attributes/cluster-location".to_string(), - region_override: Some("us-central-1".to_string()), - zone_read_url: "http://metadata.google.internal/computeMetadata/v1/instance/zone".to_string(), - zone_override: Some("us-central-1-b".to_string()), - synthesizer_per_gpu: 10, - } - } - - const CONFIG: &str = r#" - PROVER_GROUP_GROUP_0_CIRCUIT_IDS="0,18" - PROVER_GROUP_GROUP_1_CIRCUIT_IDS="1,4" - PROVER_GROUP_GROUP_2_CIRCUIT_IDS="2,5" - PROVER_GROUP_GROUP_3_CIRCUIT_IDS="6,7" - PROVER_GROUP_GROUP_4_CIRCUIT_IDS="8,9" - PROVER_GROUP_GROUP_5_CIRCUIT_IDS="10,11" - PROVER_GROUP_GROUP_6_CIRCUIT_IDS="12,13" - PROVER_GROUP_GROUP_7_CIRCUIT_IDS="14,15" - PROVER_GROUP_GROUP_8_CIRCUIT_IDS="16,17" - PROVER_GROUP_GROUP_9_CIRCUIT_IDS="3" - PROVER_GROUP_REGION_READ_URL="http://metadata.google.internal/computeMetadata/v1/instance/attributes/cluster-location" - PROVER_GROUP_REGION_OVERRIDE="us-central-1" - PROVER_GROUP_ZONE_READ_URL="http://metadata.google.internal/computeMetadata/v1/instance/zone" - PROVER_GROUP_ZONE_OVERRIDE="us-central-1-b" - PROVER_GROUP_SYNTHESIZER_PER_GPU="10" - "#; - - #[test] - fn from_env() { - let mut lock = MUTEX.lock(); - lock.set_env(CONFIG); - let actual = ProverGroupConfig::from_env().unwrap(); - assert_eq!(actual, expected_config()); - } - - #[test] - fn get_group_id_for_circuit_id() { - let prover_group_config = expected_config(); - - assert_eq!(Some(0), prover_group_config.get_group_id_for_circuit_id(0)); - assert_eq!(Some(0), prover_group_config.get_group_id_for_circuit_id(18)); - - assert_eq!(Some(1), prover_group_config.get_group_id_for_circuit_id(1)); - assert_eq!(Some(1), prover_group_config.get_group_id_for_circuit_id(4)); - - assert_eq!(Some(2), prover_group_config.get_group_id_for_circuit_id(2)); - assert_eq!(Some(2), prover_group_config.get_group_id_for_circuit_id(5)); - - assert_eq!(Some(3), prover_group_config.get_group_id_for_circuit_id(6)); - assert_eq!(Some(3), prover_group_config.get_group_id_for_circuit_id(7)); - - assert_eq!(Some(4), prover_group_config.get_group_id_for_circuit_id(8)); - assert_eq!(Some(4), prover_group_config.get_group_id_for_circuit_id(9)); - - assert_eq!(Some(5), prover_group_config.get_group_id_for_circuit_id(10)); - assert_eq!(Some(5), prover_group_config.get_group_id_for_circuit_id(11)); - - assert_eq!(Some(6), prover_group_config.get_group_id_for_circuit_id(12)); - assert_eq!(Some(6), prover_group_config.get_group_id_for_circuit_id(13)); - - assert_eq!(Some(7), prover_group_config.get_group_id_for_circuit_id(14)); - assert_eq!(Some(7), prover_group_config.get_group_id_for_circuit_id(15)); - - assert_eq!(Some(8), prover_group_config.get_group_id_for_circuit_id(16)); - assert_eq!(Some(8), prover_group_config.get_group_id_for_circuit_id(17)); - - assert_eq!(Some(9), prover_group_config.get_group_id_for_circuit_id(3)); - assert!(prover_group_config - .get_group_id_for_circuit_id(19) - .is_none()); - } - - #[test] - fn get_circuit_ids_for_group_id() { - let prover_group_config = expected_config(); - - assert_eq!( - Some(vec![0, 18]), - prover_group_config.get_circuit_ids_for_group_id(0) - ); - assert_eq!( - Some(vec![1, 4]), - prover_group_config.get_circuit_ids_for_group_id(1) - ); - assert_eq!( - Some(vec![2, 5]), - prover_group_config.get_circuit_ids_for_group_id(2) - ); - assert_eq!( - Some(vec![6, 7]), - prover_group_config.get_circuit_ids_for_group_id(3) - ); - assert_eq!( - Some(vec![8, 9]), - prover_group_config.get_circuit_ids_for_group_id(4) - ); - assert_eq!( - Some(vec![10, 11]), - prover_group_config.get_circuit_ids_for_group_id(5) - ); - assert_eq!( - Some(vec![12, 13]), - prover_group_config.get_circuit_ids_for_group_id(6) - ); - assert_eq!( - Some(vec![14, 15]), - prover_group_config.get_circuit_ids_for_group_id(7) - ); - assert_eq!( - Some(vec![16, 17]), - prover_group_config.get_circuit_ids_for_group_id(8) - ); - assert_eq!( - Some(vec![3]), - prover_group_config.get_circuit_ids_for_group_id(9) - ); - assert!(prover_group_config - .get_circuit_ids_for_group_id(10) - .is_none()); - } -} diff --git a/core/lib/eth_client/Cargo.toml b/core/lib/eth_client/Cargo.toml index 2eb37a0c9b24..ff3e56ef7311 100644 --- a/core/lib/eth_client/Cargo.toml +++ b/core/lib/eth_client/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "zksync_eth_client" version = "0.1.0" -edition = "2018" +edition = "2021" authors = ["The Matter Labs Team "] homepage = "https://zksync.io/" repository = "https://github.com/matter-labs/zksync-era" @@ -18,9 +18,10 @@ zksync_contracts = { path = "../contracts" } jsonrpc-core = "18" serde = "1.0.90" -hex = "0.4" -anyhow = "1.0" thiserror = "1" -tokio = { version = "1", features = ["full"] } async-trait = "0.1" tracing = "0.1" + +[dev-dependencies] +static_assertions = "1.1.0" +tokio = { version = "1", features = ["full"] } diff --git a/core/lib/eth_client/src/clients/generic.rs b/core/lib/eth_client/src/clients/generic.rs new file mode 100644 index 000000000000..c54a814d449f --- /dev/null +++ b/core/lib/eth_client/src/clients/generic.rs @@ -0,0 +1,170 @@ +use std::sync::Arc; + +use async_trait::async_trait; +use zksync_types::{ + web3::{ + contract::Options, + ethabi, + types::{ + Address, Block, BlockId, BlockNumber, Filter, Log, Transaction, TransactionReceipt, + H160, H256, U256, U64, + }, + }, + L1ChainId, +}; + +use crate::{ + BoundEthInterface, ContractCall, Error, EthInterface, ExecutedTxStatus, FailureInfo, + RawTransactionBytes, SignedCallResult, +}; + +#[async_trait] +impl EthInterface for Arc { + async fn nonce_at_for_account( + &self, + account: Address, + block: BlockNumber, + component: &'static str, + ) -> Result { + self.as_ref() + .nonce_at_for_account(account, block, component) + .await + } + + async fn base_fee_history( + &self, + from_block: usize, + block_count: usize, + component: &'static str, + ) -> Result, Error> { + self.as_ref() + .base_fee_history(from_block, block_count, component) + .await + } + + async fn get_pending_block_base_fee_per_gas( + &self, + component: &'static str, + ) -> Result { + self.as_ref() + .get_pending_block_base_fee_per_gas(component) + .await + } + + async fn get_gas_price(&self, component: &'static str) -> Result { + self.as_ref().get_gas_price(component).await + } + + async fn block_number(&self, component: &'static str) -> Result { + self.as_ref().block_number(component).await + } + + async fn send_raw_tx(&self, tx: RawTransactionBytes) -> Result { + self.as_ref().send_raw_tx(tx).await + } + + async fn get_tx_status( + &self, + hash: H256, + component: &'static str, + ) -> Result, Error> { + self.as_ref().get_tx_status(hash, component).await + } + + async fn failure_reason(&self, tx_hash: H256) -> Result, Error> { + self.as_ref().failure_reason(tx_hash).await + } + + async fn get_tx( + &self, + hash: H256, + component: &'static str, + ) -> Result, Error> { + self.as_ref().get_tx(hash, component).await + } + + async fn tx_receipt( + &self, + tx_hash: H256, + component: &'static str, + ) -> Result, Error> { + self.as_ref().tx_receipt(tx_hash, component).await + } + + async fn eth_balance(&self, address: Address, component: &'static str) -> Result { + self.as_ref().eth_balance(address, component).await + } + + async fn call_contract_function( + &self, + call: ContractCall, + ) -> Result, Error> { + self.as_ref().call_contract_function(call).await + } + + async fn logs(&self, filter: Filter, component: &'static str) -> Result, Error> { + self.as_ref().logs(filter, component).await + } + + async fn block( + &self, + block_id: BlockId, + component: &'static str, + ) -> Result>, Error> { + self.as_ref().block(block_id, component).await + } +} + +#[async_trait::async_trait] +impl BoundEthInterface for Arc { + fn contract(&self) -> ðabi::Contract { + self.as_ref().contract() + } + + fn contract_addr(&self) -> H160 { + self.as_ref().contract_addr() + } + + fn chain_id(&self) -> L1ChainId { + self.as_ref().chain_id() + } + + fn sender_account(&self) -> Address { + self.as_ref().sender_account() + } + + async fn allowance_on_account( + &self, + token_address: Address, + contract_address: Address, + erc20_abi: ethabi::Contract, + ) -> Result { + self.as_ref() + .allowance_on_account(token_address, contract_address, erc20_abi) + .await + } + + async fn sign_prepared_tx_for_addr( + &self, + data: Vec, + contract_addr: H160, + options: Options, + component: &'static str, + ) -> Result { + self.as_ref() + .sign_prepared_tx_for_addr(data, contract_addr, options, component) + .await + } + + async fn nonce_at(&self, block: BlockNumber, component: &'static str) -> Result { + self.as_ref().nonce_at(block, component).await + } + + async fn current_nonce(&self, component: &'static str) -> Result { + self.as_ref().current_nonce(component).await + } + + async fn pending_nonce(&self, component: &'static str) -> Result { + self.as_ref().pending_nonce(component).await + } +} diff --git a/core/lib/eth_client/src/clients/http/query.rs b/core/lib/eth_client/src/clients/http/query.rs index 3e88944ca0e4..d1abb74c46d6 100644 --- a/core/lib/eth_client/src/clients/http/query.rs +++ b/core/lib/eth_client/src/clients/http/query.rs @@ -3,10 +3,7 @@ use std::sync::Arc; use async_trait::async_trait; use zksync_types::web3::{ self, - contract::{ - tokens::{Detokenize, Tokenize}, - Contract, Options, - }, + contract::Contract, ethabi, transports::Http, types::{ @@ -18,8 +15,8 @@ use zksync_types::web3::{ use crate::{ clients::http::{Method, COUNTERS, LATENCIES}, - types::{Error, ExecutedTxStatus, FailureInfo}, - EthInterface, + types::{Error, ExecutedTxStatus, FailureInfo, RawTokens}, + ContractCall, EthInterface, RawTransactionBytes, }; /// An "anonymous" Ethereum client that can invoke read-only methods that aren't @@ -40,7 +37,7 @@ impl From for QueryClient { impl QueryClient { /// Creates a new HTTP client. pub fn new(node_url: &str) -> Result { - let transport = web3::transports::Http::new(node_url)?; + let transport = Http::new(node_url)?; Ok(transport.into()) } } @@ -80,9 +77,9 @@ impl EthInterface for QueryClient { Ok(network_gas_price) } - async fn send_raw_tx(&self, tx: Vec) -> Result { + async fn send_raw_tx(&self, tx: RawTransactionBytes) -> Result { let latency = LATENCIES.direct[&Method::SendRawTx].start(); - let tx = self.web3.eth().send_raw_transaction(Bytes(tx)).await?; + let tx = self.web3.eth().send_raw_transaction(Bytes(tx.0)).await?; latency.observe(); Ok(tx) } @@ -100,8 +97,8 @@ impl EthInterface for QueryClient { let mut history = Vec::with_capacity(block_count); let from_block = upto_block.saturating_sub(block_count); - // Here we are requesting fee_history from blocks - // (from_block; upto_block] in chunks of size MAX_REQUEST_CHUNK + // Here we are requesting `fee_history` from blocks + // `(from_block; upto_block)` in chunks of size `MAX_REQUEST_CHUNK` // starting from the oldest block. for chunk_start in (from_block..=upto_block).step_by(MAX_REQUEST_CHUNK) { let chunk_end = (chunk_start + MAX_REQUEST_CHUNK).min(upto_block); @@ -233,26 +230,21 @@ impl EthInterface for QueryClient { Ok(tx) } - #[allow(clippy::too_many_arguments)] - async fn call_contract_function( + async fn call_contract_function( &self, - func: &str, - params: P, - from: A, - options: Options, - block: B, - contract_address: Address, - contract_abi: ethabi::Contract, - ) -> Result - where - R: Detokenize + Unpin, - A: Into> + Send, - B: Into> + Send, - P: Tokenize + Send, - { + call: ContractCall, + ) -> Result, Error> { let latency = LATENCIES.direct[&Method::CallContractFunction].start(); - let contract = Contract::new(self.web3.eth(), contract_address, contract_abi); - let res = contract.query(func, params, from, options, block).await?; + let contract = Contract::new(self.web3.eth(), call.contract_address, call.contract_abi); + let RawTokens(res) = contract + .query( + &call.inner.name, + call.inner.params, + call.inner.from, + call.inner.options, + call.inner.block, + ) + .await?; latency.observe(); Ok(res) } diff --git a/core/lib/eth_client/src/clients/http/signing.rs b/core/lib/eth_client/src/clients/http/signing.rs index 8b56dc1cfbdf..6e3dd3d223d8 100644 --- a/core/lib/eth_client/src/clients/http/signing.rs +++ b/core/lib/eth_client/src/clients/http/signing.rs @@ -7,10 +7,7 @@ use zksync_eth_signer::{raw_ethereum_tx::TransactionParameters, EthereumSigner, use zksync_types::{ web3::{ self, - contract::{ - tokens::{Detokenize, Tokenize}, - Options, - }, + contract::{tokens::Detokenize, Options}, ethabi, transports::Http, types::{ @@ -24,7 +21,7 @@ use zksync_types::{ use super::{query::QueryClient, Method, LATENCIES}; use crate::{ types::{Error, ExecutedTxStatus, FailureInfo, SignedCallResult}, - BoundEthInterface, EthInterface, + BoundEthInterface, CallFunctionArgs, ContractCall, EthInterface, RawTransactionBytes, }; /// HTTP-based Ethereum client, backed by a private key to sign transactions. @@ -47,8 +44,7 @@ impl PKSigningClient { let default_priority_fee_per_gas = eth_sender.gas_adjuster.default_priority_fee_per_gas; let l1_chain_id = eth_client.chain_id; - let transport = - web3::transports::Http::new(main_node_url).expect("Failed to create transport"); + let transport = Http::new(main_node_url).expect("Failed to create transport"); let operator_address = PackedEthSignature::address_from_private_key(&operator_private_key) .expect("Failed to get address from private key"); @@ -122,7 +118,7 @@ impl EthInterface for SigningClient { self.query_client.get_gas_price(component).await } - async fn send_raw_tx(&self, tx: Vec) -> Result { + async fn send_raw_tx(&self, tx: RawTransactionBytes) -> Result { self.query_client.send_raw_tx(tx).await } @@ -166,34 +162,11 @@ impl EthInterface for SigningClient { self.query_client.get_tx(hash, component).await } - #[allow(clippy::too_many_arguments)] - async fn call_contract_function( + async fn call_contract_function( &self, - func: &str, - params: P, - from: A, - options: Options, - block: B, - contract_address: Address, - contract_abi: ethabi::Contract, - ) -> Result - where - R: Detokenize + Unpin, - A: Into> + Send, - B: Into> + Send, - P: Tokenize + Send, - { - self.query_client - .call_contract_function( - func, - params, - from, - options, - block, - contract_address, - contract_abi, - ) - .await + call: ContractCall, + ) -> Result, Error> { + self.query_client.call_contract_function(call).await } async fn tx_receipt( @@ -253,7 +226,7 @@ impl BoundEthInterface for SigningClient { None => self.inner.default_priority_fee_per_gas, }; - // Fetch current base fee and add max_priority_fee_per_gas + // Fetch current base fee and add `max_priority_fee_per_gas` let max_fee_per_gas = match options.max_fee_per_gas { Some(max_fee_per_gas) => max_fee_per_gas, None => { @@ -303,7 +276,7 @@ impl BoundEthInterface for SigningClient { let hash = web3::signing::keccak256(&signed_tx).into(); latency.observe(); Ok(SignedCallResult { - raw_tx: signed_tx, + raw_tx: RawTransactionBytes(signed_tx), max_priority_fee_per_gas, max_fee_per_gas, nonce, @@ -318,19 +291,11 @@ impl BoundEthInterface for SigningClient { erc20_abi: ethabi::Contract, ) -> Result { let latency = LATENCIES.direct[&Method::Allowance].start(); - let res = self - .call_contract_function( - "allowance", - (self.inner.sender_account, address), - None, - Options::default(), - None, - token_address, - erc20_abi, - ) - .await?; + let args = CallFunctionArgs::new("allowance", (self.inner.sender_account, address)) + .for_contract(token_address, erc20_abi); + let res = self.call_contract_function(args).await?; latency.observe(); - Ok(res) + Ok(U256::from_tokens(res)?) } } diff --git a/core/lib/eth_client/src/clients/mock.rs b/core/lib/eth_client/src/clients/mock.rs index a8eceac75aff..5541dd1d198b 100644 --- a/core/lib/eth_client/src/clients/mock.rs +++ b/core/lib/eth_client/src/clients/mock.rs @@ -1,20 +1,14 @@ use std::{ collections::{BTreeMap, HashMap}, - sync::{ - atomic::{AtomicU64, Ordering}, - RwLock, - }, + sync::RwLock, }; use async_trait::async_trait; use jsonrpc_core::types::error::Error as RpcError; use zksync_types::{ web3::{ - contract::{ - tokens::{Detokenize, Tokenize}, - Options, - }, - ethabi::{self, Token}, + contract::{tokens::Tokenize, Options}, + ethabi, types::{Block, BlockId, BlockNumber, Filter, Log, Transaction, TransactionReceipt, U64}, Error as Web3Error, }, @@ -23,55 +17,112 @@ use zksync_types::{ use crate::{ types::{Error, ExecutedTxStatus, FailureInfo, SignedCallResult}, - BoundEthInterface, EthInterface, + BoundEthInterface, ContractCall, EthInterface, RawTransactionBytes, }; -#[derive(Debug, Clone, Default, Copy)] -pub struct MockTx { - pub hash: H256, - pub nonce: u64, - pub base_fee: U256, +#[derive(Debug, Clone)] +struct MockTx { + input: Vec, + hash: H256, + nonce: u64, + max_fee_per_gas: U256, + max_priority_fee_per_gas: U256, } impl From> for MockTx { fn from(tx: Vec) -> Self { - use std::convert::TryFrom; - let len = tx.len(); - let total_gas_price = U256::try_from(&tx[len - 96..len - 64]).unwrap(); - let priority_fee = U256::try_from(&tx[len - 64..len - 32]).unwrap(); - let base_fee = total_gas_price - priority_fee; + let max_fee_per_gas = U256::try_from(&tx[len - 96..len - 64]).unwrap(); + let max_priority_fee_per_gas = U256::try_from(&tx[len - 64..len - 32]).unwrap(); let nonce = U256::try_from(&tx[len - 32..]).unwrap().as_u64(); let hash = { - let mut buffer: [u8; 32] = Default::default(); + let mut buffer = [0_u8; 32]; buffer.copy_from_slice(&tx[..32]); buffer.into() }; Self { + input: tx[32..len - 96].to_vec(), nonce, hash, - base_fee, + max_fee_per_gas, + max_priority_fee_per_gas, + } + } +} + +impl From for Transaction { + fn from(tx: MockTx) -> Self { + Self { + input: tx.input.into(), + hash: tx.hash, + nonce: tx.nonce.into(), + max_fee_per_gas: Some(tx.max_fee_per_gas), + max_priority_fee_per_gas: Some(tx.max_priority_fee_per_gas), + ..Self::default() } } } +/// Mutable part of [`MockEthereum`] that needs to be synchronized via an `RwLock`. +#[derive(Debug, Default)] +struct MockEthereumInner { + block_number: u64, + tx_statuses: HashMap, + sent_txs: HashMap, + current_nonce: u64, + pending_nonce: u64, + nonces: BTreeMap, +} + +impl MockEthereumInner { + fn execute_tx( + &mut self, + tx_hash: H256, + success: bool, + confirmations: u64, + non_ordering_confirmations: bool, + ) { + let block_number = self.block_number; + self.block_number += confirmations; + let nonce = self.current_nonce; + self.current_nonce += 1; + let tx_nonce = self.sent_txs[&tx_hash].nonce; + + if non_ordering_confirmations { + if tx_nonce >= nonce { + self.current_nonce = tx_nonce; + } + } else { + assert_eq!(tx_nonce, nonce, "nonce mismatch"); + } + self.nonces.insert(block_number, nonce + 1); + + let status = ExecutedTxStatus { + tx_hash, + success, + receipt: TransactionReceipt { + gas_used: Some(21000u32.into()), + block_number: Some(block_number.into()), + transaction_hash: tx_hash, + ..TransactionReceipt::default() + }, + }; + self.tx_statuses.insert(tx_hash, status); + } +} + /// Mock Ethereum client is capable of recording all the incoming requests for the further analysis. #[derive(Debug)] pub struct MockEthereum { - pub block_number: AtomicU64, - pub max_fee_per_gas: U256, - pub base_fee_history: RwLock>, - pub max_priority_fee_per_gas: U256, - pub tx_statuses: RwLock>, - pub sent_txs: RwLock>, - pub current_nonce: AtomicU64, - pub pending_nonce: AtomicU64, - pub nonces: RwLock>, + max_fee_per_gas: U256, + max_priority_fee_per_gas: U256, + base_fee_history: Vec, /// If true, the mock will not check the ordering nonces of the transactions. /// This is useful for testing the cases when the transactions are executed out of order. - pub non_ordering_confirmations: bool, - pub multicall_address: Address, + non_ordering_confirmations: bool, + multicall_address: Address, + inner: RwLock, } impl Default for MockEthereum { @@ -79,15 +130,10 @@ impl Default for MockEthereum { Self { max_fee_per_gas: 100.into(), max_priority_fee_per_gas: 10.into(), - block_number: Default::default(), - base_fee_history: Default::default(), - tx_statuses: Default::default(), - sent_txs: Default::default(), - current_nonce: Default::default(), - pending_nonce: Default::default(), - nonces: RwLock::new([(0, 0)].into()), + base_fee_history: vec![], non_ordering_confirmations: false, multicall_address: Address::default(), + inner: RwLock::default(), } } } @@ -95,53 +141,29 @@ impl Default for MockEthereum { impl MockEthereum { /// A fake `sha256` hasher, which calculates an `std::hash` instead. /// This is done for simplicity and it's also much faster. - pub fn fake_sha256(data: &[u8]) -> H256 { + fn fake_sha256(data: &[u8]) -> H256 { use std::{collections::hash_map::DefaultHasher, hash::Hasher}; let mut hasher = DefaultHasher::new(); hasher.write(data); - let result = hasher.finish(); - H256::from_low_u64_ne(result) } + /// Returns the number of transactions sent via this client. + pub fn sent_tx_count(&self) -> usize { + self.inner.read().unwrap().sent_txs.len() + } + /// Increments the blocks by a provided `confirmations` and marks the sent transaction /// as a success. - pub fn execute_tx( - &self, - tx_hash: H256, - success: bool, - confirmations: u64, - ) -> anyhow::Result<()> { - let block_number = self.block_number.fetch_add(confirmations, Ordering::SeqCst); - let nonce = self.current_nonce.fetch_add(1, Ordering::SeqCst); - let tx_nonce = self.sent_txs.read().unwrap()[&tx_hash].nonce; - - if self.non_ordering_confirmations { - if tx_nonce >= nonce { - self.current_nonce.store(tx_nonce, Ordering::SeqCst); - } - } else { - anyhow::ensure!(tx_nonce == nonce, "nonce mismatch"); - } - - self.nonces.write().unwrap().insert(block_number, nonce + 1); - - let status = ExecutedTxStatus { + pub fn execute_tx(&self, tx_hash: H256, success: bool, confirmations: u64) { + self.inner.write().unwrap().execute_tx( tx_hash, success, - receipt: TransactionReceipt { - gas_used: Some(21000u32.into()), - block_number: Some(block_number.into()), - transaction_hash: tx_hash, - ..Default::default() - }, - }; - - self.tx_statuses.write().unwrap().insert(tx_hash, status); - - Ok(()) + confirmations, + self.non_ordering_confirmations, + ); } pub fn sign_prepared_tx( @@ -155,18 +177,18 @@ impl MockEthereum { .unwrap_or(self.max_priority_fee_per_gas); let nonce = options.nonce.expect("Nonce must be set for every tx"); - // Nonce and gas_price are appended to distinguish the same transactions + // Nonce and `gas_price` are appended to distinguish the same transactions // with different gas by their hash in tests. raw_tx.append(&mut ethabi::encode(&max_fee_per_gas.into_tokens())); raw_tx.append(&mut ethabi::encode(&max_priority_fee_per_gas.into_tokens())); raw_tx.append(&mut ethabi::encode(&nonce.into_tokens())); let hash = Self::fake_sha256(&raw_tx); // Okay for test purposes. - // Concatenate raw_tx plus hash for test purposes + // Concatenate `raw_tx` plus hash for test purposes let mut new_raw_tx = hash.as_bytes().to_vec(); new_raw_tx.extend(raw_tx); Ok(SignedCallResult { - raw_tx: new_raw_tx, + raw_tx: RawTransactionBytes(new_raw_tx), max_priority_fee_per_gas, max_fee_per_gas, nonce, @@ -175,12 +197,14 @@ impl MockEthereum { } pub fn advance_block_number(&self, val: u64) -> u64 { - self.block_number.fetch_add(val, Ordering::SeqCst) + val + let mut inner = self.inner.write().unwrap(); + inner.block_number += val; + inner.block_number } pub fn with_fee_history(self, history: Vec) -> Self { Self { - base_fee_history: RwLock::new(history), + base_fee_history: history, ..self } } @@ -207,17 +231,19 @@ impl EthInterface for MockEthereum { hash: H256, _: &'static str, ) -> Result, Error> { - Ok(self.tx_statuses.read().unwrap().get(&hash).cloned()) + Ok(self.inner.read().unwrap().tx_statuses.get(&hash).cloned()) } async fn block_number(&self, _: &'static str) -> Result { - Ok(self.block_number.load(Ordering::SeqCst).into()) + Ok(self.inner.read().unwrap().block_number.into()) } - async fn send_raw_tx(&self, tx: Vec) -> Result { - let mock_tx = MockTx::from(tx); + async fn send_raw_tx(&self, tx: RawTransactionBytes) -> Result { + let mock_tx = MockTx::from(tx.0); + let mock_tx_hash = mock_tx.hash; + let mut inner = self.inner.write().unwrap(); - if mock_tx.nonce < self.current_nonce.load(Ordering::SeqCst) { + if mock_tx.nonce < inner.current_nonce { return Err(Error::EthereumGateway(Web3Error::Rpc(RpcError { message: "transaction with the same nonce already processed".to_string(), code: 101.into(), @@ -225,13 +251,11 @@ impl EthInterface for MockEthereum { }))); } - if mock_tx.nonce == self.pending_nonce.load(Ordering::SeqCst) { - self.pending_nonce.fetch_add(1, Ordering::SeqCst); + if mock_tx.nonce == inner.pending_nonce { + inner.pending_nonce += 1; } - - self.sent_txs.write().unwrap().insert(mock_tx.hash, mock_tx); - - Ok(mock_tx.hash) + inner.sent_txs.insert(mock_tx_hash, mock_tx); + Ok(mock_tx_hash) } async fn nonce_at_for_account( @@ -253,18 +277,15 @@ impl EthInterface for MockEthereum { block_count: usize, _component: &'static str, ) -> Result, Error> { - Ok(self.base_fee_history.read().unwrap() - [from_block.saturating_sub(block_count - 1)..=from_block] - .to_vec()) + let start_block = from_block.saturating_sub(block_count - 1); + Ok(self.base_fee_history[start_block..=from_block].to_vec()) } async fn get_pending_block_base_fee_per_gas( &self, _component: &'static str, ) -> Result { - Ok(U256::from( - *self.base_fee_history.read().unwrap().last().unwrap(), - )) + Ok(U256::from(*self.base_fee_history.last().unwrap())) } async fn failure_reason(&self, tx_hash: H256) -> Result, Error> { @@ -278,24 +299,13 @@ impl EthInterface for MockEthereum { })) } - #[allow(clippy::too_many_arguments)] - async fn call_contract_function( + async fn call_contract_function( &self, - _func: &str, - _params: P, - _from: A, - _options: Options, - _block: B, - contract_address: Address, - _contract_abi: ethabi::Contract, - ) -> Result - where - R: Detokenize + Unpin, - A: Into> + Send, - B: Into> + Send, - P: Tokenize + Send, - { - if contract_address == self.multicall_address { + call: ContractCall, + ) -> Result, Error> { + use ethabi::Token; + + if call.contract_address == self.multicall_address { let token = Token::Array(vec![ Token::Tuple(vec![Token::Bool(true), Token::Bytes(vec![1u8; 32])]), Token::Tuple(vec![Token::Bool(true), Token::Bytes(vec![2u8; 32])]), @@ -310,17 +320,21 @@ impl EthInterface for MockEthereum { ), ]), ]); - return Ok(R::from_tokens(vec![token]).unwrap()); + return Ok(vec![token]); } - Ok(R::from_tokens(vec![]).unwrap()) + Ok(vec![]) } async fn get_tx( &self, - _hash: H256, + hash: H256, _component: &'static str, ) -> Result, Error> { - unimplemented!("Not needed right now") + let txs = &self.inner.read().unwrap().sent_txs; + let Some(tx) = txs.get(&hash) else { + return Ok(None); + }; + Ok(Some(tx.clone().into())) } async fn tx_receipt( @@ -391,199 +405,79 @@ impl BoundEthInterface for MockEthereum { async fn nonce_at(&self, block: BlockNumber, _component: &'static str) -> Result { if let BlockNumber::Number(block_number) = block { - Ok((*self - .nonces - .read() - .unwrap() - .range(..=block_number.as_u64()) - .next_back() - .unwrap() - .1) - .into()) + let inner = self.inner.read().unwrap(); + let mut nonce_range = inner.nonces.range(..=block_number.as_u64()); + let (_, &nonce) = nonce_range.next_back().unwrap_or((&0, &0)); + Ok(nonce.into()) } else { panic!("MockEthereum::nonce_at called with non-number block tag"); } } async fn pending_nonce(&self, _: &'static str) -> Result { - Ok(self.pending_nonce.load(Ordering::SeqCst).into()) + Ok(self.inner.read().unwrap().pending_nonce.into()) } async fn current_nonce(&self, _: &'static str) -> Result { - Ok(self.current_nonce.load(Ordering::SeqCst).into()) + Ok(self.inner.read().unwrap().current_nonce.into()) } } -#[async_trait] -impl + Send + Sync> EthInterface for T { - async fn nonce_at_for_account( - &self, - account: Address, - block: BlockNumber, - component: &'static str, - ) -> Result { - self.as_ref() - .nonce_at_for_account(account, block, component) - .await - } - - async fn base_fee_history( - &self, - from_block: usize, - block_count: usize, - component: &'static str, - ) -> Result, Error> { - self.as_ref() - .base_fee_history(from_block, block_count, component) - .await - } - - async fn get_pending_block_base_fee_per_gas( - &self, - component: &'static str, - ) -> Result { - self.as_ref() - .get_pending_block_base_fee_per_gas(component) - .await - } - - async fn get_gas_price(&self, component: &'static str) -> Result { - self.as_ref().get_gas_price(component).await - } - - async fn block_number(&self, component: &'static str) -> Result { - self.as_ref().block_number(component).await - } - - async fn send_raw_tx(&self, tx: Vec) -> Result { - self.as_ref().send_raw_tx(tx).await - } - - async fn failure_reason(&self, tx_hash: H256) -> Result, Error> { - self.as_ref().failure_reason(tx_hash).await - } - - async fn get_tx_status( - &self, - hash: H256, - component: &'static str, - ) -> Result, Error> { - self.as_ref().get_tx_status(hash, component).await - } - - async fn get_tx( - &self, - hash: H256, - component: &'static str, - ) -> Result, Error> { - self.as_ref().get_tx(hash, component).await - } - - #[allow(clippy::too_many_arguments)] - async fn call_contract_function( - &self, - func: &str, - params: P, - from: A, - options: Options, - block: B, - contract_address: Address, - contract_abi: ethabi::Contract, - ) -> Result - where - R: Detokenize + Unpin, - A: Into> + Send, - B: Into> + Send, - P: Tokenize + Send, - { - self.as_ref() - .call_contract_function( - func, - params, - from, - options, - block, - contract_address, - contract_abi, +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn managing_block_number() { + let client = MockEthereum::default(); + let block_number = client.block_number("test").await.unwrap(); + assert_eq!(block_number, 0.into()); + + client.advance_block_number(5); + let block_number = client.block_number("test").await.unwrap(); + assert_eq!(block_number, 5.into()); + } + + #[tokio::test] + async fn managing_transactions() { + let client = MockEthereum::default().with_non_ordering_confirmation(true); + client.advance_block_number(2); + + let signed_tx = client + .sign_prepared_tx( + b"test".to_vec(), + Options { + nonce: Some(1.into()), + ..Options::default() + }, ) - .await - } - - async fn tx_receipt( - &self, - tx_hash: H256, - component: &'static str, - ) -> Result, Error> { - self.as_ref().tx_receipt(tx_hash, component).await - } - - async fn eth_balance(&self, address: Address, component: &'static str) -> Result { - self.as_ref().eth_balance(address, component).await - } + .unwrap(); + assert_eq!(signed_tx.nonce, 1.into()); + assert!(signed_tx.max_priority_fee_per_gas > 0.into()); + assert!(signed_tx.max_fee_per_gas > 0.into()); - async fn logs(&self, filter: Filter, component: &'static str) -> Result, Error> { - self.as_ref().logs(filter, component).await - } - - async fn block( - &self, - block_id: BlockId, - component: &'static str, - ) -> Result>, Error> { - self.as_ref().block(block_id, component).await - } -} - -#[async_trait::async_trait] -impl + Send + Sync> BoundEthInterface for T { - fn contract(&self) -> ðabi::Contract { - self.as_ref().contract() - } - - fn contract_addr(&self) -> H160 { - self.as_ref().contract_addr() - } - - fn chain_id(&self) -> L1ChainId { - self.as_ref().chain_id() - } - - fn sender_account(&self) -> Address { - self.as_ref().sender_account() - } + let tx_hash = client.send_raw_tx(signed_tx.raw_tx).await.unwrap(); + assert_eq!(tx_hash, signed_tx.hash); - async fn sign_prepared_tx_for_addr( - &self, - data: Vec, - contract_addr: H160, - options: Options, - component: &'static str, - ) -> Result { - self.as_ref() - .sign_prepared_tx_for_addr(data, contract_addr, options, component) + client.execute_tx(tx_hash, true, 3); + let returned_tx = client + .get_tx(tx_hash, "test") .await - } - - async fn allowance_on_account( - &self, - token_address: Address, - contract_address: Address, - erc20_abi: ethabi::Contract, - ) -> Result { - self.as_ref() - .allowance_on_account(token_address, contract_address, erc20_abi) + .unwrap() + .expect("no transaction"); + assert_eq!(returned_tx.hash, tx_hash); + assert_eq!(returned_tx.input.0, b"test"); + assert_eq!(returned_tx.nonce, 1.into()); + assert!(returned_tx.max_priority_fee_per_gas.is_some()); + assert!(returned_tx.max_fee_per_gas.is_some()); + + let tx_status = client + .get_tx_status(tx_hash, "test") .await - } - - async fn nonce_at(&self, block: BlockNumber, component: &'static str) -> Result { - self.as_ref().nonce_at(block, component).await - } - - async fn pending_nonce(&self, _: &'static str) -> Result { - self.as_ref().pending_nonce("").await - } - - async fn current_nonce(&self, _: &'static str) -> Result { - self.as_ref().current_nonce("").await + .unwrap() + .expect("no transaction status"); + assert!(tx_status.success); + assert_eq!(tx_status.tx_hash, tx_hash); + assert_eq!(tx_status.receipt.block_number, Some(2.into())); } } diff --git a/core/lib/eth_client/src/clients/mod.rs b/core/lib/eth_client/src/clients/mod.rs index e992fac2eaf6..aa77974c4945 100644 --- a/core/lib/eth_client/src/clients/mod.rs +++ b/core/lib/eth_client/src/clients/mod.rs @@ -1,2 +1,10 @@ -pub mod http; -pub mod mock; +//! Various Ethereum client implementations. + +mod generic; +mod http; +mod mock; + +pub use self::{ + http::{PKSigningClient, QueryClient, SigningClient}, + mock::MockEthereum, +}; diff --git a/core/lib/eth_client/src/lib.rs b/core/lib/eth_client/src/lib.rs index 5bb40f60a083..eeabcba47e0b 100644 --- a/core/lib/eth_client/src/lib.rs +++ b/core/lib/eth_client/src/lib.rs @@ -1,12 +1,9 @@ -#![allow(clippy::upper_case_acronyms, clippy::derive_partial_eq_without_eq)] +use std::fmt; use async_trait::async_trait; use zksync_types::{ web3::{ - contract::{ - tokens::{Detokenize, Tokenize}, - Options, - }, + contract::Options, ethabi, types::{ Address, Block, BlockId, BlockNumber, Filter, Log, Transaction, TransactionReceipt, @@ -16,10 +13,13 @@ use zksync_types::{ L1ChainId, }; -use crate::types::{Error, ExecutedTxStatus, FailureInfo, SignedCallResult}; +pub use crate::types::{ + CallFunctionArgs, ContractCall, Error, ExecutedTxStatus, FailureInfo, RawTransactionBytes, + SignedCallResult, +}; pub mod clients; -pub mod types; +mod types; /// Common Web3 interface, as seen by the core applications. /// Encapsulates the raw Web3 interaction, providing a high-level interface. @@ -38,7 +38,7 @@ pub mod types; /// unnecessary high amount of Web3 calls. Implementations are advice to count invocations /// per component and expose them to Prometheus. #[async_trait] -pub trait EthInterface: Sync + Send { +pub trait EthInterface: 'static + Sync + Send + fmt::Debug { /// Returns the nonce of the provided account at the specified block. async fn nonce_at_for_account( &self, @@ -71,7 +71,7 @@ pub trait EthInterface: Sync + Send { async fn block_number(&self, component: &'static str) -> Result; /// Sends a transaction to the Ethereum network. - async fn send_raw_tx(&self, tx: Vec) -> Result; + async fn send_raw_tx(&self, tx: RawTransactionBytes) -> Result; /// Fetches the transaction status for a specified transaction hash. /// @@ -109,22 +109,8 @@ pub trait EthInterface: Sync + Send { async fn eth_balance(&self, address: Address, component: &'static str) -> Result; /// Invokes a function on a contract specified by `contract_address` / `contract_abi` using `eth_call`. - #[allow(clippy::too_many_arguments)] - async fn call_contract_function( - &self, - func: &str, - params: P, - from: A, - options: Options, - block: B, - contract_address: Address, - contract_abi: ethabi::Contract, - ) -> Result - where - R: Detokenize + Unpin, - A: Into> + Send, - B: Into> + Send, - P: Tokenize + Send; + async fn call_contract_function(&self, call: ContractCall) + -> Result, Error>; /// Returns the logs for the specified filter. async fn logs(&self, filter: Filter, component: &'static str) -> Result, Error>; @@ -137,6 +123,9 @@ pub trait EthInterface: Sync + Send { ) -> Result>, Error>; } +#[cfg(test)] +static_assertions::assert_obj_safe!(EthInterface); + /// An extension of `EthInterface` trait, which is used to perform queries that are bound to /// a certain contract and account. /// @@ -226,40 +215,27 @@ pub trait BoundEthInterface: EthInterface { } /// Invokes a function on a contract specified by `Self::contract()` / `Self::contract_addr()`. - async fn call_main_contract_function( + async fn call_main_contract_function( &self, - func: &str, - params: P, - from: A, - options: Options, - block: B, - ) -> Result - where - R: Detokenize + Unpin, - A: Into> + Send, - P: Tokenize + Send, - B: Into> + Send, - { - self.call_contract_function( - func, - params, - from, - options, - block, - self.contract_addr(), - self.contract().clone(), - ) - .await + args: CallFunctionArgs, + ) -> Result, Error> { + let args = args.for_contract(self.contract_addr(), self.contract().clone()); + self.call_contract_function(args).await } /// Encodes a function using the `Self::contract()` ABI. - fn encode_tx_data(&self, func: &str, params: P) -> Vec { + /// + /// `params` are tokenized parameters of the function. Most of the time, you can use + /// [`Tokenize`][tokenize] trait to convert the parameters into tokens. + /// + /// [tokenize]: https://docs.rs/web3/latest/web3/contract/tokens/trait.Tokenize.html + fn encode_tx_data(&self, func: &str, params: Vec) -> Vec { let f = self .contract() .function(func) .expect("failed to get function parameters"); - f.encode_input(¶ms.into_tokens()) + f.encode_input(¶ms) .expect("failed to encode parameters") } } diff --git a/core/lib/eth_client/src/types.rs b/core/lib/eth_client/src/types.rs index bef3b63b69a9..71d9473b661a 100644 --- a/core/lib/eth_client/src/types.rs +++ b/core/lib/eth_client/src/types.rs @@ -1,9 +1,81 @@ -// External uses use zksync_types::web3::{ + contract::{ + tokens::{Detokenize, Tokenize}, + Error as ContractError, Options, + }, ethabi, - types::{TransactionReceipt, H256, U256}, + types::{Address, BlockId, TransactionReceipt, H256, U256}, }; +/// Wrapper for `Vec` that doesn't wrap them in an additional array in `Tokenize` implementation. +#[derive(Debug)] +pub(crate) struct RawTokens(pub Vec); + +impl Tokenize for RawTokens { + fn into_tokens(self) -> Vec { + self.0 + } +} + +impl Detokenize for RawTokens { + fn from_tokens(tokens: Vec) -> Result { + Ok(Self(tokens)) + } +} + +/// Arguments for calling a function in an unspecified Ethereum smart contract. +#[derive(Debug)] +pub struct CallFunctionArgs { + pub(crate) name: String, + pub(crate) from: Option
, + pub(crate) options: Options, + pub(crate) block: Option, + pub(crate) params: RawTokens, +} + +impl CallFunctionArgs { + pub fn new(name: &str, params: impl Tokenize) -> Self { + Self { + name: name.to_owned(), + from: None, + options: Options::default(), + block: None, + params: RawTokens(params.into_tokens()), + } + } + + pub fn with_sender(mut self, from: Address) -> Self { + self.from = Some(from); + self + } + + pub fn with_block(mut self, block: BlockId) -> Self { + self.block = Some(block); + self + } + + pub fn for_contract( + self, + contract_address: Address, + contract_abi: ethabi::Contract, + ) -> ContractCall { + ContractCall { + contract_address, + contract_abi, + inner: self, + } + } +} + +/// Information sufficient for calling a function in a specific Ethereum smart contract. Instantiated +/// using [`CallFunctionArgs::for_contract()`]. +#[derive(Debug)] +pub struct ContractCall { + pub(crate) contract_address: Address, + pub(crate) contract_abi: ethabi::Contract, + pub(crate) inner: CallFunctionArgs, +} + /// Common error type exposed by the crate, #[derive(Debug, thiserror::Error)] pub enum Error { @@ -24,11 +96,29 @@ pub enum Error { WrongFeeProvided(U256, U256), } +/// Raw transaction bytes. +#[derive(Debug, Clone, PartialEq)] +pub struct RawTransactionBytes(pub(crate) Vec); + +impl RawTransactionBytes { + /// Converts raw transaction bytes. It is caller's responsibility to ensure that these bytes + /// were actually obtained by signing a transaction. + pub fn new_unchecked(bytes: Vec) -> Self { + Self(bytes) + } +} + +impl AsRef<[u8]> for RawTransactionBytes { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + /// Representation of a signed transaction. #[derive(Debug, Clone, PartialEq)] pub struct SignedCallResult { /// Raw transaction bytes. - pub raw_tx: Vec, + pub raw_tx: RawTransactionBytes, /// `max_priority_fee_per_gas` field of transaction (EIP1559). pub max_priority_fee_per_gas: U256, /// `max_fee_per_gas` field of transaction (EIP1559). @@ -69,3 +159,21 @@ pub struct FailureInfo { /// Gas limit of the transaction. pub gas_limit: U256, } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn raw_tokens_are_compatible_with_actual_call() { + let vk_contract = zksync_contracts::verifier_contract(); + let args = CallFunctionArgs::new("verificationKeyHash", ()); + let func = vk_contract.function(&args.name).unwrap(); + func.encode_input(&args.params.into_tokens()).unwrap(); + + let output_tokens = vec![ethabi::Token::FixedBytes(vec![1; 32])]; + let RawTokens(output_tokens) = RawTokens::from_tokens(output_tokens).unwrap(); + let hash = H256::from_tokens(output_tokens).unwrap(); + assert_eq!(hash, H256::repeat_byte(1)); + } +} diff --git a/core/lib/eth_signer/Cargo.toml b/core/lib/eth_signer/Cargo.toml index c4efb0a7ea82..2da0fbd0a790 100644 --- a/core/lib/eth_signer/Cargo.toml +++ b/core/lib/eth_signer/Cargo.toml @@ -18,8 +18,6 @@ serde_json = "1.0.0" hex = "0.4.2" secp256k1 = "0.27.0" -# TODO (PLA-440): remove parity-crypto -parity-crypto = { version = "0.9", features = ["publickey"] } rlp = "0.5" reqwest = { version = "0.11", features = ["json", "blocking"] } diff --git a/core/lib/eth_signer/src/json_rpc_signer.rs b/core/lib/eth_signer/src/json_rpc_signer.rs index 66a7b33e9894..253418ca17e9 100644 --- a/core/lib/eth_signer/src/json_rpc_signer.rs +++ b/core/lib/eth_signer/src/json_rpc_signer.rs @@ -171,7 +171,7 @@ impl JsonRpcSigner { None => AddressOrIndex::Index(0), }; - // EthereumSigner can support many different addresses, + // `EthereumSigner` can support many different addresses, // we define only the one we need by the index // of receiving from the server or by the address itself. signer.detect_address(address_or_index).await?; @@ -439,9 +439,8 @@ mod tests { }; use futures::future::{AbortHandle, Abortable}; use jsonrpc_core::{Failure, Id, Output, Success, Version}; - use parity_crypto::publickey::{Generator, KeyPair, Random}; use serde_json::json; - use zksync_types::{tx::primitives::PackedEthSignature, Address}; + use zksync_types::{tx::primitives::PackedEthSignature, Address, H256}; use super::{is_signature_from_address, messages::JsonRpcRequest}; use crate::{raw_ethereum_tx::TransactionParameters, EthereumSigner, JsonRpcSigner}; @@ -451,8 +450,9 @@ mod tests { let resp = match req.method.as_str() { "eth_accounts" => { let mut addresses = vec![]; - for pair in &state.key_pairs { - addresses.push(pair.address()) + for pk in &state.private_keys { + let address = PackedEthSignature::address_from_private_key(pk).unwrap(); + addresses.push(address) } create_success(json!(addresses)) @@ -463,8 +463,7 @@ mod tests { let data: String = serde_json::from_value(req.params[1].clone()).unwrap(); let data_bytes = hex::decode(&data[2..]).unwrap(); let signature = - PackedEthSignature::sign(&state.key_pairs[0].secret().0.into(), &data_bytes) - .unwrap(); + PackedEthSignature::sign(&state.private_keys[0], &data_bytes).unwrap(); create_success(json!(signature)) } "eth_signTransaction" => { @@ -499,7 +498,7 @@ mod tests { } #[derive(Clone)] struct State { - key_pairs: Vec, + private_keys: Vec, } fn run_server(state: State) -> (String, AbortHandle) { @@ -533,7 +532,7 @@ mod tests { #[actix_rt::test] async fn run_client() { let (address, abort_handle) = run_server(State { - key_pairs: vec![Random.generate()], + private_keys: vec![H256::repeat_byte(0x17)], }); // Get address is ok, unlock address is ok, recover address from signature is also ok let client = JsonRpcSigner::new(address, None, None, None).await.unwrap(); diff --git a/core/lib/eth_signer/src/lib.rs b/core/lib/eth_signer/src/lib.rs index 164a124dbc93..4c053c1ba7cf 100644 --- a/core/lib/eth_signer/src/lib.rs +++ b/core/lib/eth_signer/src/lib.rs @@ -14,7 +14,7 @@ pub mod pk_signer; pub mod raw_ethereum_tx; #[async_trait] -pub trait EthereumSigner: Send + Sync + Clone { +pub trait EthereumSigner: 'static + Send + Sync + Clone { async fn sign_message(&self, message: &[u8]) -> Result; async fn sign_typed_data( &self, diff --git a/core/lib/eth_signer/src/pk_signer.rs b/core/lib/eth_signer/src/pk_signer.rs index 4f9795dca865..0ea68e2a6df9 100644 --- a/core/lib/eth_signer/src/pk_signer.rs +++ b/core/lib/eth_signer/src/pk_signer.rs @@ -62,7 +62,7 @@ impl EthereumSigner for PrivateKeySigner { let key = SecretKey::from_slice(self.private_key.as_bytes()).unwrap(); // According to the code in web3 - // We should use max_fee_per_gas as gas_price if we use EIP1559 + // We should use `max_fee_per_gas` as `gas_price` if we use EIP1559 let gas_price = raw_tx.max_fee_per_gas; let max_priority_fee_per_gas = raw_tx.max_priority_fee_per_gas; @@ -113,7 +113,7 @@ mod test { .await .unwrap(); assert_ne!(raw_tx.len(), 1); - // precalculated signature with right algorithm implementation + // pre-calculated signature with right algorithm implementation let precalculated_raw_tx: Vec = vec![ 1, 248, 100, 130, 1, 14, 1, 2, 128, 148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 131, 1, 2, 3, 192, 1, 160, 98, 201, 238, 158, 215, 98, 23, 231, diff --git a/core/lib/eth_signer/src/raw_ethereum_tx.rs b/core/lib/eth_signer/src/raw_ethereum_tx.rs index 124c09965de4..03d085d91336 100644 --- a/core/lib/eth_signer/src/raw_ethereum_tx.rs +++ b/core/lib/eth_signer/src/raw_ethereum_tx.rs @@ -104,7 +104,7 @@ impl Transaction { let list_size = if signature.is_some() { 11 } else { 8 }; stream.begin_list(list_size); - // append chain_id. from EIP-2930: chainId is defined to be an integer of arbitrary size. + // append `chain_id`. from EIP-2930: `chainId` is defined to be an integer of arbitrary size. stream.append(&chain_id); self.rlp_append_legacy(&mut stream); @@ -123,7 +123,7 @@ impl Transaction { let list_size = if signature.is_some() { 12 } else { 9 }; stream.begin_list(list_size); - // append chain_id. from EIP-2930: chainId is defined to be an integer of arbitrary size. + // append `chain_id`. from EIP-2930: `chainId` is defined to be an integer of arbitrary size. stream.append(&chain_id); stream.append(&self.nonce); diff --git a/core/lib/health_check/src/lib.rs b/core/lib/health_check/src/lib.rs index 12bb292bc850..15a0d2945493 100644 --- a/core/lib/health_check/src/lib.rs +++ b/core/lib/health_check/src/lib.rs @@ -80,10 +80,13 @@ pub struct AppHealth { impl AppHealth { /// Aggregates health info from the provided checks. - pub async fn new(health_checks: &[Box]) -> Self { + pub async fn new>(health_checks: &[T]) -> Self { let check_futures = health_checks.iter().map(|check| { - let check_name = check.name(); - check.check_health().map(move |health| (check_name, health)) + let check_name = check.as_ref().name(); + check + .as_ref() + .check_health() + .map(move |health| (check_name, health)) }); let components: HashMap<_, _> = future::join_all(check_futures).await.into_iter().collect(); diff --git a/core/lib/l1_contract_interface/Cargo.toml b/core/lib/l1_contract_interface/Cargo.toml new file mode 100644 index 000000000000..204198bdaecd --- /dev/null +++ b/core/lib/l1_contract_interface/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "zksync_l1_contract_interface" +version = "0.1.0" +edition = "2018" +authors = ["The Matter Labs Team "] +homepage = "https://zksync.io/" +repository = "https://github.com/matter-labs/zksync-era" +license = "MIT OR Apache-2.0" +keywords = ["blockchain", "zksync"] +categories = ["cryptography"] +readme = "README.md" + +[dependencies] +zksync_types = { path = "../types" } +zksync_prover_interface = { path = "../prover_interface" } + +# Used to serialize proof data +codegen = { git = "https://github.com/matter-labs/solidity_plonk_verifier.git", branch = "dev" } +# Used to calculate commitment for vk from the old L1 verifier contract (backward comatibility needs) +zkevm_test_harness = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.3.3" } diff --git a/core/lib/l1_contract_interface/src/i_executor/methods/commit_batches.rs b/core/lib/l1_contract_interface/src/i_executor/methods/commit_batches.rs new file mode 100644 index 000000000000..fe6876930153 --- /dev/null +++ b/core/lib/l1_contract_interface/src/i_executor/methods/commit_batches.rs @@ -0,0 +1,26 @@ +use zksync_types::{commitment::L1BatchWithMetadata, ethabi::Token}; + +use crate::{ + i_executor::structures::{CommitBatchInfo, StoredBatchInfo}, + Tokenizable, Tokenize, +}; + +/// Input required to encode `commitBatches` call. +#[derive(Debug, Clone)] +pub struct CommitBatches { + pub last_committed_l1_batch: L1BatchWithMetadata, + pub l1_batches: Vec, +} + +impl Tokenize for CommitBatches { + fn into_tokens(self) -> Vec { + let stored_batch_info = StoredBatchInfo(&self.last_committed_l1_batch).into_token(); + let l1_batches_to_commit = self + .l1_batches + .iter() + .map(|batch| CommitBatchInfo(batch).into_token()) + .collect(); + + vec![stored_batch_info, Token::Array(l1_batches_to_commit)] + } +} diff --git a/core/lib/l1_contract_interface/src/i_executor/methods/execute_batches.rs b/core/lib/l1_contract_interface/src/i_executor/methods/execute_batches.rs new file mode 100644 index 000000000000..9b759270a2ac --- /dev/null +++ b/core/lib/l1_contract_interface/src/i_executor/methods/execute_batches.rs @@ -0,0 +1,22 @@ +use zksync_types::{ + commitment::L1BatchWithMetadata, ethabi::Token, web3::contract::tokens::Tokenizable, +}; + +use crate::{i_executor::structures::StoredBatchInfo, Tokenize}; + +/// Input required to encode `executeBatches` call. +#[derive(Debug, Clone)] +pub struct ExecuteBatches { + pub l1_batches: Vec, +} + +impl Tokenize for ExecuteBatches { + fn into_tokens(self) -> Vec { + vec![Token::Array( + self.l1_batches + .iter() + .map(|batch| StoredBatchInfo(batch).into_token()) + .collect(), + )] + } +} diff --git a/core/lib/l1_contract_interface/src/i_executor/methods/mod.rs b/core/lib/l1_contract_interface/src/i_executor/methods/mod.rs new file mode 100644 index 000000000000..765586edb3fa --- /dev/null +++ b/core/lib/l1_contract_interface/src/i_executor/methods/mod.rs @@ -0,0 +1,9 @@ +//! Utilities for encoding input data for methods defined in `IExecutor.sol`. + +pub use self::{ + commit_batches::CommitBatches, execute_batches::ExecuteBatches, prove_batches::ProveBatches, +}; + +mod commit_batches; +mod execute_batches; +mod prove_batches; diff --git a/core/lib/l1_contract_interface/src/i_executor/methods/prove_batches.rs b/core/lib/l1_contract_interface/src/i_executor/methods/prove_batches.rs new file mode 100644 index 000000000000..3c35677d240a --- /dev/null +++ b/core/lib/l1_contract_interface/src/i_executor/methods/prove_batches.rs @@ -0,0 +1,69 @@ +use codegen::serialize_proof; +use zksync_prover_interface::outputs::L1BatchProofForL1; +use zksync_types::{ + commitment::L1BatchWithMetadata, ethabi::Token, web3::contract::tokens::Tokenizable, U256, +}; + +use crate::{i_executor::structures::StoredBatchInfo, Tokenize}; + +/// Input required to encode `proveBatches` call. +#[derive(Debug, Clone)] +pub struct ProveBatches { + pub prev_l1_batch: L1BatchWithMetadata, + pub l1_batches: Vec, + pub proofs: Vec, + pub should_verify: bool, +} + +impl Tokenize for ProveBatches { + fn into_tokens(self) -> Vec { + let prev_l1_batch = StoredBatchInfo(&self.prev_l1_batch).into_token(); + let batches_arg = self + .l1_batches + .iter() + .map(|batch| StoredBatchInfo(batch).into_token()) + .collect(); + let batches_arg = Token::Array(batches_arg); + + if self.should_verify { + // currently we only support submitting a single proof + assert_eq!(self.proofs.len(), 1); + assert_eq!(self.l1_batches.len(), 1); + + let L1BatchProofForL1 { + aggregation_result_coords, + scheduler_proof, + } = self.proofs.first().unwrap(); + + let (_, proof) = serialize_proof(scheduler_proof); + + let aggregation_result_coords = if self.l1_batches[0] + .header + .protocol_version + .unwrap() + .is_pre_boojum() + { + Token::Array( + aggregation_result_coords + .iter() + .map(|bytes| Token::Uint(U256::from_big_endian(bytes))) + .collect(), + ) + } else { + Token::Array(Vec::new()) + }; + let proof_input = Token::Tuple(vec![ + aggregation_result_coords, + Token::Array(proof.into_iter().map(Token::Uint).collect()), + ]); + + vec![prev_l1_batch, batches_arg, proof_input] + } else { + vec![ + prev_l1_batch, + batches_arg, + Token::Tuple(vec![Token::Array(vec![]), Token::Array(vec![])]), + ] + } + } +} diff --git a/core/lib/l1_contract_interface/src/i_executor/mod.rs b/core/lib/l1_contract_interface/src/i_executor/mod.rs new file mode 100644 index 000000000000..a866b45fef7a --- /dev/null +++ b/core/lib/l1_contract_interface/src/i_executor/mod.rs @@ -0,0 +1,4 @@ +//! Different interfaces exposed by the `IExecutor.sol`. + +pub mod methods; +pub mod structures; diff --git a/core/lib/l1_contract_interface/src/i_executor/structures/commit_batch_info.rs b/core/lib/l1_contract_interface/src/i_executor/structures/commit_batch_info.rs new file mode 100644 index 000000000000..c657ef9dcf52 --- /dev/null +++ b/core/lib/l1_contract_interface/src/i_executor/structures/commit_batch_info.rs @@ -0,0 +1,113 @@ +use zksync_types::{ + commitment::L1BatchWithMetadata, + ethabi::Token, + web3::{contract::Error as Web3ContractError, error::Error as Web3ApiError}, + U256, +}; + +use crate::Tokenizable; + +/// Encoding for `CommitBatchInfo` from `IExecutor.sol` +#[derive(Debug)] +pub struct CommitBatchInfo<'a>(pub &'a L1BatchWithMetadata); + +impl<'a> Tokenizable for CommitBatchInfo<'a> { + fn from_token(_token: Token) -> Result + where + Self: Sized, + { + // Currently there is no need to decode this struct. + // We still want to implement `Tokenizable` trait for it, so that *once* it's needed + // the implementation is provided here and not in some other inconsistent way. + Err(Web3ContractError::Api(Web3ApiError::Decoder( + "Not implemented".to_string(), + ))) + } + + fn into_token(self) -> Token { + if self.0.header.protocol_version.unwrap().is_pre_boojum() { + Token::Tuple(vec![ + Token::Uint(U256::from(self.0.header.number.0)), + Token::Uint(U256::from(self.0.header.timestamp)), + Token::Uint(U256::from(self.0.metadata.rollup_last_leaf_index)), + Token::FixedBytes(self.0.metadata.merkle_root_hash.as_bytes().to_vec()), + Token::Uint(U256::from(self.0.header.l1_tx_count)), + Token::FixedBytes(self.0.metadata.l2_l1_merkle_root.as_bytes().to_vec()), + Token::FixedBytes( + self.0 + .header + .priority_ops_onchain_data_hash() + .as_bytes() + .to_vec(), + ), + Token::Bytes(self.0.metadata.initial_writes_compressed.clone()), + Token::Bytes(self.0.metadata.repeated_writes_compressed.clone()), + Token::Bytes(self.0.metadata.l2_l1_messages_compressed.clone()), + Token::Array( + self.0 + .header + .l2_to_l1_messages + .iter() + .map(|message| Token::Bytes(message.to_vec())) + .collect(), + ), + Token::Array( + self.0 + .factory_deps + .iter() + .map(|bytecode| Token::Bytes(bytecode.to_vec())) + .collect(), + ), + ]) + } else { + Token::Tuple(vec![ + // `batchNumber` + Token::Uint(U256::from(self.0.header.number.0)), + // `timestamp` + Token::Uint(U256::from(self.0.header.timestamp)), + // `indexRepeatedStorageChanges` + Token::Uint(U256::from(self.0.metadata.rollup_last_leaf_index)), + // `newStateRoot` + Token::FixedBytes(self.0.metadata.merkle_root_hash.as_bytes().to_vec()), + // `numberOfLayer1Txs` + Token::Uint(U256::from(self.0.header.l1_tx_count)), + // `priorityOperationsHash` + Token::FixedBytes( + self.0 + .header + .priority_ops_onchain_data_hash() + .as_bytes() + .to_vec(), + ), + // `bootloaderHeapInitialContentsHash` + Token::FixedBytes( + self.0 + .metadata + .bootloader_initial_content_commitment + .unwrap() + .as_bytes() + .to_vec(), + ), + // `eventsQueueStateHash` + Token::FixedBytes( + self.0 + .metadata + .events_queue_commitment + .unwrap() + .as_bytes() + .to_vec(), + ), + // `systemLogs` + Token::Bytes(self.0.metadata.l2_l1_messages_compressed.clone()), + // `totalL2ToL1Pubdata` + Token::Bytes( + self.0 + .header + .pubdata_input + .clone() + .unwrap_or(self.0.construct_pubdata()), + ), + ]) + } + } +} diff --git a/core/lib/l1_contract_interface/src/i_executor/structures/mod.rs b/core/lib/l1_contract_interface/src/i_executor/structures/mod.rs new file mode 100644 index 000000000000..d1ed57e41f2e --- /dev/null +++ b/core/lib/l1_contract_interface/src/i_executor/structures/mod.rs @@ -0,0 +1,6 @@ +//! Structures exposed by the `IExecutor.sol`. + +mod commit_batch_info; +mod stored_batch_info; + +pub use self::{commit_batch_info::CommitBatchInfo, stored_batch_info::StoredBatchInfo}; diff --git a/core/lib/l1_contract_interface/src/i_executor/structures/stored_batch_info.rs b/core/lib/l1_contract_interface/src/i_executor/structures/stored_batch_info.rs new file mode 100644 index 000000000000..10fccc0198d1 --- /dev/null +++ b/core/lib/l1_contract_interface/src/i_executor/structures/stored_batch_info.rs @@ -0,0 +1,53 @@ +use zksync_types::{ + commitment::L1BatchWithMetadata, + ethabi::Token, + web3::{contract::Error as Web3ContractError, error::Error as Web3ApiError}, + U256, +}; + +use crate::Tokenizable; + +/// Encoding for `StoredBatchInfo` from `IExecutor.sol` +#[derive(Debug)] +pub struct StoredBatchInfo<'a>(pub &'a L1BatchWithMetadata); + +impl<'a> Tokenizable for StoredBatchInfo<'a> { + fn from_token(_token: Token) -> Result + where + Self: Sized, + { + // Currently there is no need to decode this struct. + // We still want to implement `Tokenizable` trait for it, so that *once* it's needed + // the implementation is provided here and not in some other inconsistent way. + Err(Web3ContractError::Api(Web3ApiError::Decoder( + "Not implemented".to_string(), + ))) + } + + fn into_token(self) -> Token { + Token::Tuple(vec![ + // `batchNumber` + Token::Uint(U256::from(self.0.header.number.0)), + // `batchHash` + Token::FixedBytes(self.0.metadata.root_hash.as_bytes().to_vec()), + // `indexRepeatedStorageChanges` + Token::Uint(U256::from(self.0.metadata.rollup_last_leaf_index)), + // `numberOfLayer1Txs` + Token::Uint(U256::from(self.0.header.l1_tx_count)), + // `priorityOperationsHash` + Token::FixedBytes( + self.0 + .header + .priority_ops_onchain_data_hash() + .as_bytes() + .to_vec(), + ), + // `l2LogsTreeRoot` + Token::FixedBytes(self.0.metadata.l2_l1_merkle_root.as_bytes().to_vec()), + // timestamp + Token::Uint(U256::from(self.0.header.timestamp)), + // commitment + Token::FixedBytes(self.0.metadata.commitment.as_bytes().to_vec()), + ]) + } +} diff --git a/core/lib/l1_contract_interface/src/lib.rs b/core/lib/l1_contract_interface/src/lib.rs new file mode 100644 index 000000000000..f4f9d04ef248 --- /dev/null +++ b/core/lib/l1_contract_interface/src/lib.rs @@ -0,0 +1,19 @@ +//! Utilities for interacting with the zkSync L1 contract +//! +//! Provides utilities both to encode input data for the contract and to decode +//! the data provided by the contract. +//! +//! This crate utilizes traits provided by the `web3` crate to encode and decode +//! data. `Tokenizable` trait represents items that are encoded via single `Token`, +//! while `Tokenize` trait represents items that are encoded via array of `Token`s +//! (for example, transaction input). + +pub use zksync_types::web3::contract::tokens::{Detokenize, Tokenizable, Tokenize}; + +/// Rust interface for (subset of) `IExector.sol`. +pub mod i_executor; +/// Utilities for interacting with `Multicall3` contract. +pub mod multicall3; +/// Utilities for interacting with the old verifier contract. +/// Required for backward compatibility only. +pub mod pre_boojum_verifier; diff --git a/core/lib/types/src/contracts.rs b/core/lib/l1_contract_interface/src/multicall3/mod.rs similarity index 99% rename from core/lib/types/src/contracts.rs rename to core/lib/l1_contract_interface/src/multicall3/mod.rs index 6b72375202a4..a47d034d5866 100644 --- a/core/lib/types/src/contracts.rs +++ b/core/lib/l1_contract_interface/src/multicall3/mod.rs @@ -1,6 +1,6 @@ use std::mem; -use crate::{ +use zksync_types::{ ethabi::Token, web3::contract::{tokens::Tokenizable, Error}, Address, diff --git a/core/lib/l1_contract_interface/src/pre_boojum_verifier/mod.rs b/core/lib/l1_contract_interface/src/pre_boojum_verifier/mod.rs new file mode 100644 index 000000000000..b1af0b253739 --- /dev/null +++ b/core/lib/l1_contract_interface/src/pre_boojum_verifier/mod.rs @@ -0,0 +1,3 @@ +mod vk_transform; + +pub use self::vk_transform::old_l1_vk_commitment; diff --git a/core/lib/types/src/vk_transform.rs b/core/lib/l1_contract_interface/src/pre_boojum_verifier/vk_transform.rs similarity index 92% rename from core/lib/types/src/vk_transform.rs rename to core/lib/l1_contract_interface/src/pre_boojum_verifier/vk_transform.rs index b19fdaef6927..70098230d9b8 100644 --- a/core/lib/types/src/vk_transform.rs +++ b/core/lib/l1_contract_interface/src/pre_boojum_verifier/vk_transform.rs @@ -1,3 +1,6 @@ +//! This module contains functions for transforming vk from the old L1 verifier contract to the hash +//! that serves as its commitment. + use std::str::FromStr; use zkevm_test_harness::{ @@ -13,16 +16,15 @@ use zkevm_test_harness::{ recursive_aggregation::{compute_vk_encoding_and_committment, erase_vk_type}, }, }; - -use crate::{ethabi::Token, H256}; +use zksync_types::{ethabi::Token, H256}; /// Calculates commitment for vk from L1 verifier contract. -pub fn l1_vk_commitment(token: Token) -> H256 { +pub fn old_l1_vk_commitment(token: Token) -> H256 { let vk = vk_from_token(token); generate_vk_commitment(vk) } -pub fn generate_vk_commitment( +fn generate_vk_commitment( vk: VerificationKey>>, ) -> H256 { let (_, scheduler_vk_commitment) = compute_vk_encoding_and_committment(erase_vk_type(vk)); diff --git a/core/lib/mempool/src/tests.rs b/core/lib/mempool/src/tests.rs index cd595509ec56..656d90c63d14 100644 --- a/core/lib/mempool/src/tests.rs +++ b/core/lib/mempool/src/tests.rs @@ -45,7 +45,7 @@ fn basic_flow() { (account0, 3) ); assert_eq!(mempool.next_transaction(&L2TxFilter::default()), None); - // unclog second account and insert more txns + // unclog second account and insert more transactions mempool.insert( vec![gen_l2_tx(account1, Nonce(0)), gen_l2_tx(account0, Nonce(3))], HashMap::new(), @@ -244,13 +244,13 @@ fn mempool_size() { fn filtering() { // Filter to find transactions with non-zero `gas_per_pubdata` values. let filter_non_zero = L2TxFilter { - l1_gas_price: 0u64, + fee_input: Default::default(), fee_per_gas: 0u64, gas_per_pubdata: 1u32, }; // No-op filter that fetches any transaction. let filter_zero = L2TxFilter { - l1_gas_price: 0u64, + fee_input: Default::default(), fee_per_gas: 0u64, gas_per_pubdata: 0u32, }; @@ -288,13 +288,13 @@ fn filtering() { #[test] fn stashed_accounts() { let filter_non_zero = L2TxFilter { - l1_gas_price: 0u64, + fee_input: Default::default(), fee_per_gas: 0u64, gas_per_pubdata: 1u32, }; // No-op filter that fetches any transaction. let filter_zero = L2TxFilter { - l1_gas_price: 0u64, + fee_input: Default::default(), fee_per_gas: 0u64, gas_per_pubdata: 0u32, }; diff --git a/core/lib/mempool/src/types.rs b/core/lib/mempool/src/types.rs index 9bc58a4e2cea..99a63ffd08e2 100644 --- a/core/lib/mempool/src/types.rs +++ b/core/lib/mempool/src/types.rs @@ -1,6 +1,8 @@ use std::{cmp::Ordering, collections::HashMap}; -use zksync_types::{fee::Fee, l2::L2Tx, Address, Nonce, Transaction, U256}; +use zksync_types::{ + fee::Fee, fee_model::BatchFeeInput, l2::L2Tx, Address, Nonce, Transaction, U256, +}; /// Pending mempool transactions of account #[derive(Debug)] @@ -128,8 +130,8 @@ pub(crate) struct InsertionMetadata { /// criteria for transaction it wants to fetch. #[derive(Debug, Default, PartialEq, Eq)] pub struct L2TxFilter { - /// L1 gas price. - pub l1_gas_price: u64, + /// Batch fee model input. It typically includes things like L1 gas price, L2 fair fee, etc. + pub fee_input: BatchFeeInput, /// Effective fee price for the transaction. The price of 1 gas in wei. pub fee_per_gas: u64, /// Effective pubdata price in gas for transaction. The number of gas per 1 pubdata byte. @@ -143,9 +145,9 @@ mod tests { /// Checks the filter logic. #[test] fn filter() { - fn filter(l1_gas_price: u64, fee_per_gas: u64, gas_per_pubdata: u32) -> L2TxFilter { + fn filter(fee_per_gas: u64, gas_per_pubdata: u32) -> L2TxFilter { L2TxFilter { - l1_gas_price, + fee_input: BatchFeeInput::sensible_l1_pegged_default(), fee_per_gas, gas_per_pubdata, } @@ -166,31 +168,31 @@ mod tests { }, }; - let noop_filter = filter(0, 0, 0); + let noop_filter = filter(0, 0); assert!( score.matches_filter(&noop_filter), "Noop filter should always match" ); - let max_gas_filter = filter(0, MAX_FEE_PER_GAS, 0); + let max_gas_filter = filter(MAX_FEE_PER_GAS, 0); assert!( score.matches_filter(&max_gas_filter), "Correct max gas should be accepted" ); - let pubdata_filter = filter(0, 0, GAS_PER_PUBDATA_LIMIT); + let pubdata_filter = filter(0, GAS_PER_PUBDATA_LIMIT); assert!( score.matches_filter(&pubdata_filter), "Correct pubdata price should be accepted" ); - let decline_gas_filter = filter(0, MAX_FEE_PER_GAS + 1, 0); + let decline_gas_filter = filter(MAX_FEE_PER_GAS + 1, 0); assert!( !score.matches_filter(&decline_gas_filter), "Incorrect max gas should be rejected" ); - let decline_pubdata_filter = filter(0, 0, GAS_PER_PUBDATA_LIMIT + 1); + let decline_pubdata_filter = filter(0, GAS_PER_PUBDATA_LIMIT + 1); assert!( !score.matches_filter(&decline_pubdata_filter), "Incorrect pubdata price should be rejected" diff --git a/core/lib/merkle_tree/Cargo.toml b/core/lib/merkle_tree/Cargo.toml index ed1669519b93..06cc0b67871e 100644 --- a/core/lib/merkle_tree/Cargo.toml +++ b/core/lib/merkle_tree/Cargo.toml @@ -13,7 +13,8 @@ categories = ["cryptography"] vise = { git = "https://github.com/matter-labs/vise.git", version = "0.1.0", rev = "1c9cc500e92cf9ea052b230e114a6f9cce4fb2c1" } zksync_types = { path = "../types" } zksync_crypto = { path = "../crypto" } -zksync_storage = { path = "../storage", default-features = false } +zksync_storage = { path = "../storage" } +zksync_prover_interface = { path = "../prover_interface" } zksync_utils = { path = "../utils" } leb128 = "0.2.5" diff --git a/core/lib/merkle_tree/README.md b/core/lib/merkle_tree/README.md index edf2ec20c417..b3c8a31c9980 100644 --- a/core/lib/merkle_tree/README.md +++ b/core/lib/merkle_tree/README.md @@ -111,7 +111,7 @@ following order of RocksDB storage consumption at the end of the test: [gauge] rocksdb.total_mem_table_size{db=merkle_tree, cf=stale_keys} = 19924992 bytes ``` -I.e., pruning reduces RocksDB size ~8.7 times in this case. +I.e., pruning reduces RocksDB size approximately 8.7 times in this case. [jellyfish merkle tree]: https://developers.diem.com/papers/jellyfish-merkle-tree/2021-01-14.pdf [`insta`]: https://docs.rs/insta/ diff --git a/core/lib/merkle_tree/examples/loadtest/main.rs b/core/lib/merkle_tree/examples/loadtest/main.rs index 185ae0543f9d..53a641750d10 100644 --- a/core/lib/merkle_tree/examples/loadtest/main.rs +++ b/core/lib/merkle_tree/examples/loadtest/main.rs @@ -90,13 +90,11 @@ impl Cli { "Created temp dir for RocksDB: {}", dir.path().to_string_lossy() ); - let db = RocksDB::with_options( - dir.path(), - RocksDBOptions { - block_cache_capacity: self.block_cache, - ..RocksDBOptions::default() - }, - ); + let db_options = RocksDBOptions { + block_cache_capacity: self.block_cache, + ..RocksDBOptions::default() + }; + let db = RocksDB::with_options(dir.path(), db_options).unwrap(); rocksdb = RocksDBWrapper::from(db); if let Some(chunk_size) = self.chunk_size { diff --git a/core/lib/merkle_tree/examples/recovery.rs b/core/lib/merkle_tree/examples/recovery.rs index 1b4e634e567a..8769f9a64acc 100644 --- a/core/lib/merkle_tree/examples/recovery.rs +++ b/core/lib/merkle_tree/examples/recovery.rs @@ -62,13 +62,11 @@ impl Cli { "Created temp dir for RocksDB: {}", dir.path().to_string_lossy() ); - let db = RocksDB::with_options( - dir.path(), - RocksDBOptions { - block_cache_capacity: self.block_cache, - ..RocksDBOptions::default() - }, - ); + let db_options = RocksDBOptions { + block_cache_capacity: self.block_cache, + ..RocksDBOptions::default() + }; + let db = RocksDB::with_options(dir.path(), db_options).unwrap(); rocksdb = RocksDBWrapper::from(db); _temp_dir = Some(dir); &mut rocksdb diff --git a/core/lib/merkle_tree/src/consistency.rs b/core/lib/merkle_tree/src/consistency.rs index 659befbe048e..7b30e8b44e01 100644 --- a/core/lib/merkle_tree/src/consistency.rs +++ b/core/lib/merkle_tree/src/consistency.rs @@ -161,8 +161,8 @@ impl MerkleTree { is_leaf: child_ref.is_leaf, })?; - // Recursion here is OK; the tree isn't that deep (~8 nibbles for a tree with - // ~1B entries). + // Recursion here is OK; the tree isn't that deep (approximately 8 nibbles for a tree with + // approximately 1B entries). let child_hash = self.validate_node(&child, child_key, leaf_data)?; if child_hash == child_ref.hash { Ok(()) diff --git a/core/lib/merkle_tree/src/domain.rs b/core/lib/merkle_tree/src/domain.rs index 2fe4b59f8217..0724804a5a7b 100644 --- a/core/lib/merkle_tree/src/domain.rs +++ b/core/lib/merkle_tree/src/domain.rs @@ -2,8 +2,8 @@ use rayon::{ThreadPool, ThreadPoolBuilder}; use zksync_crypto::hasher::blake2::Blake2Hasher; +use zksync_prover_interface::inputs::{PrepareBasicCircuitsJob, StorageLogMetadata}; use zksync_types::{ - proofs::{PrepareBasicCircuitsJob, StorageLogMetadata}, writes::{InitialStorageWrite, RepeatedStorageWrite, StateDiffRecord}, L1BatchNumber, StorageKey, U256, }; diff --git a/core/lib/merkle_tree/src/storage/rocksdb.rs b/core/lib/merkle_tree/src/storage/rocksdb.rs index 7dd4d6083d79..8fc9f202d21b 100644 --- a/core/lib/merkle_tree/src/storage/rocksdb.rs +++ b/core/lib/merkle_tree/src/storage/rocksdb.rs @@ -3,7 +3,7 @@ use std::path::Path; use rayon::prelude::*; -use zksync_storage::{db::NamedColumnFamily, rocksdb::DBPinnableSlice, RocksDB}; +use zksync_storage::{db::NamedColumnFamily, rocksdb, rocksdb::DBPinnableSlice, RocksDB}; use crate::{ errors::{DeserializeError, ErrorContext}, @@ -66,8 +66,12 @@ impl RocksDBWrapper { const MANIFEST_KEY: &'static [u8] = &[0]; /// Creates a new wrapper, initializing RocksDB at the specified directory. - pub fn new(path: &Path) -> Self { - Self::from(RocksDB::new(path)) + /// + /// # Errors + /// + /// Propagates RocksDB I/O errors. + pub fn new(path: &Path) -> Result { + Ok(Self::from(RocksDB::new(path)?)) } /// Sets the chunk size for multi-get operations. The requested keys will be split @@ -295,7 +299,7 @@ mod tests { #[test] fn garbage_is_removed_on_db_reverts() { let dir = TempDir::new().expect("failed creating temporary dir for RocksDB"); - let mut db = RocksDBWrapper::new(dir.path()); + let mut db = RocksDBWrapper::new(dir.path()).unwrap(); // Insert some data to the database. let mut expected_keys = HashSet::new(); diff --git a/core/lib/merkle_tree/src/storage/tests.rs b/core/lib/merkle_tree/src/storage/tests.rs index a0c1ae4c9494..8bcaab710814 100644 --- a/core/lib/merkle_tree/src/storage/tests.rs +++ b/core/lib/merkle_tree/src/storage/tests.rs @@ -79,7 +79,7 @@ fn inserting_entries_in_empty_database() { fn assert_storage_with_2_keys(updater: &TreeUpdater) { // Check the internal nodes with a single child that should be created at keys - // '', 'd', 'de', ..., 'deadbeef'. + // `'', 'd', 'de', ..., 'deadbeef'`. let internal_node_nibbles = (0..8).map(|i| { let nibbles = Nibbles::new(&FIRST_KEY, i); let next_nibble = Nibbles::nibble(&FIRST_KEY, i); @@ -96,7 +96,7 @@ fn assert_storage_with_2_keys(updater: &TreeUpdater) { assert!(!child_ref.is_leaf); } - // Check the final internal node with 2 leaf children at 'deadbeef0'. + // Check the final internal node with 2 leaf children at `deadbeef0`. let nibbles = Nibbles::new(&FIRST_KEY, 9); let node = updater.patch_set.get(&nibbles).unwrap(); let Node::Internal(node) = node else { diff --git a/core/lib/merkle_tree/src/types/internal.rs b/core/lib/merkle_tree/src/types/internal.rs index 4351b7b8647e..06923bac33f2 100644 --- a/core/lib/merkle_tree/src/types/internal.rs +++ b/core/lib/merkle_tree/src/types/internal.rs @@ -314,12 +314,12 @@ impl NodeKey { #[allow(clippy::cast_possible_truncation)] pub(crate) fn to_db_key(self) -> Vec { let nibbles_byte_len = (self.nibbles.nibble_count + 1) / 2; - // ^ equivalent to ceil(self.nibble_count / 2) + // ^ equivalent to `ceil(self.nibble_count / 2)` let mut bytes = Vec::with_capacity(9 + nibbles_byte_len); // ^ 8 bytes for `version` + 1 byte for nibble count bytes.extend_from_slice(&self.version.to_be_bytes()); bytes.push(self.nibbles.nibble_count as u8); - // ^ conversion is safe: nibble_count <= 64 + // ^ conversion is safe: `nibble_count <= 64` bytes.extend_from_slice(&self.nibbles.bytes[..nibbles_byte_len]); bytes } @@ -568,7 +568,7 @@ mod tests { use super::*; // `U256` uses little-endian `u64` ordering; i.e., this is - // 0x_dead_beef_0000_0000_.._0000. + // `0x_dead_beef_0000_0000_.._0000.` const TEST_KEY: Key = U256([0, 0, 0, 0x_dead_beef_0000_0000]); #[test] diff --git a/core/lib/merkle_tree/tests/integration/consistency.rs b/core/lib/merkle_tree/tests/integration/consistency.rs index b6b424e431ad..33ad521bc940 100644 --- a/core/lib/merkle_tree/tests/integration/consistency.rs +++ b/core/lib/merkle_tree/tests/integration/consistency.rs @@ -21,7 +21,7 @@ fn five_thousand_angry_monkeys_vs_merkle_tree() { const RNG_SEED: u64 = 42; let dir = TempDir::new().expect("failed creating temporary dir for RocksDB"); - let mut db = RocksDBWrapper::new(dir.path()); + let mut db = RocksDBWrapper::new(dir.path()).unwrap(); let mut tree = MerkleTree::new(&mut db); let kvs = generate_key_value_pairs(0..100); diff --git a/core/lib/merkle_tree/tests/integration/domain.rs b/core/lib/merkle_tree/tests/integration/domain.rs index e96b68fdade1..565b4d5f0fe4 100644 --- a/core/lib/merkle_tree/tests/integration/domain.rs +++ b/core/lib/merkle_tree/tests/integration/domain.rs @@ -7,11 +7,10 @@ use serde_with::{hex::Hex, serde_as}; use tempfile::TempDir; use zksync_crypto::hasher::blake2::Blake2Hasher; use zksync_merkle_tree::{domain::ZkSyncTree, HashTree, TreeEntry, TreeInstruction}; +use zksync_prover_interface::inputs::StorageLogMetadata; use zksync_storage::RocksDB; use zksync_system_constants::ACCOUNT_CODE_STORAGE_ADDRESS; -use zksync_types::{ - proofs::StorageLogMetadata, AccountTreeId, Address, L1BatchNumber, StorageKey, H256, -}; +use zksync_types::{AccountTreeId, Address, L1BatchNumber, StorageKey, H256}; fn gen_storage_logs() -> Vec> { let addrs = vec![ @@ -45,7 +44,7 @@ fn basic_workflow() { let logs = gen_storage_logs(); let (metadata, expected_root_hash) = { - let db = RocksDB::new(temp_dir.as_ref()); + let db = RocksDB::new(temp_dir.as_ref()).unwrap(); let mut tree = ZkSyncTree::new_lightweight(db.into()); let metadata = tree.process_l1_batch(&logs); tree.save(); @@ -73,7 +72,7 @@ fn basic_workflow() { ]), ); - let db = RocksDB::new(temp_dir.as_ref()); + let db = RocksDB::new(temp_dir.as_ref()).unwrap(); let tree = ZkSyncTree::new_lightweight(db.into()); tree.verify_consistency(L1BatchNumber(0)); assert_eq!(tree.root_hash(), expected_root_hash); @@ -87,7 +86,7 @@ fn basic_workflow_multiblock() { let blocks = logs.chunks(9); let expected_root_hash = { - let db = RocksDB::new(temp_dir.as_ref()); + let db = RocksDB::new(temp_dir.as_ref()).unwrap(); let mut tree = ZkSyncTree::new_lightweight(db.into()); tree.use_dedicated_thread_pool(2); for block in blocks { @@ -105,7 +104,7 @@ fn basic_workflow_multiblock() { ]), ); - let db = RocksDB::new(temp_dir.as_ref()); + let db = RocksDB::new(temp_dir.as_ref()).unwrap(); let tree = ZkSyncTree::new_lightweight(db.into()); assert_eq!(tree.root_hash(), expected_root_hash); assert_eq!(tree.next_l1_batch_number(), L1BatchNumber(12)); @@ -114,7 +113,7 @@ fn basic_workflow_multiblock() { #[test] fn filtering_out_no_op_writes() { let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); - let db = RocksDB::new(temp_dir.as_ref()); + let db = RocksDB::new(temp_dir.as_ref()).unwrap(); let mut tree = ZkSyncTree::new(db.into()); let mut logs = gen_storage_logs(); let root_hash = tree.process_l1_batch(&logs).root_hash; @@ -152,7 +151,7 @@ fn filtering_out_no_op_writes() { #[test] fn revert_blocks() { let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); - let storage = RocksDB::new(temp_dir.as_ref()); + let storage = RocksDB::new(temp_dir.as_ref()).unwrap(); // Generate logs and save them to DB. // Produce 4 blocks with distinct values and 1 block with modified values from first block @@ -210,7 +209,7 @@ fn revert_blocks() { } // Revert the last block. - let storage = RocksDB::new(temp_dir.as_ref()); + let storage = RocksDB::new(temp_dir.as_ref()).unwrap(); { let mut tree = ZkSyncTree::new_lightweight(storage.into()); assert_eq!(tree.root_hash(), tree_metadata.last().unwrap().root_hash); @@ -220,7 +219,7 @@ fn revert_blocks() { } // Revert two more blocks. - let storage = RocksDB::new(temp_dir.as_ref()); + let storage = RocksDB::new(temp_dir.as_ref()).unwrap(); { let mut tree = ZkSyncTree::new_lightweight(storage.into()); tree.revert_logs(L1BatchNumber(1)); @@ -229,7 +228,7 @@ fn revert_blocks() { } // Revert two more blocks second time; the result should be the same - let storage = RocksDB::new(temp_dir.as_ref()); + let storage = RocksDB::new(temp_dir.as_ref()).unwrap(); { let mut tree = ZkSyncTree::new_lightweight(storage.into()); tree.revert_logs(L1BatchNumber(1)); @@ -238,7 +237,7 @@ fn revert_blocks() { } // Reapply one of the reverted logs - let storage = RocksDB::new(temp_dir.as_ref()); + let storage = RocksDB::new(temp_dir.as_ref()).unwrap(); { let storage_log = mirror_logs.get(3 * block_size).unwrap(); let mut tree = ZkSyncTree::new_lightweight(storage.into()); @@ -247,7 +246,7 @@ fn revert_blocks() { } // check saved block number - let storage = RocksDB::new(temp_dir.as_ref()); + let storage = RocksDB::new(temp_dir.as_ref()).unwrap(); let tree = ZkSyncTree::new_lightweight(storage.into()); assert_eq!(tree.next_l1_batch_number(), L1BatchNumber(3)); } @@ -255,7 +254,7 @@ fn revert_blocks() { #[test] fn reset_tree() { let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); - let storage = RocksDB::new(temp_dir.as_ref()); + let storage = RocksDB::new(temp_dir.as_ref()).unwrap(); let logs = gen_storage_logs(); let mut tree = ZkSyncTree::new_lightweight(storage.into()); let empty_root_hash = tree.root_hash(); @@ -278,14 +277,14 @@ fn read_logs() { logs.truncate(5); let write_metadata = { - let db = RocksDB::new(temp_dir.as_ref()); + let db = RocksDB::new(temp_dir.as_ref()).unwrap(); let mut tree = ZkSyncTree::new_lightweight(db.into()); let metadata = tree.process_l1_batch(&logs); tree.save(); metadata }; - let db = RocksDB::new(temp_dir.as_ref()); + let db = RocksDB::new(temp_dir.as_ref()).unwrap(); let mut tree = ZkSyncTree::new_lightweight(db.into()); let read_logs: Vec<_> = logs .into_iter() @@ -315,7 +314,7 @@ fn subtract_from_max_value(diff: u8) -> [u8; 32] { #[test] fn root_hash_compatibility() { let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); - let db = RocksDB::new(temp_dir.as_ref()); + let db = RocksDB::new(temp_dir.as_ref()).unwrap(); let mut tree = ZkSyncTree::new_lightweight(db.into()); assert_eq!( tree.root_hash(), @@ -372,7 +371,7 @@ fn root_hash_compatibility() { #[test] fn process_block_idempotency_check() { let temp_dir = TempDir::new().expect("failed to get temporary directory for RocksDB"); - let rocks_db = RocksDB::new(temp_dir.as_ref()); + let rocks_db = RocksDB::new(temp_dir.as_ref()).unwrap(); let mut tree = ZkSyncTree::new_lightweight(rocks_db.into()); let logs = gen_storage_logs(); let tree_metadata = tree.process_l1_batch(&logs); @@ -435,7 +434,7 @@ fn witness_workflow() { let logs = gen_storage_logs(); let (first_chunk, _) = logs.split_at(logs.len() / 2); - let db = RocksDB::new(temp_dir.as_ref()); + let db = RocksDB::new(temp_dir.as_ref()).unwrap(); let mut tree = ZkSyncTree::new(db.into()); let metadata = tree.process_l1_batch(first_chunk); let job = metadata.witness.unwrap(); @@ -465,7 +464,7 @@ fn witnesses_with_multiple_blocks() { let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); let logs = gen_storage_logs(); - let db = RocksDB::new(temp_dir.as_ref()); + let db = RocksDB::new(temp_dir.as_ref()).unwrap(); let mut tree = ZkSyncTree::new(db.into()); let empty_tree_hashes: Vec<_> = (0..256) .map(|i| Blake2Hasher.empty_subtree_hash(i)) diff --git a/core/lib/merkle_tree/tests/integration/merkle_tree.rs b/core/lib/merkle_tree/tests/integration/merkle_tree.rs index 117ea0db4d99..fe6731fb441c 100644 --- a/core/lib/merkle_tree/tests/integration/merkle_tree.rs +++ b/core/lib/merkle_tree/tests/integration/merkle_tree.rs @@ -550,7 +550,7 @@ mod rocksdb { impl Harness { fn new() -> Self { let dir = TempDir::new().expect("failed creating temporary dir for RocksDB"); - let db = RocksDBWrapper::new(dir.path()); + let db = RocksDBWrapper::new(dir.path()).unwrap(); Self { db, dir } } } @@ -661,7 +661,7 @@ mod rocksdb { tree.extend(vec![TreeEntry::new(U256::zero(), 1, H256::zero())]); drop(tree); - let db = RocksDBWrapper::new(dir.path()); + let db = RocksDBWrapper::new(dir.path()).unwrap(); MerkleTree::with_hasher(db, ()); } } diff --git a/core/lib/merkle_tree/tests/integration/recovery.rs b/core/lib/merkle_tree/tests/integration/recovery.rs index 2bac00f02c3d..2992561bb1bf 100644 --- a/core/lib/merkle_tree/tests/integration/recovery.rs +++ b/core/lib/merkle_tree/tests/integration/recovery.rs @@ -131,7 +131,7 @@ mod rocksdb { #[test_casing(8, test_casing::Product((RecoveryKind::ALL, [6, 10, 17, 42])))] fn recovery_in_chunks(kind: RecoveryKind, chunk_size: usize) { let temp_dir = TempDir::new().unwrap(); - let db = RocksDBWrapper::new(temp_dir.path()); + let db = RocksDBWrapper::new(temp_dir.path()).unwrap(); test_recovery_in_chunks(db, kind, chunk_size); } } diff --git a/core/lib/mini_merkle_tree/README.md b/core/lib/mini_merkle_tree/README.md index a0608d78f71e..afac2fc9ebd2 100644 --- a/core/lib/mini_merkle_tree/README.md +++ b/core/lib/mini_merkle_tree/README.md @@ -12,5 +12,5 @@ cargo bench -p zksync_mini_merkle_tree --bench tree ``` The order of timings should be 2M elements/s for all tree sizes (measured on MacBook Pro with 12-core Apple M2 Max CPU), -both for calculating the root and the root + Merkle path. This translates to ~130µs for a tree with 512 leaves (the tree -size used for `L2ToL1Log`s). +both for calculating the root and the root + Merkle path. This translates to approximately 130µs for a tree with 512 +leaves (the tree size used for `L2ToL1Log`s). diff --git a/core/lib/multivm/Cargo.toml b/core/lib/multivm/Cargo.toml index 0cf207409904..7863a8e644be 100644 --- a/core/lib/multivm/Cargo.toml +++ b/core/lib/multivm/Cargo.toml @@ -10,10 +10,16 @@ keywords = ["blockchain", "zksync"] categories = ["cryptography"] [dependencies] +zk_evm_1_4_1 = { package = "zk_evm", git = "https://github.com/matter-labs/era-zk_evm.git", branch = "v1.4.1" } zk_evm_1_4_0 = { package = "zk_evm", git = "https://github.com/matter-labs/era-zk_evm.git", branch = "v1.4.0" } zk_evm_1_3_3 = { package = "zk_evm", git = "https://github.com/matter-labs/era-zk_evm.git", tag= "v1.3.3-rc2" } zk_evm_1_3_1 = { package = "zk_evm", git = "https://github.com/matter-labs/era-zk_evm.git", tag= "v1.3.1-rc2" } +zkevm_test_harness_1_3_3 = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.3.3", package = "zkevm_test_harness" } +zkevm_test_harness_1_4_0 = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.0", package = "zkevm_test_harness" } +zkevm_test_harness_1_4_1 = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.1", package = "zkevm_test_harness" } + + zksync_types = { path = "../types" } zksync_state = { path = "../state" } zksync_contracts = { path = "../contracts" } @@ -29,9 +35,8 @@ thiserror = "1.0" tracing = "0.1" vise = { git = "https://github.com/matter-labs/vise.git", version = "0.1.0", rev = "1c9cc500e92cf9ea052b230e114a6f9cce4fb2c1" } - [dev-dependencies] tokio = { version = "1", features = ["time"] } -zksync_test_account = { path = "../test_account" } +zksync_test_account = { path = "../../tests/test_account" } ethabi = "18.0.0" zksync_eth_signer = { path = "../eth_signer" } diff --git a/core/lib/multivm/src/glue/history_mode.rs b/core/lib/multivm/src/glue/history_mode.rs index ca56836d8e82..f820477c10a5 100644 --- a/core/lib/multivm/src/glue/history_mode.rs +++ b/core/lib/multivm/src/glue/history_mode.rs @@ -7,12 +7,14 @@ pub trait HistoryMode: + GlueInto + GlueInto + GlueInto + + GlueInto { type VmM6Mode: crate::vm_m6::HistoryMode; type Vm1_3_2Mode: crate::vm_1_3_2::HistoryMode; type VmVirtualBlocksMode: crate::vm_virtual_blocks::HistoryMode; type VmVirtualBlocksRefundsEnhancement: crate::vm_refunds_enhancement::HistoryMode; - type VmBoojumIntegration: crate::vm_latest::HistoryMode; + type VmBoojumIntegration: crate::vm_boojum_integration::HistoryMode; + type Vm1_4_1: crate::vm_latest::HistoryMode; } impl GlueFrom for crate::vm_m6::HistoryEnabled { @@ -39,6 +41,12 @@ impl GlueFrom for crate::vm_refunds_enhancemen } } +impl GlueFrom for crate::vm_boojum_integration::HistoryEnabled { + fn glue_from(_: crate::vm_latest::HistoryEnabled) -> Self { + Self + } +} + impl GlueFrom for crate::vm_m6::HistoryDisabled { fn glue_from(_: crate::vm_latest::HistoryDisabled) -> Self { Self @@ -65,12 +73,19 @@ impl GlueFrom } } +impl GlueFrom for crate::vm_boojum_integration::HistoryDisabled { + fn glue_from(_: crate::vm_latest::HistoryDisabled) -> Self { + Self + } +} + impl HistoryMode for crate::vm_latest::HistoryEnabled { type VmM6Mode = crate::vm_m6::HistoryEnabled; type Vm1_3_2Mode = crate::vm_1_3_2::HistoryEnabled; type VmVirtualBlocksMode = crate::vm_virtual_blocks::HistoryEnabled; type VmVirtualBlocksRefundsEnhancement = crate::vm_refunds_enhancement::HistoryEnabled; - type VmBoojumIntegration = crate::vm_latest::HistoryEnabled; + type VmBoojumIntegration = crate::vm_boojum_integration::HistoryEnabled; + type Vm1_4_1 = crate::vm_latest::HistoryEnabled; } impl HistoryMode for crate::vm_latest::HistoryDisabled { @@ -78,5 +93,6 @@ impl HistoryMode for crate::vm_latest::HistoryDisabled { type Vm1_3_2Mode = crate::vm_1_3_2::HistoryDisabled; type VmVirtualBlocksMode = crate::vm_virtual_blocks::HistoryDisabled; type VmVirtualBlocksRefundsEnhancement = crate::vm_refunds_enhancement::HistoryDisabled; - type VmBoojumIntegration = crate::vm_latest::HistoryDisabled; + type VmBoojumIntegration = crate::vm_boojum_integration::HistoryDisabled; + type Vm1_4_1 = crate::vm_latest::HistoryDisabled; } diff --git a/core/lib/multivm/src/glue/mod.rs b/core/lib/multivm/src/glue/mod.rs index 299093532bd4..5347b79d3c2f 100644 --- a/core/lib/multivm/src/glue/mod.rs +++ b/core/lib/multivm/src/glue/mod.rs @@ -29,7 +29,7 @@ pub trait GlueInto: Sized { fn glue_into(self) -> T; } -// Blaknet `GlueInto` impl for any type that implements `GlueFrom`. +// Blanket `GlueInto` impl for any type that implements `GlueFrom`. impl GlueInto for T where U: GlueFrom, diff --git a/core/lib/multivm/src/glue/tracers/mod.rs b/core/lib/multivm/src/glue/tracers/mod.rs index c58e717a646a..3ca26892113c 100644 --- a/core/lib/multivm/src/glue/tracers/mod.rs +++ b/core/lib/multivm/src/glue/tracers/mod.rs @@ -32,12 +32,16 @@ use zksync_state::WriteStorage; -use crate::HistoryMode; +use crate::{tracers::old_tracers::OldTracers, HistoryMode}; pub type MultiVmTracerPointer = Box>; pub trait MultiVMTracer: - IntoLatestTracer + IntoVmVirtualBlocksTracer + IntoVmRefundsEnhancementTracer + IntoLatestTracer + + IntoVmVirtualBlocksTracer + + IntoVmRefundsEnhancementTracer + + IntoVmBoojumIntegrationTracer + + IntoOldVmTracer { fn into_tracer_pointer(self) -> MultiVmTracerPointer where @@ -48,7 +52,7 @@ pub trait MultiVMTracer: } pub trait IntoLatestTracer { - fn latest(&self) -> crate::vm_latest::TracerPointer; + fn latest(&self) -> crate::vm_latest::TracerPointer; } pub trait IntoVmVirtualBlocksTracer { @@ -63,13 +67,31 @@ pub trait IntoVmRefundsEnhancementTracer { ) -> Box>; } +pub trait IntoVmBoojumIntegrationTracer { + fn vm_boojum_integration( + &self, + ) -> Box>; +} + +/// Into tracers for old VM versions. +/// Even though number of tracers is limited, we still need to have this trait to be able to convert +/// tracers to old VM tracers. +/// Unfortunately we can't implement this trait for `T`, because specialization is not stable yet. +/// You can follow the conversation here: https://github.com/rust-lang/rust/issues/31844 +/// For all new tracers we need to implement this trait manually. +pub trait IntoOldVmTracer { + fn old_tracer(&self) -> OldTracers { + OldTracers::None + } +} + impl IntoLatestTracer for T where S: WriteStorage, H: HistoryMode, - T: crate::vm_latest::VmTracer + Clone + 'static, + T: crate::vm_latest::VmTracer + Clone + 'static, { - fn latest(&self) -> crate::vm_latest::TracerPointer { + fn latest(&self) -> crate::vm_latest::TracerPointer { Box::new(self.clone()) } } @@ -103,12 +125,27 @@ where } } +impl IntoVmBoojumIntegrationTracer for T +where + S: WriteStorage, + H: HistoryMode, + T: crate::vm_boojum_integration::VmTracer + Clone + 'static, +{ + fn vm_boojum_integration( + &self, + ) -> Box> { + Box::new(self.clone()) + } +} + impl MultiVMTracer for T where S: WriteStorage, H: HistoryMode, T: IntoLatestTracer + IntoVmVirtualBlocksTracer - + IntoVmRefundsEnhancementTracer, + + IntoVmRefundsEnhancementTracer + + IntoVmBoojumIntegrationTracer + + IntoOldVmTracer, { } diff --git a/core/lib/multivm/src/glue/types/mod.rs b/core/lib/multivm/src/glue/types/mod.rs index c72aff347577..481abfdf85f1 100644 --- a/core/lib/multivm/src/glue/types/mod.rs +++ b/core/lib/multivm/src/glue/types/mod.rs @@ -7,3 +7,6 @@ mod vm; mod zk_evm_1_3_1; +mod zk_evm_1_3_3; +mod zk_evm_1_4_0; +mod zk_evm_1_4_1; diff --git a/core/lib/multivm/src/glue/types/vm/block_context_mode.rs b/core/lib/multivm/src/glue/types/vm/block_context_mode.rs index 0cbbcbf33e3a..094339705e14 100644 --- a/core/lib/multivm/src/glue/types/vm/block_context_mode.rs +++ b/core/lib/multivm/src/glue/types/vm/block_context_mode.rs @@ -4,15 +4,16 @@ use crate::glue::GlueFrom; impl GlueFrom for crate::vm_m5::vm_with_bootloader::BlockContextMode { fn glue_from(value: crate::interface::L1BatchEnv) -> Self { + let fee_input = value.fee_input.into_l1_pegged(); let derived = crate::vm_m5::vm_with_bootloader::DerivedBlockContext { context: crate::vm_m5::vm_with_bootloader::BlockContext { block_number: value.number.0, block_timestamp: value.timestamp, operator_address: value.fee_account, - l1_gas_price: value.l1_gas_price, - fair_l2_gas_price: value.fair_l2_gas_price, + l1_gas_price: fee_input.l1_gas_price, + fair_l2_gas_price: fee_input.fair_l2_gas_price, }, - base_fee: value.base_fee(), + base_fee: crate::vm_m5::vm_with_bootloader::get_batch_base_fee(&value), }; match value.previous_batch_hash { Some(hash) => Self::NewBlock(derived, h256_to_u256(hash)), @@ -23,15 +24,16 @@ impl GlueFrom for crate::vm_m5::vm_with_bootloader impl GlueFrom for crate::vm_m6::vm_with_bootloader::BlockContextMode { fn glue_from(value: crate::interface::L1BatchEnv) -> Self { + let fee_input = value.fee_input.into_l1_pegged(); let derived = crate::vm_m6::vm_with_bootloader::DerivedBlockContext { context: crate::vm_m6::vm_with_bootloader::BlockContext { block_number: value.number.0, block_timestamp: value.timestamp, operator_address: value.fee_account, - l1_gas_price: value.l1_gas_price, - fair_l2_gas_price: value.fair_l2_gas_price, + l1_gas_price: fee_input.l1_gas_price, + fair_l2_gas_price: fee_input.fair_l2_gas_price, }, - base_fee: value.base_fee(), + base_fee: crate::vm_m6::vm_with_bootloader::get_batch_base_fee(&value), }; match value.previous_batch_hash { Some(hash) => Self::NewBlock(derived, h256_to_u256(hash)), @@ -44,15 +46,16 @@ impl GlueFrom for crate::vm_1_3_2::vm_with_bootloader::BlockContextMode { fn glue_from(value: crate::interface::L1BatchEnv) -> Self { + let fee_input = value.fee_input.into_l1_pegged(); let derived = crate::vm_1_3_2::vm_with_bootloader::DerivedBlockContext { context: crate::vm_1_3_2::vm_with_bootloader::BlockContext { block_number: value.number.0, block_timestamp: value.timestamp, operator_address: value.fee_account, - l1_gas_price: value.l1_gas_price, - fair_l2_gas_price: value.fair_l2_gas_price, + l1_gas_price: fee_input.l1_gas_price, + fair_l2_gas_price: fee_input.fair_l2_gas_price, }, - base_fee: value.base_fee(), + base_fee: crate::vm_1_3_2::vm_with_bootloader::get_batch_base_fee(&value), }; match value.previous_batch_hash { Some(hash) => Self::NewBlock(derived, h256_to_u256(hash)), diff --git a/core/lib/multivm/src/glue/types/vm/mod.rs b/core/lib/multivm/src/glue/types/vm/mod.rs index aa3db7f2fc5b..47cddc2b8dd4 100644 --- a/core/lib/multivm/src/glue/types/vm/mod.rs +++ b/core/lib/multivm/src/glue/types/vm/mod.rs @@ -1,4 +1,5 @@ mod block_context_mode; +mod storage_query; mod tx_execution_mode; mod tx_revert_reason; mod vm_block_result; diff --git a/core/lib/multivm/src/glue/types/vm/storage_query.rs b/core/lib/multivm/src/glue/types/vm/storage_query.rs new file mode 100644 index 000000000000..21a10947e09b --- /dev/null +++ b/core/lib/multivm/src/glue/types/vm/storage_query.rs @@ -0,0 +1,66 @@ +use zksync_types::StorageLogQuery; + +use crate::glue::{GlueFrom, GlueInto}; + +impl GlueFrom for StorageLogQuery { + fn glue_from(value: crate::vm_m5::utils::StorageLogQuery) -> Self { + Self { + log_query: value.log_query.glue_into(), + log_type: value.log_type, + } + } +} + +impl GlueFrom for StorageLogQuery { + fn glue_from(value: crate::vm_m6::utils::StorageLogQuery) -> Self { + Self { + log_query: value.log_query.glue_into(), + log_type: value.log_type, + } + } +} + +impl GlueFrom for StorageLogQuery { + fn glue_from(value: crate::vm_1_3_2::utils::StorageLogQuery) -> Self { + Self { + log_query: value.log_query.glue_into(), + log_type: value.log_type, + } + } +} + +impl GlueFrom for StorageLogQuery { + fn glue_from(value: crate::vm_virtual_blocks::utils::logs::StorageLogQuery) -> Self { + Self { + log_query: value.log_query.glue_into(), + log_type: value.log_type, + } + } +} + +impl GlueFrom for StorageLogQuery { + fn glue_from(value: crate::vm_refunds_enhancement::utils::logs::StorageLogQuery) -> Self { + Self { + log_query: value.log_query.glue_into(), + log_type: value.log_type, + } + } +} + +impl GlueFrom for StorageLogQuery { + fn glue_from(value: crate::vm_boojum_integration::utils::logs::StorageLogQuery) -> Self { + Self { + log_query: value.log_query.glue_into(), + log_type: value.log_type, + } + } +} + +impl GlueFrom for StorageLogQuery { + fn glue_from(value: crate::vm_latest::utils::logs::StorageLogQuery) -> Self { + Self { + log_query: value.log_query.glue_into(), + log_type: value.log_type, + } + } +} diff --git a/core/lib/multivm/src/glue/types/vm/tx_execution_mode.rs b/core/lib/multivm/src/glue/types/vm/tx_execution_mode.rs index 1dd90e104a5a..0709b13de782 100644 --- a/core/lib/multivm/src/glue/types/vm/tx_execution_mode.rs +++ b/core/lib/multivm/src/glue/types/vm/tx_execution_mode.rs @@ -19,12 +19,12 @@ impl GlueFrom match value { crate::interface::TxExecutionMode::VerifyExecute => Self::VerifyExecute, crate::interface::TxExecutionMode::EstimateFee => Self::EstimateFee { - // We used it only for api services we don't have limit for storage invocation inside statekeeper + // We used it only for API services we don't have limit for storage invocation inside statekeeper // It's impossible to recover this value for the vm integration after virtual blocks missed_storage_invocation_limit: usize::MAX, }, crate::interface::TxExecutionMode::EthCall => Self::EthCall { - // We used it only for api services we don't have limit for storage invocation inside statekeeper + // We used it only for API services we don't have limit for storage invocation inside statekeeper // It's impossible to recover this value for the vm integration after virtual blocks missed_storage_invocation_limit: usize::MAX, }, @@ -39,12 +39,12 @@ impl GlueFrom match value { crate::interface::TxExecutionMode::VerifyExecute => Self::VerifyExecute, crate::interface::TxExecutionMode::EstimateFee => Self::EstimateFee { - // We used it only for api services we don't have limit for storage invocation inside statekeeper + // We used it only for API services we don't have limit for storage invocation inside statekeeper // It's impossible to recover this value for the vm integration after virtual blocks missed_storage_invocation_limit: usize::MAX, }, crate::interface::TxExecutionMode::EthCall => Self::EthCall { - // We used it only for api services we don't have limit for storage invocation inside statekeeper + // We used it only for API services we don't have limit for storage invocation inside statekeeper // It's impossible to recover this value for the vm integration after virtual blocks missed_storage_invocation_limit: usize::MAX, }, diff --git a/core/lib/multivm/src/glue/types/vm/vm_block_result.rs b/core/lib/multivm/src/glue/types/vm/vm_block_result.rs index 623d3d735d19..9867c0c95b94 100644 --- a/core/lib/multivm/src/glue/types/vm/vm_block_result.rs +++ b/core/lib/multivm/src/glue/types/vm/vm_block_result.rs @@ -1,3 +1,6 @@ +use itertools::Itertools; +use zk_evm_1_3_1::aux_structures::LogQuery as LogQuery_1_3_1; +use zkevm_test_harness_1_3_3::witness::sort_storage_access::sort_storage_access_queries as sort_storage_access_queries_1_3_3; use zksync_types::l2_to_l1_log::UserL2ToL1Log; use crate::{ @@ -8,13 +11,28 @@ use crate::{ }, }; -// Note: In version after vm VmVirtualBlocks the bootloader memory knowledge is encapsulated into the VM. +// Note: In version after vm `VmVirtualBlocks` the bootloader memory knowledge is encapsulated into the VM. // But before it was a part of a public API. // Bootloader memory required only for producing witnesses, // and server doesn't need to generate witnesses for old blocks impl GlueFrom for crate::interface::FinishedL1Batch { fn glue_from(value: crate::vm_m5::vm_instance::VmBlockResult) -> Self { + let storage_log_queries = value.full_result.storage_log_queries.clone(); + let deduplicated_storage_log_queries: Vec = + sort_storage_access_queries_1_3_3( + &storage_log_queries + .iter() + .map(|log| { + GlueInto::::glue_into(log.log_query) + }) + .collect_vec(), + ) + .1 + .into_iter() + .map(GlueInto::::glue_into) + .collect(); + crate::interface::FinishedL1Batch { block_tip_execution_result: VmExecutionResultAndLogs { result: value.block_tip_result.revert_reason.glue_into(), @@ -26,12 +44,20 @@ impl GlueFrom for crate::interface::Fi computational_gas_used: value.full_result.gas_used, gas_used: value.full_result.gas_used, pubdata_published: 0, + circuit_statistic: Default::default(), }, refunds: Refunds::default(), }, final_execution_state: CurrentExecutionState { events: value.full_result.events, - storage_log_queries: value.full_result.storage_log_queries, + storage_log_queries: storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), + deduplicated_storage_log_queries: deduplicated_storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), used_contract_hashes: value.full_result.used_contract_hashes, user_l2_to_l1_logs: value .full_result @@ -53,6 +79,21 @@ impl GlueFrom for crate::interface::Fi impl GlueFrom for crate::interface::FinishedL1Batch { fn glue_from(value: crate::vm_m6::vm_instance::VmBlockResult) -> Self { + let storage_log_queries = value.full_result.storage_log_queries.clone(); + let deduplicated_storage_log_queries: Vec = + sort_storage_access_queries_1_3_3( + &storage_log_queries + .iter() + .map(|log| { + GlueInto::::glue_into(log.log_query) + }) + .collect_vec(), + ) + .1 + .into_iter() + .map(GlueInto::::glue_into) + .collect(); + crate::interface::FinishedL1Batch { block_tip_execution_result: VmExecutionResultAndLogs { result: value.block_tip_result.revert_reason.glue_into(), @@ -64,12 +105,20 @@ impl GlueFrom for crate::interface::Fi computational_gas_used: value.full_result.computational_gas_used, gas_used: value.full_result.gas_used, pubdata_published: 0, + circuit_statistic: Default::default(), }, refunds: Refunds::default(), }, final_execution_state: CurrentExecutionState { events: value.full_result.events, - storage_log_queries: value.full_result.storage_log_queries, + storage_log_queries: storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), + deduplicated_storage_log_queries: deduplicated_storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), used_contract_hashes: value.full_result.used_contract_hashes, user_l2_to_l1_logs: value .full_result @@ -91,6 +140,13 @@ impl GlueFrom for crate::interface::Fi impl GlueFrom for crate::interface::FinishedL1Batch { fn glue_from(value: crate::vm_1_3_2::vm_instance::VmBlockResult) -> Self { + let storage_log_queries = value.full_result.storage_log_queries.clone(); + let deduplicated_storage_log_queries = + zkevm_test_harness_1_3_3::witness::sort_storage_access::sort_storage_access_queries( + storage_log_queries.iter().map(|log| &log.log_query), + ) + .1; + crate::interface::FinishedL1Batch { block_tip_execution_result: VmExecutionResultAndLogs { result: value.block_tip_result.revert_reason.glue_into(), @@ -108,12 +164,20 @@ impl GlueFrom for crate::interface: computational_gas_used: value.full_result.computational_gas_used, gas_used: value.full_result.gas_used, pubdata_published: 0, + circuit_statistic: Default::default(), }, refunds: Refunds::default(), }, final_execution_state: CurrentExecutionState { events: value.full_result.events, - storage_log_queries: value.full_result.storage_log_queries, + storage_log_queries: storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), + deduplicated_storage_log_queries: deduplicated_storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), used_contract_hashes: value.full_result.used_contract_hashes, user_l2_to_l1_logs: value .full_result @@ -158,7 +222,12 @@ impl GlueFrom .map(UserL2ToL1Log) .collect(), system_l2_to_l1_logs: vec![], - storage_logs: value.full_result.storage_log_queries, + storage_logs: value + .full_result + .storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), total_log_queries_count: value.full_result.total_log_queries, }, statistics: VmExecutionStatistics { @@ -168,6 +237,7 @@ impl GlueFrom computational_gas_used: value.full_result.computational_gas_used, gas_used: value.full_result.gas_used, pubdata_published: 0, + circuit_statistic: Default::default(), }, refunds: Refunds::default(), } @@ -198,6 +268,7 @@ impl GlueFrom computational_gas_used: 0, gas_used: value.full_result.gas_used, pubdata_published: 0, + circuit_statistic: Default::default(), }, refunds: Refunds::default(), } @@ -229,7 +300,12 @@ impl GlueFrom .map(UserL2ToL1Log) .collect(), system_l2_to_l1_logs: vec![], - storage_logs: value.full_result.storage_log_queries, + storage_logs: value + .full_result + .storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), total_log_queries_count: value.full_result.total_log_queries, }, statistics: VmExecutionStatistics { @@ -239,6 +315,7 @@ impl GlueFrom computational_gas_used: value.full_result.computational_gas_used, gas_used: value.full_result.gas_used, pubdata_published: 0, + circuit_statistic: Default::default(), }, refunds: Refunds::default(), } diff --git a/core/lib/multivm/src/glue/types/vm/vm_partial_execution_result.rs b/core/lib/multivm/src/glue/types/vm/vm_partial_execution_result.rs index 4de727a04c10..932b7616521f 100644 --- a/core/lib/multivm/src/glue/types/vm/vm_partial_execution_result.rs +++ b/core/lib/multivm/src/glue/types/vm/vm_partial_execution_result.rs @@ -11,11 +11,12 @@ impl GlueFrom contracts_used: value.contracts_used, cycles_used: value.cycles_used, total_log_queries: value.logs.total_log_queries_count, - // There are no such fields in m5 + // There are no such fields in `m5` gas_used: 0, - // There are no such fields in m5 + // There are no such fields in `m5` computational_gas_used: 0, pubdata_published: 0, + circuit_statistic: Default::default(), }, refunds: crate::interface::Refunds { gas_refunded: 0, @@ -39,6 +40,7 @@ impl GlueFrom computational_gas_used: value.computational_gas_used, total_log_queries: value.logs.total_log_queries_count, pubdata_published: 0, + circuit_statistic: Default::default(), }, refunds: crate::interface::Refunds { gas_refunded: 0, @@ -62,6 +64,7 @@ impl GlueFrom computational_gas_used: value.computational_gas_used, total_log_queries: value.logs.total_log_queries_count, pubdata_published: 0, + circuit_statistic: Default::default(), }, refunds: crate::interface::Refunds { gas_refunded: 0, diff --git a/core/lib/multivm/src/glue/types/zk_evm_1_3_1.rs b/core/lib/multivm/src/glue/types/zk_evm_1_3_1.rs index f7c1f1c359c7..dfe1121c04ec 100644 --- a/core/lib/multivm/src/glue/types/zk_evm_1_3_1.rs +++ b/core/lib/multivm/src/glue/types/zk_evm_1_3_1.rs @@ -1,14 +1,16 @@ +use zksync_utils::u256_to_h256; + use crate::glue::{GlueFrom, GlueInto}; -impl GlueFrom for zksync_types::Timestamp { +impl GlueFrom for zksync_types::zk_evm_types::Timestamp { fn glue_from(timestamp: zk_evm_1_3_1::aux_structures::Timestamp) -> Self { - zksync_types::Timestamp(timestamp.0) + zksync_types::zk_evm_types::Timestamp(timestamp.0) } } -impl GlueFrom for zksync_types::LogQuery { +impl GlueFrom for zksync_types::zk_evm_types::LogQuery { fn glue_from(query: zk_evm_1_3_1::aux_structures::LogQuery) -> Self { - zksync_types::LogQuery { + zksync_types::zk_evm_types::LogQuery { address: query.address, key: query.key, written_value: query.written_value, @@ -24,14 +26,14 @@ impl GlueFrom for zksync_types::LogQuery } } -impl GlueFrom for zk_evm_1_3_1::aux_structures::Timestamp { - fn glue_from(timestamp: zksync_types::Timestamp) -> Self { +impl GlueFrom for zk_evm_1_3_1::aux_structures::Timestamp { + fn glue_from(timestamp: zksync_types::zk_evm_types::Timestamp) -> Self { zk_evm_1_3_1::aux_structures::Timestamp(timestamp.0) } } -impl GlueFrom for zk_evm_1_3_1::aux_structures::LogQuery { - fn glue_from(query: zksync_types::LogQuery) -> Self { +impl GlueFrom for zk_evm_1_3_1::aux_structures::LogQuery { + fn glue_from(query: zksync_types::zk_evm_types::LogQuery) -> Self { zk_evm_1_3_1::aux_structures::LogQuery { address: query.address, key: query.key, @@ -48,22 +50,9 @@ impl GlueFrom for zk_evm_1_3_1::aux_structures::LogQuery } } -impl GlueFrom - for zksync_types::EventMessage +impl GlueFrom + for zksync_types::zk_evm_types::FarCallOpcode { - fn glue_from(event: zk_evm_1_3_1::reference_impls::event_sink::EventMessage) -> Self { - zksync_types::EventMessage { - shard_id: event.shard_id, - is_first: event.is_first, - tx_number_in_block: event.tx_number_in_block, - address: event.address, - key: event.key, - value: event.value, - } - } -} - -impl GlueFrom for zksync_types::FarCallOpcode { fn glue_from(value: zk_evm_1_3_1::zkevm_opcode_defs::FarCallOpcode) -> Self { match value { zk_evm_1_3_1::zkevm_opcode_defs::FarCallOpcode::Normal => Self::Normal, @@ -73,12 +62,79 @@ impl GlueFrom for zksync_types:: } } -impl GlueFrom for zk_evm_1_3_1::zkevm_opcode_defs::FarCallOpcode { - fn glue_from(value: zksync_types::FarCallOpcode) -> Self { +impl GlueFrom + for zk_evm_1_3_1::zkevm_opcode_defs::FarCallOpcode +{ + fn glue_from(value: zksync_types::zk_evm_types::FarCallOpcode) -> Self { match value { - zksync_types::FarCallOpcode::Normal => Self::Normal, - zksync_types::FarCallOpcode::Delegate => Self::Delegate, - zksync_types::FarCallOpcode::Mimic => Self::Mimic, + zksync_types::zk_evm_types::FarCallOpcode::Normal => Self::Normal, + zksync_types::zk_evm_types::FarCallOpcode::Delegate => Self::Delegate, + zksync_types::zk_evm_types::FarCallOpcode::Mimic => Self::Mimic, + } + } +} + +// Special for `zk_evm_1_3_1`: it re-used the same sorting function from `zkevm_test_harness` as the `v1.3.3` used. +// To continue calling this functions, we need to add the conversion for `Timestamp` and `LogQuery`. +impl GlueFrom for zk_evm_1_3_3::aux_structures::Timestamp { + fn glue_from(timestamp: zk_evm_1_3_1::aux_structures::Timestamp) -> Self { + zk_evm_1_3_3::aux_structures::Timestamp(timestamp.0) + } +} + +impl GlueFrom for zk_evm_1_3_3::aux_structures::LogQuery { + fn glue_from(query: zk_evm_1_3_1::aux_structures::LogQuery) -> Self { + zk_evm_1_3_3::aux_structures::LogQuery { + address: query.address, + key: query.key, + written_value: query.written_value, + timestamp: query.timestamp.glue_into(), + shard_id: query.shard_id, + rollback: query.rollback, + tx_number_in_block: query.tx_number_in_block, + aux_byte: query.aux_byte, + read_value: query.read_value, + rw_flag: query.rw_flag, + is_service: query.is_service, + } + } +} + +impl GlueFrom for zk_evm_1_3_1::aux_structures::Timestamp { + fn glue_from(timestamp: zk_evm_1_3_3::aux_structures::Timestamp) -> Self { + zk_evm_1_3_1::aux_structures::Timestamp(timestamp.0) + } +} + +impl GlueFrom for zk_evm_1_3_1::aux_structures::LogQuery { + fn glue_from(query: zk_evm_1_3_3::aux_structures::LogQuery) -> Self { + zk_evm_1_3_1::aux_structures::LogQuery { + address: query.address, + key: query.key, + written_value: query.written_value, + timestamp: query.timestamp.glue_into(), + shard_id: query.shard_id, + rollback: query.rollback, + tx_number_in_block: query.tx_number_in_block, + aux_byte: query.aux_byte, + read_value: query.read_value, + rw_flag: query.rw_flag, + is_service: query.is_service, + } + } +} + +impl GlueFrom + for zksync_types::l2_to_l1_log::L2ToL1Log +{ + fn glue_from(event: zk_evm_1_3_1::reference_impls::event_sink::EventMessage) -> Self { + Self { + shard_id: event.shard_id, + is_service: event.is_first, + tx_number_in_block: event.tx_number_in_block, + sender: event.address, + key: u256_to_h256(event.key), + value: u256_to_h256(event.value), } } } diff --git a/core/lib/multivm/src/glue/types/zk_evm_1_3_3.rs b/core/lib/multivm/src/glue/types/zk_evm_1_3_3.rs new file mode 100644 index 000000000000..4c554c1bd53d --- /dev/null +++ b/core/lib/multivm/src/glue/types/zk_evm_1_3_3.rs @@ -0,0 +1,93 @@ +use zk_evm_1_3_3::{ + aux_structures::{LogQuery as LogQuery_1_3_3, Timestamp as Timestamp_1_3_3}, + zkevm_opcode_defs::FarCallOpcode as FarCallOpcode_1_3_3, +}; +use zksync_types::zk_evm_types::{FarCallOpcode, LogQuery, Timestamp}; +use zksync_utils::u256_to_h256; + +use crate::glue::{GlueFrom, GlueInto}; + +impl GlueFrom for FarCallOpcode { + fn glue_from(value: FarCallOpcode_1_3_3) -> Self { + match value { + FarCallOpcode_1_3_3::Normal => FarCallOpcode::Normal, + FarCallOpcode_1_3_3::Delegate => FarCallOpcode::Delegate, + FarCallOpcode_1_3_3::Mimic => FarCallOpcode::Mimic, + } + } +} + +impl GlueFrom + for zk_evm_1_3_3::zkevm_opcode_defs::FarCallOpcode +{ + fn glue_from(value: zksync_types::zk_evm_types::FarCallOpcode) -> Self { + match value { + zksync_types::zk_evm_types::FarCallOpcode::Normal => Self::Normal, + zksync_types::zk_evm_types::FarCallOpcode::Delegate => Self::Delegate, + zksync_types::zk_evm_types::FarCallOpcode::Mimic => Self::Mimic, + } + } +} + +impl GlueFrom for Timestamp { + fn glue_from(value: Timestamp_1_3_3) -> Timestamp { + Timestamp(value.0) + } +} + +impl GlueFrom for Timestamp_1_3_3 { + fn glue_from(value: Timestamp) -> Timestamp_1_3_3 { + Timestamp_1_3_3(value.0) + } +} + +impl GlueFrom for LogQuery { + fn glue_from(value: LogQuery_1_3_3) -> LogQuery { + LogQuery { + timestamp: value.timestamp.glue_into(), + tx_number_in_block: value.tx_number_in_block, + aux_byte: value.aux_byte, + shard_id: value.shard_id, + address: value.address, + key: value.key, + read_value: value.read_value, + written_value: value.written_value, + rw_flag: value.rw_flag, + rollback: value.rollback, + is_service: value.is_service, + } + } +} + +impl GlueFrom for LogQuery_1_3_3 { + fn glue_from(value: LogQuery) -> LogQuery_1_3_3 { + LogQuery_1_3_3 { + timestamp: value.timestamp.glue_into(), + tx_number_in_block: value.tx_number_in_block, + aux_byte: value.aux_byte, + shard_id: value.shard_id, + address: value.address, + key: value.key, + read_value: value.read_value, + written_value: value.written_value, + rw_flag: value.rw_flag, + rollback: value.rollback, + is_service: value.is_service, + } + } +} + +impl GlueFrom + for zksync_types::l2_to_l1_log::L2ToL1Log +{ + fn glue_from(event: zk_evm_1_3_3::reference_impls::event_sink::EventMessage) -> Self { + Self { + shard_id: event.shard_id, + is_service: event.is_first, + tx_number_in_block: event.tx_number_in_block, + sender: event.address, + key: u256_to_h256(event.key), + value: u256_to_h256(event.value), + } + } +} diff --git a/core/lib/multivm/src/glue/types/zk_evm_1_4_0.rs b/core/lib/multivm/src/glue/types/zk_evm_1_4_0.rs new file mode 100644 index 000000000000..5af0e57c4bf9 --- /dev/null +++ b/core/lib/multivm/src/glue/types/zk_evm_1_4_0.rs @@ -0,0 +1,20 @@ +use zksync_utils::u256_to_h256; + +use crate::glue::GlueFrom; + +// Most of the types between `zk_evm@1.4.0` and `zk_evm@1.3.3` are shared and so we need only the additional conversion +// for `EventMessage` only. +impl GlueFrom + for zksync_types::l2_to_l1_log::L2ToL1Log +{ + fn glue_from(event: zk_evm_1_4_0::reference_impls::event_sink::EventMessage) -> Self { + Self { + shard_id: event.shard_id, + is_service: event.is_first, + tx_number_in_block: event.tx_number_in_block, + sender: event.address, + key: u256_to_h256(event.key), + value: u256_to_h256(event.value), + } + } +} diff --git a/core/lib/multivm/src/glue/types/zk_evm_1_4_1.rs b/core/lib/multivm/src/glue/types/zk_evm_1_4_1.rs new file mode 100644 index 000000000000..933eafbb0354 --- /dev/null +++ b/core/lib/multivm/src/glue/types/zk_evm_1_4_1.rs @@ -0,0 +1,81 @@ +use zk_evm_1_4_1::{ + aux_structures::{LogQuery as LogQuery_1_4_1, Timestamp as Timestamp_1_4_1}, + zkevm_opcode_defs::FarCallOpcode as FarCallOpcode_1_4_1, +}; +use zksync_types::zk_evm_types::{FarCallOpcode, LogQuery, Timestamp}; +use zksync_utils::u256_to_h256; + +use crate::glue::{GlueFrom, GlueInto}; + +impl GlueFrom for FarCallOpcode { + fn glue_from(value: FarCallOpcode_1_4_1) -> Self { + match value { + FarCallOpcode_1_4_1::Normal => FarCallOpcode::Normal, + FarCallOpcode_1_4_1::Delegate => FarCallOpcode::Delegate, + FarCallOpcode_1_4_1::Mimic => FarCallOpcode::Mimic, + } + } +} + +impl GlueFrom for Timestamp { + fn glue_from(value: Timestamp_1_4_1) -> Timestamp { + Timestamp(value.0) + } +} + +impl GlueFrom for Timestamp_1_4_1 { + fn glue_from(value: Timestamp) -> Timestamp_1_4_1 { + Timestamp_1_4_1(value.0) + } +} + +impl GlueFrom for LogQuery { + fn glue_from(value: LogQuery_1_4_1) -> LogQuery { + LogQuery { + timestamp: value.timestamp.glue_into(), + tx_number_in_block: value.tx_number_in_block, + aux_byte: value.aux_byte, + shard_id: value.shard_id, + address: value.address, + key: value.key, + read_value: value.read_value, + written_value: value.written_value, + rw_flag: value.rw_flag, + rollback: value.rollback, + is_service: value.is_service, + } + } +} + +impl GlueFrom for LogQuery_1_4_1 { + fn glue_from(value: LogQuery) -> LogQuery_1_4_1 { + LogQuery_1_4_1 { + timestamp: value.timestamp.glue_into(), + tx_number_in_block: value.tx_number_in_block, + aux_byte: value.aux_byte, + shard_id: value.shard_id, + address: value.address, + key: value.key, + read_value: value.read_value, + written_value: value.written_value, + rw_flag: value.rw_flag, + rollback: value.rollback, + is_service: value.is_service, + } + } +} + +impl GlueFrom + for zksync_types::l2_to_l1_log::L2ToL1Log +{ + fn glue_from(event: zk_evm_1_4_1::reference_impls::event_sink::EventMessage) -> Self { + Self { + shard_id: event.shard_id, + is_service: event.is_first, + tx_number_in_block: event.tx_number_in_block, + sender: event.address, + key: u256_to_h256(event.key), + value: u256_to_h256(event.value), + } + } +} diff --git a/core/lib/multivm/src/interface/traits/tracers/dyn_tracers/mod.rs b/core/lib/multivm/src/interface/traits/tracers/dyn_tracers/mod.rs index bc34775e6133..8a0fbbe93cdc 100644 --- a/core/lib/multivm/src/interface/traits/tracers/dyn_tracers/mod.rs +++ b/core/lib/multivm/src/interface/traits/tracers/dyn_tracers/mod.rs @@ -1,2 +1,3 @@ pub mod vm_1_3_3; pub mod vm_1_4_0; +pub mod vm_1_4_1; diff --git a/core/lib/multivm/src/interface/traits/tracers/dyn_tracers/vm_1_4_0.rs b/core/lib/multivm/src/interface/traits/tracers/dyn_tracers/vm_1_4_0.rs index 3ce69d02942b..7237e24cb681 100644 --- a/core/lib/multivm/src/interface/traits/tracers/dyn_tracers/vm_1_4_0.rs +++ b/core/lib/multivm/src/interface/traits/tracers/dyn_tracers/vm_1_4_0.rs @@ -4,7 +4,7 @@ use zk_evm_1_4_0::{ }; use zksync_state::StoragePtr; -/// Version of zk_evm_1_3_3::Tracer suitable for dynamic dispatch. +/// Version of `zk_evm_1_4_0::Tracer` suitable for dynamic dispatch. pub trait DynTracer { fn before_decoding(&mut self, _state: VmLocalStateData<'_>, _memory: &M) {} fn after_decoding( diff --git a/core/lib/multivm/src/interface/traits/tracers/dyn_tracers/vm_1_4_1.rs b/core/lib/multivm/src/interface/traits/tracers/dyn_tracers/vm_1_4_1.rs new file mode 100644 index 000000000000..4772d14cd20f --- /dev/null +++ b/core/lib/multivm/src/interface/traits/tracers/dyn_tracers/vm_1_4_1.rs @@ -0,0 +1,33 @@ +use zk_evm_1_4_1::{ + abstractions::Memory, + tracing::{AfterDecodingData, AfterExecutionData, BeforeExecutionData, VmLocalStateData}, +}; +use zksync_state::StoragePtr; + +/// Version of `zk_evm_1_4_1::Tracer` suitable for dynamic dispatch. +pub trait DynTracer { + fn before_decoding(&mut self, _state: VmLocalStateData<'_>, _memory: &M) {} + fn after_decoding( + &mut self, + _state: VmLocalStateData<'_>, + _data: AfterDecodingData, + _memory: &M, + ) { + } + fn before_execution( + &mut self, + _state: VmLocalStateData<'_>, + _data: BeforeExecutionData, + _memory: &M, + _storage: StoragePtr, + ) { + } + fn after_execution( + &mut self, + _state: VmLocalStateData<'_>, + _data: AfterExecutionData, + _memory: &M, + _storage: StoragePtr, + ) { + } +} diff --git a/core/lib/multivm/src/interface/traits/vm.rs b/core/lib/multivm/src/interface/traits/vm.rs index cfee13d2031b..dd31c00e98f3 100644 --- a/core/lib/multivm/src/interface/traits/vm.rs +++ b/core/lib/multivm/src/interface/traits/vm.rs @@ -104,7 +104,10 @@ pub trait VmInterface { &mut self, tx: Transaction, with_compression: bool, - ) -> Result { + ) -> ( + Result<(), BytecodeCompressionError>, + VmExecutionResultAndLogs, + ) { self.inspect_transaction_with_bytecode_compression( Self::TracerDispatcher::default(), tx, @@ -118,11 +121,17 @@ pub trait VmInterface { tracer: Self::TracerDispatcher, tx: Transaction, with_compression: bool, - ) -> Result; + ) -> ( + Result<(), BytecodeCompressionError>, + VmExecutionResultAndLogs, + ); /// Record VM memory metrics. fn record_vm_memory_metrics(&self) -> VmMemoryMetrics; + /// Whether the VM still has enough gas to execute the batch tip + fn has_enough_gas_for_batch_tip(&self) -> bool; + /// Execute batch till the end and return the result, with final execution state /// and bootloader memory. fn finish_batch(&mut self) -> FinishedL1Batch { diff --git a/core/lib/multivm/src/interface/types/errors/halt.rs b/core/lib/multivm/src/interface/types/errors/halt.rs index 3323a128c682..70de7548f14e 100644 --- a/core/lib/multivm/src/interface/types/errors/halt.rs +++ b/core/lib/multivm/src/interface/types/errors/halt.rs @@ -7,7 +7,7 @@ use super::VmRevertReason; /// Differentiates VM-specific issues from contract-related errors. #[derive(Debug, Clone, PartialEq)] pub enum Halt { - // Can only be returned in VerifyAndExecute + // Can only be returned in `VerifyAndExecute` ValidationFailed(VmRevertReason), PaymasterValidationFailed(VmRevertReason), PrePaymasterPreparationFailed(VmRevertReason), @@ -16,7 +16,7 @@ pub enum Halt { FailedToChargeFee(VmRevertReason), // Emitted when trying to call a transaction from an account that has not // been deployed as an account (i.e. the `from` is just a contract). - // Can only be returned in VerifyAndExecute + // Can only be returned in `VerifyAndExecute` FromIsNotAnAccount, // Currently cannot be returned. Should be removed when refactoring errors. InnerTxError, @@ -41,6 +41,7 @@ pub enum Halt { FailedToAppendTransactionToL2Block(String), VMPanic, TracerCustom(String), + FailedToPublishCompressedBytecodes, } impl Display for Halt { @@ -112,6 +113,9 @@ impl Display for Halt { Halt::ValidationOutOfGas => { write!(f, "Validation run out of gas") } + Halt::FailedToPublishCompressedBytecodes => { + write!(f, "Failed to publish compressed bytecodes") + } } } } diff --git a/core/lib/multivm/src/interface/types/errors/tx_revert_reason.rs b/core/lib/multivm/src/interface/types/errors/tx_revert_reason.rs index 9578a06ea0a5..d863e387e019 100644 --- a/core/lib/multivm/src/interface/types/errors/tx_revert_reason.rs +++ b/core/lib/multivm/src/interface/types/errors/tx_revert_reason.rs @@ -55,7 +55,7 @@ impl TxRevertReason { BootloaderErrorCode::UnacceptablePubdataPrice => { Self::Halt(Halt::UnexpectedVMBehavior("UnacceptablePubdataPrice".to_owned())) } - // This is different from AccountTxValidationFailed error in a way that it means that + // This is different from `AccountTxValidationFailed` error in a way that it means that // the error was not produced by the account itself, but for some other unknown reason (most likely not enough gas) BootloaderErrorCode::TxValidationError => Self::Halt(Halt::ValidationFailed(revert_reason)), // Note, that `InnerTxError` is derived only after the actual tx execution, so diff --git a/core/lib/multivm/src/interface/types/errors/vm_revert_reason.rs b/core/lib/multivm/src/interface/types/errors/vm_revert_reason.rs index 4a6457491264..25b394ce2582 100644 --- a/core/lib/multivm/src/interface/types/errors/vm_revert_reason.rs +++ b/core/lib/multivm/src/interface/types/errors/vm_revert_reason.rs @@ -68,7 +68,7 @@ impl VmRevertReason { pub fn to_user_friendly_string(&self) -> String { match self { - // In case of `Unknown` reason we suppress it to prevent verbose Error function_selector = 0x{} + // In case of `Unknown` reason we suppress it to prevent verbose `Error function_selector = 0x{}` // message shown to user. VmRevertReason::Unknown { .. } => "".to_owned(), _ => self.to_string(), diff --git a/core/lib/multivm/src/interface/types/inputs/l1_batch_env.rs b/core/lib/multivm/src/interface/types/inputs/l1_batch_env.rs index b5cb0cbe5e8f..1258e6b472f9 100644 --- a/core/lib/multivm/src/interface/types/inputs/l1_batch_env.rs +++ b/core/lib/multivm/src/interface/types/inputs/l1_batch_env.rs @@ -1,32 +1,22 @@ -use zksync_types::{Address, L1BatchNumber, H256}; +use zksync_types::{fee_model::BatchFeeInput, Address, L1BatchNumber, H256}; use super::L2BlockEnv; -use crate::vm_latest::utils::fee::derive_base_fee_and_gas_per_pubdata; -/// Unique params for each block +/// Unique params for each L1 batch. +/// +/// Eventually, most of these parameters (`l1_gas_price`, `fair_l2_gas_price`, `fee_account`, +/// `enforced_base_fee`) will be moved to [`L2BlockEnv`]. For now, the VM doesn't support changing +/// them in the middle of execution; that's why these params are specified here. #[derive(Debug, Clone)] pub struct L1BatchEnv { // If previous batch hash is None, then this is the first batch pub previous_batch_hash: Option, pub number: L1BatchNumber, pub timestamp: u64, - pub l1_gas_price: u64, - pub fair_l2_gas_price: u64, + + /// The fee input into the batch. It contains information such as L1 gas price, L2 fair gas price, etc. + pub fee_input: BatchFeeInput, pub fee_account: Address, pub enforced_base_fee: Option, pub first_l2_block: L2BlockEnv, } - -impl L1BatchEnv { - pub fn base_fee(&self) -> u64 { - if let Some(base_fee) = self.enforced_base_fee { - return base_fee; - } - let (base_fee, _) = - derive_base_fee_and_gas_per_pubdata(self.l1_gas_price, self.fair_l2_gas_price); - base_fee - } - pub(crate) fn block_gas_price_per_pubdata(&self) -> u64 { - derive_base_fee_and_gas_per_pubdata(self.l1_gas_price, self.fair_l2_gas_price).1 - } -} diff --git a/core/lib/multivm/src/interface/types/outputs/execution_result.rs b/core/lib/multivm/src/interface/types/outputs/execution_result.rs index e177b6300120..a3c201e79706 100644 --- a/core/lib/multivm/src/interface/types/outputs/execution_result.rs +++ b/core/lib/multivm/src/interface/types/outputs/execution_result.rs @@ -101,6 +101,7 @@ impl VmExecutionResultAndLogs { cycles_used: self.statistics.cycles_used, computational_gas_used: self.statistics.computational_gas_used, pubdata_published: self.statistics.pubdata_published, + circuit_statistic: self.statistics.circuit_statistic, } } } diff --git a/core/lib/multivm/src/interface/types/outputs/execution_state.rs b/core/lib/multivm/src/interface/types/outputs/execution_state.rs index 24034a962218..523d90b7fd69 100644 --- a/core/lib/multivm/src/interface/types/outputs/execution_state.rs +++ b/core/lib/multivm/src/interface/types/outputs/execution_state.rs @@ -1,6 +1,7 @@ use zksync_types::{ l2_to_l1_log::{SystemL2ToL1Log, UserL2ToL1Log}, - LogQuery, StorageLogQuery, VmEvent, U256, + zk_evm_types::LogQuery, + StorageLogQuery, VmEvent, U256, }; /// State of the VM since the start of the batch execution. @@ -10,6 +11,9 @@ pub struct CurrentExecutionState { pub events: Vec, /// Storage logs produced by the VM. pub storage_log_queries: Vec, + /// The deduplicated storage logs produced by the VM. + /// It is the deduplicated version of the `storage_log_queries` field. + pub deduplicated_storage_log_queries: Vec, /// Hashes of the contracts used by the VM. pub used_contract_hashes: Vec, /// L2 to L1 logs produced by the VM. diff --git a/core/lib/multivm/src/interface/types/outputs/statistic.rs b/core/lib/multivm/src/interface/types/outputs/statistic.rs index c1312fc95da8..88c45166b55e 100644 --- a/core/lib/multivm/src/interface/types/outputs/statistic.rs +++ b/core/lib/multivm/src/interface/types/outputs/statistic.rs @@ -1,3 +1,5 @@ +use zksync_types::circuit::CircuitStatistic; + /// Statistics of the tx execution. #[derive(Debug, Default, Clone)] pub struct VmExecutionStatistics { @@ -12,6 +14,7 @@ pub struct VmExecutionStatistics { /// Number of log queries produced by the VM during the tx execution. pub total_log_queries: usize, pub pubdata_published: u32, + pub circuit_statistic: CircuitStatistic, } /// Oracle metrics of the VM. diff --git a/core/lib/multivm/src/lib.rs b/core/lib/multivm/src/lib.rs index 23ea80a68602..aa55026d88fe 100644 --- a/core/lib/multivm/src/lib.rs +++ b/core/lib/multivm/src/lib.rs @@ -1,15 +1,14 @@ -// #![deny(unreachable_pub)] #![deny(unused_crate_dependencies)] #![warn(unused_extern_crates)] #![warn(unused_imports)] -pub use zk_evm_1_3_1; -pub use zk_evm_1_3_3; -pub use zk_evm_1_4_0; +pub use zk_evm_1_4_1 as zk_evm_latest; +pub use zkevm_test_harness_1_4_1 as zkevm_test_harness_latest; pub use zksync_types::vm_version::VmVersion; pub use self::versions::{ - vm_1_3_2, vm_latest, vm_m5, vm_m6, vm_refunds_enhancement, vm_virtual_blocks, + vm_1_3_2, vm_boojum_integration, vm_latest, vm_m5, vm_m6, vm_refunds_enhancement, + vm_virtual_blocks, }; pub use crate::{ glue::{ @@ -22,5 +21,6 @@ pub use crate::{ mod glue; pub mod interface; pub mod tracers; +pub mod utils; pub mod versions; mod vm_instance; diff --git a/core/lib/multivm/src/tracers/call_tracer/mod.rs b/core/lib/multivm/src/tracers/call_tracer/mod.rs index 0c7e4d3c2800..b3a98902f4b9 100644 --- a/core/lib/multivm/src/tracers/call_tracer/mod.rs +++ b/core/lib/multivm/src/tracers/call_tracer/mod.rs @@ -3,9 +3,10 @@ use std::sync::Arc; use once_cell::sync::OnceCell; use zksync_types::vm_trace::Call; -use crate::tracers::call_tracer::metrics::CALL_METRICS; +use crate::{glue::tracers::IntoOldVmTracer, tracers::call_tracer::metrics::CALL_METRICS}; mod metrics; +pub mod vm_boojum_integration; pub mod vm_latest; pub mod vm_refunds_enhancement; pub mod vm_virtual_blocks; @@ -87,3 +88,9 @@ impl CallTracer { } } } + +impl IntoOldVmTracer for CallTracer { + fn old_tracer(&self) -> crate::tracers::old_tracers::OldTracers { + crate::tracers::old_tracers::OldTracers::CallTracer(self.result.clone()) + } +} diff --git a/core/lib/multivm/src/tracers/call_tracer/vm_boojum_integration/mod.rs b/core/lib/multivm/src/tracers/call_tracer/vm_boojum_integration/mod.rs new file mode 100644 index 000000000000..c36bfb0f9662 --- /dev/null +++ b/core/lib/multivm/src/tracers/call_tracer/vm_boojum_integration/mod.rs @@ -0,0 +1,218 @@ +use zk_evm_1_4_0::{ + tracing::{AfterExecutionData, VmLocalStateData}, + zkevm_opcode_defs::{ + FarCallABI, FatPointer, Opcode, RetOpcode, CALL_IMPLICIT_CALLDATA_FAT_PTR_REGISTER, + RET_IMPLICIT_RETURNDATA_PARAMS_REGISTER, + }, +}; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_system_constants::CONTRACT_DEPLOYER_ADDRESS; +use zksync_types::{ + vm_trace::{Call, CallType}, + zk_evm_types::FarCallOpcode, + U256, +}; + +use crate::{ + glue::GlueInto, + interface::{ + tracer::VmExecutionStopReason, traits::tracers::dyn_tracers::vm_1_4_0::DynTracer, + VmRevertReason, + }, + tracers::call_tracer::CallTracer, + vm_boojum_integration::{BootloaderState, HistoryMode, SimpleMemory, VmTracer, ZkSyncVmState}, +}; + +impl DynTracer> for CallTracer { + fn after_execution( + &mut self, + state: VmLocalStateData<'_>, + data: AfterExecutionData, + memory: &SimpleMemory, + _storage: StoragePtr, + ) { + match data.opcode.variant.opcode { + Opcode::NearCall(_) => { + self.increase_near_call_count(); + } + Opcode::FarCall(far_call) => { + // We use parent gas for properly calculating gas used in the trace. + let current_ergs = state.vm_local_state.callstack.current.ergs_remaining; + let parent_gas = state + .vm_local_state + .callstack + .inner + .last() + .map(|call| call.ergs_remaining + current_ergs) + .unwrap_or(current_ergs); + + let mut current_call = Call { + r#type: CallType::Call(far_call.glue_into()), + gas: 0, + parent_gas, + ..Default::default() + }; + + self.handle_far_call_op_code_vm_boojum_integration( + state, + memory, + &mut current_call, + ); + self.push_call_and_update_stats(current_call, 0); + } + Opcode::Ret(ret_code) => { + self.handle_ret_op_code_vm_boojum_integration(state, memory, ret_code); + } + _ => {} + }; + } +} + +impl VmTracer for CallTracer { + fn after_vm_execution( + &mut self, + _state: &mut ZkSyncVmState, + _bootloader_state: &BootloaderState, + _stop_reason: VmExecutionStopReason, + ) { + self.store_result() + } +} + +impl CallTracer { + fn handle_far_call_op_code_vm_boojum_integration( + &mut self, + state: VmLocalStateData<'_>, + memory: &SimpleMemory, + current_call: &mut Call, + ) { + let current = state.vm_local_state.callstack.current; + // All calls from the actual users are mimic calls, + // so we need to check that the previous call was to the deployer. + // Actually it's a call of the constructor. + // And at this stage caller is user and callee is deployed contract. + let call_type = if let CallType::Call(far_call) = current_call.r#type { + if matches!(far_call.glue_into(), FarCallOpcode::Mimic) { + let previous_caller = state + .vm_local_state + .callstack + .inner + .last() + .map(|call| call.this_address) + // Actually it's safe to just unwrap here, because we have at least one call in the stack + // But i want to be sure that we will not have any problems in the future + .unwrap_or(current.this_address); + if previous_caller == CONTRACT_DEPLOYER_ADDRESS { + CallType::Create + } else { + CallType::Call(far_call) + } + } else { + CallType::Call(far_call) + } + } else { + unreachable!() + }; + let calldata = if current.code_page.0 == 0 || current.ergs_remaining == 0 { + vec![] + } else { + let packed_abi = + state.vm_local_state.registers[CALL_IMPLICIT_CALLDATA_FAT_PTR_REGISTER as usize]; + assert!(packed_abi.is_pointer); + let far_call_abi = FarCallABI::from_u256(packed_abi.value); + memory.read_unaligned_bytes( + far_call_abi.memory_quasi_fat_pointer.memory_page as usize, + far_call_abi.memory_quasi_fat_pointer.start as usize, + far_call_abi.memory_quasi_fat_pointer.length as usize, + ) + }; + + current_call.input = calldata; + current_call.r#type = call_type; + current_call.from = current.msg_sender; + current_call.to = current.this_address; + current_call.value = U256::from(current.context_u128_value); + current_call.gas = current.ergs_remaining; + } + + fn save_output_vm_boojum_integration( + &mut self, + state: VmLocalStateData<'_>, + memory: &SimpleMemory, + ret_opcode: RetOpcode, + current_call: &mut Call, + ) { + let fat_data_pointer = + state.vm_local_state.registers[RET_IMPLICIT_RETURNDATA_PARAMS_REGISTER as usize]; + + // if `fat_data_pointer` is not a pointer then there is no output + let output = if fat_data_pointer.is_pointer { + let fat_data_pointer = FatPointer::from_u256(fat_data_pointer.value); + if !fat_data_pointer.is_trivial() { + Some(memory.read_unaligned_bytes( + fat_data_pointer.memory_page as usize, + fat_data_pointer.start as usize, + fat_data_pointer.length as usize, + )) + } else { + None + } + } else { + None + }; + + match ret_opcode { + RetOpcode::Ok => { + current_call.output = output.unwrap_or_default(); + } + RetOpcode::Revert => { + if let Some(output) = output { + current_call.revert_reason = + Some(VmRevertReason::from(output.as_slice()).to_string()); + } else { + current_call.revert_reason = Some("Unknown revert reason".to_string()); + } + } + RetOpcode::Panic => { + current_call.error = Some("Panic".to_string()); + } + } + } + + fn handle_ret_op_code_vm_boojum_integration( + &mut self, + state: VmLocalStateData<'_>, + memory: &SimpleMemory, + ret_opcode: RetOpcode, + ) { + let Some(mut current_call) = self.stack.pop() else { + return; + }; + + if current_call.near_calls_after > 0 { + current_call.near_calls_after -= 1; + self.push_call_and_update_stats(current_call.farcall, current_call.near_calls_after); + return; + } + + current_call.farcall.gas_used = current_call + .farcall + .parent_gas + .saturating_sub(state.vm_local_state.callstack.current.ergs_remaining); + + self.save_output_vm_boojum_integration( + state, + memory, + ret_opcode, + &mut current_call.farcall, + ); + + // If there is a parent call, push the current call to it + // Otherwise, push the current call to the stack, because it's the top level call + if let Some(parent_call) = self.stack.last_mut() { + parent_call.farcall.calls.push(current_call.farcall); + } else { + self.push_call_and_update_stats(current_call.farcall, current_call.near_calls_after); + } + } +} diff --git a/core/lib/multivm/src/tracers/call_tracer/vm_latest/mod.rs b/core/lib/multivm/src/tracers/call_tracer/vm_latest/mod.rs index 09b5b828fc03..4d5a9857c938 100644 --- a/core/lib/multivm/src/tracers/call_tracer/vm_latest/mod.rs +++ b/core/lib/multivm/src/tracers/call_tracer/vm_latest/mod.rs @@ -1,4 +1,4 @@ -use zk_evm_1_4_0::{ +use zk_evm_1_4_1::{ tracing::{AfterExecutionData, VmLocalStateData}, zkevm_opcode_defs::{ FarCallABI, FatPointer, Opcode, RetOpcode, CALL_IMPLICIT_CALLDATA_FAT_PTR_REGISTER, @@ -9,12 +9,14 @@ use zksync_state::{StoragePtr, WriteStorage}; use zksync_system_constants::CONTRACT_DEPLOYER_ADDRESS; use zksync_types::{ vm_trace::{Call, CallType}, - FarCallOpcode, U256, + zk_evm_types::FarCallOpcode, + U256, }; use crate::{ + glue::GlueInto, interface::{ - tracer::VmExecutionStopReason, traits::tracers::dyn_tracers::vm_1_4_0::DynTracer, + tracer::VmExecutionStopReason, traits::tracers::dyn_tracers::vm_1_4_1::DynTracer, VmRevertReason, }, tracers::call_tracer::CallTracer, @@ -45,7 +47,7 @@ impl DynTracer> for CallTracer { .unwrap_or(current_ergs); let mut current_call = Call { - r#type: CallType::Call(far_call), + r#type: CallType::Call(far_call.glue_into()), gas: 0, parent_gas, ..Default::default() @@ -139,7 +141,7 @@ impl CallTracer { let fat_data_pointer = state.vm_local_state.registers[RET_IMPLICIT_RETURNDATA_PARAMS_REGISTER as usize]; - // if fat_data_pointer is not a pointer then there is no output + // if `fat_data_pointer` is not a pointer then there is no output let output = if fat_data_pointer.is_pointer { let fat_data_pointer = FatPointer::from_u256(fat_data_pointer.value); if !fat_data_pointer.is_trivial() { diff --git a/core/lib/multivm/src/tracers/call_tracer/vm_refunds_enhancement/mod.rs b/core/lib/multivm/src/tracers/call_tracer/vm_refunds_enhancement/mod.rs index 3bc4426e8cc2..4c9a9d8e8d66 100644 --- a/core/lib/multivm/src/tracers/call_tracer/vm_refunds_enhancement/mod.rs +++ b/core/lib/multivm/src/tracers/call_tracer/vm_refunds_enhancement/mod.rs @@ -9,10 +9,12 @@ use zksync_state::{StoragePtr, WriteStorage}; use zksync_system_constants::CONTRACT_DEPLOYER_ADDRESS; use zksync_types::{ vm_trace::{Call, CallType}, - FarCallOpcode, U256, + zk_evm_types::FarCallOpcode, + U256, }; use crate::{ + glue::GlueInto, interface::{ tracer::VmExecutionStopReason, traits::tracers::dyn_tracers::vm_1_3_3::DynTracer, VmRevertReason, @@ -45,7 +47,7 @@ impl DynTracer> for CallTracer { .unwrap_or(current_ergs); let mut current_call = Call { - r#type: CallType::Call(far_call), + r#type: CallType::Call(far_call.glue_into()), gas: 0, parent_gas, ..Default::default() @@ -140,7 +142,7 @@ impl CallTracer { let fat_data_pointer = state.vm_local_state.registers[RET_IMPLICIT_RETURNDATA_PARAMS_REGISTER as usize]; - // if fat_data_pointer is not a pointer then there is no output + // if `fat_data_pointer` is not a pointer then there is no output let output = if fat_data_pointer.is_pointer { let fat_data_pointer = FatPointer::from_u256(fat_data_pointer.value); if !fat_data_pointer.is_trivial() { diff --git a/core/lib/multivm/src/tracers/call_tracer/vm_virtual_blocks/mod.rs b/core/lib/multivm/src/tracers/call_tracer/vm_virtual_blocks/mod.rs index f96b2cb0f58f..7ffaab1392ba 100644 --- a/core/lib/multivm/src/tracers/call_tracer/vm_virtual_blocks/mod.rs +++ b/core/lib/multivm/src/tracers/call_tracer/vm_virtual_blocks/mod.rs @@ -9,10 +9,12 @@ use zksync_state::{StoragePtr, WriteStorage}; use zksync_system_constants::CONTRACT_DEPLOYER_ADDRESS; use zksync_types::{ vm_trace::{Call, CallType}, - FarCallOpcode, U256, + zk_evm_types::FarCallOpcode, + U256, }; use crate::{ + glue::GlueInto, interface::{dyn_tracers::vm_1_3_3::DynTracer, VmExecutionResultAndLogs, VmRevertReason}, tracers::call_tracer::CallTracer, vm_virtual_blocks::{ @@ -44,7 +46,7 @@ impl DynTracer> for CallTracer { .unwrap_or(current_ergs); let mut current_call = Call { - r#type: CallType::Call(far_call), + r#type: CallType::Call(far_call.glue_into()), gas: 0, parent_gas, ..Default::default() @@ -138,7 +140,7 @@ impl CallTracer { let fat_data_pointer = state.vm_local_state.registers[RET_IMPLICIT_RETURNDATA_PARAMS_REGISTER as usize]; - // if fat_data_pointer is not a pointer then there is no output + // if `fat_data_pointer` is not a pointer then there is no output let output = if fat_data_pointer.is_pointer { let fat_data_pointer = FatPointer::from_u256(fat_data_pointer.value); if !fat_data_pointer.is_trivial() { diff --git a/core/lib/multivm/src/tracers/mod.rs b/core/lib/multivm/src/tracers/mod.rs index 728a15a6a6b2..8d858ae03ed5 100644 --- a/core/lib/multivm/src/tracers/mod.rs +++ b/core/lib/multivm/src/tracers/mod.rs @@ -1,5 +1,6 @@ pub mod call_tracer; mod multivm_dispatcher; +pub mod old_tracers; pub mod storage_invocation; pub mod validator; diff --git a/core/lib/multivm/src/tracers/multivm_dispatcher.rs b/core/lib/multivm/src/tracers/multivm_dispatcher.rs index 8ee858a61108..0e8585884fa5 100644 --- a/core/lib/multivm/src/tracers/multivm_dispatcher.rs +++ b/core/lib/multivm/src/tracers/multivm_dispatcher.rs @@ -1,6 +1,6 @@ use zksync_state::WriteStorage; -use crate::{HistoryMode, MultiVmTracerPointer}; +use crate::{tracers::old_tracers, HistoryMode, MultiVmTracerPointer}; /// Tracer dispatcher is a tracer that can dispatch calls to multiple tracers. pub struct TracerDispatcher { @@ -30,13 +30,27 @@ impl Default for TracerDispatcher { } impl From> - for crate::vm_latest::TracerDispatcher + for crate::vm_latest::TracerDispatcher { fn from(value: TracerDispatcher) -> Self { Self::new(value.tracers.into_iter().map(|x| x.latest()).collect()) } } +impl From> + for crate::vm_boojum_integration::TracerDispatcher +{ + fn from(value: TracerDispatcher) -> Self { + Self::new( + value + .tracers + .into_iter() + .map(|x| x.vm_boojum_integration()) + .collect(), + ) + } +} + impl From> for crate::vm_refunds_enhancement::TracerDispatcher { @@ -69,3 +83,9 @@ impl From> impl From> for () { fn from(_value: TracerDispatcher) -> Self {} } + +impl From> for old_tracers::TracerDispatcher { + fn from(value: TracerDispatcher) -> Self { + Self::new(value.tracers.into_iter().map(|x| x.old_tracer()).collect()) + } +} diff --git a/core/lib/multivm/src/tracers/old_tracers.rs b/core/lib/multivm/src/tracers/old_tracers.rs new file mode 100644 index 000000000000..54e5e45aa2ce --- /dev/null +++ b/core/lib/multivm/src/tracers/old_tracers.rs @@ -0,0 +1,48 @@ +use std::sync::Arc; + +use once_cell::sync::OnceCell; +use zksync_types::vm_trace::Call; + +/// For backward compatibility with vm before vm with virtual blocks. +/// These tracers are tightly coupled with the VM implementation and we have to pass only params for them and not tracers by itself. +#[derive(Debug, Clone)] +pub enum OldTracers { + CallTracer(Arc>>), + StorageInvocations(usize), + /// Special cases for not supported tracers. + None, +} + +impl OldTracers { + pub fn call_tracer(&self) -> Option>>> { + match self { + OldTracers::CallTracer(a) => Some(a.clone()), + _ => None, + } + } + pub fn storage_invocations(&self) -> Option { + match self { + OldTracers::StorageInvocations(a) => Some(*a), + _ => None, + } + } +} + +/// Tracer dispatcher is a tracer that can convert list of tracers to params for old VM. +#[derive(Debug, Default, Clone)] +pub struct TracerDispatcher { + pub(crate) call_tracer: Option>>>, + pub(crate) storage_invocations: Option, +} + +impl TracerDispatcher { + pub fn new(tracers: Vec) -> Self { + let call_tracer = tracers.iter().find_map(|x| x.call_tracer()); + let storage_invocations = tracers.iter().find_map(|x| x.storage_invocations()); + + Self { + call_tracer, + storage_invocations, + } + } +} diff --git a/core/lib/multivm/src/tracers/storage_invocation/mod.rs b/core/lib/multivm/src/tracers/storage_invocation/mod.rs index 3816d2a07a14..db4e936e0112 100644 --- a/core/lib/multivm/src/tracers/storage_invocation/mod.rs +++ b/core/lib/multivm/src/tracers/storage_invocation/mod.rs @@ -1,3 +1,6 @@ +use crate::{glue::tracers::IntoOldVmTracer, tracers::old_tracers::OldTracers}; + +pub mod vm_boojum_integration; pub mod vm_latest; pub mod vm_refunds_enhancement; pub mod vm_virtual_blocks; @@ -15,3 +18,9 @@ impl StorageInvocations { Self { limit, current: 0 } } } + +impl IntoOldVmTracer for StorageInvocations { + fn old_tracer(&self) -> OldTracers { + OldTracers::StorageInvocations(self.limit) + } +} diff --git a/core/lib/multivm/src/tracers/storage_invocation/vm_boojum_integration/mod.rs b/core/lib/multivm/src/tracers/storage_invocation/vm_boojum_integration/mod.rs new file mode 100644 index 000000000000..05651485bd79 --- /dev/null +++ b/core/lib/multivm/src/tracers/storage_invocation/vm_boojum_integration/mod.rs @@ -0,0 +1,35 @@ +use zksync_state::WriteStorage; + +use crate::{ + interface::{ + tracer::{TracerExecutionStatus, TracerExecutionStopReason}, + traits::tracers::dyn_tracers::vm_1_4_0::DynTracer, + Halt, + }, + tracers::storage_invocation::StorageInvocations, + vm_boojum_integration::{BootloaderState, HistoryMode, SimpleMemory, VmTracer, ZkSyncVmState}, +}; + +impl DynTracer> for StorageInvocations {} + +impl VmTracer for StorageInvocations { + fn finish_cycle( + &mut self, + state: &mut ZkSyncVmState, + _bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + let current = state + .storage + .storage + .get_ptr() + .borrow() + .missed_storage_invocations(); + + if current >= self.limit { + return TracerExecutionStatus::Stop(TracerExecutionStopReason::Abort( + Halt::TracerCustom("Storage invocations limit reached".to_string()), + )); + } + TracerExecutionStatus::Continue + } +} diff --git a/core/lib/multivm/src/tracers/storage_invocation/vm_latest/mod.rs b/core/lib/multivm/src/tracers/storage_invocation/vm_latest/mod.rs index 46213ff54fc1..3fa04401782c 100644 --- a/core/lib/multivm/src/tracers/storage_invocation/vm_latest/mod.rs +++ b/core/lib/multivm/src/tracers/storage_invocation/vm_latest/mod.rs @@ -3,7 +3,7 @@ use zksync_state::WriteStorage; use crate::{ interface::{ tracer::{TracerExecutionStatus, TracerExecutionStopReason}, - traits::tracers::dyn_tracers::vm_1_4_0::DynTracer, + traits::tracers::dyn_tracers::vm_1_4_1::DynTracer, Halt, }, tracers::storage_invocation::StorageInvocations, diff --git a/core/lib/multivm/src/tracers/validator/mod.rs b/core/lib/multivm/src/tracers/validator/mod.rs index 0f43f235ade4..c56424f3013e 100644 --- a/core/lib/multivm/src/tracers/validator/mod.rs +++ b/core/lib/multivm/src/tracers/validator/mod.rs @@ -12,10 +12,14 @@ use zksync_types::{ }; use zksync_utils::{be_bytes_to_safe_address, u256_to_account_address, u256_to_h256}; -use crate::tracers::validator::types::{NewTrustedValidationItems, ValidationTracerMode}; pub use crate::tracers::validator::types::{ValidationError, ValidationTracerParams}; +use crate::{ + glue::tracers::IntoOldVmTracer, + tracers::validator::types::{NewTrustedValidationItems, ValidationTracerMode}, +}; mod types; +mod vm_boojum_integration; mod vm_latest; mod vm_refunds_enhancement; mod vm_virtual_blocks; @@ -101,7 +105,7 @@ impl ValidationTracer { return true; } - // The pair of MSG_VALUE_SIMULATOR_ADDRESS & L2_ETH_TOKEN_ADDRESS simulates the behavior of transferring ETH + // The pair of `MSG_VALUE_SIMULATOR_ADDRESS` & `L2_ETH_TOKEN_ADDRESS` simulates the behavior of transferring ETH // that is safe for the DDoS protection rules. if valid_eth_token_call(address, msg_sender) { return true; @@ -145,11 +149,11 @@ impl ValidationTracer { let (potential_address_bytes, potential_position_bytes) = calldata.split_at(32); let potential_address = be_bytes_to_safe_address(potential_address_bytes); - // If the validation_address is equal to the potential_address, - // then it is a request that could be used for mapping of kind mapping(address => ...). + // If the `validation_address` is equal to the `potential_address`, + // then it is a request that could be used for mapping of kind `mapping(address => ...).` // - // If the potential_position_bytes were already allowed before, then this keccak might be used - // for ERC-20 allowance or any other of mapping(address => mapping(...)) + // If the `potential_position_bytes` were already allowed before, then this keccak might be used + // for ERC-20 allowance or any other of `mapping(address => mapping(...))` if potential_address == Some(validated_address) || self .auxilary_allowed_slots @@ -187,7 +191,7 @@ fn touches_allowed_context(address: Address, key: U256) -> bool { return false; } - // Only chain_id is allowed to be touched. + // Only `chain_id` is allowed to be touched. key == U256::from(0u32) } @@ -215,3 +219,5 @@ fn valid_eth_token_call(address: Address, msg_sender: Address) -> bool { || msg_sender == BOOTLOADER_ADDRESS; address == L2_ETH_TOKEN_ADDRESS && is_valid_caller } + +impl IntoOldVmTracer for ValidationTracer {} diff --git a/core/lib/multivm/src/tracers/validator/vm_boojum_integration/mod.rs b/core/lib/multivm/src/tracers/validator/vm_boojum_integration/mod.rs new file mode 100644 index 000000000000..2c9a708abcaa --- /dev/null +++ b/core/lib/multivm/src/tracers/validator/vm_boojum_integration/mod.rs @@ -0,0 +1,201 @@ +use zk_evm_1_4_0::{ + tracing::{BeforeExecutionData, VmLocalStateData}, + zkevm_opcode_defs::{ContextOpcode, FarCallABI, LogOpcode, Opcode}, +}; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_system_constants::KECCAK256_PRECOMPILE_ADDRESS; +use zksync_types::{ + get_code_key, vm_trace::ViolatedValidationRule, AccountTreeId, StorageKey, H256, +}; +use zksync_utils::{h256_to_account_address, u256_to_account_address, u256_to_h256}; + +use crate::{ + interface::{ + traits::tracers::dyn_tracers::vm_1_4_0::DynTracer, + types::tracer::{TracerExecutionStatus, TracerExecutionStopReason}, + Halt, + }, + tracers::validator::{ + types::{NewTrustedValidationItems, ValidationTracerMode}, + ValidationRoundResult, ValidationTracer, + }, + vm_boojum_integration::{ + tracers::utils::{ + computational_gas_price, get_calldata_page_via_abi, print_debug_if_needed, VmHook, + }, + BootloaderState, SimpleMemory, VmTracer, ZkSyncVmState, + }, + HistoryMode, +}; + +impl ValidationTracer { + fn check_user_restrictions_vm_boojum_integration( + &mut self, + state: VmLocalStateData<'_>, + data: BeforeExecutionData, + memory: &SimpleMemory, + storage: StoragePtr, + ) -> ValidationRoundResult { + if self.computational_gas_used > self.computational_gas_limit { + return Err(ViolatedValidationRule::TookTooManyComputationalGas( + self.computational_gas_limit, + )); + } + + let opcode_variant = data.opcode.variant; + match opcode_variant.opcode { + Opcode::FarCall(_) => { + let packed_abi = data.src0_value.value; + let call_destination_value = data.src1_value.value; + + let called_address = u256_to_account_address(&call_destination_value); + let far_call_abi = FarCallABI::from_u256(packed_abi); + + if called_address == KECCAK256_PRECOMPILE_ADDRESS + && far_call_abi.memory_quasi_fat_pointer.length == 64 + { + let calldata_page = get_calldata_page_via_abi( + &far_call_abi, + state.vm_local_state.callstack.current.base_memory_page, + ); + let calldata = memory.read_unaligned_bytes( + calldata_page as usize, + far_call_abi.memory_quasi_fat_pointer.start as usize, + 64, + ); + + let slot_to_add = + self.slot_to_add_from_keccak_call(&calldata, self.user_address); + + if let Some(slot) = slot_to_add { + return Ok(NewTrustedValidationItems { + new_allowed_slots: vec![slot], + ..Default::default() + }); + } + } else if called_address != self.user_address { + let code_key = get_code_key(&called_address); + let code = storage.borrow_mut().read_value(&code_key); + + if code == H256::zero() { + // The users are not allowed to call contracts with no code + return Err(ViolatedValidationRule::CalledContractWithNoCode( + called_address, + )); + } + } + } + Opcode::Context(context) => { + match context { + ContextOpcode::Meta => { + return Err(ViolatedValidationRule::TouchedUnallowedContext); + } + ContextOpcode::ErgsLeft => { + // TODO (SMA-1168): implement the correct restrictions for the gas left opcode. + } + _ => {} + } + } + Opcode::Log(LogOpcode::StorageRead) => { + let key = data.src0_value.value; + let this_address = state.vm_local_state.callstack.current.this_address; + let msg_sender = state.vm_local_state.callstack.current.msg_sender; + + if !self.is_allowed_storage_read(storage.clone(), this_address, key, msg_sender) { + return Err(ViolatedValidationRule::TouchedUnallowedStorageSlots( + this_address, + key, + )); + } + + if self.trusted_address_slots.contains(&(this_address, key)) { + let storage_key = + StorageKey::new(AccountTreeId::new(this_address), u256_to_h256(key)); + + let value = storage.borrow_mut().read_value(&storage_key); + + return Ok(NewTrustedValidationItems { + new_trusted_addresses: vec![h256_to_account_address(&value)], + ..Default::default() + }); + } + } + _ => {} + } + + Ok(Default::default()) + } +} + +impl DynTracer> + for ValidationTracer +{ + fn before_execution( + &mut self, + state: VmLocalStateData<'_>, + data: BeforeExecutionData, + memory: &SimpleMemory, + storage: StoragePtr, + ) { + // For now, we support only validations for users. + if let ValidationTracerMode::UserTxValidation = self.validation_mode { + self.computational_gas_used = self + .computational_gas_used + .saturating_add(computational_gas_price(state, &data)); + + let validation_round_result = + self.check_user_restrictions_vm_boojum_integration(state, data, memory, storage); + self.process_validation_round_result(validation_round_result); + } + + let hook = VmHook::from_opcode_memory(&state, &data); + print_debug_if_needed(&hook, &state, memory); + + let current_mode = self.validation_mode; + match (current_mode, hook) { + (ValidationTracerMode::NoValidation, VmHook::AccountValidationEntered) => { + // Account validation can be entered when there is no prior validation (i.e. "nested" validations are not allowed) + self.validation_mode = ValidationTracerMode::UserTxValidation; + } + (ValidationTracerMode::NoValidation, VmHook::PaymasterValidationEntered) => { + // Paymaster validation can be entered when there is no prior validation (i.e. "nested" validations are not allowed) + self.validation_mode = ValidationTracerMode::PaymasterTxValidation; + } + (_, VmHook::AccountValidationEntered | VmHook::PaymasterValidationEntered) => { + panic!( + "Unallowed transition inside the validation tracer. Mode: {:#?}, hook: {:#?}", + self.validation_mode, hook + ); + } + (_, VmHook::NoValidationEntered) => { + // Validation can be always turned off + self.validation_mode = ValidationTracerMode::NoValidation; + } + (_, VmHook::ValidationStepEndeded) => { + // The validation step has ended. + self.should_stop_execution = true; + } + (_, _) => { + // The hook is not relevant to the validation tracer. Ignore. + } + } + } +} + +impl VmTracer for ValidationTracer { + fn finish_cycle( + &mut self, + _state: &mut ZkSyncVmState, + _bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + if self.should_stop_execution { + return TracerExecutionStatus::Stop(TracerExecutionStopReason::Finish); + } + if let Some(result) = self.result.get() { + return TracerExecutionStatus::Stop(TracerExecutionStopReason::Abort( + Halt::TracerCustom(format!("Validation error: {:#?}", result)), + )); + } + TracerExecutionStatus::Continue + } +} diff --git a/core/lib/multivm/src/tracers/validator/vm_latest/mod.rs b/core/lib/multivm/src/tracers/validator/vm_latest/mod.rs index dbdc7253f75d..095f1a20b38b 100644 --- a/core/lib/multivm/src/tracers/validator/vm_latest/mod.rs +++ b/core/lib/multivm/src/tracers/validator/vm_latest/mod.rs @@ -1,4 +1,4 @@ -use zk_evm_1_4_0::{ +use zk_evm_1_4_1::{ tracing::{BeforeExecutionData, VmLocalStateData}, zkevm_opcode_defs::{ContextOpcode, FarCallABI, LogOpcode, Opcode}, }; @@ -11,7 +11,7 @@ use zksync_utils::{h256_to_account_address, u256_to_account_address, u256_to_h25 use crate::{ interface::{ - traits::tracers::dyn_tracers::vm_1_4_0::DynTracer, + traits::tracers::dyn_tracers::vm_1_4_1::DynTracer, types::tracer::{TracerExecutionStatus, TracerExecutionStopReason}, Halt, }, @@ -33,7 +33,7 @@ impl ValidationTracer { &mut self, state: VmLocalStateData<'_>, data: BeforeExecutionData, - memory: &SimpleMemory, + memory: &SimpleMemory, storage: StoragePtr, ) -> ValidationRoundResult { if self.computational_gas_used > self.computational_gas_limit { @@ -127,14 +127,14 @@ impl ValidationTracer { } } -impl DynTracer> +impl DynTracer> for ValidationTracer { fn before_execution( &mut self, state: VmLocalStateData<'_>, data: BeforeExecutionData, - memory: &SimpleMemory, + memory: &SimpleMemory, storage: StoragePtr, ) { // For now, we support only validations for users. @@ -182,10 +182,10 @@ impl DynTracer VmTracer for ValidationTracer { +impl VmTracer for ValidationTracer { fn finish_cycle( &mut self, - _state: &mut ZkSyncVmState, + _state: &mut ZkSyncVmState, _bootloader_state: &mut BootloaderState, ) -> TracerExecutionStatus { if self.should_stop_execution { diff --git a/core/lib/multivm/src/utils.rs b/core/lib/multivm/src/utils.rs new file mode 100644 index 000000000000..459739c45baf --- /dev/null +++ b/core/lib/multivm/src/utils.rs @@ -0,0 +1,249 @@ +use zksync_types::{fee_model::BatchFeeInput, VmVersion, U256}; + +use crate::vm_latest::L1BatchEnv; + +/// Calculates the base fee and gas per pubdata for the given L1 gas price. +pub fn derive_base_fee_and_gas_per_pubdata( + batch_fee_input: BatchFeeInput, + vm_version: VmVersion, +) -> (u64, u64) { + match vm_version { + VmVersion::M5WithRefunds | VmVersion::M5WithoutRefunds => { + crate::vm_m5::vm_with_bootloader::derive_base_fee_and_gas_per_pubdata( + batch_fee_input.into_l1_pegged(), + ) + } + VmVersion::M6Initial | VmVersion::M6BugWithCompressionFixed => { + crate::vm_m6::vm_with_bootloader::derive_base_fee_and_gas_per_pubdata( + batch_fee_input.into_l1_pegged(), + ) + } + VmVersion::Vm1_3_2 => { + crate::vm_1_3_2::vm_with_bootloader::derive_base_fee_and_gas_per_pubdata( + batch_fee_input.into_l1_pegged(), + ) + } + VmVersion::VmVirtualBlocks => { + crate::vm_virtual_blocks::utils::fee::derive_base_fee_and_gas_per_pubdata( + batch_fee_input.into_l1_pegged(), + ) + } + VmVersion::VmVirtualBlocksRefundsEnhancement => { + crate::vm_refunds_enhancement::utils::fee::derive_base_fee_and_gas_per_pubdata( + batch_fee_input.into_l1_pegged(), + ) + } + VmVersion::VmBoojumIntegration => { + crate::vm_boojum_integration::utils::fee::derive_base_fee_and_gas_per_pubdata( + batch_fee_input.into_l1_pegged(), + ) + } + VmVersion::Vm1_4_1 => crate::vm_latest::utils::fee::derive_base_fee_and_gas_per_pubdata( + batch_fee_input.into_pubdata_independent(), + ), + } +} + +pub fn get_batch_base_fee(l1_batch_env: &L1BatchEnv, vm_version: VmVersion) -> u64 { + match vm_version { + VmVersion::M5WithRefunds | VmVersion::M5WithoutRefunds => { + crate::vm_m5::vm_with_bootloader::get_batch_base_fee(l1_batch_env) + } + VmVersion::M6Initial | VmVersion::M6BugWithCompressionFixed => { + crate::vm_m6::vm_with_bootloader::get_batch_base_fee(l1_batch_env) + } + VmVersion::Vm1_3_2 => crate::vm_1_3_2::vm_with_bootloader::get_batch_base_fee(l1_batch_env), + VmVersion::VmVirtualBlocks => { + crate::vm_virtual_blocks::utils::fee::get_batch_base_fee(l1_batch_env) + } + VmVersion::VmVirtualBlocksRefundsEnhancement => { + crate::vm_refunds_enhancement::utils::fee::get_batch_base_fee(l1_batch_env) + } + VmVersion::VmBoojumIntegration => { + crate::vm_boojum_integration::utils::fee::get_batch_base_fee(l1_batch_env) + } + VmVersion::Vm1_4_1 => crate::vm_latest::utils::fee::get_batch_base_fee(l1_batch_env), + } +} + +/// Changes the batch fee input so that the expected gas per pubdata is smaller than or the `tx_gas_per_pubdata_limit`. +pub fn adjust_pubdata_price_for_tx( + batch_fee_input: BatchFeeInput, + tx_gas_per_pubdata_limit: U256, + vm_version: VmVersion, +) -> BatchFeeInput { + if U256::from(derive_base_fee_and_gas_per_pubdata(batch_fee_input, vm_version).1) + <= tx_gas_per_pubdata_limit + { + return batch_fee_input; + } + + // The latest VM supports adjusting the pubdata price for all the types of the fee models. + crate::vm_latest::utils::fee::adjust_pubdata_price_for_tx( + batch_fee_input, + tx_gas_per_pubdata_limit, + ) +} + +pub fn derive_overhead( + gas_limit: u32, + gas_price_per_pubdata: u32, + encoded_len: usize, + tx_type: u8, + vm_version: VmVersion, +) -> u32 { + match vm_version { + VmVersion::M5WithRefunds | VmVersion::M5WithoutRefunds => { + crate::vm_m5::transaction_data::derive_overhead( + gas_limit, + gas_price_per_pubdata, + encoded_len, + ) + } + VmVersion::M6Initial | VmVersion::M6BugWithCompressionFixed => { + crate::vm_m6::transaction_data::derive_overhead( + gas_limit, + gas_price_per_pubdata, + encoded_len, + crate::vm_m6::transaction_data::OverheadCoefficients::from_tx_type(tx_type), + ) + } + VmVersion::Vm1_3_2 => crate::vm_1_3_2::transaction_data::derive_overhead( + gas_limit, + gas_price_per_pubdata, + encoded_len, + crate::vm_1_3_2::transaction_data::OverheadCoefficients::from_tx_type(tx_type), + ), + VmVersion::VmVirtualBlocks => crate::vm_virtual_blocks::utils::overhead::derive_overhead( + gas_limit, + gas_price_per_pubdata, + encoded_len, + crate::vm_virtual_blocks::utils::overhead::OverheadCoefficients::from_tx_type(tx_type), + ), + VmVersion::VmVirtualBlocksRefundsEnhancement => { + crate::vm_refunds_enhancement::utils::overhead::derive_overhead( + gas_limit, + gas_price_per_pubdata, + encoded_len, + crate::vm_refunds_enhancement::utils::overhead::OverheadCoefficients::from_tx_type( + tx_type, + ), + ) + } + VmVersion::VmBoojumIntegration => { + crate::vm_boojum_integration::utils::overhead::derive_overhead( + gas_limit, + gas_price_per_pubdata, + encoded_len, + crate::vm_boojum_integration::utils::overhead::OverheadCoefficients::from_tx_type( + tx_type, + ), + ) + } + VmVersion::Vm1_4_1 => crate::vm_latest::utils::overhead::derive_overhead(encoded_len), + } +} + +pub fn get_bootloader_encoding_space(version: VmVersion) -> u32 { + match version { + VmVersion::M5WithRefunds | VmVersion::M5WithoutRefunds => { + crate::vm_m5::vm_with_bootloader::BOOTLOADER_TX_ENCODING_SPACE + } + VmVersion::M6Initial | VmVersion::M6BugWithCompressionFixed => { + crate::vm_m6::vm_with_bootloader::BOOTLOADER_TX_ENCODING_SPACE + } + VmVersion::Vm1_3_2 => crate::vm_1_3_2::vm_with_bootloader::BOOTLOADER_TX_ENCODING_SPACE, + VmVersion::VmVirtualBlocks => { + crate::vm_virtual_blocks::constants::BOOTLOADER_TX_ENCODING_SPACE + } + VmVersion::VmVirtualBlocksRefundsEnhancement => { + crate::vm_refunds_enhancement::constants::BOOTLOADER_TX_ENCODING_SPACE + } + VmVersion::VmBoojumIntegration => { + crate::vm_boojum_integration::constants::BOOTLOADER_TX_ENCODING_SPACE + } + VmVersion::Vm1_4_1 => crate::vm_latest::constants::BOOTLOADER_TX_ENCODING_SPACE, + } +} + +pub fn get_bootloader_max_txs_in_batch(version: VmVersion) -> usize { + match version { + VmVersion::M5WithRefunds | VmVersion::M5WithoutRefunds => { + crate::vm_m5::vm_with_bootloader::MAX_TXS_IN_BLOCK + } + VmVersion::M6Initial | VmVersion::M6BugWithCompressionFixed => { + crate::vm_m6::vm_with_bootloader::MAX_TXS_IN_BLOCK + } + VmVersion::Vm1_3_2 => crate::vm_1_3_2::vm_with_bootloader::MAX_TXS_IN_BLOCK, + VmVersion::VmVirtualBlocks => crate::vm_virtual_blocks::constants::MAX_TXS_IN_BLOCK, + VmVersion::VmVirtualBlocksRefundsEnhancement => { + crate::vm_refunds_enhancement::constants::MAX_TXS_IN_BLOCK + } + VmVersion::VmBoojumIntegration => crate::vm_boojum_integration::constants::MAX_TXS_IN_BLOCK, + VmVersion::Vm1_4_1 => crate::vm_latest::constants::MAX_TXS_IN_BATCH, + } +} + +pub fn get_max_gas_per_pubdata_byte(version: VmVersion) -> u64 { + match version { + VmVersion::M5WithRefunds | VmVersion::M5WithoutRefunds => { + crate::vm_m5::vm_with_bootloader::MAX_GAS_PER_PUBDATA_BYTE + } + VmVersion::M6Initial | VmVersion::M6BugWithCompressionFixed => { + crate::vm_m6::vm_with_bootloader::MAX_GAS_PER_PUBDATA_BYTE + } + VmVersion::Vm1_3_2 => crate::vm_1_3_2::vm_with_bootloader::MAX_GAS_PER_PUBDATA_BYTE, + VmVersion::VmVirtualBlocks => crate::vm_virtual_blocks::constants::MAX_GAS_PER_PUBDATA_BYTE, + VmVersion::VmVirtualBlocksRefundsEnhancement => { + crate::vm_refunds_enhancement::constants::MAX_GAS_PER_PUBDATA_BYTE + } + VmVersion::VmBoojumIntegration => { + crate::vm_boojum_integration::constants::MAX_GAS_PER_PUBDATA_BYTE + } + VmVersion::Vm1_4_1 => crate::vm_latest::constants::MAX_GAS_PER_PUBDATA_BYTE, + } +} + +pub fn get_used_bootloader_memory_bytes(version: VmVersion) -> usize { + match version { + VmVersion::M5WithRefunds | VmVersion::M5WithoutRefunds => { + crate::vm_m5::vm_with_bootloader::USED_BOOTLOADER_MEMORY_BYTES + } + VmVersion::M6Initial | VmVersion::M6BugWithCompressionFixed => { + crate::vm_m6::vm_with_bootloader::USED_BOOTLOADER_MEMORY_BYTES + } + VmVersion::Vm1_3_2 => crate::vm_1_3_2::vm_with_bootloader::USED_BOOTLOADER_MEMORY_BYTES, + VmVersion::VmVirtualBlocks => { + crate::vm_virtual_blocks::constants::USED_BOOTLOADER_MEMORY_BYTES + } + VmVersion::VmVirtualBlocksRefundsEnhancement => { + crate::vm_refunds_enhancement::constants::USED_BOOTLOADER_MEMORY_BYTES + } + VmVersion::VmBoojumIntegration => { + crate::vm_boojum_integration::constants::USED_BOOTLOADER_MEMORY_BYTES + } + VmVersion::Vm1_4_1 => crate::vm_latest::constants::USED_BOOTLOADER_MEMORY_BYTES, + } +} + +pub fn get_used_bootloader_memory_words(version: VmVersion) -> usize { + match version { + VmVersion::M5WithRefunds | VmVersion::M5WithoutRefunds => { + crate::vm_m5::vm_with_bootloader::USED_BOOTLOADER_MEMORY_WORDS + } + VmVersion::M6Initial | VmVersion::M6BugWithCompressionFixed => { + crate::vm_m6::vm_with_bootloader::USED_BOOTLOADER_MEMORY_WORDS + } + VmVersion::Vm1_3_2 => crate::vm_1_3_2::vm_with_bootloader::USED_BOOTLOADER_MEMORY_WORDS, + VmVersion::VmVirtualBlocks => { + crate::vm_virtual_blocks::constants::USED_BOOTLOADER_MEMORY_WORDS + } + VmVersion::VmVirtualBlocksRefundsEnhancement => { + crate::vm_refunds_enhancement::constants::USED_BOOTLOADER_MEMORY_WORDS + } + VmVersion::VmBoojumIntegration => { + crate::vm_boojum_integration::constants::USED_BOOTLOADER_MEMORY_WORDS + } + VmVersion::Vm1_4_1 => crate::vm_latest::constants::USED_BOOTLOADER_MEMORY_WORDS, + } +} diff --git a/core/lib/multivm/src/versions/README.md b/core/lib/multivm/src/versions/README.md index a7a4a18c5169..01c575091974 100644 --- a/core/lib/multivm/src/versions/README.md +++ b/core/lib/multivm/src/versions/README.md @@ -4,3 +4,14 @@ This folder contains the old versions of the VM we have used in the past. The `m switch the version we use to be able to sync from the genesis. This is a temporary measure until a "native" solution is implemented (i.e., the `vm` crate would itself know the changes between versions, and thus we will have only the functional diff between versions, not several fully-fledged VMs). + +## Versions + +| Name | Protocol versions | Description | +| ---------------------- | ----------------- | --------------------------------------------------------------------- | +| vm_m5 | 0 - 3 | Release for the testnet launch | +| vm_m6 | 4 - 6 | Release for the mainnet launch | +| vm_1_3_2 | 7 - 12 | Release 1.3.2 of the crypto circuits | +| vm_virtual_blocks | 13 - 15 | Adding virtual blocks to help with block number / timestamp migration | +| vm_refunds_enhancement | 16 - 17 | Fixing issue related to refunds in VM | +| vm_boojum_integration | 18 - | New Proving system (boojum), vm version 1.4.0 | diff --git a/core/lib/multivm/src/versions/mod.rs b/core/lib/multivm/src/versions/mod.rs index 71379f6df5c4..0fc9111aa9a2 100644 --- a/core/lib/multivm/src/versions/mod.rs +++ b/core/lib/multivm/src/versions/mod.rs @@ -1,4 +1,5 @@ pub mod vm_1_3_2; +pub mod vm_boojum_integration; pub mod vm_latest; pub mod vm_m5; pub mod vm_m6; diff --git a/core/lib/multivm/src/versions/vm_1_3_2/errors/tx_revert_reason.rs b/core/lib/multivm/src/versions/vm_1_3_2/errors/tx_revert_reason.rs index 4775d8339f79..3ddaa0684614 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/errors/tx_revert_reason.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/errors/tx_revert_reason.rs @@ -7,11 +7,11 @@ use super::{BootloaderErrorCode, VmRevertReason}; // Reasons why the transaction executed inside the bootloader could fail. #[derive(Debug, Clone, PartialEq)] pub enum TxRevertReason { - // Can only be returned in EthCall execution mode (=ExecuteOnly) + // Can only be returned in EthCall execution mode `(=ExecuteOnly)` EthCall(VmRevertReason), // Returned when the execution of an L2 transaction has failed TxReverted(VmRevertReason), - // Can only be returned in VerifyAndExecute + // Can only be returned in `VerifyAndExecute` ValidationFailed(VmRevertReason), PaymasterValidationFailed(VmRevertReason), PrePaymasterPreparationFailed(VmRevertReason), @@ -20,7 +20,7 @@ pub enum TxRevertReason { FailedToChargeFee(VmRevertReason), // Emitted when trying to call a transaction from an account that has not // been deployed as an account (i.e. the `from` is just a contract). - // Can only be returned in VerifyAndExecute + // Can only be returned in `VerifyAndExecute` FromIsNotAnAccount, // Currently cannot be returned. Should be removed when refactoring errors. InnerTxError, @@ -101,7 +101,7 @@ impl TxRevertReason { BootloaderErrorCode::UnacceptablePubdataPrice => { Self::UnexpectedVMBehavior("UnacceptablePubdataPrice".to_owned()) } - // This is different from AccountTxValidationFailed error in a way that it means that + // This is different from `AccountTxValidationFailed` error in a way that it means that // the error was not produced by the account itself, but for some other unknown reason (most likely not enough gas) BootloaderErrorCode::TxValidationError => Self::ValidationFailed(revert_reason), // Note, that `InnerTxError` is derived only after the actual tx execution, so diff --git a/core/lib/multivm/src/versions/vm_1_3_2/errors/vm_revert_reason.rs b/core/lib/multivm/src/versions/vm_1_3_2/errors/vm_revert_reason.rs index 70c954425f46..ed17ffc4c39b 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/errors/vm_revert_reason.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/errors/vm_revert_reason.rs @@ -73,7 +73,7 @@ impl VmRevertReason { pub fn to_user_friendly_string(&self) -> String { match self { - // In case of `Unknown` reason we suppress it to prevent verbose Error function_selector = 0x{} + // In case of `Unknown` reason we suppress it to prevent verbose `Error function_selector = 0x{}` // message shown to user. VmRevertReason::Unknown { .. } => "".to_owned(), _ => self.to_string(), diff --git a/core/lib/multivm/src/versions/vm_1_3_2/event_sink.rs b/core/lib/multivm/src/versions/vm_1_3_2/event_sink.rs index cbf7c183d3a7..b9aea7e09afc 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/event_sink.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/event_sink.rs @@ -50,7 +50,7 @@ impl InMemoryEventSink { pub fn log_queries_after_timestamp(&self, from_timestamp: Timestamp) -> &[Box] { let events = self.frames_stack.forward().current_frame(); - // Select all of the last elements where e.timestamp >= from_timestamp. + // Select all of the last elements where `e.timestamp >= from_timestamp`. // Note, that using binary search here is dangerous, because the logs are not sorted by timestamp. events .rsplit(|e| e.timestamp < from_timestamp) diff --git a/core/lib/multivm/src/versions/vm_1_3_2/history_recorder.rs b/core/lib/multivm/src/versions/vm_1_3_2/history_recorder.rs index 263c1f023dd2..bb3c12580c4f 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/history_recorder.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/history_recorder.rs @@ -12,14 +12,14 @@ use zksync_utils::{h256_to_u256, u256_to_h256}; pub type MemoryWithHistory = HistoryRecorder; pub type IntFrameManagerWithHistory = HistoryRecorder, H>; -// Within the same cycle, timestamps in range timestamp..timestamp+TIME_DELTA_PER_CYCLE-1 +// Within the same cycle, timestamps in range `timestamp..timestamp+TIME_DELTA_PER_CYCLE-1` // can be used. This can sometimes violate monotonicity of the timestamp within the // same cycle, so it should be normalized. #[inline] fn normalize_timestamp(timestamp: Timestamp) -> Timestamp { let timestamp = timestamp.0; - // Making sure it is divisible by TIME_DELTA_PER_CYCLE + // Making sure it is divisible by `TIME_DELTA_PER_CYCLE` Timestamp(timestamp - timestamp % zkevm_opcode_defs::TIME_DELTA_PER_CYCLE) } diff --git a/core/lib/multivm/src/versions/vm_1_3_2/memory.rs b/core/lib/multivm/src/versions/vm_1_3_2/memory.rs index 91fdbe223d8b..c9f97c0c2254 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/memory.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/memory.rs @@ -282,7 +282,7 @@ impl Memory for SimpleMemory { let returndata_page = returndata_fat_pointer.memory_page; for &page in current_observable_pages { - // If the page's number is greater than or equal to the base_page, + // If the page's number is greater than or equal to the `base_page`, // it means that it was created by the internal calls of this contract. // We need to add this check as the calldata pointer is also part of the // observable pages. @@ -299,7 +299,7 @@ impl Memory for SimpleMemory { } } -// It is expected that there is some intersection between [word_number*32..word_number*32+31] and [start, end] +// It is expected that there is some intersection between `[word_number*32..word_number*32+31]` and `[start, end]` fn extract_needed_bytes_from_word( word_value: Vec, word_number: usize, @@ -307,7 +307,7 @@ fn extract_needed_bytes_from_word( end: usize, ) -> Vec { let word_start = word_number * 32; - let word_end = word_start + 31; // Note, that at word_start + 32 a new word already starts + let word_end = word_start + 31; // Note, that at `word_start + 32` a new word already starts let intersection_left = std::cmp::max(word_start, start); let intersection_right = std::cmp::min(word_end, end); diff --git a/core/lib/multivm/src/versions/vm_1_3_2/mod.rs b/core/lib/multivm/src/versions/vm_1_3_2/mod.rs index 37c5f34ffd0e..45fb0cfa388f 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/mod.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/mod.rs @@ -10,7 +10,6 @@ pub use self::{ oracle_tools::OracleTools, oracles::storage::StorageOracle, vm::Vm, - vm_instance::{VmBlockResult, VmExecutionResult}, }; mod bootloader_state; @@ -24,8 +23,6 @@ pub mod oracles; mod pubdata_utils; mod refunds; pub mod test_utils; -#[cfg(test)] -mod tests; pub mod transaction_data; pub mod utils; mod vm; diff --git a/core/lib/multivm/src/versions/vm_1_3_2/oracles/decommitter.rs b/core/lib/multivm/src/versions/vm_1_3_2/oracles/decommitter.rs index d58b501b244d..8bf0e70026b8 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/oracles/decommitter.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/oracles/decommitter.rs @@ -15,7 +15,7 @@ use crate::vm_1_3_2::history_recorder::{ HistoryEnabled, HistoryMode, HistoryRecorder, WithHistory, }; -/// The main job of the DecommiterOracle is to implement the DecommittmentProcessor trait - that is +/// The main job of the DecommiterOracle is to implement the DecommitmentProcessor trait - that is /// used by the VM to 'load' bytecodes into memory. #[derive(Debug)] pub struct DecommitterOracle { diff --git a/core/lib/multivm/src/versions/vm_1_3_2/oracles/mod.rs b/core/lib/multivm/src/versions/vm_1_3_2/oracles/mod.rs index 08eb1c6e1747..59b0601e1483 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/oracles/mod.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/oracles/mod.rs @@ -1,9 +1,9 @@ use zk_evm_1_3_3::aux_structures::Timestamp; // All the changes to the events in the DB will be applied after the tx is executed, -// so fow now it is fine. +// so for now it is fine. pub use zk_evm_1_3_3::reference_impls::event_sink::InMemoryEventSink as EventSinkOracle; // We will discard RAM as soon as the execution of a tx ends, so -// it is ok for now to use SimpleMemory +// it is ok for now to use `SimpleMemory` pub use zk_evm_1_3_3::reference_impls::memory::SimpleMemory as RamOracle; pub use zk_evm_1_3_3::testing::simple_tracer::NoopTracer; diff --git a/core/lib/multivm/src/versions/vm_1_3_2/oracles/storage.rs b/core/lib/multivm/src/versions/vm_1_3_2/oracles/storage.rs index ea2ecf83a3d6..3b72f89fcbd6 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/oracles/storage.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/oracles/storage.rs @@ -7,15 +7,18 @@ use zk_evm_1_3_3::{ }; use zksync_state::{StoragePtr, WriteStorage}; use zksync_types::{ - utils::storage_key_for_eth_balance, AccountTreeId, Address, StorageKey, StorageLogQuery, - StorageLogQueryType, BOOTLOADER_ADDRESS, U256, + utils::storage_key_for_eth_balance, AccountTreeId, Address, StorageKey, StorageLogQueryType, + BOOTLOADER_ADDRESS, U256, }; use zksync_utils::u256_to_h256; use super::OracleWithHistory; -use crate::vm_1_3_2::history_recorder::{ - AppDataFrameManagerWithHistory, HashMapHistoryEvent, HistoryEnabled, HistoryMode, - HistoryRecorder, StorageWrapper, WithHistory, +use crate::vm_1_3_2::{ + history_recorder::{ + AppDataFrameManagerWithHistory, HashMapHistoryEvent, HistoryEnabled, HistoryMode, + HistoryRecorder, StorageWrapper, WithHistory, + }, + utils::StorageLogQuery, }; // While the storage does not support different shards, it was decided to write the @@ -167,14 +170,14 @@ impl StorageOracle { ) -> &[Box] { let logs = self.frames_stack.forward().current_frame(); - // Select all of the last elements where l.log_query.timestamp >= from_timestamp. + // Select all of the last elements where `l.log_query.timestamp >= from_timestamp`. // Note, that using binary search here is dangerous, because the logs are not sorted by timestamp. logs.rsplit(|l| l.log_query.timestamp < from_timestamp) .next() .unwrap_or(&[]) } - pub fn get_final_log_queries(&self) -> Vec { + pub(crate) fn get_final_log_queries(&self) -> Vec { assert_eq!( self.frames_stack.len(), 1, @@ -208,13 +211,14 @@ impl StorageOracle { } impl VmStorageOracle for StorageOracle { - // Perform a storage read/write access by taking an partially filled query + // Perform a storage read / write access by taking an partially filled query // and returning filled query and cold/warm marker for pricing purposes fn execute_partial_query( &mut self, _monotonic_cycle_counter: u32, query: LogQuery, ) -> LogQuery { + // ``` // tracing::trace!( // "execute partial query cyc {:?} addr {:?} key {:?}, rw {:?}, wr {:?}, tx {:?}", // _monotonic_cycle_counter, @@ -224,6 +228,7 @@ impl VmStorageOracle for StorageOracle { // query.written_value, // query.tx_number_in_block // ); + // ``` assert!(!query.rollback); if query.rw_flag { // The number of bytes that have been compensated by the user to perform this write @@ -303,7 +308,7 @@ impl VmStorageOracle for StorageOracle { ); // Additional validation that the current value was correct - // Unwrap is safe because the return value from write_inner is the previous value in this leaf. + // Unwrap is safe because the return value from `write_inner` is the previous value in this leaf. // It is impossible to set leaf value to `None` assert_eq!(current_value, written_value); } @@ -317,8 +322,8 @@ impl VmStorageOracle for StorageOracle { /// Returns the number of bytes needed to publish a slot. // Since we need to publish the state diffs onchain, for each of the updated storage slot -// we basically need to publish the following pair: (). -// While new_value is always 32 bytes long, for key we use the following optimization: +// we basically need to publish the following pair: `()`. +// While `new_value` is always 32 bytes long, for key we use the following optimization: // - The first time we publish it, we use 32 bytes. // Then, we remember a 8-byte id for this slot and assign it to it. We call this initial write. // - The second time we publish it, we will use this 8-byte instead of the 32 bytes of the entire key. diff --git a/core/lib/multivm/src/versions/vm_1_3_2/oracles/tracer/bootloader.rs b/core/lib/multivm/src/versions/vm_1_3_2/oracles/tracer/bootloader.rs index 3bc80f311194..fac4a74a1ebd 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/oracles/tracer/bootloader.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/oracles/tracer/bootloader.rs @@ -100,7 +100,7 @@ impl PubdataSpentTracer for BootloaderTracer { impl BootloaderTracer { fn current_frame_is_bootloader(local_state: &VmLocalState) -> bool { - // The current frame is bootloader if the callstack depth is 1. + // The current frame is bootloader if the call stack depth is 1. // Some of the near calls inside the bootloader can be out of gas, which is totally normal behavior // and it shouldn't result in `is_bootloader_out_of_gas` becoming true. local_state.callstack.inner.len() == 1 diff --git a/core/lib/multivm/src/versions/vm_1_3_2/oracles/tracer/call.rs b/core/lib/multivm/src/versions/vm_1_3_2/oracles/tracer/call.rs index 88b21818fc34..8160f5911a9e 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/oracles/tracer/call.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/oracles/tracer/call.rs @@ -5,18 +5,20 @@ use zk_evm_1_3_3::{ AfterDecodingData, AfterExecutionData, BeforeExecutionData, Tracer, VmLocalStateData, }, zkevm_opcode_defs::{ - FarCallABI, FarCallOpcode, FatPointer, Opcode, RetOpcode, - CALL_IMPLICIT_CALLDATA_FAT_PTR_REGISTER, RET_IMPLICIT_RETURNDATA_PARAMS_REGISTER, + FarCallABI, FatPointer, Opcode, RetOpcode, CALL_IMPLICIT_CALLDATA_FAT_PTR_REGISTER, + RET_IMPLICIT_RETURNDATA_PARAMS_REGISTER, }, }; use zksync_system_constants::CONTRACT_DEPLOYER_ADDRESS; use zksync_types::{ vm_trace::{Call, CallType}, + zk_evm_types::FarCallOpcode, U256, }; -use crate::vm_1_3_2::{ - errors::VmRevertReason, history_recorder::HistoryMode, memory::SimpleMemory, +use crate::{ + glue::GlueInto, + vm_1_3_2::{errors::VmRevertReason, history_recorder::HistoryMode, memory::SimpleMemory}, }; /// NOTE Auto implementing clone for this tracer can cause stack overflow. @@ -69,7 +71,7 @@ impl Tracer for CallTracer { ) { let call_type = match data.opcode.variant.opcode { Opcode::NearCall(_) => CallType::NearCall, - Opcode::FarCall(far_call) => CallType::Call(far_call), + Opcode::FarCall(far_call) => CallType::Call(far_call.glue_into()), Opcode::Ret(ret_code) => { self.handle_ret_op_code(state, data, memory, ret_code); return; @@ -188,7 +190,7 @@ impl CallTracer { let fat_data_pointer = state.vm_local_state.registers[RET_IMPLICIT_RETURNDATA_PARAMS_REGISTER as usize]; - // if fat_data_pointer is not a pointer then there is no output + // if `fat_data_pointer` is not a pointer then there is no output let output = if fat_data_pointer.is_pointer { let fat_data_pointer = FatPointer::from_u256(fat_data_pointer.value); if !fat_data_pointer.is_trivial() { @@ -255,8 +257,8 @@ impl CallTracer { // Filter all near calls from the call stack // Important that the very first call is near call - // And this NearCall includes several Normal or Mimic calls - // So we return all childrens of this NearCall + // And this `NearCall` includes several Normal or Mimic calls + // So we return all children of this `NearCall` pub fn extract_calls(&mut self) -> Vec { if let Some(current_call) = self.stack.pop() { filter_near_call(current_call) @@ -267,7 +269,7 @@ impl CallTracer { } // Filter all near calls from the call stack -// Normally wr are not interested in NearCall, because it's just a wrapper for internal calls +// Normally we are not interested in `NearCall`, because it's just a wrapper for internal calls fn filter_near_call(mut call: Call) -> Vec { let mut calls = vec![]; let original_calls = std::mem::take(&mut call.calls); @@ -285,7 +287,7 @@ fn filter_near_call(mut call: Call) -> Vec { #[cfg(test)] mod tests { - use zk_evm_1_3_3::zkevm_opcode_defs::FarCallOpcode; + use zksync_types::zk_evm_types::FarCallOpcode; use crate::vm_1_3_2::oracles::tracer::call::{filter_near_call, Call, CallType}; diff --git a/core/lib/multivm/src/versions/vm_1_3_2/oracles/tracer/one_tx.rs b/core/lib/multivm/src/versions/vm_1_3_2/oracles/tracer/one_tx.rs index 896befb8abc5..9bf5a9b7d224 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/oracles/tracer/one_tx.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/oracles/tracer/one_tx.rs @@ -19,7 +19,7 @@ use crate::vm_1_3_2::{ }; /// Allows any opcodes, but tells the VM to end the execution once the tx is over. -// Internally depeds on Bootloader's VMHooks to get the notification once the transaction is finished. +// Internally depends on Bootloader's `VMHooks` to get the notification once the transaction is finished. #[derive(Debug)] pub struct OneTxTracer { tx_has_been_processed: bool, diff --git a/core/lib/multivm/src/versions/vm_1_3_2/oracles/tracer/utils.rs b/core/lib/multivm/src/versions/vm_1_3_2/oracles/tracer/utils.rs index 76890b042de1..5ee8d8554b65 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/oracles/tracer/utils.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/oracles/tracer/utils.rs @@ -48,7 +48,7 @@ impl VmHook { let value = data.src1_value.value; - // Only UMA opcodes in the bootloader serve for vm hooks + // Only `UMA` opcodes in the bootloader serve for vm hooks if !matches!(opcode_variant.opcode, Opcode::UMA(UMAOpcode::HeapWrite)) || heap_page != BOOTLOADER_HEAP_PAGE || fat_ptr.offset != VM_HOOK_POSITION * 32 diff --git a/core/lib/multivm/src/versions/vm_1_3_2/oracles/tracer/validation.rs b/core/lib/multivm/src/versions/vm_1_3_2/oracles/tracer/validation.rs index d3308c7ea2dc..caea2688bb99 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/oracles/tracer/validation.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/oracles/tracer/validation.rs @@ -100,7 +100,7 @@ fn touches_allowed_context(address: Address, key: U256) -> bool { return false; } - // Only chain_id is allowed to be touched. + // Only `chain_id` is allowed to be touched. key == U256::from(0u32) } @@ -223,7 +223,7 @@ impl ValidationTracer { return true; } - // The pair of MSG_VALUE_SIMULATOR_ADDRESS & L2_ETH_TOKEN_ADDRESS simulates the behavior of transferring ETH + // The pair of `MSG_VALUE_SIMULATOR_ADDRESS` & `L2_ETH_TOKEN_ADDRESS` simulates the behavior of transferring ETH // that is safe for the DDoS protection rules. if valid_eth_token_call(address, msg_sender) { return true; @@ -267,20 +267,20 @@ impl ValidationTracer { let (potential_address_bytes, potential_position_bytes) = calldata.split_at(32); let potential_address = be_bytes_to_safe_address(potential_address_bytes); - // If the validation_address is equal to the potential_address, - // then it is a request that could be used for mapping of kind mapping(address => ...). + // If the `validation_address` is equal to the `potential_address`, + // then it is a request that could be used for mapping of kind `mapping(address => ...)`. // - // If the potential_position_bytes were already allowed before, then this keccak might be used - // for ERC-20 allowance or any other of mapping(address => mapping(...)) + // If the `potential_position_bytes` were already allowed before, then this keccak might be used + // for ERC-20 allowance or any other of `mapping(address => mapping(...))` if potential_address == Some(validated_address) || self .auxilary_allowed_slots .contains(&H256::from_slice(potential_position_bytes)) { - // This is request that could be used for mapping of kind mapping(address => ...) + // This is request that could be used for mapping of kind `mapping(address => ...)` // We could theoretically wait for the slot number to be returned by the - // keccak256 precompile itself, but this would complicate the code even further + // `keccak256` precompile itself, but this would complicate the code even further // so let's calculate it here. let slot = keccak256(calldata); diff --git a/core/lib/multivm/src/versions/vm_1_3_2/pubdata_utils.rs b/core/lib/multivm/src/versions/vm_1_3_2/pubdata_utils.rs index 23d42fc2b5a3..517077bd6a2a 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/pubdata_utils.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/pubdata_utils.rs @@ -1,10 +1,10 @@ use std::collections::HashMap; use zk_evm_1_3_3::aux_structures::Timestamp; +use zkevm_test_harness_1_3_3::witness::sort_storage_access::sort_storage_access_queries; use zksync_state::WriteStorage; use zksync_types::{ event::{extract_long_l2_to_l1_messages, extract_published_bytecodes}, - zkevm_test_harness::witness::sort_storage_access::sort_storage_access_queries, StorageKey, PUBLISH_BYTECODE_OVERHEAD, SYSTEM_CONTEXT_ADDRESS, }; use zksync_utils::bytecode::bytecode_len_in_bytes; diff --git a/core/lib/multivm/src/versions/vm_1_3_2/refunds.rs b/core/lib/multivm/src/versions/vm_1_3_2/refunds.rs index 9de2ee9676bf..555dd0f643ea 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/refunds.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/refunds.rs @@ -76,7 +76,7 @@ impl VmInstance { ) -> u32 { // TODO (SMA-1715): Make users pay for the block overhead 0 - + // ``` // let pubdata_published = self.pubdata_published(from_timestamp); // // let total_gas_spent = gas_remaining_before - self.gas_remaining(); @@ -121,6 +121,7 @@ impl VmInstance { // ); // 0 // } + // ``` } // TODO (SMA-1715): Make users pay for the block overhead @@ -134,39 +135,39 @@ impl VmInstance { _l2_l1_logs: usize, ) -> u32 { 0 - + // ``` // let overhead_for_block_gas = U256::from(crate::transaction_data::block_overhead_gas( // gas_per_pubdata_byte_limit, // )); - + // // let encoded_len = U256::from(encoded_len); // let pubdata_published = U256::from(pubdata_published); // let gas_spent_on_computation = U256::from(gas_spent_on_computation); // let number_of_decommitment_requests = U256::from(number_of_decommitment_requests); // let l2_l1_logs = U256::from(l2_l1_logs); - + // // let tx_slot_overhead = ceil_div_u256(overhead_for_block_gas, MAX_TXS_IN_BLOCK.into()); - + // // let overhead_for_length = ceil_div_u256( // encoded_len * overhead_for_block_gas, // BOOTLOADER_TX_ENCODING_SPACE.into(), // ); - + // // let actual_overhead_for_pubdata = ceil_div_u256( // pubdata_published * overhead_for_block_gas, // MAX_PUBDATA_PER_BLOCK.into(), // ); - + // // let actual_gas_limit_overhead = ceil_div_u256( // gas_spent_on_computation * overhead_for_block_gas, // MAX_BLOCK_MULTIINSTANCE_GAS_LIMIT.into(), // ); - + // // let code_decommitter_sorter_circuit_overhead = ceil_div_u256( // number_of_decommitment_requests * overhead_for_block_gas, // GEOMETRY_CONFIG.limit_for_code_decommitter_sorter.into(), // ); - + // // let l1_l2_logs_overhead = ceil_div_u256( // l2_l1_logs * overhead_for_block_gas, // std::cmp::min( @@ -175,7 +176,7 @@ impl VmInstance { // ) // .into(), // ); - + // // let overhead = vec![ // tx_slot_overhead, // overhead_for_length, @@ -187,8 +188,9 @@ impl VmInstance { // .into_iter() // .max() // .unwrap(); - + // // overhead.as_u32() + // ``` } /// Returns the given transactions' gas limit - by reading it directly from the VM memory. diff --git a/core/lib/multivm/src/versions/vm_1_3_2/test_utils.rs b/core/lib/multivm/src/versions/vm_1_3_2/test_utils.rs index c3aa161543aa..3c4367232aac 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/test_utils.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/test_utils.rs @@ -20,8 +20,7 @@ use zksync_types::{ fee::Fee, l2::L2Tx, web3::signing::keccak256, - Execute, L2ChainId, Nonce, StorageKey, StorageLogQuery, StorageValue, - CONTRACT_DEPLOYER_ADDRESS, H256, U256, + Execute, L2ChainId, Nonce, StorageKey, StorageValue, CONTRACT_DEPLOYER_ADDRESS, H256, U256, }; use zksync_utils::{ address_to_h256, bytecode::hash_bytecode, h256_to_account_address, u256_to_h256, @@ -34,6 +33,7 @@ use crate::vm_1_3_2::{ AppDataFrameManagerWithHistory, HistoryEnabled, HistoryMode, HistoryRecorder, }, memory::SimpleMemory, + utils::StorageLogQuery, vm_instance::ZkSyncVmState, VmInstance, }; @@ -69,7 +69,7 @@ pub struct DecommitterTestInnerState { } #[derive(Clone, PartialEq, Debug)] -pub struct StorageOracleInnerState { +pub(crate) struct StorageOracleInnerState { /// There is no way to "truly" compare the storage pointer, /// so we just compare the modified keys. This is reasonable enough. pub modified_storage_keys: ModifiedKeysMap, diff --git a/core/lib/multivm/src/versions/vm_1_3_2/tests/bootloader.rs b/core/lib/multivm/src/versions/vm_1_3_2/tests/bootloader.rs deleted file mode 100644 index b42c17363b0a..000000000000 --- a/core/lib/multivm/src/versions/vm_1_3_2/tests/bootloader.rs +++ /dev/null @@ -1,2144 +0,0 @@ -// //! -// //! Tests for the bootloader -// //! The description for each of the tests can be found in the corresponding `.yul` file. -// //! -// use itertools::Itertools; -// use std::{ -// collections::{HashMap, HashSet}, -// convert::{TryFrom, TryInto}, -// }; -// use zksync_eth_signer::{raw_ethereum_tx::TransactionParameters, EthereumSigner, PrivateKeySigner}; - -// use crate::{ -// errors::VmRevertReason, -// history_recorder::HistoryMode, -// oracles::tracer::{StorageInvocationTracer, TransactionResultTracer}, -// test_utils::{ -// get_create_zksync_address, get_deploy_tx, get_error_tx, mock_loadnext_test_call, -// verify_required_storage, -// }, -// tests::utils::{ -// get_l1_deploy_tx, get_l1_execute_test_contract_tx_with_sender, read_error_contract, -// read_long_return_data_contract, read_test_contract, -// }, -// transaction_data::TransactionData, -// utils::{ -// create_test_block_params, read_bootloader_test_code, BASE_SYSTEM_CONTRACTS, BLOCK_GAS_LIMIT, -// }, -// vm::{tx_has_failed, VmExecutionStopReason, ZkSyncVmState}, -// vm_with_bootloader::{ -// bytecode_to_factory_dep, get_bootloader_memory, get_bootloader_memory_for_encoded_tx, -// push_raw_transaction_to_bootloader_memory, BlockContext, BlockContextMode, -// BootloaderJobType, TxExecutionMode, -// }, -// vm_with_bootloader::{ -// init_vm_inner, push_transaction_to_bootloader_memory, DerivedBlockContext, -// BOOTLOADER_HEAP_PAGE, TX_DESCRIPTION_OFFSET, TX_GAS_LIMIT_OFFSET, -// }, -// HistoryEnabled, OracleTools, TxRevertReason, VmBlockResult, VmExecutionResult, VmInstance, -// }; - -// use zk_evm_1_3_3::{ -// aux_structures::Timestamp, block_properties::BlockProperties, zkevm_opcode_defs::FarCallOpcode, -// }; -// use zksync_state::{InMemoryStorage, ReadStorage, StoragePtr, StorageView, WriteStorage}; -// use zksync_types::{ -// block::DeployedContract, -// ethabi::encode, -// ethabi::Token, -// fee::Fee, -// get_code_key, get_is_account_key, get_known_code_key, get_nonce_key, -// l2::L2Tx, -// l2_to_l1_log::L2ToL1Log, -// storage_writes_deduplicator::StorageWritesDeduplicator, -// system_contracts::{DEPLOYMENT_NONCE_INCREMENT, TX_NONCE_INCREMENT}, -// transaction_request::TransactionRequest, -// tx::tx_execution_info::TxExecutionStatus, -// utils::{ -// deployed_address_create, storage_key_for_eth_balance, -// storage_key_for_standard_token_balance, -// }, -// vm_trace::{Call, CallType}, -// AccountTreeId, Address, Eip712Domain, Execute, ExecuteTransactionCommon, L1TxCommonData, -// L2ChainId, Nonce, PackedEthSignature, Transaction, BOOTLOADER_ADDRESS, H160, H256, -// L1_MESSENGER_ADDRESS, L2_ETH_TOKEN_ADDRESS, MAX_GAS_PER_PUBDATA_BYTE, -// REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE, SYSTEM_CONTEXT_ADDRESS, U256, -// }; -// use zksync_utils::{ -// bytecode::CompressedBytecodeInfo, -// test_utils::LoadnextContractExecutionParams, -// {bytecode::hash_bytecode, bytes_to_be_words, h256_to_u256, u256_to_h256}, -// }; - -// use zksync_contracts::{ -// get_loadnext_contract, load_contract, SystemContractCode, PLAYGROUND_BLOCK_BOOTLOADER_CODE, -// }; - -// use super::utils::{read_many_owners_custom_account_contract, read_nonce_holder_tester}; -// /// Helper struct for tests, that takes care of setting the database and provides some functions to get and set balances. -// /// Example use: -// ///```ignore -// /// let test_env = VmTestEnv::default(); -// /// test_env.set_rich_account(address); -// /// // To create VM and run a single transaction: -// /// test_env.run_vm_or_die(transaction_data); -// /// // To create VM: -// /// let mut helper = VmTestHelper::new(&test_env); -// /// let mut vm = helper.vm(); -// /// ``` -// #[derive(Debug)] -// pub struct VmTestEnv { -// pub block_context: DerivedBlockContext, -// pub block_properties: BlockProperties, -// pub storage_ptr: Box>, -// } - -// impl VmTestEnv { -// /// Creates a new test helper with a bunch of already deployed contracts. -// pub fn new_with_contracts(contracts: &[(H160, Vec)]) -> Self { -// let (block_context, block_properties): (DerivedBlockContext, BlockProperties) = { -// let (block_context, block_properties) = create_test_block_params(); -// (block_context.into(), block_properties) -// }; - -// let mut raw_storage = InMemoryStorage::with_system_contracts(hash_bytecode); -// for (address, bytecode) in contracts { -// let account = DeployedContract { -// account_id: AccountTreeId::new(*address), -// bytecode: bytecode.clone(), -// }; - -// insert_contracts(&mut raw_storage, vec![(account, true)]); -// } - -// let storage_ptr = Box::new(StorageView::new(raw_storage)); - -// VmTestEnv { -// block_context, -// block_properties, -// storage_ptr, -// } -// } - -// /// Gets the current ETH balance for a given account. -// pub fn get_eth_balance(&mut self, address: &H160) -> U256 { -// get_eth_balance(address, self.storage_ptr.as_mut()) -// } - -// /// Sets a large balance for a given account. -// pub fn set_rich_account(&mut self, address: &H160) { -// let key = storage_key_for_eth_balance(address); - -// self.storage_ptr -// .set_value(key, u256_to_h256(U256::from(10u64.pow(19)))); -// } - -// /// Runs a given transaction in a VM. -// // Note: that storage changes will be preserved, but not changed to events etc. -// // Strongly suggest to use this function only if this is the only transaction executed within the test. -// pub fn run_vm(&mut self, transaction_data: TransactionData) -> (VmExecutionResult, bool) { -// let mut oracle_tools = OracleTools::new(self.storage_ptr.as_mut(), HistoryEnabled); -// let (result, tx_has_failed) = run_vm_with_raw_tx( -// &mut oracle_tools, -// self.block_context, -// &self.block_properties, -// transaction_data, -// ); -// (result, tx_has_failed) -// } - -// /// Runs a given transaction in a VM and asserts if it fails. -// pub fn run_vm_or_die(&mut self, transaction_data: TransactionData) { -// let (result, tx_has_failed) = self.run_vm(transaction_data); -// assert!( -// !tx_has_failed, -// "Transaction failed with: {:?}", -// result.revert_reason -// ); -// } -// } - -// impl Default for VmTestEnv { -// fn default() -> Self { -// VmTestEnv::new_with_contracts(&[]) -// } -// } - -// /// Helper struct to create a default VM for a given environment. -// #[derive(Debug)] -// pub struct VmTestHelper<'a> { -// pub oracle_tools: OracleTools<'a, false, HistoryEnabled>, -// pub block_context: DerivedBlockContext, -// pub block_properties: BlockProperties, -// vm_created: bool, -// } - -// impl<'a> VmTestHelper<'a> { -// pub fn new(test_env: &'a mut VmTestEnv) -> Self { -// let block_context = test_env.block_context; -// let block_properties = test_env.block_properties; - -// let oracle_tools = OracleTools::new(test_env.storage_ptr.as_mut(), HistoryEnabled); -// VmTestHelper { -// oracle_tools, -// block_context, -// block_properties, -// vm_created: false, -// } -// } - -// /// Creates the VM that can be used in tests. -// pub fn vm(&'a mut self) -> Box> { -// assert!(!self.vm_created, "Vm can be created only once"); -// let vm = init_vm_inner( -// &mut self.oracle_tools, -// BlockContextMode::NewBlock(self.block_context, Default::default()), -// &self.block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); -// self.vm_created = true; -// vm -// } -// } - -// fn run_vm_with_custom_factory_deps<'a, H: HistoryMode>( -// oracle_tools: &'a mut OracleTools<'a, false, H>, -// block_context: BlockContext, -// block_properties: &'a BlockProperties, -// encoded_tx: Vec, -// predefined_overhead: u32, -// expected_error: Option, -// ) { -// let mut base_system_contracts = BASE_SYSTEM_CONTRACTS.clone(); -// base_system_contracts.bootloader = PLAYGROUND_BLOCK_BOOTLOADER_CODE.clone(); -// let mut vm = init_vm_inner( -// oracle_tools, -// BlockContextMode::OverrideCurrent(block_context.into()), -// block_properties, -// BLOCK_GAS_LIMIT, -// &base_system_contracts, -// TxExecutionMode::VerifyExecute, -// ); - -// vm.bootloader_state.add_tx_data(encoded_tx.len()); -// vm.state.memory.populate_page( -// BOOTLOADER_HEAP_PAGE as usize, -// get_bootloader_memory_for_encoded_tx( -// encoded_tx, -// 0, -// TxExecutionMode::VerifyExecute, -// 0, -// 0, -// predefined_overhead, -// u32::MAX, -// 0, -// vec![], -// ), -// Timestamp(0), -// ); - -// let result = vm.execute_next_tx(u32::MAX, false).err(); - -// assert_eq!(expected_error, result); -// } - -// fn get_balance(token_id: AccountTreeId, account: &Address, main_storage: StoragePtr) -> U256 { -// let key = storage_key_for_standard_token_balance(token_id, account); -// h256_to_u256(main_storage.borrow_mut().read_value(&key)) -// } - -// fn get_eth_balance(account: &Address, main_storage: &mut StorageView) -> U256 { -// let key = -// storage_key_for_standard_token_balance(AccountTreeId::new(L2_ETH_TOKEN_ADDRESS), account); -// h256_to_u256(main_storage.read_value(&key)) -// } - -// #[test] -// fn test_dummy_bootloader() { -// let mut vm_test_env = VmTestEnv::default(); -// let mut oracle_tools = OracleTools::new(vm_test_env.storage_ptr.as_mut(), HistoryEnabled); -// let mut base_system_contracts = BASE_SYSTEM_CONTRACTS.clone(); -// let bootloader_code = read_bootloader_test_code("dummy"); -// let bootloader_hash = hash_bytecode(&bootloader_code); - -// base_system_contracts.bootloader = SystemContractCode { -// code: bytes_to_be_words(bootloader_code), -// hash: bootloader_hash, -// }; - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(vm_test_env.block_context, Default::default()), -// &vm_test_env.block_properties, -// BLOCK_GAS_LIMIT, -// &base_system_contracts, -// TxExecutionMode::VerifyExecute, -// ); - -// let VmBlockResult { -// full_result: res, .. -// } = vm.execute_till_block_end(BootloaderJobType::BlockPostprocessing); - -// // Dummy bootloader should not panic -// assert!(res.revert_reason.is_none()); - -// let correct_first_cell = U256::from_str_radix("123123123", 16).unwrap(); - -// verify_required_memory( -// &vm.state, -// vec![(correct_first_cell, BOOTLOADER_HEAP_PAGE, 0)], -// ); -// } - -// #[test] -// fn test_bootloader_out_of_gas() { -// let mut vm_test_env = VmTestEnv::default(); -// let mut oracle_tools = OracleTools::new(vm_test_env.storage_ptr.as_mut(), HistoryEnabled); - -// let mut base_system_contracts = BASE_SYSTEM_CONTRACTS.clone(); - -// let bootloader_code = read_bootloader_test_code("dummy"); -// let bootloader_hash = hash_bytecode(&bootloader_code); - -// base_system_contracts.bootloader = SystemContractCode { -// code: bytes_to_be_words(bootloader_code), -// hash: bootloader_hash, -// }; - -// // init vm with only 10 ergs -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(vm_test_env.block_context, Default::default()), -// &vm_test_env.block_properties, -// 10, -// &base_system_contracts, -// TxExecutionMode::VerifyExecute, -// ); - -// let res = vm.execute_block_tip(); - -// assert_eq!(res.revert_reason, Some(TxRevertReason::BootloaderOutOfGas)); -// } - -// fn verify_required_memory( -// state: &ZkSyncVmState<'_, H>, -// required_values: Vec<(U256, u32, u32)>, -// ) { -// for (required_value, memory_page, cell) in required_values { -// let current_value = state -// .memory -// .read_slot(memory_page as usize, cell as usize) -// .value; -// assert_eq!(current_value, required_value); -// } -// } - -// #[test] -// fn test_default_aa_interaction() { -// // In this test, we aim to test whether a simple account interaction (without any fee logic) -// // will work. The account will try to deploy a simple contract from integration tests. - -// let mut vm_test_env = VmTestEnv::default(); - -// let operator_address = vm_test_env.block_context.context.operator_address; -// let base_fee = vm_test_env.block_context.base_fee; -// // We deploy here counter contract, because its logic is trivial -// let contract_code = read_test_contract(); -// let contract_code_hash = hash_bytecode(&contract_code); -// let tx: Transaction = get_deploy_tx( -// H256::random(), -// Nonce(0), -// &contract_code, -// vec![], -// &[], -// Fee { -// gas_limit: U256::from(20000000u32), -// max_fee_per_gas: U256::from(base_fee), -// max_priority_fee_per_gas: U256::from(0), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); -// let tx_data: TransactionData = tx.clone().into(); - -// let maximal_fee = tx_data.gas_limit * tx_data.max_fee_per_gas; -// let sender_address = tx_data.from(); - -// vm_test_env.set_rich_account(&sender_address); - -// let mut vm_helper = VmTestHelper::new(&mut vm_test_env); -// let mut vm = vm_helper.vm(); - -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); - -// let tx_execution_result = vm -// .execute_next_tx(u32::MAX, false) -// .expect("Bootloader failed while processing transaction"); - -// assert_eq!( -// tx_execution_result.status, -// TxExecutionStatus::Success, -// "Transaction wasn't successful" -// ); - -// let VmBlockResult { -// full_result: res, .. -// } = vm.execute_till_block_end(BootloaderJobType::TransactionExecution); -// // Should not panic -// assert!( -// res.revert_reason.is_none(), -// "Bootloader was not expected to revert: {:?}", -// res.revert_reason -// ); - -// // Both deployment and ordinary nonce should be incremented by one. -// let account_nonce_key = get_nonce_key(&sender_address); -// let expected_nonce = TX_NONCE_INCREMENT + DEPLOYMENT_NONCE_INCREMENT; - -// // The code hash of the deployed contract should be marked as republished. -// let known_codes_key = get_known_code_key(&contract_code_hash); - -// // The contract should be deployed successfully. -// let deployed_address = deployed_address_create(sender_address, U256::zero()); -// let account_code_key = get_code_key(&deployed_address); - -// let expected_slots = vec![ -// (u256_to_h256(expected_nonce), account_nonce_key), -// (u256_to_h256(U256::from(1u32)), known_codes_key), -// (contract_code_hash, account_code_key), -// ]; - -// verify_required_storage(&vm.state, expected_slots); - -// assert!(!tx_has_failed(&vm.state, 0)); - -// let expected_fee = -// maximal_fee - U256::from(tx_execution_result.gas_refunded) * U256::from(base_fee); -// let operator_balance = get_balance( -// AccountTreeId::new(L2_ETH_TOKEN_ADDRESS), -// &operator_address, -// vm.state.storage.storage.get_ptr(), -// ); - -// assert_eq!( -// operator_balance, expected_fee, -// "Operator did not receive his fee" -// ); -// } - -// fn execute_vm_with_predetermined_refund( -// txs: Vec, -// refunds: Vec, -// compressed_bytecodes: Vec>, -// ) -> VmBlockResult { -// let mut vm_test_env = VmTestEnv::default(); -// let block_context = vm_test_env.block_context; - -// for tx in txs.iter() { -// let sender_address = tx.initiator_account(); -// vm_test_env.set_rich_account(&sender_address); -// } - -// let mut vm_helper = VmTestHelper::new(&mut vm_test_env); -// let mut vm = vm_helper.vm(); - -// let codes_for_decommiter = txs -// .iter() -// .flat_map(|tx| { -// tx.execute -// .factory_deps -// .clone() -// .unwrap_or_default() -// .iter() -// .map(|dep| bytecode_to_factory_dep(dep.clone())) -// .collect::)>>() -// }) -// .collect(); - -// vm.state.decommittment_processor.populate( -// codes_for_decommiter, -// Timestamp(vm.state.local_state.timestamp), -// ); - -// let memory_with_suggested_refund = get_bootloader_memory( -// txs.into_iter().map(Into::into).collect(), -// refunds, -// compressed_bytecodes, -// TxExecutionMode::VerifyExecute, -// BlockContextMode::NewBlock(block_context, Default::default()), -// ); - -// vm.state.memory.populate_page( -// BOOTLOADER_HEAP_PAGE as usize, -// memory_with_suggested_refund, -// Timestamp(0), -// ); - -// vm.execute_till_block_end(BootloaderJobType::TransactionExecution) -// } - -// #[test] -// fn test_predetermined_refunded_gas() { -// // In this test, we compare the execution of the bootloader with the predefined -// // refunded gas and without them - -// let mut vm_test_env = VmTestEnv::default(); -// let base_fee = vm_test_env.block_context.base_fee; - -// // We deploy here counter contract, because its logic is trivial -// let contract_code = read_test_contract(); -// let published_bytecode = CompressedBytecodeInfo::from_original(contract_code.clone()).unwrap(); -// let tx: Transaction = get_deploy_tx( -// H256::random(), -// Nonce(0), -// &contract_code, -// vec![], -// &[], -// Fee { -// gas_limit: U256::from(20000000u32), -// max_fee_per_gas: U256::from(base_fee), -// max_priority_fee_per_gas: U256::from(0), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); - -// let sender_address = tx.initiator_account(); - -// // set balance -// vm_test_env.set_rich_account(&sender_address); - -// let mut vm_helper = VmTestHelper::new(&mut vm_test_env); -// let mut vm = vm_helper.vm(); - -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); - -// let tx_execution_result = vm -// .execute_next_tx(u32::MAX, false) -// .expect("Bootloader failed while processing transaction"); - -// assert_eq!( -// tx_execution_result.status, -// TxExecutionStatus::Success, -// "Transaction wasn't successful" -// ); - -// // If the refund provided by the operator or the final refund are the 0 -// // there is no impact of the operator's refund at all and so this test does not -// // make much sense. -// assert!( -// tx_execution_result.operator_suggested_refund > 0, -// "The operator's refund is 0" -// ); -// assert!( -// tx_execution_result.gas_refunded > 0, -// "The final refund is 0" -// ); - -// let mut result = vm.execute_till_block_end(BootloaderJobType::TransactionExecution); -// assert!( -// result.full_result.revert_reason.is_none(), -// "Bootloader was not expected to revert: {:?}", -// result.full_result.revert_reason -// ); - -// let mut result_with_predetermined_refund = execute_vm_with_predetermined_refund( -// vec![tx], -// vec![tx_execution_result.operator_suggested_refund], -// vec![vec![published_bytecode]], -// ); -// // We need to sort these lists as those are flattened from HashMaps -// result.full_result.used_contract_hashes.sort(); -// result_with_predetermined_refund -// .full_result -// .used_contract_hashes -// .sort(); - -// assert_eq!( -// result.full_result.events, -// result_with_predetermined_refund.full_result.events -// ); -// assert_eq!( -// result.full_result.l2_to_l1_logs, -// result_with_predetermined_refund.full_result.l2_to_l1_logs -// ); -// assert_eq!( -// result.full_result.storage_log_queries, -// result_with_predetermined_refund -// .full_result -// .storage_log_queries -// ); -// assert_eq!( -// result.full_result.used_contract_hashes, -// result_with_predetermined_refund -// .full_result -// .used_contract_hashes -// ); -// } - -// #[derive(Debug, Clone)] -// enum TransactionRollbackTestInfo { -// Rejected(Transaction, TxRevertReason), -// Processed(Transaction, bool, TxExecutionStatus), -// } - -// impl TransactionRollbackTestInfo { -// fn new_rejected(transaction: Transaction, revert_reason: TxRevertReason) -> Self { -// Self::Rejected(transaction, revert_reason) -// } - -// fn new_processed( -// transaction: Transaction, -// should_be_rollbacked: bool, -// expected_status: TxExecutionStatus, -// ) -> Self { -// Self::Processed(transaction, should_be_rollbacked, expected_status) -// } - -// fn get_transaction(&self) -> &Transaction { -// match self { -// TransactionRollbackTestInfo::Rejected(tx, _) => tx, -// TransactionRollbackTestInfo::Processed(tx, _, _) => tx, -// } -// } - -// fn rejection_reason(&self) -> Option { -// match self { -// TransactionRollbackTestInfo::Rejected(_, revert_reason) => Some(revert_reason.clone()), -// TransactionRollbackTestInfo::Processed(_, _, _) => None, -// } -// } - -// fn should_rollback(&self) -> bool { -// match self { -// TransactionRollbackTestInfo::Rejected(_, _) => true, -// TransactionRollbackTestInfo::Processed(_, x, _) => *x, -// } -// } - -// fn expected_status(&self) -> TxExecutionStatus { -// match self { -// TransactionRollbackTestInfo::Rejected(_, _) => { -// panic!("There is no execution status for rejected transaction") -// } -// TransactionRollbackTestInfo::Processed(_, _, status) => *status, -// } -// } -// } - -// // Accepts the address of the sender as well as the list of pairs of its transactions -// // and whether these transactions should succeed. -// fn execute_vm_with_possible_rollbacks( -// sender_address: Address, -// transactions: Vec, -// block_context: DerivedBlockContext, -// block_properties: BlockProperties, -// ) -> VmExecutionResult { -// let mut vm_test_env = VmTestEnv { -// block_context, -// block_properties, -// ..Default::default() -// }; - -// // Setting infinite balance for the sender. -// vm_test_env.set_rich_account(&sender_address); - -// let mut vm_helper = VmTestHelper::new(&mut vm_test_env); -// let mut vm = vm_helper.vm(); - -// for test_info in transactions { -// vm.save_current_vm_as_snapshot(); -// let vm_state_before_tx = vm.dump_inner_state(); -// push_transaction_to_bootloader_memory( -// &mut vm, -// test_info.get_transaction(), -// TxExecutionMode::VerifyExecute, -// None, -// ); - -// match vm.execute_next_tx(u32::MAX, false) { -// Err(reason) => { -// assert_eq!(test_info.rejection_reason(), Some(reason)); -// } -// Ok(res) => { -// assert_eq!(test_info.rejection_reason(), None); -// assert_eq!( -// res.status, -// test_info.expected_status(), -// "Transaction status is not correct" -// ); -// } -// }; - -// if test_info.should_rollback() { -// // Some error has occurred, we should reject the transaction -// vm.rollback_to_latest_snapshot(); - -// // vm_state_before_tx. -// let state_after_rollback = vm.dump_inner_state(); -// assert_eq!( -// vm_state_before_tx, state_after_rollback, -// "Did not rollback VM state correctly" -// ); -// } -// } - -// let VmBlockResult { -// full_result: mut result, -// .. -// } = vm.execute_till_block_end(BootloaderJobType::BlockPostprocessing); -// // Used contract hashes are retrieved in unordered manner. -// // However it must be sorted for the comparisons in tests to work -// result.used_contract_hashes.sort(); - -// result -// } - -// // Sets the signature for an L2 transaction and returns the same transaction -// // but this different signature. -// fn change_signature(mut tx: Transaction, signature: Vec) -> Transaction { -// tx.common_data = match tx.common_data { -// ExecuteTransactionCommon::L2(mut data) => { -// data.signature = signature; -// ExecuteTransactionCommon::L2(data) -// } -// _ => unreachable!(), -// }; - -// tx -// } - -// #[test] -// fn test_vm_rollbacks() { -// let (block_context, block_properties): (DerivedBlockContext, BlockProperties) = { -// let (block_context, block_properties) = create_test_block_params(); -// (block_context.into(), block_properties) -// }; - -// let base_fee = U256::from(block_context.base_fee); - -// let sender_private_key = H256::random(); -// let contract_code = read_test_contract(); - -// let tx_nonce_0: Transaction = get_deploy_tx( -// sender_private_key, -// Nonce(0), -// &contract_code, -// vec![], -// &[], -// Fee { -// gas_limit: U256::from(12000000u32), -// max_fee_per_gas: base_fee, -// max_priority_fee_per_gas: U256::zero(), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); -// let tx_nonce_1: Transaction = get_deploy_tx( -// sender_private_key, -// Nonce(1), -// &contract_code, -// vec![], -// &[], -// Fee { -// gas_limit: U256::from(12000000u32), -// max_fee_per_gas: base_fee, -// max_priority_fee_per_gas: U256::zero(), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); -// let tx_nonce_2: Transaction = get_deploy_tx( -// sender_private_key, -// Nonce(2), -// &contract_code, -// vec![], -// &[], -// Fee { -// gas_limit: U256::from(12000000u32), -// max_fee_per_gas: base_fee, -// max_priority_fee_per_gas: U256::zero(), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); - -// let wrong_signature_length_tx = change_signature(tx_nonce_0.clone(), vec![1u8; 32]); -// let wrong_v_tx = change_signature(tx_nonce_0.clone(), vec![1u8; 65]); -// let wrong_signature_tx = change_signature(tx_nonce_0.clone(), vec![27u8; 65]); - -// let sender_address = tx_nonce_0.initiator_account(); - -// let result_without_rollbacks = execute_vm_with_possible_rollbacks( -// sender_address, -// vec![ -// // The nonces are ordered correctly, all the transactions should succeed. -// TransactionRollbackTestInfo::new_processed( -// tx_nonce_0.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// TransactionRollbackTestInfo::new_processed( -// tx_nonce_1.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// TransactionRollbackTestInfo::new_processed( -// tx_nonce_2.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// ], -// block_context, -// block_properties, -// ); - -// let incorrect_nonce = TxRevertReason::ValidationFailed(VmRevertReason::General { -// msg: "Incorrect nonce".to_string(), -// data: vec![ -// 8, 195, 121, 160, 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, 32, 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, 15, 73, 110, 99, 111, 114, 114, 101, 99, 116, 32, 110, -// 111, 110, 99, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -// ], -// }); -// let reusing_nonce_twice = TxRevertReason::ValidationFailed(VmRevertReason::General { -// msg: "Reusing the same nonce twice".to_string(), -// data: vec![ -// 8, 195, 121, 160, 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, 32, 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, 28, 82, 101, 117, 115, 105, 110, 103, 32, 116, 104, -// 101, 32, 115, 97, 109, 101, 32, 110, 111, 110, 99, 101, 32, 116, 119, 105, 99, 101, 0, -// 0, 0, 0, -// ], -// }); -// let signature_length_is_incorrect = TxRevertReason::ValidationFailed(VmRevertReason::General { -// msg: "Signature length is incorrect".to_string(), -// data: vec![ -// 8, 195, 121, 160, 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, 32, 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, 29, 83, 105, 103, 110, 97, 116, 117, 114, 101, 32, -// 108, 101, 110, 103, 116, 104, 32, 105, 115, 32, 105, 110, 99, 111, 114, 114, 101, 99, -// 116, 0, 0, 0, -// ], -// }); -// let v_is_incorrect = TxRevertReason::ValidationFailed(VmRevertReason::General { -// msg: "v is neither 27 nor 28".to_string(), -// data: vec![ -// 8, 195, 121, 160, 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, 32, 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, 22, 118, 32, 105, 115, 32, 110, 101, 105, 116, 104, -// 101, 114, 32, 50, 55, 32, 110, 111, 114, 32, 50, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -// ], -// }); -// let signature_is_incorrect = TxRevertReason::ValidationFailed(VmRevertReason::General { -// msg: "Account validation returned invalid magic value. Most often this means that the signature is incorrect".to_string(), -// data: vec![], -// }); - -// let result_with_rollbacks = execute_vm_with_possible_rollbacks( -// sender_address, -// vec![ -// TransactionRollbackTestInfo::new_rejected( -// wrong_signature_length_tx, -// signature_length_is_incorrect, -// ), -// TransactionRollbackTestInfo::new_rejected(wrong_v_tx, v_is_incorrect), -// TransactionRollbackTestInfo::new_rejected(wrong_signature_tx, signature_is_incorrect), -// // The correct nonce is 0, this tx will fail -// TransactionRollbackTestInfo::new_rejected(tx_nonce_2.clone(), incorrect_nonce.clone()), -// // This tx will succeed -// TransactionRollbackTestInfo::new_processed( -// tx_nonce_0.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// // The correct nonce is 1, this tx will fail -// TransactionRollbackTestInfo::new_rejected( -// tx_nonce_0.clone(), -// reusing_nonce_twice.clone(), -// ), -// // The correct nonce is 1, this tx will fail -// TransactionRollbackTestInfo::new_rejected(tx_nonce_2.clone(), incorrect_nonce), -// // This tx will succeed -// TransactionRollbackTestInfo::new_processed( -// tx_nonce_1, -// false, -// TxExecutionStatus::Success, -// ), -// // The correct nonce is 2, this tx will fail -// TransactionRollbackTestInfo::new_rejected(tx_nonce_0, reusing_nonce_twice.clone()), -// // This tx will succeed -// TransactionRollbackTestInfo::new_processed( -// tx_nonce_2.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// // This tx will fail -// TransactionRollbackTestInfo::new_rejected(tx_nonce_2, reusing_nonce_twice.clone()), -// ], -// block_context, -// block_properties, -// ); - -// assert_eq!(result_without_rollbacks, result_with_rollbacks); - -// let loadnext_contract = get_loadnext_contract(); - -// let loadnext_constructor_data = encode(&[Token::Uint(U256::from(100))]); -// let loadnext_deploy_tx: Transaction = get_deploy_tx( -// sender_private_key, -// Nonce(0), -// &loadnext_contract.bytecode, -// loadnext_contract.factory_deps, -// &loadnext_constructor_data, -// Fee { -// gas_limit: U256::from(70000000u32), -// max_fee_per_gas: base_fee, -// max_priority_fee_per_gas: U256::zero(), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); -// let loadnext_contract_address = -// get_create_zksync_address(loadnext_deploy_tx.initiator_account(), Nonce(0)); -// let deploy_loadnext_tx_info = TransactionRollbackTestInfo::new_processed( -// loadnext_deploy_tx, -// false, -// TxExecutionStatus::Success, -// ); - -// let get_load_next_tx = |params: LoadnextContractExecutionParams, nonce: Nonce| { -// // Here we test loadnext with various kinds of operations -// let tx: Transaction = mock_loadnext_test_call( -// sender_private_key, -// nonce, -// loadnext_contract_address, -// Fee { -// gas_limit: U256::from(100000000u32), -// max_fee_per_gas: base_fee, -// max_priority_fee_per_gas: U256::zero(), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// params, -// ) -// .into(); - -// tx -// }; - -// let loadnext_tx_0 = get_load_next_tx( -// LoadnextContractExecutionParams { -// reads: 100, -// writes: 100, -// events: 100, -// hashes: 500, -// recursive_calls: 10, -// deploys: 60, -// }, -// Nonce(1), -// ); -// let loadnext_tx_1 = get_load_next_tx( -// LoadnextContractExecutionParams { -// reads: 100, -// writes: 100, -// events: 100, -// hashes: 500, -// recursive_calls: 10, -// deploys: 60, -// }, -// Nonce(2), -// ); - -// let result_without_rollbacks = execute_vm_with_possible_rollbacks( -// sender_address, -// vec![ -// deploy_loadnext_tx_info.clone(), -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_0.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_1.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// ], -// block_context, -// block_properties, -// ); - -// let result_with_rollbacks = execute_vm_with_possible_rollbacks( -// sender_address, -// vec![ -// deploy_loadnext_tx_info, -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_0.clone(), -// true, -// TxExecutionStatus::Success, -// ), -// // After the previous tx has been rolled back, this one should succeed -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_0.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// // The nonce has been bumped up, this transaction should now fail -// TransactionRollbackTestInfo::new_rejected(loadnext_tx_0, reusing_nonce_twice.clone()), -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_1.clone(), -// true, -// TxExecutionStatus::Success, -// ), -// // After the previous tx has been rolled back, this one should succeed -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_1.clone(), -// true, -// TxExecutionStatus::Success, -// ), -// // After the previous tx has been rolled back, this one should succeed -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_1.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// // The nonce has been bumped up, this transaction should now fail -// TransactionRollbackTestInfo::new_rejected(loadnext_tx_1, reusing_nonce_twice), -// ], -// block_context, -// block_properties, -// ); - -// assert_eq!(result_without_rollbacks, result_with_rollbacks); -// } - -// // Inserts the contracts into the test environment, bypassing the -// // deployer system contract. Besides the reference to storage -// // it accepts a `contracts` tuple of information about the contract -// // and whether or not it is an account. -// fn insert_contracts(raw_storage: &mut InMemoryStorage, contracts: Vec<(DeployedContract, bool)>) { -// for (contract, is_account) in contracts { -// let deployer_code_key = get_code_key(contract.account_id.address()); -// raw_storage.set_value(deployer_code_key, hash_bytecode(&contract.bytecode)); - -// if is_account { -// let is_account_key = get_is_account_key(contract.account_id.address()); -// raw_storage.set_value(is_account_key, u256_to_h256(1_u32.into())); -// } - -// raw_storage.store_factory_dep(hash_bytecode(&contract.bytecode), contract.bytecode); -// } -// } - -// enum NonceHolderTestMode { -// SetValueUnderNonce, -// IncreaseMinNonceBy5, -// IncreaseMinNonceTooMuch, -// LeaveNonceUnused, -// IncreaseMinNonceBy1, -// SwitchToArbitraryOrdering, -// } - -// impl From for u8 { -// fn from(mode: NonceHolderTestMode) -> u8 { -// match mode { -// NonceHolderTestMode::SetValueUnderNonce => 0, -// NonceHolderTestMode::IncreaseMinNonceBy5 => 1, -// NonceHolderTestMode::IncreaseMinNonceTooMuch => 2, -// NonceHolderTestMode::LeaveNonceUnused => 3, -// NonceHolderTestMode::IncreaseMinNonceBy1 => 4, -// NonceHolderTestMode::SwitchToArbitraryOrdering => 5, -// } -// } -// } - -// fn get_nonce_holder_test_tx( -// nonce: U256, -// account_address: Address, -// test_mode: NonceHolderTestMode, -// block_context: &DerivedBlockContext, -// ) -> TransactionData { -// TransactionData { -// tx_type: 113, -// from: account_address, -// to: account_address, -// gas_limit: U256::from(10000000u32), -// pubdata_price_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// max_fee_per_gas: U256::from(block_context.base_fee), -// max_priority_fee_per_gas: U256::zero(), -// nonce, -// // The reserved fields that are unique for different types of transactions. -// // E.g. nonce is currently used in all transaction, but it should not be mandatory -// // in the long run. -// reserved: [U256::zero(); 4], -// data: vec![12], -// signature: vec![test_mode.into()], - -// ..Default::default() -// } -// } - -// fn run_vm_with_raw_tx<'a, H: HistoryMode>( -// oracle_tools: &'a mut OracleTools<'a, false, H>, -// block_context: DerivedBlockContext, -// block_properties: &'a BlockProperties, -// tx: TransactionData, -// ) -> (VmExecutionResult, bool) { -// let mut base_system_contracts = BASE_SYSTEM_CONTRACTS.clone(); -// base_system_contracts.bootloader = PLAYGROUND_BLOCK_BOOTLOADER_CODE.clone(); -// let mut vm = init_vm_inner( -// oracle_tools, -// BlockContextMode::OverrideCurrent(block_context), -// block_properties, -// BLOCK_GAS_LIMIT, -// &base_system_contracts, -// TxExecutionMode::VerifyExecute, -// ); - -// let block_gas_price_per_pubdata = block_context.context.block_gas_price_per_pubdata(); - -// let overhead = tx.overhead_gas(block_gas_price_per_pubdata as u32); -// push_raw_transaction_to_bootloader_memory( -// &mut vm, -// tx, -// TxExecutionMode::VerifyExecute, -// overhead, -// None, -// ); -// let VmBlockResult { -// full_result: result, -// .. -// } = vm.execute_till_block_end(BootloaderJobType::TransactionExecution); - -// (result, tx_has_failed(&vm.state, 0)) -// } - -// #[test] -// fn test_nonce_holder() { -// let account_address = H160::random(); -// let mut vm_test_env = -// VmTestEnv::new_with_contracts(&[(account_address, read_nonce_holder_tester())]); - -// vm_test_env.set_rich_account(&account_address); - -// let mut run_nonce_test = |nonce: U256, -// test_mode: NonceHolderTestMode, -// error_message: Option, -// comment: &'static str| { -// let tx = get_nonce_holder_test_tx( -// nonce, -// account_address, -// test_mode, -// &vm_test_env.block_context, -// ); - -// let (result, tx_has_failed) = vm_test_env.run_vm(tx); -// if let Some(msg) = error_message { -// let expected_error = -// TxRevertReason::ValidationFailed(VmRevertReason::General { msg, data: vec![] }); -// assert_eq!( -// result -// .revert_reason -// .expect("No revert reason") -// .revert_reason -// .to_string(), -// expected_error.to_string(), -// "{}", -// comment -// ); -// } else { -// assert!(!tx_has_failed, "{}", comment); -// } -// }; - -// // Test 1: trying to set value under non sequential nonce value. -// run_nonce_test( -// 1u32.into(), -// NonceHolderTestMode::SetValueUnderNonce, -// Some("Previous nonce has not been used".to_string()), -// "Allowed to set value under non sequential value", -// ); - -// // Test 2: increase min nonce by 1 with sequential nonce ordering: -// run_nonce_test( -// 0u32.into(), -// NonceHolderTestMode::IncreaseMinNonceBy1, -// None, -// "Failed to increment nonce by 1 for sequential account", -// ); - -// // Test 3: correctly set value under nonce with sequential nonce ordering: -// run_nonce_test( -// 1u32.into(), -// NonceHolderTestMode::SetValueUnderNonce, -// None, -// "Failed to set value under nonce sequential value", -// ); - -// // Test 5: migrate to the arbitrary nonce ordering: -// run_nonce_test( -// 2u32.into(), -// NonceHolderTestMode::SwitchToArbitraryOrdering, -// None, -// "Failed to switch to arbitrary ordering", -// ); - -// // Test 6: increase min nonce by 5 -// run_nonce_test( -// 6u32.into(), -// NonceHolderTestMode::IncreaseMinNonceBy5, -// None, -// "Failed to increase min nonce by 5", -// ); - -// // Test 7: since the nonces in range [6,10] are no longer allowed, the -// // tx with nonce 10 should not be allowed -// run_nonce_test( -// 10u32.into(), -// NonceHolderTestMode::IncreaseMinNonceBy5, -// Some("Reusing the same nonce twice".to_string()), -// "Allowed to reuse nonce below the minimal one", -// ); - -// // Test 8: we should be able to use nonce 13 -// run_nonce_test( -// 13u32.into(), -// NonceHolderTestMode::SetValueUnderNonce, -// None, -// "Did not allow to use unused nonce 10", -// ); - -// // Test 9: we should not be able to reuse nonce 13 -// run_nonce_test( -// 13u32.into(), -// NonceHolderTestMode::IncreaseMinNonceBy5, -// Some("Reusing the same nonce twice".to_string()), -// "Allowed to reuse the same nonce twice", -// ); - -// // Test 10: we should be able to simply use nonce 14, while bumping the minimal nonce by 5 -// run_nonce_test( -// 14u32.into(), -// NonceHolderTestMode::IncreaseMinNonceBy5, -// None, -// "Did not allow to use a bumped nonce", -// ); - -// // Test 6: Do not allow bumping nonce by too much -// run_nonce_test( -// 16u32.into(), -// NonceHolderTestMode::IncreaseMinNonceTooMuch, -// Some("The value for incrementing the nonce is too high".to_string()), -// "Allowed for incrementing min nonce too much", -// ); - -// // Test 7: Do not allow not setting a nonce as used -// run_nonce_test( -// 16u32.into(), -// NonceHolderTestMode::LeaveNonceUnused, -// Some("The nonce was not set as used".to_string()), -// "Allowed to leave nonce as unused", -// ); -// } - -// #[test] -// fn test_l1_tx_execution() { -// // In this test, we try to execute a contract deployment from L1 -// let mut vm_test_env = VmTestEnv::default(); -// let mut vm_helper = VmTestHelper::new(&mut vm_test_env); -// // Here instead of marking code hash via the bootloader means, we will -// // using L1->L2 communication, the same it would likely be done during the priority mode. -// let contract_code = read_test_contract(); -// let contract_code_hash = hash_bytecode(&contract_code); -// let l1_deploy_tx = get_l1_deploy_tx(&contract_code, &[]); -// let l1_deploy_tx_data: TransactionData = l1_deploy_tx.clone().into(); - -// let required_l2_to_l1_logs = vec![ -// L2ToL1Log { -// shard_id: 0, -// is_service: false, -// tx_number_in_block: 0, -// sender: SYSTEM_CONTEXT_ADDRESS, -// key: u256_to_h256(U256::from(vm_helper.block_context.context.block_timestamp)), -// value: Default::default(), -// }, -// L2ToL1Log { -// shard_id: 0, -// is_service: true, -// tx_number_in_block: 0, -// sender: BOOTLOADER_ADDRESS, -// key: l1_deploy_tx_data.canonical_l1_tx_hash(), -// value: u256_to_h256(U256::from(1u32)), -// }, -// ]; - -// let sender_address = l1_deploy_tx_data.from(); - -// vm_helper.oracle_tools.decommittment_processor.populate( -// vec![( -// h256_to_u256(contract_code_hash), -// bytes_to_be_words(contract_code), -// )], -// Timestamp(0), -// ); - -// let mut vm = vm_helper.vm(); - -// push_transaction_to_bootloader_memory( -// &mut vm, -// &l1_deploy_tx, -// TxExecutionMode::VerifyExecute, -// None, -// ); - -// let res = vm.execute_next_tx(u32::MAX, false).unwrap(); - -// // The code hash of the deployed contract should be marked as republished. -// let known_codes_key = get_known_code_key(&contract_code_hash); - -// // The contract should be deployed successfully. -// let deployed_address = deployed_address_create(sender_address, U256::zero()); -// let account_code_key = get_code_key(&deployed_address); - -// let expected_slots = vec![ -// (u256_to_h256(U256::from(1u32)), known_codes_key), -// (contract_code_hash, account_code_key), -// ]; -// assert!(!tx_has_failed(&vm.state, 0)); - -// verify_required_storage(&vm.state, expected_slots); - -// assert_eq!(res.result.logs.l2_to_l1_logs, required_l2_to_l1_logs); - -// let tx = get_l1_execute_test_contract_tx(deployed_address, true); -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); - -// let res = StorageWritesDeduplicator::apply_on_empty_state( -// &vm.execute_next_tx(u32::MAX, false) -// .unwrap() -// .result -// .logs -// .storage_logs, -// ); -// assert_eq!(res.initial_storage_writes, 0); - -// let tx = get_l1_execute_test_contract_tx(deployed_address, false); -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); -// let res = StorageWritesDeduplicator::apply_on_empty_state( -// &vm.execute_next_tx(u32::MAX, false) -// .unwrap() -// .result -// .logs -// .storage_logs, -// ); -// assert_eq!(res.initial_storage_writes, 2); - -// let repeated_writes = res.repeated_storage_writes; - -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); -// let res = StorageWritesDeduplicator::apply_on_empty_state( -// &vm.execute_next_tx(u32::MAX, false) -// .unwrap() -// .result -// .logs -// .storage_logs, -// ); -// assert_eq!(res.initial_storage_writes, 1); -// // We do the same storage write, so it will be deduplicated -// assert_eq!(res.repeated_storage_writes, repeated_writes); - -// let mut tx = get_l1_execute_test_contract_tx(deployed_address, false); -// tx.execute.value = U256::from(1); -// match &mut tx.common_data { -// ExecuteTransactionCommon::L1(l1_data) => { -// l1_data.to_mint = U256::from(4); -// } -// _ => unreachable!(), -// } -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); -// let execution_result = vm.execute_next_tx(u32::MAX, false).unwrap(); -// // The method is not payable, so the transaction with non-zero value should fail -// assert_eq!( -// execution_result.status, -// TxExecutionStatus::Failure, -// "The transaction should fail" -// ); - -// let res = -// StorageWritesDeduplicator::apply_on_empty_state(&execution_result.result.logs.storage_logs); - -// // There are 2 initial writes here: -// // - totalSupply of ETH token -// // - balance of the refund recipient -// assert_eq!(res.initial_storage_writes, 2); -// } - -// #[test] -// fn test_invalid_bytecode() { -// let mut vm_test_env = VmTestEnv::default(); - -// let block_gas_per_pubdata = vm_test_env -// .block_context -// .context -// .block_gas_price_per_pubdata(); - -// let mut test_vm_with_custom_bytecode_hash = -// |bytecode_hash: H256, expected_revert_reason: Option| { -// let mut oracle_tools = -// OracleTools::new(vm_test_env.storage_ptr.as_mut(), HistoryEnabled); - -// let (encoded_tx, predefined_overhead) = get_l1_tx_with_custom_bytecode_hash( -// h256_to_u256(bytecode_hash), -// block_gas_per_pubdata as u32, -// ); - -// run_vm_with_custom_factory_deps( -// &mut oracle_tools, -// vm_test_env.block_context.context, -// &vm_test_env.block_properties, -// encoded_tx, -// predefined_overhead, -// expected_revert_reason, -// ); -// }; - -// let failed_to_mark_factory_deps = |msg: &str, data: Vec| { -// TxRevertReason::FailedToMarkFactoryDependencies(VmRevertReason::General { -// msg: msg.to_string(), -// data, -// }) -// }; - -// // Here we provide the correctly-formatted bytecode hash of -// // odd length, so it should work. -// test_vm_with_custom_bytecode_hash( -// H256([ -// 1, 0, 0, 1, 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, -// ]), -// None, -// ); - -// // Here we provide correctly formatted bytecode of even length, so -// // it should fail. -// test_vm_with_custom_bytecode_hash( -// H256([ -// 1, 0, 2, 2, 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, -// ]), -// Some(failed_to_mark_factory_deps( -// "Code length in words must be odd", -// vec![ -// 8, 195, 121, 160, 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, 32, 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, 32, 67, 111, 100, 101, 32, 108, 101, 110, -// 103, 116, 104, 32, 105, 110, 32, 119, 111, 114, 100, 115, 32, 109, 117, 115, 116, -// 32, 98, 101, 32, 111, 100, 100, -// ], -// )), -// ); - -// // Here we provide incorrectly formatted bytecode of odd length, so -// // it should fail. -// test_vm_with_custom_bytecode_hash( -// H256([ -// 1, 1, 0, 1, 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, -// ]), -// Some(failed_to_mark_factory_deps( -// "Incorrectly formatted bytecodeHash", -// vec![ -// 8, 195, 121, 160, 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, 32, 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, 34, 73, 110, 99, 111, 114, 114, 101, 99, -// 116, 108, 121, 32, 102, 111, 114, 109, 97, 116, 116, 101, 100, 32, 98, 121, 116, -// 101, 99, 111, 100, 101, 72, 97, 115, 104, 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, -// ], -// )), -// ); - -// // Here we provide incorrectly formatted bytecode of odd length, so -// // it should fail. -// test_vm_with_custom_bytecode_hash( -// H256([ -// 2, 0, 0, 1, 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, -// ]), -// Some(failed_to_mark_factory_deps( -// "Incorrectly formatted bytecodeHash", -// vec![ -// 8, 195, 121, 160, 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, 32, 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, 34, 73, 110, 99, 111, 114, 114, 101, 99, -// 116, 108, 121, 32, 102, 111, 114, 109, 97, 116, 116, 101, 100, 32, 98, 121, 116, -// 101, 99, 111, 100, 101, 72, 97, 115, 104, 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, -// ], -// )), -// ); -// } - -// #[test] -// fn test_tracing_of_execution_errors() { -// // In this test, we are checking that the execution errors are transmitted correctly from the bootloader. -// let contract_address = Address::random(); - -// let mut vm_test_env = -// VmTestEnv::new_with_contracts(&[(contract_address, read_error_contract())]); - -// let private_key = H256::random(); - -// let tx = get_error_tx( -// private_key, -// Nonce(0), -// contract_address, -// Fee { -// gas_limit: U256::from(1000000u32), -// max_fee_per_gas: U256::from(10000000000u64), -// max_priority_fee_per_gas: U256::zero(), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ); - -// vm_test_env.set_rich_account(&tx.common_data.initiator_address); -// let mut vm_helper = VmTestHelper::new(&mut vm_test_env); -// let mut vm = vm_helper.vm(); - -// push_transaction_to_bootloader_memory( -// &mut vm, -// &tx.into(), -// TxExecutionMode::VerifyExecute, -// None, -// ); - -// let mut tracer = TransactionResultTracer::new(usize::MAX, false); -// assert_eq!( -// vm.execute_with_custom_tracer(&mut tracer), -// VmExecutionStopReason::VmFinished, -// "Tracer should never request stop" -// ); - -// match tracer.revert_reason { -// Some(revert_reason) => { -// let revert_reason = VmRevertReason::try_from(&revert_reason as &[u8]).unwrap(); -// assert_eq!( -// revert_reason, -// VmRevertReason::General { -// msg: "short".to_string(), -// data: vec![ -// 8, 195, 121, 160, 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, 32, 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, 5, 115, 104, 111, -// 114, 116, 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 -// ], -// } -// ) -// } -// _ => panic!( -// "Tracer captured incorrect result {:#?}", -// tracer.revert_reason -// ), -// } - -// let mut vm_helper = VmTestHelper::new(&mut vm_test_env); -// let mut vm = vm_helper.vm(); -// let tx = get_error_tx( -// private_key, -// Nonce(1), -// contract_address, -// Fee { -// gas_limit: U256::from(1000000u32), -// max_fee_per_gas: U256::from(10000000000u64), -// max_priority_fee_per_gas: U256::zero(), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ); -// push_transaction_to_bootloader_memory( -// &mut vm, -// &tx.into(), -// TxExecutionMode::VerifyExecute, -// None, -// ); - -// let mut tracer = TransactionResultTracer::new(10, false); -// assert_eq!( -// vm.execute_with_custom_tracer(&mut tracer), -// VmExecutionStopReason::TracerRequestedStop, -// ); -// assert!(tracer.is_limit_reached()); -// } - -// /// Checks that `TX_GAS_LIMIT_OFFSET` constant is correct. -// #[test] -// fn test_tx_gas_limit_offset() { -// let gas_limit = U256::from(999999); -// let mut vm_test_env = VmTestEnv::default(); - -// let contract_code = read_test_contract(); -// let tx: Transaction = get_deploy_tx( -// H256::random(), -// Nonce(0), -// &contract_code, -// Default::default(), -// Default::default(), -// Fee { -// gas_limit, -// ..Default::default() -// }, -// ) -// .into(); - -// let mut vm_helper = VmTestHelper::new(&mut vm_test_env); -// let mut vm = vm_helper.vm(); -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); - -// let gas_limit_from_memory = vm -// .state -// .memory -// .read_slot( -// BOOTLOADER_HEAP_PAGE as usize, -// TX_DESCRIPTION_OFFSET + TX_GAS_LIMIT_OFFSET, -// ) -// .value; -// assert_eq!(gas_limit_from_memory, gas_limit); -// } - -// #[test] -// fn test_is_write_initial_behaviour() { -// // In this test, we check result of `is_write_initial` at different stages. -// let mut vm_test_env = VmTestEnv::default(); - -// let base_fee = vm_test_env.block_context.base_fee; -// let account_pk = H256::random(); -// let contract_code = read_test_contract(); -// let tx: Transaction = get_deploy_tx( -// account_pk, -// Nonce(0), -// &contract_code, -// vec![], -// &[], -// Fee { -// gas_limit: U256::from(20000000u32), -// max_fee_per_gas: U256::from(base_fee), -// max_priority_fee_per_gas: U256::from(0), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); - -// let sender_address = tx.initiator_account(); -// let nonce_key = get_nonce_key(&sender_address); - -// // Check that the next write to the nonce key will be initial. -// assert!(vm_test_env.storage_ptr.is_write_initial(&nonce_key)); - -// // Set balance to be able to pay fee for txs. -// vm_test_env.set_rich_account(&sender_address); - -// let mut vm_helper = VmTestHelper::new(&mut vm_test_env); -// let mut vm = vm_helper.vm(); - -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); - -// vm.execute_next_tx(u32::MAX, false) -// .expect("Bootloader failed while processing the first transaction"); -// // Check that `is_write_initial` still returns true for the nonce key. -// assert!(vm_test_env.storage_ptr.is_write_initial(&nonce_key)); -// } - -// pub fn get_l1_tx_with_custom_bytecode_hash( -// bytecode_hash: U256, -// block_gas_per_pubdata: u32, -// ) -> (Vec, u32) { -// let tx: TransactionData = get_l1_execute_test_contract_tx(Default::default(), false).into(); -// let predefined_overhead = -// tx.overhead_gas_with_custom_factory_deps(vec![bytecode_hash], block_gas_per_pubdata); -// let tx_bytes = tx.abi_encode_with_custom_factory_deps(vec![bytecode_hash]); - -// (bytes_to_be_words(tx_bytes), predefined_overhead) -// } - -// pub fn get_l1_execute_test_contract_tx(deployed_address: Address, with_panic: bool) -> Transaction { -// let sender = H160::random(); -// get_l1_execute_test_contract_tx_with_sender( -// sender, -// deployed_address, -// with_panic, -// U256::zero(), -// false, -// ) -// } - -// pub fn get_l1_tx_with_large_output(sender: Address, deployed_address: Address) -> Transaction { -// let test_contract = load_contract( -// "etc/contracts-test-data/artifacts-zk/contracts/long-return-data/long-return-data.sol/LongReturnData.json", -// ); - -// let function = test_contract.function("longReturnData").unwrap(); - -// let calldata = function -// .encode_input(&[]) -// .expect("failed to encode parameters"); - -// Transaction { -// common_data: ExecuteTransactionCommon::L1(L1TxCommonData { -// sender, -// gas_limit: U256::from(100000000u32), -// gas_per_pubdata_limit: REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE.into(), -// ..Default::default() -// }), -// execute: Execute { -// contract_address: deployed_address, -// calldata, -// value: U256::zero(), -// factory_deps: None, -// }, -// received_timestamp_ms: 0, -// } -// } - -// #[test] -// fn test_call_tracer() { -// let mut vm_test_env = VmTestEnv::default(); - -// let sender = H160::random(); - -// let contract_code = read_test_contract(); -// let contract_code_hash = hash_bytecode(&contract_code); -// let l1_deploy_tx = get_l1_deploy_tx(&contract_code, &[]); -// let l1_deploy_tx_data: TransactionData = l1_deploy_tx.clone().into(); - -// let sender_address_counter = l1_deploy_tx_data.from(); - -// vm_test_env.set_rich_account(&sender_address_counter); -// let mut vm_helper = VmTestHelper::new(&mut vm_test_env); - -// vm_helper.oracle_tools.decommittment_processor.populate( -// vec![( -// h256_to_u256(contract_code_hash), -// bytes_to_be_words(contract_code), -// )], -// Timestamp(0), -// ); - -// let contract_code = read_long_return_data_contract(); -// let contract_code_hash = hash_bytecode(&contract_code); -// let l1_deploy_long_return_data_tx = get_l1_deploy_tx(&contract_code, &[]); -// vm_helper.oracle_tools.decommittment_processor.populate( -// vec![( -// h256_to_u256(contract_code_hash), -// bytes_to_be_words(contract_code), -// )], -// Timestamp(0), -// ); - -// let tx_data: TransactionData = l1_deploy_long_return_data_tx.clone().into(); -// let sender_long_return_address = tx_data.from(); -// // The contract should be deployed successfully. -// let deployed_address_long_return_data = -// deployed_address_create(sender_long_return_address, U256::zero()); -// let mut vm = vm_helper.vm(); - -// push_transaction_to_bootloader_memory( -// &mut vm, -// &l1_deploy_tx, -// TxExecutionMode::VerifyExecute, -// None, -// ); - -// // The contract should be deployed successfully. -// let deployed_address = deployed_address_create(sender_address_counter, U256::zero()); -// let res = vm.execute_next_tx(u32::MAX, true).unwrap(); -// let calls = res.call_traces; -// let mut create_call = None; -// // The first MIMIC call is call to value simulator. All calls goes through it. -// // The second MIMIC call is call to Deployer contract. -// // And only third level call is construct call to the newly deployed contract And we call it create_call. -// for call in &calls { -// if let CallType::Call(FarCallOpcode::Mimic) = call.r#type { -// for call in &call.calls { -// if let CallType::Call(FarCallOpcode::Mimic) = call.r#type { -// for call in &call.calls { -// if let CallType::Create = call.r#type { -// create_call = Some(call.clone()); -// } -// } -// } -// } -// } -// } -// let expected = Call { -// r#type: CallType::Create, -// to: deployed_address, -// from: sender_address_counter, -// parent_gas: 0, -// gas_used: 0, -// gas: 0, -// value: U256::zero(), -// input: vec![], -// output: vec![ -// 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, 32, 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, -// ], -// error: None, -// revert_reason: None, -// calls: vec![], -// }; -// assert_eq!(create_call.unwrap(), expected); - -// push_transaction_to_bootloader_memory( -// &mut vm, -// &l1_deploy_long_return_data_tx, -// TxExecutionMode::VerifyExecute, -// None, -// ); - -// vm.execute_next_tx(u32::MAX, false).unwrap(); - -// let tx = get_l1_execute_test_contract_tx_with_sender( -// sender, -// deployed_address, -// false, -// U256::from(1u8), -// true, -// ); - -// let tx_data: TransactionData = tx.clone().into(); -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); - -// let res = vm.execute_next_tx(u32::MAX, true).unwrap(); -// let calls = res.call_traces; - -// // We don't want to compare gas used, because it's not fully deterministic. -// let expected = Call { -// r#type: CallType::Call(FarCallOpcode::Mimic), -// to: deployed_address, -// from: tx_data.from(), -// parent_gas: 0, -// gas_used: 0, -// gas: 0, -// value: U256::from(1), -// input: tx_data.data, -// output: vec![ -// 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, 1, -// ], -// error: None, -// revert_reason: None, -// calls: vec![], -// }; - -// // First loop filter out the bootloaders calls and -// // the second loop filters out the calls msg value simulator calls -// for call in calls { -// if let CallType::Call(FarCallOpcode::Mimic) = call.r#type { -// for call in call.calls { -// if let CallType::Call(FarCallOpcode::Mimic) = call.r#type { -// assert_eq!(expected, call); -// } -// } -// } -// } - -// let tx = get_l1_execute_test_contract_tx_with_sender( -// sender, -// deployed_address, -// true, -// U256::from(1u8), -// true, -// ); - -// let tx_data: TransactionData = tx.clone().into(); -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); - -// let res = vm.execute_next_tx(u32::MAX, true).unwrap(); -// let calls = res.call_traces; - -// let expected = Call { -// r#type: CallType::Call(FarCallOpcode::Mimic), -// to: deployed_address, -// from: tx_data.from(), -// parent_gas: 257030, -// gas_used: 348, -// gas: 253008, -// value: U256::from(1u8), -// input: tx_data.data, -// output: vec![], -// error: None, -// revert_reason: Some("This method always reverts".to_string()), -// calls: vec![], -// }; - -// for call in calls { -// if let CallType::Call(FarCallOpcode::Mimic) = call.r#type { -// for call in call.calls { -// if let CallType::Call(FarCallOpcode::Mimic) = call.r#type { -// assert_eq!(expected, call); -// } -// } -// } -// } - -// let tx = get_l1_tx_with_large_output(sender, deployed_address_long_return_data); - -// let tx_data: TransactionData = tx.clone().into(); -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); - -// assert_ne!(deployed_address_long_return_data, deployed_address); -// let res = vm.execute_next_tx(u32::MAX, true).unwrap(); -// let calls = res.call_traces; -// for call in calls { -// if let CallType::Call(FarCallOpcode::Mimic) = call.r#type { -// for call in call.calls { -// if let CallType::Call(FarCallOpcode::Mimic) = call.r#type { -// assert_eq!(call.input, tx_data.data); -// assert_eq!( -// call.revert_reason, -// Some("Unknown revert reason".to_string()) -// ); -// } -// } -// } -// } -// } - -// #[test] -// fn test_get_used_contracts() { -// let mut vm_test_env = VmTestEnv::default(); - -// let mut vm_helper = VmTestHelper::new(&mut vm_test_env); -// let mut vm = vm_helper.vm(); - -// assert!(known_bytecodes_without_aa_code(&vm).is_empty()); - -// // create and push and execute some not-empty factory deps transaction with success status -// // to check that get_used_contracts() updates -// let contract_code = read_test_contract(); -// let contract_code_hash = hash_bytecode(&contract_code); -// let tx1 = get_l1_deploy_tx(&contract_code, &[]); - -// push_transaction_to_bootloader_memory(&mut vm, &tx1, TxExecutionMode::VerifyExecute, None); - -// let res1 = vm.execute_next_tx(u32::MAX, true).unwrap(); -// assert_eq!(res1.status, TxExecutionStatus::Success); -// assert!(vm -// .get_used_contracts() -// .contains(&h256_to_u256(contract_code_hash))); - -// assert_eq!( -// vm.get_used_contracts() -// .into_iter() -// .collect::>(), -// known_bytecodes_without_aa_code(&vm) -// .keys() -// .cloned() -// .collect::>() -// ); - -// // create push and execute some non-empty factory deps transaction that fails -// // (known_bytecodes will be updated but we expect get_used_contracts() to not be updated) - -// let mut tx2 = tx1; -// tx2.execute.contract_address = L1_MESSENGER_ADDRESS; - -// let calldata = vec![1, 2, 3]; -// let big_calldata: Vec = calldata -// .iter() -// .cycle() -// .take(calldata.len() * 1024) -// .cloned() -// .collect(); - -// tx2.execute.calldata = big_calldata; -// tx2.execute.factory_deps = Some(vec![vec![1; 32]]); - -// push_transaction_to_bootloader_memory(&mut vm, &tx2, TxExecutionMode::VerifyExecute, None); - -// let res2 = vm.execute_next_tx(u32::MAX, false).unwrap(); - -// assert_eq!(res2.status, TxExecutionStatus::Failure); - -// for factory_dep in tx2.execute.factory_deps.unwrap() { -// let hash = hash_bytecode(&factory_dep); -// let hash_to_u256 = h256_to_u256(hash); -// assert!(known_bytecodes_without_aa_code(&vm) -// .keys() -// .contains(&hash_to_u256)); -// assert!(!vm.get_used_contracts().contains(&hash_to_u256)); -// } -// } - -// fn known_bytecodes_without_aa_code(vm: &VmInstance) -> HashMap> { -// let mut known_bytecodes_without_aa_code = vm -// .state -// .decommittment_processor -// .known_bytecodes -// .inner() -// .clone(); - -// known_bytecodes_without_aa_code -// .remove(&h256_to_u256(BASE_SYSTEM_CONTRACTS.default_aa.hash)) -// .unwrap(); - -// known_bytecodes_without_aa_code -// } - -// #[tokio::test] -// /// This test deploys 'buggy' account abstraction code, and then tries accessing it both with legacy -// /// and EIP712 transactions. -// /// Currently we support both, but in the future, we should allow only EIP712 transactions to access the AA accounts. -// async fn test_require_eip712() { -// // Use 3 accounts: -// // - private_address - EOA account, where we have the key -// // - account_address - AA account, where the contract is deployed -// // - beneficiary - an EOA account, where we'll try to transfer the tokens. -// let account_address = H160::random(); - -// let (bytecode, contract) = read_many_owners_custom_account_contract(); - -// let mut vm_test_env = VmTestEnv::new_with_contracts(&[(account_address, bytecode)]); - -// let beneficiary = H160::random(); - -// assert_eq!(vm_test_env.get_eth_balance(&beneficiary), U256::from(0)); - -// let private_key = H256::random(); -// let private_address = PackedEthSignature::address_from_private_key(&private_key).unwrap(); -// let pk_signer = PrivateKeySigner::new(private_key); - -// vm_test_env.set_rich_account(&account_address); -// vm_test_env.set_rich_account(&private_address); - -// let chain_id: u16 = 270; - -// // First, let's set the owners of the AA account to the private_address. -// // (so that messages signed by private_address, are authorized to act on behalf of the AA account). -// { -// let set_owners_function = contract.function("setOwners").unwrap(); -// let encoded_input = set_owners_function -// .encode_input(&[Token::Array(vec![Token::Address(private_address)])]); - -// // Create a legacy transaction to set the owners. -// let raw_tx = TransactionParameters { -// nonce: U256::from(0), -// to: Some(account_address), -// gas: U256::from(100000000), -// gas_price: Some(U256::from(10000000)), -// value: U256::from(0), -// data: encoded_input.unwrap(), -// chain_id: chain_id as u64, -// transaction_type: None, -// access_list: None, -// max_fee_per_gas: U256::from(1000000000), -// max_priority_fee_per_gas: U256::from(1000000000), -// }; -// let txn = pk_signer.sign_transaction(raw_tx).await.unwrap(); - -// let (txn_request, hash) = TransactionRequest::from_bytes(&txn, chain_id).unwrap(); - -// let mut l2_tx: L2Tx = L2Tx::from_request(txn_request, 100000).unwrap(); -// l2_tx.set_input(txn, hash); -// let transaction: Transaction = l2_tx.try_into().unwrap(); -// let transaction_data: TransactionData = transaction.try_into().unwrap(); - -// vm_test_env.run_vm_or_die(transaction_data); -// } - -// let private_account_balance = vm_test_env.get_eth_balance(&private_address); - -// // And now let's do the transfer from the 'account abstraction' to 'beneficiary' (using 'legacy' transaction). -// // Normally this would not work - unless the operator is malicious. -// { -// let aa_raw_tx = TransactionParameters { -// nonce: U256::from(0), -// to: Some(beneficiary), -// gas: U256::from(100000000), -// gas_price: Some(U256::from(10000000)), -// value: U256::from(888000088), -// data: vec![], -// chain_id: 270, -// transaction_type: None, -// access_list: None, -// max_fee_per_gas: U256::from(1000000000), -// max_priority_fee_per_gas: U256::from(1000000000), -// }; - -// let aa_txn = pk_signer.sign_transaction(aa_raw_tx).await.unwrap(); - -// let (aa_txn_request, aa_hash) = TransactionRequest::from_bytes(&aa_txn, 270).unwrap(); - -// let mut l2_tx: L2Tx = L2Tx::from_request(aa_txn_request, 100000).unwrap(); -// l2_tx.set_input(aa_txn, aa_hash); -// // Pretend that operator is malicious and sets the initiator to the AA account. -// l2_tx.common_data.initiator_address = account_address; - -// let transaction: Transaction = l2_tx.try_into().unwrap(); - -// let transaction_data: TransactionData = transaction.try_into().unwrap(); - -// vm_test_env.run_vm_or_die(transaction_data); -// assert_eq!( -// vm_test_env.get_eth_balance(&beneficiary), -// U256::from(888000088) -// ); -// // Make sure that the tokens were transferred from the AA account. -// assert_eq!( -// private_account_balance, -// vm_test_env.get_eth_balance(&private_address) -// ) -// } - -// // Now send the 'classic' EIP712 transaction -// { -// let tx_712 = L2Tx::new( -// beneficiary, -// vec![], -// Nonce(1), -// Fee { -// gas_limit: U256::from(1000000000), -// max_fee_per_gas: U256::from(1000000000), -// max_priority_fee_per_gas: U256::from(1000000000), -// gas_per_pubdata_limit: U256::from(1000000000), -// }, -// account_address, -// U256::from(28374938), -// None, -// Default::default(), -// ); - -// let transaction_request: TransactionRequest = tx_712.into(); - -// let domain = Eip712Domain::new(L2ChainId(chain_id)); -// let signature = pk_signer -// .sign_typed_data(&domain, &transaction_request) -// .await -// .unwrap(); -// let encoded_tx = transaction_request.get_signed_bytes(&signature, L2ChainId(chain_id)); - -// let (aa_txn_request, aa_hash) = -// TransactionRequest::from_bytes(&encoded_tx, chain_id).unwrap(); - -// let mut l2_tx: L2Tx = L2Tx::from_request(aa_txn_request, 100000).unwrap(); -// l2_tx.set_input(encoded_tx, aa_hash); - -// let transaction: Transaction = l2_tx.try_into().unwrap(); -// let transaction_data: TransactionData = transaction.try_into().unwrap(); - -// vm_test_env.run_vm_or_die(transaction_data); - -// assert_eq!( -// vm_test_env.get_eth_balance(&beneficiary), -// U256::from(916375026) -// ); -// assert_eq!( -// private_account_balance, -// vm_test_env.get_eth_balance(&private_address) -// ); -// } -// } diff --git a/core/lib/multivm/src/versions/vm_1_3_2/tests/mod.rs b/core/lib/multivm/src/versions/vm_1_3_2/tests/mod.rs deleted file mode 100644 index af4748e38645..000000000000 --- a/core/lib/multivm/src/versions/vm_1_3_2/tests/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -// mod bootloader; -// mod upgrades; - -// mod utils; diff --git a/core/lib/multivm/src/versions/vm_1_3_2/tests/upgrades.rs b/core/lib/multivm/src/versions/vm_1_3_2/tests/upgrades.rs deleted file mode 100644 index 47e9ad5d4eb8..000000000000 --- a/core/lib/multivm/src/versions/vm_1_3_2/tests/upgrades.rs +++ /dev/null @@ -1,377 +0,0 @@ -// use crate::{ -// test_utils::verify_required_storage, -// tests::utils::get_l1_deploy_tx, -// utils::{create_test_block_params, BASE_SYSTEM_CONTRACTS, BLOCK_GAS_LIMIT}, -// vm::tx_has_failed, -// vm_with_bootloader::{init_vm_inner, push_transaction_to_bootloader_memory}, -// vm_with_bootloader::{BlockContextMode, TxExecutionMode}, -// HistoryEnabled, OracleTools, TxRevertReason, -// }; - -// use zk_evm_1_3_3::aux_structures::Timestamp; - -// use zksync_types::{ -// ethabi::Contract, -// tx::tx_execution_info::TxExecutionStatus, -// Execute, COMPLEX_UPGRADER_ADDRESS, CONTRACT_DEPLOYER_ADDRESS, CONTRACT_FORCE_DEPLOYER_ADDRESS, -// REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE, -// {ethabi::Token, Address, ExecuteTransactionCommon, Transaction, H256, U256}, -// {get_code_key, get_known_code_key, H160}, -// }; - -// use zksync_utils::{bytecode::hash_bytecode, bytes_to_be_words, h256_to_u256, u256_to_h256}; - -// use zksync_contracts::{deployer_contract, load_contract, load_sys_contract, read_bytecode}; -// use zksync_state::WriteStorage; - -// use crate::tests::utils::create_storage_view; -// use zksync_types::protocol_version::ProtocolUpgradeTxCommonData; - -// use super::utils::read_test_contract; - -// /// In this test we ensure that the requirements for protocol upgrade transactions are enforced by the bootloader: -// /// - This transaction must be the only one in block -// /// - If present, this transaction must be the first one in block -// #[test] -// fn test_protocol_upgrade_is_first() { -// let mut storage_view = create_storage_view(); -// let mut oracle_tools = OracleTools::new(&mut storage_view, HistoryEnabled); -// let (block_context, block_properties) = create_test_block_params(); - -// let bytecode_hash = hash_bytecode(&read_test_contract()); - -// // Here we just use some random transaction of protocol upgrade type: -// let protocol_upgrade_transaction = get_forced_deploy_tx(&[ForceDeployment { -// // The bytecode hash to put on an address -// bytecode_hash, -// // The address on which to deploy the bytecodehash to -// address: H160::random(), -// // Whether to run the constructor on the force deployment -// call_constructor: false, -// // The value with which to initialize a contract -// value: U256::zero(), -// // The constructor calldata -// input: vec![], -// }]); - -// let normal_l1_transaction = get_l1_deploy_tx(&read_test_contract(), &[]); - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context.into(), Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); - -// let expected_error = TxRevertReason::UnexpectedVMBehavior( -// "Assertion error: Protocol upgrade tx not first".to_string(), -// ); - -// // Test 1: there must be only one system transaction in block -// vm.save_current_vm_as_snapshot(); - -// push_transaction_to_bootloader_memory( -// &mut vm, -// &protocol_upgrade_transaction, -// TxExecutionMode::VerifyExecute, -// None, -// ); -// push_transaction_to_bootloader_memory( -// &mut vm, -// &normal_l1_transaction, -// TxExecutionMode::VerifyExecute, -// None, -// ); -// push_transaction_to_bootloader_memory( -// &mut vm, -// &protocol_upgrade_transaction, -// TxExecutionMode::VerifyExecute, -// None, -// ); - -// vm.execute_next_tx(u32::MAX, false).unwrap(); -// vm.execute_next_tx(u32::MAX, false).unwrap(); -// let res = vm.execute_next_tx(u32::MAX, false); -// assert_eq!(res, Err(expected_error.clone())); - -// // Test 2: the protocol upgrade tx must be the first one in block -// vm.rollback_to_latest_snapshot(); - -// push_transaction_to_bootloader_memory( -// &mut vm, -// &normal_l1_transaction, -// TxExecutionMode::VerifyExecute, -// None, -// ); -// push_transaction_to_bootloader_memory( -// &mut vm, -// &protocol_upgrade_transaction, -// TxExecutionMode::VerifyExecute, -// None, -// ); - -// vm.execute_next_tx(u32::MAX, false).unwrap(); -// let res = vm.execute_next_tx(u32::MAX, false); -// assert_eq!(res, Err(expected_error)); -// } - -// /// In this test we try to test how force deployments could be done via protocol upgrade transactions. -// #[test] -// fn test_force_deploy_upgrade() { -// let mut storage_view = create_storage_view(); - -// let bytecode_hash = hash_bytecode(&read_test_contract()); - -// let known_code_key = get_known_code_key(&bytecode_hash); -// // It is generally expected that all the keys will be set as known prior to the protocol upgrade. -// storage_view.set_value(known_code_key, u256_to_h256(1.into())); - -// let mut oracle_tools = OracleTools::new(&mut storage_view, HistoryEnabled); -// let (block_context, block_properties) = create_test_block_params(); - -// let address_to_deploy = H160::random(); -// // Here we just use some random transaction of protocol upgrade type: -// let transaction = get_forced_deploy_tx(&[ForceDeployment { -// // The bytecode hash to put on an address -// bytecode_hash, -// // The address on which to deploy the bytecodehash to -// address: address_to_deploy, -// // Whether to run the constructor on the force deployment -// call_constructor: false, -// // The value with which to initialize a contract -// value: U256::zero(), -// // The constructor calldata -// input: vec![], -// }]); - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context.into(), Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); -// push_transaction_to_bootloader_memory( -// &mut vm, -// &transaction, -// TxExecutionMode::VerifyExecute, -// None, -// ); -// let result = vm.execute_next_tx(u32::MAX, false).unwrap(); -// assert_eq!( -// result.status, -// TxExecutionStatus::Success, -// "The force upgrade was not successful" -// ); -// assert!(!tx_has_failed(&vm.state, 0)); - -// let expected_slots = vec![(bytecode_hash, get_code_key(&address_to_deploy))]; - -// // Verify that the bytecode has been set correctly -// verify_required_storage(&vm.state, expected_slots); -// } - -// /// Here we show how the work with the complex upgrader could be done -// #[test] -// fn test_complex_upgrader() { -// let mut storage_view = create_storage_view(); - -// let bytecode_hash = hash_bytecode(&read_complex_upgrade()); -// let msg_sender_test_hash = hash_bytecode(&read_msg_sender_test()); - -// // Let's assume that the bytecode for the implementation of the complex upgrade -// // is already deployed in some address in userspace -// let upgrade_impl = H160::random(); -// let account_code_key = get_code_key(&upgrade_impl); - -// storage_view.set_value(get_known_code_key(&bytecode_hash), u256_to_h256(1.into())); -// storage_view.set_value( -// get_known_code_key(&msg_sender_test_hash), -// u256_to_h256(1.into()), -// ); -// storage_view.set_value(account_code_key, bytecode_hash); - -// let mut oracle_tools: OracleTools = -// OracleTools::new(&mut storage_view, HistoryEnabled); -// oracle_tools.decommittment_processor.populate( -// vec![ -// ( -// h256_to_u256(bytecode_hash), -// bytes_to_be_words(read_complex_upgrade()), -// ), -// ( -// h256_to_u256(msg_sender_test_hash), -// bytes_to_be_words(read_msg_sender_test()), -// ), -// ], -// Timestamp(0), -// ); - -// let (block_context, block_properties) = create_test_block_params(); - -// let address_to_deploy1 = H160::random(); -// let address_to_deploy2 = H160::random(); - -// let transaction = get_complex_upgrade_tx( -// upgrade_impl, -// address_to_deploy1, -// address_to_deploy2, -// bytecode_hash, -// ); - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context.into(), Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); -// push_transaction_to_bootloader_memory( -// &mut vm, -// &transaction, -// TxExecutionMode::VerifyExecute, -// None, -// ); -// let result = vm.execute_next_tx(u32::MAX, false).unwrap(); -// assert_eq!( -// result.status, -// TxExecutionStatus::Success, -// "The force upgrade was not successful" -// ); -// assert!(!tx_has_failed(&vm.state, 0)); - -// let expected_slots = vec![ -// (bytecode_hash, get_code_key(&address_to_deploy1)), -// (bytecode_hash, get_code_key(&address_to_deploy2)), -// ]; - -// // Verify that the bytecode has been set correctly -// verify_required_storage(&vm.state, expected_slots); -// } - -// #[derive(Debug, Clone)] -// struct ForceDeployment { -// // The bytecode hash to put on an address -// bytecode_hash: H256, -// // The address on which to deploy the bytecodehash to -// address: Address, -// // Whether to run the constructor on the force deployment -// call_constructor: bool, -// // The value with which to initialize a contract -// value: U256, -// // The constructor calldata -// input: Vec, -// } - -// fn get_forced_deploy_tx(deployment: &[ForceDeployment]) -> Transaction { -// let deployer = deployer_contract(); -// let contract_function = deployer.function("forceDeployOnAddresses").unwrap(); - -// let encoded_deployments: Vec<_> = deployment -// .iter() -// .map(|deployment| { -// Token::Tuple(vec![ -// Token::FixedBytes(deployment.bytecode_hash.as_bytes().to_vec()), -// Token::Address(deployment.address), -// Token::Bool(deployment.call_constructor), -// Token::Uint(deployment.value), -// Token::Bytes(deployment.input.clone()), -// ]) -// }) -// .collect(); - -// let params = [Token::Array(encoded_deployments)]; - -// let calldata = contract_function -// .encode_input(¶ms) -// .expect("failed to encode parameters"); - -// let execute = Execute { -// contract_address: CONTRACT_DEPLOYER_ADDRESS, -// calldata, -// factory_deps: None, -// value: U256::zero(), -// }; - -// Transaction { -// common_data: ExecuteTransactionCommon::ProtocolUpgrade(ProtocolUpgradeTxCommonData { -// sender: CONTRACT_FORCE_DEPLOYER_ADDRESS, -// gas_limit: U256::from(200_000_000u32), -// gas_per_pubdata_limit: REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE.into(), -// ..Default::default() -// }), -// execute, -// received_timestamp_ms: 0, -// } -// } - -// // Returns the transaction that performs a complex protocol upgrade. -// // The first param is the address of the implementation of the complex upgrade -// // in user-space, while the next 3 params are params of the implenentaiton itself -// // For the explanatation for the parameters, please refer to: -// // etc/contracts-test-data/complex-upgrade/complex-upgrade.sol -// fn get_complex_upgrade_tx( -// implementation_address: Address, -// address1: Address, -// address2: Address, -// bytecode_hash: H256, -// ) -> Transaction { -// let impl_contract = get_complex_upgrade_abi(); -// let impl_function = impl_contract.function("someComplexUpgrade").unwrap(); -// let impl_calldata = impl_function -// .encode_input(&[ -// Token::Address(address1), -// Token::Address(address2), -// Token::FixedBytes(bytecode_hash.as_bytes().to_vec()), -// ]) -// .unwrap(); - -// let complex_upgrader = get_complex_upgrader_abi(); -// let upgrade_function = complex_upgrader.function("upgrade").unwrap(); -// let complex_upgrader_calldata = upgrade_function -// .encode_input(&[ -// Token::Address(implementation_address), -// Token::Bytes(impl_calldata), -// ]) -// .unwrap(); - -// let execute = Execute { -// contract_address: COMPLEX_UPGRADER_ADDRESS, -// calldata: complex_upgrader_calldata, -// factory_deps: None, -// value: U256::zero(), -// }; - -// Transaction { -// common_data: ExecuteTransactionCommon::ProtocolUpgrade(ProtocolUpgradeTxCommonData { -// sender: CONTRACT_FORCE_DEPLOYER_ADDRESS, -// gas_limit: U256::from(200_000_000u32), -// gas_per_pubdata_limit: REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE.into(), -// ..Default::default() -// }), -// execute, -// received_timestamp_ms: 0, -// } -// } - -// fn read_complex_upgrade() -> Vec { -// read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/complex-upgrade/complex-upgrade.sol/ComplexUpgrade.json") -// } - -// fn read_msg_sender_test() -> Vec { -// read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/complex-upgrade/msg-sender.sol/MsgSenderTest.json") -// } - -// fn get_complex_upgrade_abi() -> Contract { -// load_contract( -// "etc/contracts-test-data/artifacts-zk/contracts/complex-upgrade/complex-upgrade.sol/ComplexUpgrade.json" -// ) -// } - -// fn get_complex_upgrader_abi() -> Contract { -// load_sys_contract("ComplexUpgrader") -// } diff --git a/core/lib/multivm/src/versions/vm_1_3_2/tests/utils.rs b/core/lib/multivm/src/versions/vm_1_3_2/tests/utils.rs deleted file mode 100644 index 865f8503701c..000000000000 --- a/core/lib/multivm/src/versions/vm_1_3_2/tests/utils.rs +++ /dev/null @@ -1,110 +0,0 @@ -// //! -// //! Tests for the bootloader -// //! The description for each of the tests can be found in the corresponding `.yul` file. -// //! -// use zksync_types::{ -// ethabi::Contract, -// Execute, L1TxCommonData, H160, REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE, -// {ethabi::Token, Address, ExecuteTransactionCommon, Transaction, U256}, -// }; - -// use zksync_contracts::{load_contract, read_bytecode}; -// use zksync_state::{InMemoryStorage, StorageView}; -// use zksync_utils::bytecode::hash_bytecode; - -// use crate::test_utils::get_create_execute; - -// pub fn read_test_contract() -> Vec { -// read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/counter/counter.sol/Counter.json") -// } - -// pub fn read_long_return_data_contract() -> Vec { -// read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/long-return-data/long-return-data.sol/LongReturnData.json") -// } - -// pub fn read_nonce_holder_tester() -> Vec { -// read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/custom-account/nonce-holder-test.sol/NonceHolderTest.json") -// } - -// pub fn read_error_contract() -> Vec { -// read_bytecode( -// "etc/contracts-test-data/artifacts-zk/contracts/error/error.sol/SimpleRequire.json", -// ) -// } - -// pub fn read_many_owners_custom_account_contract() -> (Vec, Contract) { -// let path = "etc/contracts-test-data/artifacts-zk/contracts/custom-account/many-owners-custom-account.sol/ManyOwnersCustomAccount.json"; -// (read_bytecode(path), load_contract(path)) -// } - -// pub fn get_l1_execute_test_contract_tx_with_sender( -// sender: Address, -// deployed_address: Address, -// with_panic: bool, -// value: U256, -// payable: bool, -// ) -> Transaction { -// let execute = execute_test_contract(deployed_address, with_panic, value, payable); - -// Transaction { -// common_data: ExecuteTransactionCommon::L1(L1TxCommonData { -// sender, -// gas_limit: U256::from(200_000_000u32), -// gas_per_pubdata_limit: REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE.into(), -// to_mint: value, -// ..Default::default() -// }), -// execute, -// received_timestamp_ms: 0, -// } -// } - -// fn execute_test_contract( -// address: Address, -// with_panic: bool, -// value: U256, -// payable: bool, -// ) -> Execute { -// let test_contract = load_contract( -// "etc/contracts-test-data/artifacts-zk/contracts/counter/counter.sol/Counter.json", -// ); - -// let function = if payable { -// test_contract -// .function("incrementWithRevertPayable") -// .unwrap() -// } else { -// test_contract.function("incrementWithRevert").unwrap() -// }; - -// let calldata = function -// .encode_input(&[Token::Uint(U256::from(1u8)), Token::Bool(with_panic)]) -// .expect("failed to encode parameters"); - -// Execute { -// contract_address: address, -// calldata, -// value, -// factory_deps: None, -// } -// } - -// pub fn get_l1_deploy_tx(code: &[u8], calldata: &[u8]) -> Transaction { -// let execute = get_create_execute(code, calldata); - -// Transaction { -// common_data: ExecuteTransactionCommon::L1(L1TxCommonData { -// sender: H160::random(), -// gas_limit: U256::from(2000000u32), -// gas_per_pubdata_limit: REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE.into(), -// ..Default::default() -// }), -// execute, -// received_timestamp_ms: 0, -// } -// } - -// pub fn create_storage_view() -> StorageView { -// let raw_storage = InMemoryStorage::with_system_contracts(hash_bytecode); -// StorageView::new(raw_storage) -// } diff --git a/core/lib/multivm/src/versions/vm_1_3_2/transaction_data.rs b/core/lib/multivm/src/versions/vm_1_3_2/transaction_data.rs index f2c8f278f56d..58d8d29b6044 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/transaction_data.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/transaction_data.rs @@ -4,14 +4,16 @@ use zksync_types::{ fee::encoding_len, l1::is_l1_tx_type, l2::TransactionType, - ExecuteTransactionCommon, Transaction, MAX_L2_TX_GAS_LIMIT, MAX_TXS_IN_BLOCK, U256, + ExecuteTransactionCommon, Transaction, MAX_L2_TX_GAS_LIMIT, U256, }; use zksync_utils::{ address_to_h256, bytecode::hash_bytecode, bytes_to_be_words, ceil_div_u256, h256_to_u256, }; +use super::vm_with_bootloader::MAX_TXS_IN_BLOCK; use crate::vm_1_3_2::vm_with_bootloader::{ BLOCK_OVERHEAD_GAS, BLOCK_OVERHEAD_PUBDATA, BOOTLOADER_TX_ENCODING_SPACE, + MAX_GAS_PER_PUBDATA_BYTE, }; // This structure represents the data that is used by @@ -58,12 +60,22 @@ impl From for TransactionData { U256::zero() }; + // Ethereum transactions do not sign gas per pubdata limit, and so for them we need to use + // some default value. We use the maximum possible value that is allowed by the bootloader + // (i.e. we can not use u64::MAX, because the bootloader requires gas per pubdata for such + // transactions to be higher than `MAX_GAS_PER_PUBDATA_BYTE`). + let gas_per_pubdata_limit = if common_data.transaction_type.is_ethereum_type() { + MAX_GAS_PER_PUBDATA_BYTE.into() + } else { + common_data.fee.gas_per_pubdata_limit + }; + TransactionData { tx_type: (common_data.transaction_type as u32) as u8, from: common_data.initiator_address, to: execute_tx.execute.contract_address, gas_limit: common_data.fee.gas_limit, - pubdata_price_limit: common_data.fee.gas_per_pubdata_limit, + pubdata_price_limit: gas_per_pubdata_limit, max_fee_per_gas: common_data.fee.max_fee_per_gas, max_priority_fee_per_gas: common_data.fee.max_priority_fee_per_gas, paymaster: common_data.paymaster_params.paymaster, @@ -229,13 +241,13 @@ impl TransactionData { } } -pub fn derive_overhead( +pub(crate) fn derive_overhead( gas_limit: u32, gas_price_per_pubdata: u32, encoded_len: usize, coefficients: OverheadCoefficients, ) -> u32 { - // Even if the gas limit is greater than the MAX_TX_ERGS_LIMIT, we assume that everything beyond MAX_TX_ERGS_LIMIT + // Even if the gas limit is greater than the `MAX_TX_ERGS_LIMIT`, we assume that everything beyond `MAX_TX_ERGS_LIMIT` // will be spent entirely on publishing bytecodes and so we derive the overhead solely based on the capped value let gas_limit = std::cmp::min(MAX_TX_ERGS_LIMIT, gas_limit); @@ -244,8 +256,8 @@ pub fn derive_overhead( let gas_limit = U256::from(gas_limit); let encoded_len = U256::from(encoded_len); - // The MAX_TX_ERGS_LIMIT is formed in a way that may fulfills a single-instance circuits - // if used in full. That is, within MAX_TX_ERGS_LIMIT it is possible to fully saturate all the single-instance + // The `MAX_TX_ERGS_LIMIT` is formed in a way that may fulfills a single-instance circuits + // if used in full. That is, within `MAX_TX_ERGS_LIMIT` it is possible to fully saturate all the single-instance // circuits. let overhead_for_single_instance_circuits = ceil_div_u256(gas_limit * max_block_overhead, MAX_TX_ERGS_LIMIT.into()); @@ -259,15 +271,17 @@ pub fn derive_overhead( // The overhead for occupying a single tx slot let tx_slot_overhead = ceil_div_u256(max_block_overhead, MAX_TXS_IN_BLOCK.into()); - // We use "ceil" here for formal reasons to allow easier approach for calculating the overhead in O(1) - // let max_pubdata_in_tx = ceil_div_u256(gas_limit, gas_price_per_pubdata); + // We use `ceil` here for formal reasons to allow easier approach for calculating the overhead in O(1) + // `let max_pubdata_in_tx = ceil_div_u256(gas_limit, gas_price_per_pubdata);` // The maximal potential overhead from pubdata // TODO (EVM-67): possibly use overhead for pubdata + // ``` // let pubdata_overhead = ceil_div_u256( // max_pubdata_in_tx * max_block_overhead, // MAX_PUBDATA_PER_BLOCK.into(), // ); + // ``` vec![ (coefficients.ergs_limit_overhead_coeficient @@ -285,7 +299,7 @@ pub fn derive_overhead( /// Contains the coefficients with which the overhead for transactions will be calculated. /// All of the coefficients should be <= 1. There are here to provide a certain "discount" for normal transactions /// at the risk of malicious transactions that may close the block prematurely. -/// IMPORTANT: to perform correct computations, `MAX_TX_ERGS_LIMIT / coefficients.ergs_limit_overhead_coeficient` MUST +/// IMPORTANT: to perform correct computations, `MAX_TX_ERGS_LIMIT / coefficients.ergs_limit_overhead_coefficient` MUST /// result in an integer number #[derive(Debug, Clone, Copy)] pub struct OverheadCoefficients { @@ -323,8 +337,8 @@ impl OverheadCoefficients { OverheadCoefficients::new_checked( 1.0, 1.0, // For L2 transactions we allow a certain default discount with regard to the number of ergs. - // Multiinstance circuits can in theory be spawned infinite times, while projected future limitations - // on gas per pubdata allow for roughly 800kk gas per L1 batch, so the rough trust "discount" on the proof's part + // Multi-instance circuits can in theory be spawned infinite times, while projected future limitations + // on gas per pubdata allow for roughly 800k gas per L1 batch, so the rough trust "discount" on the proof's part // to be paid by the users is 0.1. 0.1, ) @@ -352,28 +366,28 @@ pub fn get_amortized_overhead( let encoded_len = U256::from(encoded_len); // Derivation of overhead consists of 4 parts: - // 1. The overhead for taking up a transaction's slot. (O1): O1 = 1 / MAX_TXS_IN_BLOCK - // 2. The overhead for taking up the bootloader's memory (O2): O2 = encoded_len / BOOTLOADER_TX_ENCODING_SPACE - // 3. The overhead for possible usage of pubdata. (O3): O3 = max_pubdata_in_tx / MAX_PUBDATA_PER_BLOCK - // 4. The overhead for possible usage of all the single-instance circuits. (O4): O4 = gas_limit / MAX_TX_ERGS_LIMIT + // 1. The overhead for taking up a transaction's slot. `(O1): O1 = 1 / MAX_TXS_IN_BLOCK` + // 2. The overhead for taking up the bootloader's memory `(O2): O2 = encoded_len / BOOTLOADER_TX_ENCODING_SPACE` + // 3. The overhead for possible usage of pubdata. `(O3): O3 = max_pubdata_in_tx / MAX_PUBDATA_PER_BLOCK` + // 4. The overhead for possible usage of all the single-instance circuits. `(O4): O4 = gas_limit / MAX_TX_ERGS_LIMIT` // // The maximum of these is taken to derive the part of the block's overhead to be paid by the users: // - // max_overhead = max(O1, O2, O3, O4) - // overhead_gas = ceil(max_overhead * overhead_for_block_gas). Thus, overhead_gas is a function of - // tx_gas_limit, gas_per_pubdata_byte_limit and encoded_len. + // `max_overhead = max(O1, O2, O3, O4)` + // `overhead_gas = ceil(max_overhead * overhead_for_block_gas)`. Thus, `overhead_gas` is a function of + // `tx_gas_limit`, `gas_per_pubdata_byte_limit` and `encoded_len`. // - // While it is possible to derive the overhead with binary search in O(log n), it is too expensive to be done + // While it is possible to derive the overhead with binary search in `O(log n)`, it is too expensive to be done // on L1, so here is a reference implementation of finding the overhead for transaction in O(1): // - // Given total_gas_limit = tx_gas_limit + overhead_gas, we need to find overhead_gas and tx_gas_limit, such that: - // 1. overhead_gas is maximal possible (the operator is paid fairly) - // 2. overhead_gas(tx_gas_limit, gas_per_pubdata_byte_limit, encoded_len) >= overhead_gas (the user does not overpay) + // Given `total_gas_limit = tx_gas_limit + overhead_gas`, we need to find `overhead_gas` and `tx_gas_limit`, such that: + // 1. `overhead_gas` is maximal possible (the operator is paid fairly) + // 2. `overhead_gas(tx_gas_limit, gas_per_pubdata_byte_limit, encoded_len) >= overhead_gas` (the user does not overpay) // The third part boils to the following 4 inequalities (at least one of these must hold): - // ceil(O1 * overhead_for_block_gas) >= overhead_gas - // ceil(O2 * overhead_for_block_gas) >= overhead_gas - // ceil(O3 * overhead_for_block_gas) >= overhead_gas - // ceil(O4 * overhead_for_block_gas) >= overhead_gas + // `ceil(O1 * overhead_for_block_gas) >= overhead_gas` + // `ceil(O2 * overhead_for_block_gas) >= overhead_gas` + // `ceil(O3 * overhead_for_block_gas) >= overhead_gas` + // `ceil(O4 * overhead_for_block_gas) >= overhead_gas` // // Now, we need to solve each of these separately: @@ -384,7 +398,7 @@ pub fn get_amortized_overhead( (coefficients.slot_overhead_coeficient * tx_slot_overhead as f64).floor() as u32 }; - // 2. The overhead for occupying the bootloader memory can be derived from encoded_len + // 2. The overhead for occupying the bootloader memory can be derived from `encoded_len` let overhead_for_length = { let overhead_for_length = ceil_div_u256( encoded_len * overhead_for_block_gas, @@ -397,13 +411,17 @@ pub fn get_amortized_overhead( }; // TODO (EVM-67): possibly include the overhead for pubdata. The formula below has not been properly maintained, - // since the pubdat is not published. If decided to use the pubdata overhead, it needs to be updated. + // since the pubdata is not published. If decided to use the pubdata overhead, it needs to be updated. + // ``` // 3. ceil(O3 * overhead_for_block_gas) >= overhead_gas // O3 = max_pubdata_in_tx / MAX_PUBDATA_PER_BLOCK = ceil(gas_limit / gas_per_pubdata_byte_limit) / MAX_PUBDATA_PER_BLOCK - // >= (gas_limit / (gas_per_pubdata_byte_limit * MAX_PUBDATA_PER_BLOCK). Throwing off the `ceil`, while may provide marginally lower + // >= (gas_limit / (gas_per_pubdata_byte_limit * MAX_PUBDATA_PER_BLOCK). + // ``` + // Throwing off the `ceil`, while may provide marginally lower // overhead to the operator, provides substantially easier formula to work with. // - // For better clarity, let's denote gas_limit = GL, MAX_PUBDATA_PER_BLOCK = MP, gas_per_pubdata_byte_limit = EP, overhead_for_block_gas = OB, total_gas_limit = TL, overhead_gas = OE + // For better clarity, let's denote `gas_limit = GL, MAX_PUBDATA_PER_BLOCK = MP, gas_per_pubdata_byte_limit = EP, overhead_for_block_gas = OB, total_gas_limit = TL, overhead_gas = OE` + // ``` // ceil(OB * (TL - OE) / (EP * MP)) >= OE // // OB * (TL - OE) / (MP * EP) > OE - 1 @@ -416,7 +434,7 @@ pub fn get_amortized_overhead( // + gas_per_pubdata_byte_limit * U256::from(MAX_PUBDATA_PER_BLOCK); // let denominator = // gas_per_pubdata_byte_limit * U256::from(MAX_PUBDATA_PER_BLOCK) + overhead_for_block_gas; - + // // // Corner case: if `total_gas_limit` = `gas_per_pubdata_byte_limit` = 0 // // then the numerator will be 0 and subtracting 1 will cause a panic, so we just return a zero. // if numerator.is_zero() { @@ -425,7 +443,7 @@ pub fn get_amortized_overhead( // (numerator - 1) / denominator // } // }; - + // // 4. K * ceil(O4 * overhead_for_block_gas) >= overhead_gas, where K is the discount // O4 = gas_limit / MAX_TX_ERGS_LIMIT. Using the notation from the previous equation: // ceil(OB * GL / MAX_TX_ERGS_LIMIT) >= (OE / K) @@ -434,6 +452,7 @@ pub fn get_amortized_overhead( // OB * (TL - OE) > (OE/K) * MAX_TX_ERGS_LIMIT - MAX_TX_ERGS_LIMIT // OB * TL + MAX_TX_ERGS_LIMIT > OE * ( MAX_TX_ERGS_LIMIT/K + OB) // OE = floor(OB * TL + MAX_TX_ERGS_LIMIT / (MAX_TX_ERGS_LIMIT/K + OB)), with possible -1 if the division is without remainder + // ``` let overhead_for_gas = { let numerator = overhead_for_block_gas * total_gas_limit + U256::from(MAX_TX_ERGS_LIMIT); let denominator: U256 = U256::from( @@ -448,16 +467,16 @@ pub fn get_amortized_overhead( let overhead = vec![tx_slot_overhead, overhead_for_length, overhead_for_gas] .into_iter() .max() - // For the sake of consistency making sure that total_gas_limit >= max_overhead + // For the sake of consistency making sure that `total_gas_limit >= max_overhead` .map(|max_overhead| std::cmp::min(max_overhead, total_gas_limit.as_u32())) .unwrap(); let limit_after_deducting_overhead = total_gas_limit - overhead; // During double checking of the overhead, the bootloader will assume that the - // body of the transaction does not have any more than MAX_L2_TX_GAS_LIMIT ergs available to it. + // body of the transaction does not have any more than `MAX_L2_TX_GAS_LIMIT` ergs available to it. if limit_after_deducting_overhead.as_u64() > MAX_L2_TX_GAS_LIMIT { - // We derive the same overhead that would exist for the MAX_L2_TX_GAS_LIMIT ergs + // We derive the same overhead that would exist for the `MAX_L2_TX_GAS_LIMIT` ergs derive_overhead( MAX_L2_TX_GAS_LIMIT as u32, gas_per_pubdata_byte_limit, diff --git a/core/lib/multivm/src/versions/vm_1_3_2/utils.rs b/core/lib/multivm/src/versions/vm_1_3_2/utils.rs index 9b3a26320d8a..51732ccaa79b 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/utils.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/utils.rs @@ -1,6 +1,6 @@ use once_cell::sync::Lazy; use zk_evm_1_3_3::{ - aux_structures::{MemoryPage, Timestamp}, + aux_structures::{LogQuery, MemoryPage, Timestamp}, block_properties::BlockProperties, vm_state::PrimitiveValue, zkevm_opcode_defs::FatPointer, @@ -8,7 +8,7 @@ use zk_evm_1_3_3::{ use zksync_contracts::{read_zbin_bytecode, BaseSystemContracts}; use zksync_state::WriteStorage; use zksync_system_constants::ZKPORTER_IS_AVAILABLE; -use zksync_types::{Address, H160, MAX_L2_TX_GAS_LIMIT, U256}; +use zksync_types::{Address, StorageLogQueryType, H160, MAX_L2_TX_GAS_LIMIT, U256}; use zksync_utils::h256_to_u256; use crate::vm_1_3_2::{ @@ -190,7 +190,7 @@ impl IntoFixedLengthByteIterator<32> for U256 { /// Receives sorted slice of timestamps. /// Returns count of timestamps that are greater than or equal to `from_timestamp`. -/// Works in O(log(sorted_timestamps.len())). +/// Works in `O(log(sorted_timestamps.len()))`. pub fn precompile_calls_count_after_timestamp( sorted_timestamps: &[Timestamp], from_timestamp: Timestamp, @@ -221,8 +221,8 @@ pub fn create_test_block_params() -> (BlockContext, BlockProperties) { pub fn read_bootloader_test_code(test: &str) -> Vec { read_zbin_bytecode(format!( - "contracts/system-contracts/bootloader/tests/artifacts/{}.yul/{}.yul.zbin", - test, test + "contracts/system-contracts/bootloader/tests/artifacts/{}.yul.zbin", + test )) } @@ -252,3 +252,10 @@ pub(crate) fn calculate_computational_gas_used< 0 }) } + +/// Log query, which handle initial and repeated writes to the storage +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct StorageLogQuery { + pub log_query: LogQuery, + pub log_type: StorageLogQueryType, +} diff --git a/core/lib/multivm/src/versions/vm_1_3_2/vm.rs b/core/lib/multivm/src/versions/vm_1_3_2/vm.rs index f0cf5d9c1aa2..ea5647c5636e 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/vm.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/vm.rs @@ -1,5 +1,6 @@ use std::collections::HashSet; +use zkevm_test_harness_1_3_3::witness::sort_storage_access::sort_storage_access_queries; use zksync_state::{StoragePtr, WriteStorage}; use zksync_types::{ l2_to_l1_log::{L2ToL1Log, UserL2ToL1Log}, @@ -17,6 +18,7 @@ use crate::{ L1BatchEnv, L2BlockEnv, SystemEnv, TxExecutionMode, VmExecutionMode, VmExecutionResultAndLogs, VmInterface, VmInterfaceHistoryEnabled, VmMemoryMetrics, }, + tracers::old_tracers::TracerDispatcher, vm_1_3_2::{events::merge_events, VmInstance}, }; @@ -29,8 +31,7 @@ pub struct Vm { } impl VmInterface for Vm { - /// Tracers are not supported for vm 1.3.2. So we use `()` as a placeholder - type TracerDispatcher = (); + type TracerDispatcher = TracerDispatcher; fn new(batch_env: L1BatchEnv, system_env: SystemEnv, storage: StoragePtr) -> Self { let oracle_tools = crate::vm_1_3_2::OracleTools::new(storage.clone()); @@ -68,18 +69,31 @@ impl VmInterface for Vm { fn inspect( &mut self, - _tracer: Self::TracerDispatcher, + tracer: Self::TracerDispatcher, execution_mode: VmExecutionMode, ) -> VmExecutionResultAndLogs { + if let Some(storage_invocations) = tracer.storage_invocations { + self.vm + .execution_mode + .set_invocation_limit(storage_invocations); + } + match execution_mode { VmExecutionMode::OneTx => { match self.system_env.execution_mode { TxExecutionMode::VerifyExecute => { - // Even that call tracer is supported here, we don't use it now - self.vm.execute_next_tx( + let enable_call_tracer = tracer + .call_tracer.is_some(); + let result = self.vm.execute_next_tx( self.system_env.default_validation_computational_gas_limit, - false, - ).glue_into() + enable_call_tracer, + ); + if let (Ok(result), Some(call_tracer)) = (&result, &tracer.call_tracer) { + call_tracer.set( result.call_traces.clone()).unwrap(); + + } + result.glue_into() + } TxExecutionMode::EstimateFee | TxExecutionMode::EthCall => self.vm .execute_till_block_end( @@ -143,9 +157,21 @@ impl VmInterface for Vm { .cloned() .collect(); + let storage_log_queries = self.vm.state.storage.get_final_log_queries(); + + let deduped_storage_log_queries = + sort_storage_access_queries(storage_log_queries.iter().map(|log| &log.log_query)).1; + CurrentExecutionState { events, - storage_log_queries: self.vm.state.storage.get_final_log_queries(), + storage_log_queries: storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), + deduplicated_storage_log_queries: deduped_storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), used_contract_hashes, user_l2_to_l1_logs: l2_to_l1_logs, system_logs: vec![], @@ -159,10 +185,18 @@ impl VmInterface for Vm { fn inspect_transaction_with_bytecode_compression( &mut self, - _tracer: Self::TracerDispatcher, + tracer: Self::TracerDispatcher, tx: Transaction, with_compression: bool, - ) -> Result { + ) -> ( + Result<(), BytecodeCompressionError>, + VmExecutionResultAndLogs, + ) { + if let Some(storage_invocations) = tracer.storage_invocations { + self.vm + .execution_mode + .set_invocation_limit(storage_invocations); + } self.last_tx_compressed_bytecodes = vec![]; let bytecodes = if with_compression { let deps = tx.execute.factory_deps.as_deref().unwrap_or_default(); @@ -201,17 +235,35 @@ impl VmInterface for Vm { }; // Even that call tracer is supported here, we don't use it. - let result = self.vm.execute_next_tx( - self.system_env.default_validation_computational_gas_limit, - false, - ); + let result = match self.system_env.execution_mode { + TxExecutionMode::VerifyExecute => { + let enable_call_tracer = tracer.call_tracer.is_some(); + let result = self.vm.execute_next_tx( + self.system_env.default_validation_computational_gas_limit, + enable_call_tracer, + ); + if let (Ok(result), Some(call_tracer)) = (&result, &tracer.call_tracer) { + call_tracer.set(result.call_traces.clone()).unwrap(); + } + result.glue_into() + } + TxExecutionMode::EstimateFee | TxExecutionMode::EthCall => self + .vm + .execute_till_block_end( + crate::vm_1_3_2::vm_with_bootloader::BootloaderJobType::TransactionExecution, + ) + .glue_into(), + }; if bytecodes .iter() .any(|info| !self.vm.is_bytecode_known(info)) { - Err(crate::interface::BytecodeCompressionError::BytecodeCompressionFailed) + ( + Err(BytecodeCompressionError::BytecodeCompressionFailed), + result, + ) } else { - Ok(result.glue_into()) + (Ok(()), result) } } @@ -232,6 +284,12 @@ impl VmInterface for Vm { } } + fn has_enough_gas_for_batch_tip(&self) -> bool { + // For this version this overhead has not been calculated and it has not been used with those versions. + // We return some value just in case for backwards compatibility + true + } + fn finish_batch(&mut self) -> FinishedL1Batch { self.vm .execute_till_block_end( diff --git a/core/lib/multivm/src/versions/vm_1_3_2/vm_instance.rs b/core/lib/multivm/src/versions/vm_1_3_2/vm_instance.rs index 2217b4f50d66..fabdf541b712 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/vm_instance.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/vm_instance.rs @@ -1,5 +1,6 @@ use std::{convert::TryFrom, fmt::Debug}; +use itertools::Itertools; use zk_evm_1_3_3::{ aux_structures::Timestamp, vm_state::{PrimitiveValue, VmLocalState, VmState}, @@ -10,15 +11,15 @@ use zk_evm_1_3_3::{ }, }; use zksync_state::WriteStorage; -use zksync_system_constants::MAX_TXS_IN_BLOCK; use zksync_types::{ l2_to_l1_log::{L2ToL1Log, UserL2ToL1Log}, tx::tx_execution_info::TxExecutionStatus, vm_trace::{Call, VmExecutionTrace, VmTrace}, - L1BatchNumber, StorageLogQuery, VmEvent, H256, U256, + L1BatchNumber, VmEvent, H256, U256, }; use crate::{ + glue::GlueInto, interface::types::outputs::VmExecutionLogs, vm_1_3_2::{ bootloader_state::BootloaderState, @@ -40,7 +41,7 @@ use crate::{ }, utils::{ calculate_computational_gas_used, dump_memory_page_using_primitive_value, - precompile_calls_count_after_timestamp, + precompile_calls_count_after_timestamp, StorageLogQuery, }, vm_with_bootloader::{ BootloaderJobType, DerivedBlockContext, TxExecutionMode, BOOTLOADER_HEAP_PAGE, @@ -162,6 +163,7 @@ pub enum VmExecutionStopReason { TracerRequestedStop, } +use super::vm_with_bootloader::MAX_TXS_IN_BLOCK; use crate::vm_1_3_2::utils::VmExecutionResult as NewVmExecutionResult; fn vm_may_have_ended_inner( @@ -184,7 +186,7 @@ fn vm_may_have_ended_inner( } (false, _) => None, (true, l) if l == outer_eh_location => { - // check r1,r2,r3 + // check `r1,r2,r3` if vm.local_state.flags.overflow_or_less_than_flag { Some(NewVmExecutionResult::Panic) } else { @@ -217,7 +219,7 @@ fn vm_may_have_ended( NewVmExecutionResult::Ok(data) => { Some(VmExecutionResult { // The correct `events` value for this field should be set separately - // later on based on the information inside the event_sink oracle. + // later on based on the information inside the `event_sink` oracle. events: vec![], storage_log_queries: vm.state.storage.get_final_log_queries(), used_contract_hashes: vm.get_used_contracts(), @@ -417,7 +419,7 @@ impl VmInstance { .collect(); ( events, - l1_messages.into_iter().map(L2ToL1Log::from).collect(), + l1_messages.into_iter().map(GlueInto::glue_into).collect(), ) } @@ -428,7 +430,7 @@ impl VmInstance { .storage_log_queries_after_timestamp(from_timestamp) .to_vec(); let storage_logs_count = storage_logs.len(); - let storage_logs = storage_logs.iter().map(|x| **x).collect(); + let storage_logs = storage_logs.iter().map(|x| **x).collect_vec(); let (events, l2_to_l1_logs) = self.collect_events_and_l1_logs_after_timestamp(from_timestamp); @@ -443,7 +445,7 @@ impl VmInstance { from_timestamp, ); VmExecutionLogs { - storage_logs, + storage_logs: storage_logs.into_iter().map(GlueInto::glue_into).collect(), events, user_l2_to_l1_logs: l2_to_l1_logs.into_iter().map(UserL2ToL1Log).collect(), total_log_queries_count: storage_logs_count @@ -490,8 +492,8 @@ impl VmInstance { ); } - // This means that the bootloader has informed the system (usually via VMHooks) - that some gas - // should be refunded back (see askOperatorForRefund in bootloader.yul for details). + // This means that the bootloader has informed the system (usually via `VMHooks`) - that some gas + // should be refunded back (see `askOperatorForRefund` in `bootloader.yul` for details). if let Some(bootloader_refund) = tracer.requested_refund() { assert!( operator_refund.is_none(), @@ -587,8 +589,8 @@ impl VmInstance { /// Panics if there are no new transactions in bootloader. /// Internally uses the OneTxTracer to stop the VM when the last opcode from the transaction is reached. // Err when transaction is rejected. - // Ok(status: TxExecutionStatus::Success) when the transaction succeeded - // Ok(status: TxExecutionStatus::Failure) when the transaction failed. + // `Ok(status: TxExecutionStatus::Success)` when the transaction succeeded + // `Ok(status: TxExecutionStatus::Failure)` when the transaction failed. // Note that failed transactions are considered properly processed and are included in blocks pub fn execute_next_tx( &mut self, @@ -648,7 +650,7 @@ impl VmInstance { revert_reason: None, // getting contracts used during this transaction // at least for now the number returned here is always <= to the number - // of the code hashes actually used by the transaction, since it might've + // of the code hashes actually used by the transaction, since it might have // reused bytecode hashes from some of the previous ones. contracts_used: self .state @@ -770,7 +772,8 @@ impl VmInstance { e.into_vm_event(L1BatchNumber(self.block_context.context.block_number)) }) .collect(); - full_result.l2_to_l1_logs = l1_messages.into_iter().map(L2ToL1Log::from).collect(); + full_result.l2_to_l1_logs = + l1_messages.into_iter().map(GlueInto::glue_into).collect(); full_result.computational_gas_used = block_tip_result.computational_gas_used; VmBlockResult { full_result, @@ -913,8 +916,8 @@ impl VmInstance { pub fn save_current_vm_as_snapshot(&mut self) { self.snapshots.push(VmSnapshot { // Vm local state contains O(1) various parameters (registers/etc). - // The only "expensive" copying here is copying of the callstack. - // It will take O(callstack_depth) to copy it. + // The only "expensive" copying here is copying of the call stack. + // It will take `O(callstack_depth)` to copy it. // So it is generally recommended to get snapshots of the bootloader frame, // where the depth is 1. local_state: self.state.local_state.clone(), diff --git a/core/lib/multivm/src/versions/vm_1_3_2/vm_with_bootloader.rs b/core/lib/multivm/src/versions/vm_1_3_2/vm_with_bootloader.rs index 71c108cae326..b01cf7f12efb 100644 --- a/core/lib/multivm/src/versions/vm_1_3_2/vm_with_bootloader.rs +++ b/core/lib/multivm/src/versions/vm_1_3_2/vm_with_bootloader.rs @@ -11,13 +11,13 @@ use zk_evm_1_3_3::{ STARTING_TIMESTAMP, }, }; +use zkevm_test_harness_1_3_3::INITIAL_MONOTONIC_CYCLE_COUNTER; use zksync_contracts::BaseSystemContracts; use zksync_state::WriteStorage; -use zksync_system_constants::MAX_TXS_IN_BLOCK; +use zksync_system_constants::MAX_L2_TX_GAS_LIMIT; use zksync_types::{ - l1::is_l1_tx_type, zkevm_test_harness::INITIAL_MONOTONIC_CYCLE_COUNTER, Address, Transaction, - BOOTLOADER_ADDRESS, L1_GAS_PER_PUBDATA_BYTE, MAX_GAS_PER_PUBDATA_BYTE, MAX_NEW_FACTORY_DEPS, - U256, USED_BOOTLOADER_MEMORY_WORDS, + fee_model::L1PeggedBatchFeeModelInput, l1::is_l1_tx_type, Address, Transaction, + BOOTLOADER_ADDRESS, L1_GAS_PER_PUBDATA_BYTE, MAX_NEW_FACTORY_DEPS, U256, }; use zksync_utils::{ address_to_u256, @@ -26,19 +26,22 @@ use zksync_utils::{ misc::ceil_div, }; -use crate::vm_1_3_2::{ - bootloader_state::BootloaderState, - history_recorder::HistoryMode, - transaction_data::TransactionData, - utils::{ - code_page_candidate_from_base, heap_page_from_base, BLOCK_GAS_LIMIT, INITIAL_BASE_PAGE, +use crate::{ + vm_1_3_2::{ + bootloader_state::BootloaderState, + history_recorder::HistoryMode, + transaction_data::TransactionData, + utils::{ + code_page_candidate_from_base, heap_page_from_base, BLOCK_GAS_LIMIT, INITIAL_BASE_PAGE, + }, + vm_instance::ZkSyncVmState, + OracleTools, VmInstance, }, - vm_instance::ZkSyncVmState, - OracleTools, VmInstance, + vm_latest::L1BatchEnv, }; -// TODO (SMA-1703): move these to config and make them programmatically generatable. -// fill these values in the similar fasion as other overhead-related constants +// TODO (SMA-1703): move these to config and make them programmatically generable. +// fill these values in the similar fashion as other overhead-related constants pub const BLOCK_OVERHEAD_GAS: u32 = 1200000; pub const BLOCK_OVERHEAD_L1_GAS: u32 = 1000000; pub const BLOCK_OVERHEAD_PUBDATA: u32 = BLOCK_OVERHEAD_L1_GAS / L1_GAS_PER_PUBDATA_BYTE; @@ -60,7 +63,11 @@ pub struct BlockContext { impl BlockContext { pub fn block_gas_price_per_pubdata(&self) -> u64 { - derive_base_fee_and_gas_per_pubdata(self.l1_gas_price, self.fair_l2_gas_price).1 + derive_base_fee_and_gas_per_pubdata(L1PeggedBatchFeeModelInput { + l1_gas_price: self.l1_gas_price, + fair_l2_gas_price: self.fair_l2_gas_price, + }) + .1 } } @@ -84,31 +91,70 @@ pub fn base_fee_to_gas_per_pubdata(l1_gas_price: u64, base_fee: u64) -> u64 { ceil_div(eth_price_per_pubdata_byte, base_fee) } -pub fn derive_base_fee_and_gas_per_pubdata(l1_gas_price: u64, fair_gas_price: u64) -> (u64, u64) { +pub(crate) fn derive_base_fee_and_gas_per_pubdata( + fee_input: L1PeggedBatchFeeModelInput, +) -> (u64, u64) { + let L1PeggedBatchFeeModelInput { + l1_gas_price, + fair_l2_gas_price, + } = fee_input; + let eth_price_per_pubdata_byte = eth_price_per_pubdata_byte(l1_gas_price); - // The baseFee is set in such a way that it is always possible for a transaction to + // The `baseFee` is set in such a way that it is always possible for a transaction to // publish enough public data while compensating us for it. let base_fee = std::cmp::max( - fair_gas_price, + fair_l2_gas_price, ceil_div(eth_price_per_pubdata_byte, MAX_GAS_PER_PUBDATA_BYTE), ); ( base_fee, - base_fee_to_gas_per_pubdata(l1_gas_price, base_fee), + base_fee_to_gas_per_pubdata(fee_input.l1_gas_price, base_fee), ) } +pub(crate) fn get_batch_base_fee(l1_batch_env: &L1BatchEnv) -> u64 { + if let Some(base_fee) = l1_batch_env.enforced_base_fee { + return base_fee; + } + let (base_fee, _) = + derive_base_fee_and_gas_per_pubdata(l1_batch_env.fee_input.into_l1_pegged()); + base_fee +} + impl From for DerivedBlockContext { fn from(context: BlockContext) -> Self { - let base_fee = - derive_base_fee_and_gas_per_pubdata(context.l1_gas_price, context.fair_l2_gas_price).0; + let base_fee = derive_base_fee_and_gas_per_pubdata(L1PeggedBatchFeeModelInput { + l1_gas_price: context.l1_gas_price, + fair_l2_gas_price: context.fair_l2_gas_price, + }) + .0; DerivedBlockContext { context, base_fee } } } +/// The size of the bootloader memory in bytes which is used by the protocol. +/// While the maximal possible size is a lot higher, we restrict ourselves to a certain limit to reduce +/// the requirements on RAM. +pub(crate) const USED_BOOTLOADER_MEMORY_BYTES: usize = 1 << 24; +pub(crate) const USED_BOOTLOADER_MEMORY_WORDS: usize = USED_BOOTLOADER_MEMORY_BYTES / 32; + +// This the number of pubdata such that it should be always possible to publish +// from a single transaction. Note, that these pubdata bytes include only bytes that are +// to be published inside the body of transaction (i.e. excluding of factory deps). +const GUARANTEED_PUBDATA_PER_L1_BATCH: u64 = 4000; + +// The users should always be able to provide `MAX_GAS_PER_PUBDATA_BYTE` gas per pubdata in their +// transactions so that they are able to send at least `GUARANTEED_PUBDATA_PER_L1_BATCH` bytes per +// transaction. +pub(crate) const MAX_GAS_PER_PUBDATA_BYTE: u64 = + MAX_L2_TX_GAS_LIMIT / GUARANTEED_PUBDATA_PER_L1_BATCH; + +// The maximal number of transactions in a single batch +pub(crate) const MAX_TXS_IN_BLOCK: usize = 1024; + // The first 32 slots are reserved for debugging purposes pub const DEBUG_SLOTS_OFFSET: usize = 8; pub const DEBUG_FIRST_SLOTS: usize = 32; @@ -199,6 +245,18 @@ impl TxExecutionMode { } => *missed_storage_invocation_limit, } } + + pub fn set_invocation_limit(&mut self, limit: usize) { + match self { + Self::VerifyExecute => {} + TxExecutionMode::EstimateFee { + missed_storage_invocation_limit, + } => *missed_storage_invocation_limit = limit, + TxExecutionMode::EthCall { + missed_storage_invocation_limit, + } => *missed_storage_invocation_limit = limit, + } + } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -249,12 +307,12 @@ pub fn init_vm_with_gas_limit( } #[derive(Debug, Clone, Copy)] -// The block.number/block.timestamp data are stored in the CONTEXT_SYSTEM_CONTRACT. +// The `block.number` / `block.timestamp` data are stored in the `CONTEXT_SYSTEM_CONTRACT`. // The bootloader can support execution in two modes: -// - "NewBlock" when the new block is created. It is enforced that the block.number is incremented by 1 +// - `NewBlock` when the new block is created. It is enforced that the block.number is incremented by 1 // and the timestamp is non-decreasing. Also, the L2->L1 message used to verify the correctness of the previous root hash is sent. // This is the mode that should be used in the state keeper. -// - "OverrideCurrent" when we need to provide custom block.number and block.timestamp. ONLY to be used in testing/ethCalls. +// - `OverrideCurrent` when we need to provide custom block.number and block.timestamp. ONLY to be used in testing / `ethCalls`. pub enum BlockContextMode { NewBlock(DerivedBlockContext, U256), OverrideCurrent(DerivedBlockContext), diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/README.md b/core/lib/multivm/src/versions/vm_boojum_integration/README.md new file mode 100644 index 000000000000..d515df0dfc60 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/README.md @@ -0,0 +1,44 @@ +# VM Crate + +This crate contains code that interacts with the VM (Virtual Machine). The VM itself is in a separate repository +[era-zk_evm][zk_evm_repo_ext]. + +## VM Dependencies + +The VM relies on several subcomponents or traits, such as Memory and Storage. These traits are defined in the `zk_evm` +repository, while their implementations can be found in this crate, such as the storage implementation in +`oracles/storage.rs` and the Memory implementation in `memory.rs`. + +Many of these implementations also support easy rollbacks and history, which is useful when creating a block with +multiple transactions and needing to return the VM to a previous state if a transaction doesn't fit. + +## Running the VM + +To interact with the VM, you must initialize it with `L1BatchEnv`, which represents the initial parameters of the batch, +`SystemEnv`, that represents the system parameters, and a reference to the Storage. To execute a transaction, you have +to push the transaction into the bootloader memory and call the `execute_next_transaction` method. + +### Tracers + +The VM implementation allows for the addition of `Tracers`, which are activated before and after each instruction. This +provides a more in-depth look into the VM, collecting detailed debugging information and logs. More details can be found +in the `tracer/` directory. + +This VM also supports custom tracers. You can call the `inspect_next_transaction` method with a custom tracer and +receive the result of the execution. + +### Bootloader + +In the context of zkEVM, we usually think about transactions. However, from the VM's perspective, it runs a single +program called the bootloader, which internally processes multiple transactions. + +### Rollbacks + +The `VMInstance` in `vm.rs` allows for easy rollbacks. You can save the current state at any moment by calling +`make_snapshot()` and return to that state using `rollback_to_the_latest_snapshot()`. + +This rollback affects all subcomponents, such as memory, storage, and events, and is mainly used if a transaction +doesn't fit in a block. + +[zk_evm_repo]: https://github.com/matter-labs/zk_evm 'internal zk EVM repo' +[zk_evm_repo_ext]: https://github.com/matter-labs/era-zk_evm 'external zk EVM repo' diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/bootloader_state/l2_block.rs b/core/lib/multivm/src/versions/vm_boojum_integration/bootloader_state/l2_block.rs new file mode 100644 index 000000000000..f032c301c948 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/bootloader_state/l2_block.rs @@ -0,0 +1,87 @@ +use std::cmp::Ordering; + +use zksync_types::{MiniblockNumber, H256}; +use zksync_utils::concat_and_hash; + +use crate::{ + interface::{L2Block, L2BlockEnv}, + vm_boojum_integration::{ + bootloader_state::{snapshot::L2BlockSnapshot, tx::BootloaderTx}, + utils::l2_blocks::l2_block_hash, + }, +}; + +const EMPTY_TXS_ROLLING_HASH: H256 = H256::zero(); + +#[derive(Debug, Clone)] +pub(crate) struct BootloaderL2Block { + pub(crate) number: u32, + pub(crate) timestamp: u64, + pub(crate) txs_rolling_hash: H256, // The rolling hash of all the transactions in the miniblock + pub(crate) prev_block_hash: H256, + // Number of the first L2 block tx in L1 batch + pub(crate) first_tx_index: usize, + pub(crate) max_virtual_blocks_to_create: u32, + pub(super) txs: Vec, +} + +impl BootloaderL2Block { + pub(crate) fn new(l2_block: L2BlockEnv, first_tx_place: usize) -> Self { + Self { + number: l2_block.number, + timestamp: l2_block.timestamp, + txs_rolling_hash: EMPTY_TXS_ROLLING_HASH, + prev_block_hash: l2_block.prev_block_hash, + first_tx_index: first_tx_place, + max_virtual_blocks_to_create: l2_block.max_virtual_blocks_to_create, + txs: vec![], + } + } + + pub(super) fn push_tx(&mut self, tx: BootloaderTx) { + self.update_rolling_hash(tx.hash); + self.txs.push(tx) + } + + pub(crate) fn get_hash(&self) -> H256 { + l2_block_hash( + MiniblockNumber(self.number), + self.timestamp, + self.prev_block_hash, + self.txs_rolling_hash, + ) + } + + fn update_rolling_hash(&mut self, tx_hash: H256) { + self.txs_rolling_hash = concat_and_hash(self.txs_rolling_hash, tx_hash) + } + + pub(crate) fn interim_version(&self) -> BootloaderL2Block { + let mut interim = self.clone(); + interim.max_virtual_blocks_to_create = 0; + interim + } + + pub(crate) fn make_snapshot(&self) -> L2BlockSnapshot { + L2BlockSnapshot { + txs_rolling_hash: self.txs_rolling_hash, + txs_len: self.txs.len(), + } + } + + pub(crate) fn apply_snapshot(&mut self, snapshot: L2BlockSnapshot) { + self.txs_rolling_hash = snapshot.txs_rolling_hash; + match self.txs.len().cmp(&snapshot.txs_len) { + Ordering::Greater => self.txs.truncate(snapshot.txs_len), + Ordering::Less => panic!("Applying snapshot from future is not supported"), + Ordering::Equal => {} + } + } + pub(crate) fn l2_block(&self) -> L2Block { + L2Block { + number: self.number, + timestamp: self.timestamp, + hash: self.get_hash(), + } + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/bootloader_state/mod.rs b/core/lib/multivm/src/versions/vm_boojum_integration/bootloader_state/mod.rs new file mode 100644 index 000000000000..73830de2759b --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/bootloader_state/mod.rs @@ -0,0 +1,8 @@ +mod l2_block; +mod snapshot; +mod state; +mod tx; + +pub(crate) mod utils; +pub(crate) use snapshot::BootloaderStateSnapshot; +pub use state::BootloaderState; diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/bootloader_state/snapshot.rs b/core/lib/multivm/src/versions/vm_boojum_integration/bootloader_state/snapshot.rs new file mode 100644 index 000000000000..8f1cec3cb7f1 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/bootloader_state/snapshot.rs @@ -0,0 +1,25 @@ +use zksync_types::H256; + +#[derive(Debug, Clone)] +pub(crate) struct BootloaderStateSnapshot { + /// ID of the next transaction to be executed. + pub(crate) tx_to_execute: usize, + /// Stored L2 blocks in bootloader memory + pub(crate) l2_blocks_len: usize, + /// Snapshot of the last L2 block. Only this block could be changed during the rollback + pub(crate) last_l2_block: L2BlockSnapshot, + /// The number of 32-byte words spent on the already included compressed bytecodes. + pub(crate) compressed_bytecodes_encoding: usize, + /// Current offset of the free space in the bootloader memory. + pub(crate) free_tx_offset: usize, + /// Whether the pubdata information has been provided already + pub(crate) is_pubdata_information_provided: bool, +} + +#[derive(Debug, Clone)] +pub(crate) struct L2BlockSnapshot { + /// The rolling hash of all the transactions in the miniblock + pub(crate) txs_rolling_hash: H256, + /// The number of transactions in the last L2 block + pub(crate) txs_len: usize, +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/bootloader_state/state.rs b/core/lib/multivm/src/versions/vm_boojum_integration/bootloader_state/state.rs new file mode 100644 index 000000000000..db13d2aace5d --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/bootloader_state/state.rs @@ -0,0 +1,295 @@ +use std::cmp::Ordering; + +use once_cell::sync::OnceCell; +use zksync_types::{L2ChainId, U256}; +use zksync_utils::bytecode::CompressedBytecodeInfo; + +use super::{tx::BootloaderTx, utils::apply_pubdata_to_memory}; +use crate::{ + interface::{BootloaderMemory, L2BlockEnv, TxExecutionMode}, + vm_boojum_integration::{ + bootloader_state::{ + l2_block::BootloaderL2Block, + snapshot::BootloaderStateSnapshot, + utils::{apply_l2_block, apply_tx_to_memory}, + }, + constants::TX_DESCRIPTION_OFFSET, + types::internals::{PubdataInput, TransactionData}, + utils::l2_blocks::assert_next_block, + }, +}; + +/// Intermediate bootloader-related VM state. +/// +/// Required to process transactions one by one (since we intercept the VM execution to execute +/// transactions and add new ones to the memory on the fly). +/// Keeps tracking everything related to the bootloader memory and can restore the whole memory. +/// +/// +/// Serves two purposes: +/// - Tracks where next tx should be pushed to in the bootloader memory. +/// - Tracks which transaction should be executed next. +#[derive(Debug, Clone)] +pub struct BootloaderState { + /// ID of the next transaction to be executed. + /// See the structure doc-comment for a better explanation of purpose. + tx_to_execute: usize, + /// Stored txs in bootloader memory + l2_blocks: Vec, + /// The number of 32-byte words spent on the already included compressed bytecodes. + compressed_bytecodes_encoding: usize, + /// Initial memory of bootloader + initial_memory: BootloaderMemory, + /// Mode of txs for execution, it can be changed once per vm lunch + execution_mode: TxExecutionMode, + /// Current offset of the free space in the bootloader memory. + free_tx_offset: usize, + /// Information about the the pubdata that will be needed to supply to the L1Messenger + pubdata_information: OnceCell, +} + +impl BootloaderState { + pub(crate) fn new( + execution_mode: TxExecutionMode, + initial_memory: BootloaderMemory, + first_l2_block: L2BlockEnv, + ) -> Self { + let l2_block = BootloaderL2Block::new(first_l2_block, 0); + Self { + tx_to_execute: 0, + compressed_bytecodes_encoding: 0, + l2_blocks: vec![l2_block], + initial_memory, + execution_mode, + free_tx_offset: 0, + pubdata_information: Default::default(), + } + } + + pub(crate) fn set_refund_for_current_tx(&mut self, refund: u32) { + let current_tx = self.current_tx(); + // We can't set the refund for the latest tx or using the latest `l2_block` for fining tx + // Because we can fill the whole batch first and then execute txs one by one + let tx = self.find_tx_mut(current_tx); + tx.refund = refund; + } + + pub(crate) fn set_pubdata_input(&mut self, info: PubdataInput) { + self.pubdata_information + .set(info) + .expect("Pubdata information is already set"); + } + + pub(crate) fn start_new_l2_block(&mut self, l2_block: L2BlockEnv) { + let last_block = self.last_l2_block(); + assert!( + !last_block.txs.is_empty(), + "Can not create new miniblocks on top of empty ones" + ); + assert_next_block(&last_block.l2_block(), &l2_block); + self.push_l2_block(l2_block); + } + + /// This method bypass sanity checks and should be used carefully. + pub(crate) fn push_l2_block(&mut self, l2_block: L2BlockEnv) { + self.l2_blocks + .push(BootloaderL2Block::new(l2_block, self.free_tx_index())) + } + + pub(crate) fn push_tx( + &mut self, + tx: TransactionData, + predefined_overhead: u32, + predefined_refund: u32, + compressed_bytecodes: Vec, + trusted_ergs_limit: U256, + chain_id: L2ChainId, + ) -> BootloaderMemory { + let tx_offset = self.free_tx_offset(); + let bootloader_tx = BootloaderTx::new( + tx, + predefined_refund, + predefined_overhead, + trusted_ergs_limit, + compressed_bytecodes, + tx_offset, + chain_id, + ); + + let mut memory = vec![]; + let compressed_bytecode_size = apply_tx_to_memory( + &mut memory, + &bootloader_tx, + self.last_l2_block(), + self.free_tx_index(), + self.free_tx_offset(), + self.compressed_bytecodes_encoding, + self.execution_mode, + self.last_l2_block().txs.is_empty(), + ); + self.compressed_bytecodes_encoding += compressed_bytecode_size; + self.free_tx_offset = tx_offset + bootloader_tx.encoded_len(); + self.last_mut_l2_block().push_tx(bootloader_tx); + memory + } + + pub(crate) fn last_l2_block(&self) -> &BootloaderL2Block { + self.l2_blocks.last().unwrap() + } + pub(crate) fn get_pubdata_information(&self) -> &PubdataInput { + self.pubdata_information + .get() + .expect("Pubdata information is not set") + } + + fn last_mut_l2_block(&mut self) -> &mut BootloaderL2Block { + self.l2_blocks.last_mut().unwrap() + } + + /// Apply all bootloader transaction to the initial memory + pub(crate) fn bootloader_memory(&self) -> BootloaderMemory { + let mut initial_memory = self.initial_memory.clone(); + let mut offset = 0; + let mut compressed_bytecodes_offset = 0; + let mut tx_index = 0; + for l2_block in &self.l2_blocks { + for (num, tx) in l2_block.txs.iter().enumerate() { + let compressed_bytecodes_size = apply_tx_to_memory( + &mut initial_memory, + tx, + l2_block, + tx_index, + offset, + compressed_bytecodes_offset, + self.execution_mode, + num == 0, + ); + offset += tx.encoded_len(); + compressed_bytecodes_offset += compressed_bytecodes_size; + tx_index += 1; + } + if l2_block.txs.is_empty() { + apply_l2_block(&mut initial_memory, l2_block, tx_index) + } + } + + let pubdata_information = self + .pubdata_information + .clone() + .into_inner() + .expect("Empty pubdata information"); + + apply_pubdata_to_memory(&mut initial_memory, pubdata_information); + initial_memory + } + + fn free_tx_offset(&self) -> usize { + self.free_tx_offset + } + + pub(crate) fn free_tx_index(&self) -> usize { + let l2_block = self.last_l2_block(); + l2_block.first_tx_index + l2_block.txs.len() + } + + pub(crate) fn get_last_tx_compressed_bytecodes(&self) -> Vec { + if let Some(tx) = self.last_l2_block().txs.last() { + tx.compressed_bytecodes.clone() + } else { + vec![] + } + } + + /// Returns the id of current tx + pub(crate) fn current_tx(&self) -> usize { + self.tx_to_execute + .checked_sub(1) + .expect("There are no current tx to execute") + } + + /// Returns the ID of the next transaction to be executed and increments the local transaction counter. + pub(crate) fn move_tx_to_execute_pointer(&mut self) -> usize { + assert!( + self.tx_to_execute < self.free_tx_index(), + "Attempt to execute tx that was not pushed to memory. Tx ID: {}, txs in bootloader: {}", + self.tx_to_execute, + self.free_tx_index() + ); + + let old = self.tx_to_execute; + self.tx_to_execute += 1; + old + } + + /// Get offset of tx description + pub(crate) fn get_tx_description_offset(&self, tx_index: usize) -> usize { + TX_DESCRIPTION_OFFSET + self.find_tx(tx_index).offset + } + + pub(crate) fn insert_fictive_l2_block(&mut self) -> &BootloaderL2Block { + let block = self.last_l2_block(); + if !block.txs.is_empty() { + self.start_new_l2_block(L2BlockEnv { + timestamp: block.timestamp + 1, + number: block.number + 1, + prev_block_hash: block.get_hash(), + max_virtual_blocks_to_create: 1, + }); + } + self.last_l2_block() + } + + fn find_tx(&self, tx_index: usize) -> &BootloaderTx { + for block in self.l2_blocks.iter().rev() { + if tx_index >= block.first_tx_index { + return &block.txs[tx_index - block.first_tx_index]; + } + } + panic!("The tx with index {} must exist", tx_index) + } + + fn find_tx_mut(&mut self, tx_index: usize) -> &mut BootloaderTx { + for block in self.l2_blocks.iter_mut().rev() { + if tx_index >= block.first_tx_index { + return &mut block.txs[tx_index - block.first_tx_index]; + } + } + panic!("The tx with index {} must exist", tx_index) + } + + pub(crate) fn get_snapshot(&self) -> BootloaderStateSnapshot { + BootloaderStateSnapshot { + tx_to_execute: self.tx_to_execute, + l2_blocks_len: self.l2_blocks.len(), + last_l2_block: self.last_l2_block().make_snapshot(), + compressed_bytecodes_encoding: self.compressed_bytecodes_encoding, + free_tx_offset: self.free_tx_offset, + is_pubdata_information_provided: self.pubdata_information.get().is_some(), + } + } + + pub(crate) fn apply_snapshot(&mut self, snapshot: BootloaderStateSnapshot) { + self.tx_to_execute = snapshot.tx_to_execute; + self.compressed_bytecodes_encoding = snapshot.compressed_bytecodes_encoding; + self.free_tx_offset = snapshot.free_tx_offset; + match self.l2_blocks.len().cmp(&snapshot.l2_blocks_len) { + Ordering::Greater => self.l2_blocks.truncate(snapshot.l2_blocks_len), + Ordering::Less => panic!("Applying snapshot from future is not supported"), + Ordering::Equal => {} + } + self.last_mut_l2_block() + .apply_snapshot(snapshot.last_l2_block); + + if !snapshot.is_pubdata_information_provided { + self.pubdata_information = Default::default(); + } else { + // Under the correct usage of the snapshots of the bootloader state, + // this assertion should never fail, i.e. since the pubdata information + // can be set only once. However, we have this assertion just in case. + assert!( + self.pubdata_information.get().is_some(), + "Snapshot with no pubdata can not rollback to snapshot with one" + ); + } + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/bootloader_state/tx.rs b/core/lib/multivm/src/versions/vm_boojum_integration/bootloader_state/tx.rs new file mode 100644 index 000000000000..3030427281bf --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/bootloader_state/tx.rs @@ -0,0 +1,49 @@ +use zksync_types::{L2ChainId, H256, U256}; +use zksync_utils::bytecode::CompressedBytecodeInfo; + +use crate::vm_boojum_integration::types::internals::TransactionData; + +/// Information about tx necessary for execution in bootloader. +#[derive(Debug, Clone)] +pub(super) struct BootloaderTx { + pub(super) hash: H256, + /// Encoded transaction + pub(super) encoded: Vec, + /// Compressed bytecodes, which has been published during this transaction + pub(super) compressed_bytecodes: Vec, + /// Refunds for this transaction + pub(super) refund: u32, + /// Gas overhead + pub(super) gas_overhead: u32, + /// Gas Limit for this transaction. It can be different from the gas limit inside the transaction + pub(super) trusted_gas_limit: U256, + /// Offset of the tx in bootloader memory + pub(super) offset: usize, +} + +impl BootloaderTx { + pub(super) fn new( + tx: TransactionData, + predefined_refund: u32, + predefined_overhead: u32, + trusted_gas_limit: U256, + compressed_bytecodes: Vec, + offset: usize, + chain_id: L2ChainId, + ) -> Self { + let hash = tx.tx_hash(chain_id); + Self { + hash, + encoded: tx.into_tokens(), + compressed_bytecodes, + refund: predefined_refund, + gas_overhead: predefined_overhead, + trusted_gas_limit, + offset, + } + } + + pub(super) fn encoded_len(&self) -> usize { + self.encoded.len() + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/bootloader_state/utils.rs b/core/lib/multivm/src/versions/vm_boojum_integration/bootloader_state/utils.rs new file mode 100644 index 000000000000..77a8ed2ce9b9 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/bootloader_state/utils.rs @@ -0,0 +1,177 @@ +use zksync_types::{ethabi, U256}; +use zksync_utils::{bytecode::CompressedBytecodeInfo, bytes_to_be_words, h256_to_u256}; + +use super::tx::BootloaderTx; +use crate::{ + interface::{BootloaderMemory, TxExecutionMode}, + vm_boojum_integration::{ + bootloader_state::l2_block::BootloaderL2Block, + constants::{ + BOOTLOADER_TX_DESCRIPTION_OFFSET, BOOTLOADER_TX_DESCRIPTION_SIZE, + COMPRESSED_BYTECODES_OFFSET, OPERATOR_PROVIDED_L1_MESSENGER_PUBDATA_OFFSET, + OPERATOR_PROVIDED_L1_MESSENGER_PUBDATA_SLOTS, OPERATOR_REFUNDS_OFFSET, + TX_DESCRIPTION_OFFSET, TX_OPERATOR_L2_BLOCK_INFO_OFFSET, + TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO, TX_OVERHEAD_OFFSET, TX_TRUSTED_GAS_LIMIT_OFFSET, + }, + types::internals::PubdataInput, + }, +}; + +pub(super) fn get_memory_for_compressed_bytecodes( + compressed_bytecodes: &[CompressedBytecodeInfo], +) -> Vec { + let memory_addition: Vec<_> = compressed_bytecodes + .iter() + .flat_map(|x| x.encode_call()) + .collect(); + + bytes_to_be_words(memory_addition) +} + +#[allow(clippy::too_many_arguments)] +pub(super) fn apply_tx_to_memory( + memory: &mut BootloaderMemory, + bootloader_tx: &BootloaderTx, + bootloader_l2_block: &BootloaderL2Block, + tx_index: usize, + tx_offset: usize, + compressed_bytecodes_size: usize, + execution_mode: TxExecutionMode, + start_new_l2_block: bool, +) -> usize { + let bootloader_description_offset = + BOOTLOADER_TX_DESCRIPTION_OFFSET + BOOTLOADER_TX_DESCRIPTION_SIZE * tx_index; + let tx_description_offset = TX_DESCRIPTION_OFFSET + tx_offset; + + memory.push(( + bootloader_description_offset, + assemble_tx_meta(execution_mode, true), + )); + + memory.push(( + bootloader_description_offset + 1, + U256::from_big_endian(&(32 * tx_description_offset).to_be_bytes()), + )); + + let refund_offset = OPERATOR_REFUNDS_OFFSET + tx_index; + memory.push((refund_offset, bootloader_tx.refund.into())); + + let overhead_offset = TX_OVERHEAD_OFFSET + tx_index; + memory.push((overhead_offset, bootloader_tx.gas_overhead.into())); + + let trusted_gas_limit_offset = TX_TRUSTED_GAS_LIMIT_OFFSET + tx_index; + memory.push((trusted_gas_limit_offset, bootloader_tx.trusted_gas_limit)); + + memory.extend( + (tx_description_offset..tx_description_offset + bootloader_tx.encoded_len()) + .zip(bootloader_tx.encoded.clone()), + ); + + let bootloader_l2_block = if start_new_l2_block { + bootloader_l2_block.clone() + } else { + bootloader_l2_block.interim_version() + }; + apply_l2_block(memory, &bootloader_l2_block, tx_index); + + // Note, `+1` is moving for pointer + let compressed_bytecodes_offset = COMPRESSED_BYTECODES_OFFSET + 1 + compressed_bytecodes_size; + + let encoded_compressed_bytecodes = + get_memory_for_compressed_bytecodes(&bootloader_tx.compressed_bytecodes); + let compressed_bytecodes_encoding = encoded_compressed_bytecodes.len(); + + memory.extend( + (compressed_bytecodes_offset + ..compressed_bytecodes_offset + encoded_compressed_bytecodes.len()) + .zip(encoded_compressed_bytecodes), + ); + compressed_bytecodes_encoding +} + +pub(crate) fn apply_l2_block( + memory: &mut BootloaderMemory, + bootloader_l2_block: &BootloaderL2Block, + txs_index: usize, +) { + // Since L2 block information starts from the `TX_OPERATOR_L2_BLOCK_INFO_OFFSET` and each + // L2 block info takes `TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO slots`, the position where the L2 block info + // for this transaction needs to be written is: + + let block_position = + TX_OPERATOR_L2_BLOCK_INFO_OFFSET + txs_index * TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO; + + memory.extend(vec![ + (block_position, bootloader_l2_block.number.into()), + (block_position + 1, bootloader_l2_block.timestamp.into()), + ( + block_position + 2, + h256_to_u256(bootloader_l2_block.prev_block_hash), + ), + ( + block_position + 3, + bootloader_l2_block.max_virtual_blocks_to_create.into(), + ), + ]) +} + +pub(crate) fn apply_pubdata_to_memory( + memory: &mut BootloaderMemory, + pubdata_information: PubdataInput, +) { + // Skipping two slots as they will be filled by the bootloader itself: + // - One slot is for the selector of the call to the `L1Messenger`. + // - The other slot is for the 0x20 offset for the calldata. + let l1_messenger_pubdata_start_slot = OPERATOR_PROVIDED_L1_MESSENGER_PUBDATA_OFFSET + 2; + + // Need to skip first word as it represents array offset + // while bootloader expects only `[len || data]` + let pubdata = ethabi::encode(&[ethabi::Token::Bytes( + pubdata_information.build_pubdata(true), + )])[32..] + .to_vec(); + + assert!( + pubdata.len() / 32 <= OPERATOR_PROVIDED_L1_MESSENGER_PUBDATA_SLOTS - 2, + "The encoded pubdata is too big" + ); + + pubdata + .chunks(32) + .enumerate() + .for_each(|(slot_offset, value)| { + memory.push(( + l1_messenger_pubdata_start_slot + slot_offset, + U256::from(value), + )) + }); +} + +/// Forms a word that contains meta information for the transaction execution. +/// +/// # Current layout +/// +/// - 0 byte (MSB): server-side tx execution mode +/// In the server, we may want to execute different parts of the transaction in the different context +/// For example, when checking validity, we don't want to actually execute transaction and have side effects. +/// +/// Possible values: +/// - `0x00`: validate & execute (normal mode) +/// - `0x02`: execute but DO NOT validate +/// +/// - 31 byte (LSB): whether to execute transaction or not (at all). +pub(super) fn assemble_tx_meta(execution_mode: TxExecutionMode, execute_tx: bool) -> U256 { + let mut output = [0u8; 32]; + + // Set 0 byte (execution mode) + output[0] = match execution_mode { + TxExecutionMode::VerifyExecute => 0x00, + TxExecutionMode::EstimateFee { .. } => 0x00, + TxExecutionMode::EthCall { .. } => 0x02, + }; + + // Set 31 byte (marker for tx execution) + output[31] = u8::from(execute_tx); + + U256::from_big_endian(&output) +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/constants.rs b/core/lib/multivm/src/versions/vm_boojum_integration/constants.rs new file mode 100644 index 000000000000..bf6a49473595 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/constants.rs @@ -0,0 +1,147 @@ +use zk_evm_1_4_0::aux_structures::MemoryPage; +pub use zk_evm_1_4_0::zkevm_opcode_defs::system_params::{ + ERGS_PER_CIRCUIT, INITIAL_STORAGE_WRITE_PUBDATA_BYTES, MAX_PUBDATA_PER_BLOCK, +}; +use zksync_system_constants::{L1_GAS_PER_PUBDATA_BYTE, MAX_L2_TX_GAS_LIMIT, MAX_NEW_FACTORY_DEPS}; + +use crate::vm_boojum_integration::old_vm::utils::heap_page_from_base; + +/// The amount of ergs to be reserved at the end of the batch to ensure that it has enough ergs to verify compression, etc. +pub(crate) const BOOTLOADER_BATCH_TIP_OVERHEAD: u32 = 80_000_000; + +/// The size of the bootloader memory in bytes which is used by the protocol. +/// While the maximal possible size is a lot higher, we restrict ourselves to a certain limit to reduce +/// the requirements on RAM. +pub(crate) const USED_BOOTLOADER_MEMORY_BYTES: usize = 1 << 24; +pub(crate) const USED_BOOTLOADER_MEMORY_WORDS: usize = USED_BOOTLOADER_MEMORY_BYTES / 32; + +// This the number of pubdata such that it should be always possible to publish +// from a single transaction. Note, that these pubdata bytes include only bytes that are +// to be published inside the body of transaction (i.e. excluding of factory deps). +pub(crate) const GUARANTEED_PUBDATA_PER_L1_BATCH: u64 = 4000; + +// The users should always be able to provide `MAX_GAS_PER_PUBDATA_BYTE` gas per pubdata in their +// transactions so that they are able to send at least `GUARANTEED_PUBDATA_PER_L1_BATCH` bytes per +// transaction. +pub(crate) const MAX_GAS_PER_PUBDATA_BYTE: u64 = + MAX_L2_TX_GAS_LIMIT / GUARANTEED_PUBDATA_PER_L1_BATCH; + +// The maximal number of transactions in a single batch +pub(crate) const MAX_TXS_IN_BLOCK: usize = 1024; + +/// Max cycles for a single transaction. +pub const MAX_CYCLES_FOR_TX: u32 = u32::MAX; + +/// The first 32 slots are reserved for debugging purposes +pub(crate) const DEBUG_SLOTS_OFFSET: usize = 8; +pub(crate) const DEBUG_FIRST_SLOTS: usize = 32; +/// The next 33 slots are reserved for dealing with the paymaster context (1 slot for storing length + 32 slots for storing the actual context). +pub(crate) const PAYMASTER_CONTEXT_SLOTS: usize = 32 + 1; +/// The next PAYMASTER_CONTEXT_SLOTS + 7 slots free slots are needed before each tx, so that the +/// postOp operation could be encoded correctly. +pub(crate) const MAX_POSTOP_SLOTS: usize = PAYMASTER_CONTEXT_SLOTS + 7; + +/// Slots used to store the current L2 transaction's hash and the hash recommended +/// to be used for signing the transaction's content. +const CURRENT_L2_TX_HASHES_SLOTS: usize = 2; + +/// Slots used to store the calldata for the KnownCodesStorage to mark new factory +/// dependencies as known ones. Besides the slots for the new factory dependencies themselves +/// another 4 slots are needed for: selector, marker of whether the user should pay for the pubdata, +/// the offset for the encoding of the array as well as the length of the array. +const NEW_FACTORY_DEPS_RESERVED_SLOTS: usize = MAX_NEW_FACTORY_DEPS + 4; + +/// The operator can provide for each transaction the proposed minimal refund +pub(crate) const OPERATOR_REFUNDS_SLOTS: usize = MAX_TXS_IN_BLOCK; + +pub(crate) const OPERATOR_REFUNDS_OFFSET: usize = DEBUG_SLOTS_OFFSET + + DEBUG_FIRST_SLOTS + + PAYMASTER_CONTEXT_SLOTS + + CURRENT_L2_TX_HASHES_SLOTS + + NEW_FACTORY_DEPS_RESERVED_SLOTS; + +pub(crate) const TX_OVERHEAD_OFFSET: usize = OPERATOR_REFUNDS_OFFSET + OPERATOR_REFUNDS_SLOTS; +pub(crate) const TX_OVERHEAD_SLOTS: usize = MAX_TXS_IN_BLOCK; + +pub(crate) const TX_TRUSTED_GAS_LIMIT_OFFSET: usize = TX_OVERHEAD_OFFSET + TX_OVERHEAD_SLOTS; +pub(crate) const TX_TRUSTED_GAS_LIMIT_SLOTS: usize = MAX_TXS_IN_BLOCK; + +pub(crate) const COMPRESSED_BYTECODES_SLOTS: usize = 32768; + +pub(crate) const PRIORITY_TXS_L1_DATA_OFFSET: usize = + COMPRESSED_BYTECODES_OFFSET + COMPRESSED_BYTECODES_SLOTS; +pub(crate) const PRIORITY_TXS_L1_DATA_SLOTS: usize = 2; + +pub const OPERATOR_PROVIDED_L1_MESSENGER_PUBDATA_OFFSET: usize = + PRIORITY_TXS_L1_DATA_OFFSET + PRIORITY_TXS_L1_DATA_SLOTS; + +/// One of "worst case" scenarios for the number of state diffs in a batch is when 120kb of pubdata is spent +/// on repeated writes, that are all zeroed out. In this case, the number of diffs is 120k / 5 = 24k. This means that they will have +/// accommodate 6528000 bytes of calldata for the uncompressed state diffs. Adding 120k on top leaves us with +/// roughly 6650000 bytes needed for calldata. 207813 slots are needed to accommodate this amount of data. +/// We round up to 208000 slots just in case. +/// +/// In theory though much more calldata could be used (if for instance 1 byte is used for enum index). It is the responsibility of the +/// operator to ensure that it can form the correct calldata for the L1Messenger. +pub(crate) const OPERATOR_PROVIDED_L1_MESSENGER_PUBDATA_SLOTS: usize = 208000; + +pub(crate) const BOOTLOADER_TX_DESCRIPTION_OFFSET: usize = + OPERATOR_PROVIDED_L1_MESSENGER_PUBDATA_OFFSET + OPERATOR_PROVIDED_L1_MESSENGER_PUBDATA_SLOTS; + +/// The size of the bootloader memory dedicated to the encodings of transactions +pub(crate) const BOOTLOADER_TX_ENCODING_SPACE: u32 = + (USED_BOOTLOADER_MEMORY_WORDS - TX_DESCRIPTION_OFFSET - MAX_TXS_IN_BLOCK) as u32; + +// Size of the bootloader tx description in words +pub(crate) const BOOTLOADER_TX_DESCRIPTION_SIZE: usize = 2; + +/// The actual descriptions of transactions should start after the minor descriptions and a MAX_POSTOP_SLOTS +/// free slots to allow postOp encoding. +pub(crate) const TX_DESCRIPTION_OFFSET: usize = BOOTLOADER_TX_DESCRIPTION_OFFSET + + BOOTLOADER_TX_DESCRIPTION_SIZE * MAX_TXS_IN_BLOCK + + MAX_POSTOP_SLOTS; + +pub(crate) const TX_GAS_LIMIT_OFFSET: usize = 4; + +const INITIAL_BASE_PAGE: u32 = 8; +pub const BOOTLOADER_HEAP_PAGE: u32 = heap_page_from_base(MemoryPage(INITIAL_BASE_PAGE)).0; +pub const BLOCK_OVERHEAD_GAS: u32 = 1200000; +pub const BLOCK_OVERHEAD_L1_GAS: u32 = 1000000; +pub const BLOCK_OVERHEAD_PUBDATA: u32 = BLOCK_OVERHEAD_L1_GAS / L1_GAS_PER_PUBDATA_BYTE; + +/// VM Hooks are used for communication between bootloader and tracers. +/// The 'type' / 'opcode' is put into VM_HOOK_POSITION slot, +/// and VM_HOOKS_PARAMS_COUNT parameters (each 32 bytes) are put in the slots before. +/// So the layout looks like this: +/// `[param 0][param 1][vmhook opcode]` +pub const VM_HOOK_POSITION: u32 = RESULT_SUCCESS_FIRST_SLOT - 1; +pub const VM_HOOK_PARAMS_COUNT: u32 = 2; +pub const VM_HOOK_PARAMS_START_POSITION: u32 = VM_HOOK_POSITION - VM_HOOK_PARAMS_COUNT; + +pub(crate) const MAX_MEM_SIZE_BYTES: u32 = 16777216; // 2^24 + +/// Arbitrary space in memory closer to the end of the page +pub const RESULT_SUCCESS_FIRST_SLOT: u32 = + (MAX_MEM_SIZE_BYTES - (MAX_TXS_IN_BLOCK as u32) * 32) / 32; + +/// How many gas bootloader is allowed to spend within one block. +/// Note that this value doesn't correspond to the gas limit of any particular transaction +/// (except for the fact that, of course, gas limit for each transaction should be <= `BLOCK_GAS_LIMIT`). +pub const BLOCK_GAS_LIMIT: u32 = + zk_evm_1_4_0::zkevm_opcode_defs::system_params::VM_INITIAL_FRAME_ERGS; + +/// How many gas is allowed to spend on a single transaction in eth_call method +pub const ETH_CALL_GAS_LIMIT: u32 = MAX_L2_TX_GAS_LIMIT as u32; + +/// ID of the transaction from L1 +pub const L1_TX_TYPE: u8 = 255; + +pub(crate) const TX_OPERATOR_L2_BLOCK_INFO_OFFSET: usize = + TX_TRUSTED_GAS_LIMIT_OFFSET + TX_TRUSTED_GAS_LIMIT_SLOTS; + +pub(crate) const TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO: usize = 4; +pub(crate) const TX_OPERATOR_L2_BLOCK_INFO_SLOTS: usize = + (MAX_TXS_IN_BLOCK + 1) * TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO; + +pub(crate) const COMPRESSED_BYTECODES_OFFSET: usize = + TX_OPERATOR_L2_BLOCK_INFO_OFFSET + TX_OPERATOR_L2_BLOCK_INFO_SLOTS; diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/implementation/bytecode.rs b/core/lib/multivm/src/versions/vm_boojum_integration/implementation/bytecode.rs new file mode 100644 index 000000000000..2e3770a9c52e --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/implementation/bytecode.rs @@ -0,0 +1,58 @@ +use itertools::Itertools; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_types::U256; +use zksync_utils::{ + bytecode::{compress_bytecode, hash_bytecode, CompressedBytecodeInfo}, + bytes_to_be_words, +}; + +use crate::{interface::VmInterface, vm_boojum_integration::Vm, HistoryMode}; + +impl Vm { + /// Checks the last transaction has successfully published compressed bytecodes and returns `true` if there is at least one is still unknown. + pub(crate) fn has_unpublished_bytecodes(&mut self) -> bool { + self.get_last_tx_compressed_bytecodes().iter().any(|info| { + !self + .state + .storage + .storage + .get_ptr() + .borrow_mut() + .is_bytecode_known(&hash_bytecode(&info.original)) + }) + } +} + +/// Converts bytecode to tokens and hashes it. +pub(crate) fn bytecode_to_factory_dep(bytecode: Vec) -> (U256, Vec) { + let bytecode_hash = hash_bytecode(&bytecode); + let bytecode_hash = U256::from_big_endian(bytecode_hash.as_bytes()); + + let bytecode_words = bytes_to_be_words(bytecode); + + (bytecode_hash, bytecode_words) +} + +pub(crate) fn compress_bytecodes( + bytecodes: &[Vec], + storage: StoragePtr, +) -> Vec { + bytecodes + .iter() + .enumerate() + .sorted_by_key(|(_idx, dep)| *dep) + .dedup_by(|x, y| x.1 == y.1) + .filter(|(_idx, dep)| !storage.borrow_mut().is_bytecode_known(&hash_bytecode(dep))) + .sorted_by_key(|(idx, _dep)| *idx) + .filter_map(|(_idx, dep)| { + let compressed_bytecode = compress_bytecode(dep); + + compressed_bytecode + .ok() + .map(|compressed| CompressedBytecodeInfo { + original: dep.clone(), + compressed, + }) + }) + .collect() +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/implementation/execution.rs b/core/lib/multivm/src/versions/vm_boojum_integration/implementation/execution.rs new file mode 100644 index 000000000000..0f608c833331 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/implementation/execution.rs @@ -0,0 +1,138 @@ +use zk_evm_1_4_0::aux_structures::Timestamp; +use zksync_state::WriteStorage; + +use crate::{ + interface::{ + types::tracer::{TracerExecutionStatus, VmExecutionStopReason}, + VmExecutionMode, VmExecutionResultAndLogs, + }, + vm_boojum_integration::{ + old_vm::utils::{vm_may_have_ended_inner, VmExecutionResult}, + tracers::{ + circuits_capacity::circuit_statistic_from_cycles, dispatcher::TracerDispatcher, + DefaultExecutionTracer, PubdataTracer, RefundsTracer, + }, + vm::Vm, + }, + HistoryMode, +}; + +impl Vm { + pub(crate) fn inspect_inner( + &mut self, + dispatcher: TracerDispatcher, + execution_mode: VmExecutionMode, + ) -> VmExecutionResultAndLogs { + let mut enable_refund_tracer = false; + if let VmExecutionMode::OneTx = execution_mode { + // Move the pointer to the next transaction + self.bootloader_state.move_tx_to_execute_pointer(); + enable_refund_tracer = true; + } + + let (_, result) = + self.inspect_and_collect_results(dispatcher, execution_mode, enable_refund_tracer); + result + } + + /// Execute VM with given traces until the stop reason is reached. + /// Collect the result from the default tracers. + fn inspect_and_collect_results( + &mut self, + dispatcher: TracerDispatcher, + execution_mode: VmExecutionMode, + with_refund_tracer: bool, + ) -> (VmExecutionStopReason, VmExecutionResultAndLogs) { + let refund_tracers = + with_refund_tracer.then_some(RefundsTracer::new(self.batch_env.clone())); + let mut tx_tracer: DefaultExecutionTracer = + DefaultExecutionTracer::new( + self.system_env.default_validation_computational_gas_limit, + execution_mode, + dispatcher, + self.storage.clone(), + refund_tracers, + Some(PubdataTracer::new(self.batch_env.clone(), execution_mode)), + ); + + let timestamp_initial = Timestamp(self.state.local_state.timestamp); + let cycles_initial = self.state.local_state.monotonic_cycle_counter; + let gas_remaining_before = self.gas_remaining(); + let spent_pubdata_counter_before = self.state.local_state.spent_pubdata_counter; + + let stop_reason = self.execute_with_default_tracer(&mut tx_tracer); + + let gas_remaining_after = self.gas_remaining(); + + let logs = self.collect_execution_logs_after_timestamp(timestamp_initial); + + let (refunds, pubdata_published) = tx_tracer + .refund_tracer + .as_ref() + .map(|x| (x.get_refunds(), x.pubdata_published())) + .unwrap_or_default(); + + let statistics = self.get_statistics( + timestamp_initial, + cycles_initial, + &tx_tracer, + gas_remaining_before, + gas_remaining_after, + spent_pubdata_counter_before, + pubdata_published, + logs.total_log_queries_count, + circuit_statistic_from_cycles(tx_tracer.circuits_tracer.statistics), + ); + let result = tx_tracer.result_tracer.into_result(); + + let result = VmExecutionResultAndLogs { + result, + logs, + statistics, + refunds, + }; + + (stop_reason, result) + } + + /// Execute vm with given tracers until the stop reason is reached. + fn execute_with_default_tracer( + &mut self, + tracer: &mut DefaultExecutionTracer, + ) -> VmExecutionStopReason { + tracer.initialize_tracer(&mut self.state); + let result = loop { + // Sanity check: we should never reach the maximum value, because then we won't be able to process the next cycle. + assert_ne!( + self.state.local_state.monotonic_cycle_counter, + u32::MAX, + "VM reached maximum possible amount of cycles. Vm state: {:?}", + self.state + ); + + self.state + .cycle(tracer) + .expect("Failed execution VM cycle."); + + if let TracerExecutionStatus::Stop(reason) = + tracer.finish_cycle(&mut self.state, &mut self.bootloader_state) + { + break VmExecutionStopReason::TracerRequestedStop(reason); + } + if self.has_ended() { + break VmExecutionStopReason::VmFinished; + } + }; + tracer.after_vm_execution(&mut self.state, &self.bootloader_state, result.clone()); + result + } + + fn has_ended(&self) -> bool { + match vm_may_have_ended_inner(&self.state) { + None | Some(VmExecutionResult::MostLikelyDidNotFinish(_, _)) => false, + Some( + VmExecutionResult::Ok(_) | VmExecutionResult::Revert(_) | VmExecutionResult::Panic, + ) => true, + } + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/implementation/gas.rs b/core/lib/multivm/src/versions/vm_boojum_integration/implementation/gas.rs new file mode 100644 index 000000000000..56f13de05e54 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/implementation/gas.rs @@ -0,0 +1,43 @@ +use zksync_state::WriteStorage; + +use crate::{ + vm_boojum_integration::{tracers::DefaultExecutionTracer, vm::Vm}, + HistoryMode, +}; + +impl Vm { + /// Returns the amount of gas remaining to the VM. + /// Note that this *does not* correspond to the gas limit of a transaction. + /// To calculate the amount of gas spent by transaction, you should call this method before and after + /// the execution, and subtract these values. + /// + /// Note: this method should only be called when either transaction is fully completed or VM completed + /// its execution. Remaining gas value is read from the current stack frame, so if you'll attempt to + /// read it during the transaction execution, you may receive invalid value. + pub(crate) fn gas_remaining(&self) -> u32 { + self.state.local_state.callstack.current.ergs_remaining + } + + pub(crate) fn calculate_computational_gas_used( + &self, + tracer: &DefaultExecutionTracer, + gas_remaining_before: u32, + spent_pubdata_counter_before: u32, + ) -> u32 { + let total_gas_used = gas_remaining_before + .checked_sub(self.gas_remaining()) + .expect("underflow"); + let gas_used_on_pubdata = + tracer.gas_spent_on_pubdata(&self.state.local_state) - spent_pubdata_counter_before; + total_gas_used + .checked_sub(gas_used_on_pubdata) + .unwrap_or_else(|| { + tracing::error!( + "Gas used on pubdata is greater than total gas used. On pubdata: {}, total: {}", + gas_used_on_pubdata, + total_gas_used + ); + 0 + }) + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/implementation/logs.rs b/core/lib/multivm/src/versions/vm_boojum_integration/implementation/logs.rs new file mode 100644 index 000000000000..73be046d7978 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/implementation/logs.rs @@ -0,0 +1,78 @@ +use zk_evm_1_4_0::aux_structures::Timestamp; +use zksync_state::WriteStorage; +use zksync_types::{ + event::extract_l2tol1logs_from_l1_messenger, + l2_to_l1_log::{L2ToL1Log, SystemL2ToL1Log, UserL2ToL1Log}, + VmEvent, +}; + +use crate::{ + glue::GlueInto, + interface::types::outputs::VmExecutionLogs, + vm_boojum_integration::{ + old_vm::utils::precompile_calls_count_after_timestamp, utils::logs, vm::Vm, + }, + HistoryMode, +}; + +impl Vm { + pub(crate) fn collect_execution_logs_after_timestamp( + &self, + from_timestamp: Timestamp, + ) -> VmExecutionLogs { + let storage_logs: Vec<_> = self + .state + .storage + .storage_log_queries_after_timestamp(from_timestamp) + .iter() + .map(|log| **log) + .collect(); + let storage_logs_count = storage_logs.len(); + + let (events, system_l2_to_l1_logs) = + self.collect_events_and_l1_system_logs_after_timestamp(from_timestamp); + + let log_queries = self + .state + .event_sink + .log_queries_after_timestamp(from_timestamp); + + let precompile_calls_count = precompile_calls_count_after_timestamp( + self.state.precompiles_processor.timestamp_history.inner(), + from_timestamp, + ); + + let user_logs = extract_l2tol1logs_from_l1_messenger(&events); + + let total_log_queries_count = + storage_logs_count + log_queries.len() + precompile_calls_count; + + VmExecutionLogs { + storage_logs: storage_logs + .into_iter() + .map(|log| log.glue_into()) + .collect(), + events, + user_l2_to_l1_logs: user_logs + .into_iter() + .map(|log| UserL2ToL1Log(log.into())) + .collect(), + system_l2_to_l1_logs: system_l2_to_l1_logs + .into_iter() + .map(SystemL2ToL1Log) + .collect(), + total_log_queries_count, + } + } + + pub(crate) fn collect_events_and_l1_system_logs_after_timestamp( + &self, + from_timestamp: Timestamp, + ) -> (Vec, Vec) { + logs::collect_events_and_l1_system_logs_after_timestamp( + &self.state, + &self.batch_env, + from_timestamp, + ) + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/implementation/mod.rs b/core/lib/multivm/src/versions/vm_boojum_integration/implementation/mod.rs new file mode 100644 index 000000000000..161732cf0348 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/implementation/mod.rs @@ -0,0 +1,7 @@ +mod bytecode; +mod execution; +mod gas; +mod logs; +mod snapshots; +mod statistics; +mod tx; diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/implementation/snapshots.rs b/core/lib/multivm/src/versions/vm_boojum_integration/implementation/snapshots.rs new file mode 100644 index 000000000000..b5b09c0fd6d2 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/implementation/snapshots.rs @@ -0,0 +1,89 @@ +use std::time::Duration; + +use vise::{Buckets, EncodeLabelSet, EncodeLabelValue, Family, Histogram, Metrics}; +use zk_evm_1_4_0::aux_structures::Timestamp; +use zksync_state::WriteStorage; + +use crate::vm_boojum_integration::{ + old_vm::oracles::OracleWithHistory, types::internals::VmSnapshot, vm::Vm, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelSet, EncodeLabelValue)] +#[metrics(label = "stage", rename_all = "snake_case")] +enum RollbackStage { + DecommitmentProcessorRollback, + EventSinkRollback, + StorageRollback, + MemoryRollback, + PrecompilesProcessorRollback, + ApplyBootloaderSnapshot, +} + +#[derive(Debug, Metrics)] +#[metrics(prefix = "server_vm_boojum_integration")] +struct VmMetrics { + #[metrics(buckets = Buckets::LATENCIES)] + rollback_time: Family>, +} + +#[vise::register] +static METRICS: vise::Global = vise::Global::new(); + +/// Implementation of VM related to rollbacks inside virtual machine +impl Vm { + pub(crate) fn make_snapshot_inner(&mut self) { + self.snapshots.push(VmSnapshot { + // Vm local state contains O(1) various parameters (registers/etc). + // The only "expensive" copying here is copying of the call stack. + // It will take `O(callstack_depth)` to copy it. + // So it is generally recommended to get snapshots of the bootloader frame, + // where the depth is 1. + local_state: self.state.local_state.clone(), + bootloader_state: self.bootloader_state.get_snapshot(), + }); + } + + pub(crate) fn rollback_to_snapshot(&mut self, snapshot: VmSnapshot) { + let VmSnapshot { + local_state, + bootloader_state, + } = snapshot; + + let stage_latency = + METRICS.rollback_time[&RollbackStage::DecommitmentProcessorRollback].start(); + let timestamp = Timestamp(local_state.timestamp); + tracing::trace!("Rolling back decomitter"); + self.state + .decommittment_processor + .rollback_to_timestamp(timestamp); + stage_latency.observe(); + + let stage_latency = METRICS.rollback_time[&RollbackStage::EventSinkRollback].start(); + tracing::trace!("Rolling back event_sink"); + self.state.event_sink.rollback_to_timestamp(timestamp); + stage_latency.observe(); + + let stage_latency = METRICS.rollback_time[&RollbackStage::StorageRollback].start(); + tracing::trace!("Rolling back storage"); + self.state.storage.rollback_to_timestamp(timestamp); + stage_latency.observe(); + + let stage_latency = METRICS.rollback_time[&RollbackStage::MemoryRollback].start(); + tracing::trace!("Rolling back memory"); + self.state.memory.rollback_to_timestamp(timestamp); + stage_latency.observe(); + + let stage_latency = + METRICS.rollback_time[&RollbackStage::PrecompilesProcessorRollback].start(); + tracing::trace!("Rolling back precompiles_processor"); + self.state + .precompiles_processor + .rollback_to_timestamp(timestamp); + stage_latency.observe(); + + self.state.local_state = local_state; + let stage_latency = METRICS.rollback_time[&RollbackStage::ApplyBootloaderSnapshot].start(); + self.bootloader_state.apply_snapshot(bootloader_state); + stage_latency.observe(); + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/implementation/statistics.rs b/core/lib/multivm/src/versions/vm_boojum_integration/implementation/statistics.rs new file mode 100644 index 000000000000..2bb0f1dc0f72 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/implementation/statistics.rs @@ -0,0 +1,72 @@ +use zk_evm_1_4_0::aux_structures::Timestamp; +use zksync_state::WriteStorage; +use zksync_types::{circuit::CircuitStatistic, U256}; + +use crate::{ + interface::{VmExecutionStatistics, VmMemoryMetrics}, + vm_boojum_integration::{tracers::DefaultExecutionTracer, vm::Vm}, + HistoryMode, +}; + +/// Module responsible for observing the VM behavior, i.e. calculating the statistics of the VM runs +/// or reporting the VM memory usage. + +impl Vm { + /// Get statistics about TX execution. + #[allow(clippy::too_many_arguments)] + pub(crate) fn get_statistics( + &self, + timestamp_initial: Timestamp, + cycles_initial: u32, + tracer: &DefaultExecutionTracer, + gas_remaining_before: u32, + gas_remaining_after: u32, + spent_pubdata_counter_before: u32, + pubdata_published: u32, + total_log_queries_count: usize, + circuit_statistic: CircuitStatistic, + ) -> VmExecutionStatistics { + let computational_gas_used = self.calculate_computational_gas_used( + tracer, + gas_remaining_before, + spent_pubdata_counter_before, + ); + VmExecutionStatistics { + contracts_used: self + .state + .decommittment_processor + .get_decommitted_bytecodes_after_timestamp(timestamp_initial), + cycles_used: self.state.local_state.monotonic_cycle_counter - cycles_initial, + gas_used: gas_remaining_before - gas_remaining_after, + computational_gas_used, + total_log_queries: total_log_queries_count, + pubdata_published, + circuit_statistic, + } + } + + /// Returns the hashes the bytecodes that have been decommitted by the decommitment processor. + pub(crate) fn get_used_contracts(&self) -> Vec { + self.state + .decommittment_processor + .decommitted_code_hashes + .inner() + .keys() + .cloned() + .collect() + } + + /// Returns the info about all oracles' sizes. + pub(crate) fn record_vm_memory_metrics_inner(&self) -> VmMemoryMetrics { + VmMemoryMetrics { + event_sink_inner: self.state.event_sink.get_size(), + event_sink_history: self.state.event_sink.get_history_size(), + memory_inner: self.state.memory.get_size(), + memory_history: self.state.memory.get_history_size(), + decommittment_processor_inner: self.state.decommittment_processor.get_size(), + decommittment_processor_history: self.state.decommittment_processor.get_history_size(), + storage_inner: self.state.storage.get_size(), + storage_history: self.state.storage.get_history_size(), + } + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/implementation/tx.rs b/core/lib/multivm/src/versions/vm_boojum_integration/implementation/tx.rs new file mode 100644 index 000000000000..9eac3e749837 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/implementation/tx.rs @@ -0,0 +1,68 @@ +use zk_evm_1_4_0::aux_structures::Timestamp; +use zksync_state::WriteStorage; +use zksync_types::{l1::is_l1_tx_type, Transaction}; + +use crate::{ + vm_boojum_integration::{ + constants::BOOTLOADER_HEAP_PAGE, + implementation::bytecode::{bytecode_to_factory_dep, compress_bytecodes}, + types::internals::TransactionData, + utils::fee::get_batch_gas_per_pubdata, + vm::Vm, + }, + HistoryMode, +}; + +impl Vm { + pub(crate) fn push_raw_transaction( + &mut self, + tx: TransactionData, + predefined_overhead: u32, + predefined_refund: u32, + with_compression: bool, + ) { + let timestamp = Timestamp(self.state.local_state.timestamp); + let codes_for_decommiter = tx + .factory_deps + .iter() + .map(|dep| bytecode_to_factory_dep(dep.clone())) + .collect(); + + let compressed_bytecodes = if is_l1_tx_type(tx.tx_type) || !with_compression { + // L1 transactions do not need compression + vec![] + } else { + compress_bytecodes(&tx.factory_deps, self.state.storage.storage.get_ptr()) + }; + + self.state + .decommittment_processor + .populate(codes_for_decommiter, timestamp); + + let trusted_ergs_limit = tx.trusted_ergs_limit(get_batch_gas_per_pubdata(&self.batch_env)); + + let memory = self.bootloader_state.push_tx( + tx, + predefined_overhead, + predefined_refund, + compressed_bytecodes, + trusted_ergs_limit, + self.system_env.chain_id, + ); + + self.state + .memory + .populate_page(BOOTLOADER_HEAP_PAGE as usize, memory, timestamp); + } + + pub(crate) fn push_transaction_with_compression( + &mut self, + tx: Transaction, + with_compression: bool, + ) { + let tx: TransactionData = tx.into(); + let block_gas_per_pubdata_byte = get_batch_gas_per_pubdata(&self.batch_env); + let overhead = tx.overhead_gas(block_gas_per_pubdata_byte as u32); + self.push_raw_transaction(tx, overhead, 0, with_compression); + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/mod.rs b/core/lib/multivm/src/versions/vm_boojum_integration/mod.rs new file mode 100644 index 000000000000..83693e4b24e9 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/mod.rs @@ -0,0 +1,34 @@ +pub use self::{ + bootloader_state::BootloaderState, + old_vm::{ + history_recorder::{ + AppDataFrameManagerWithHistory, HistoryDisabled, HistoryEnabled, HistoryMode, + }, + memory::SimpleMemory, + }, + oracles::storage::StorageOracle, + tracers::{ + dispatcher::TracerDispatcher, + traits::{ToTracerPointer, TracerPointer, VmTracer}, + }, + types::internals::ZkSyncVmState, + utils::transaction_encoding::TransactionVmExt, + vm::Vm, +}; +pub use crate::interface::types::{ + inputs::{L1BatchEnv, L2BlockEnv, SystemEnv, TxExecutionMode, VmExecutionMode}, + outputs::{ + BootloaderMemory, CurrentExecutionState, ExecutionResult, FinishedL1Batch, L2Block, + Refunds, VmExecutionLogs, VmExecutionResultAndLogs, VmExecutionStatistics, VmMemoryMetrics, + }, +}; + +mod bootloader_state; +pub mod constants; +mod implementation; +mod old_vm; +mod oracles; +pub(crate) mod tracers; +mod types; +pub mod utils; +mod vm; diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/event_sink.rs b/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/event_sink.rs new file mode 100644 index 000000000000..6638057643d4 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/event_sink.rs @@ -0,0 +1,263 @@ +use std::collections::HashMap; + +use itertools::Itertools; +use zk_evm_1_4_0::{ + abstractions::EventSink, + aux_structures::{LogQuery, Timestamp}, + reference_impls::event_sink::EventMessage, + zkevm_opcode_defs::system_params::{ + BOOTLOADER_FORMAL_ADDRESS, EVENT_AUX_BYTE, L1_MESSAGE_AUX_BYTE, + }, +}; +use zksync_types::U256; + +use crate::vm_boojum_integration::old_vm::{ + history_recorder::{AppDataFrameManagerWithHistory, HistoryEnabled, HistoryMode}, + oracles::OracleWithHistory, +}; + +#[derive(Debug, Clone, PartialEq, Default)] +pub struct InMemoryEventSink { + frames_stack: AppDataFrameManagerWithHistory, H>, +} + +impl OracleWithHistory for InMemoryEventSink { + fn rollback_to_timestamp(&mut self, timestamp: Timestamp) { + self.frames_stack.rollback_to_timestamp(timestamp); + } +} + +// as usual, if we rollback the current frame then we apply changes to storage immediately, +// otherwise we carry rollbacks to the parent's frames + +impl InMemoryEventSink { + pub fn flatten(&self) -> (Vec, Vec, Vec) { + assert_eq!( + self.frames_stack.len(), + 1, + "there must exist an initial keeper frame" + ); + // we forget rollbacks as we have finished the execution and can just apply them + let history = self.frames_stack.forward().current_frame(); + + let (events, l1_messages) = Self::events_and_l1_messages_from_history(history); + let events_logs = Self::events_logs_from_history(history); + + (events_logs, events, l1_messages) + } + + pub fn get_log_queries(&self) -> usize { + self.frames_stack.forward().current_frame().len() + } + + /// Returns the log queries in the current frame where `log_query.timestamp >= from_timestamp`. + pub fn log_queries_after_timestamp(&self, from_timestamp: Timestamp) -> &[Box] { + let events = self.frames_stack.forward().current_frame(); + + // Select all of the last elements where `e.timestamp >= from_timestamp`. + // Note, that using binary search here is dangerous, because the logs are not sorted by timestamp. + events + .rsplit(|e| e.timestamp < from_timestamp) + .next() + .unwrap_or(&[]) + } + + pub fn get_events_and_l2_l1_logs_after_timestamp( + &self, + from_timestamp: Timestamp, + ) -> (Vec, Vec) { + Self::events_and_l1_messages_from_history(self.log_queries_after_timestamp(from_timestamp)) + } + + fn events_logs_from_history(history: &[Box]) -> Vec { + // Filter out all the L2->L1 logs and leave only events + let mut events = history + .iter() + .filter_map(|log_query| (log_query.aux_byte == EVENT_AUX_BYTE).then_some(**log_query)) + .collect_vec(); + + // Sort the events by timestamp and rollback flag, basically ensuring that + // if an event has been rolled back, the original event and its rollback will be put together + events.sort_by_key(|log| (log.timestamp, log.rollback)); + + let mut stack = Vec::::new(); + let mut net_history = vec![]; + for el in events.iter() { + assert_eq!(el.shard_id, 0, "only rollup shard is supported"); + if stack.is_empty() { + assert!(!el.rollback); + stack.push(*el); + } else { + // we can always pop as it's either one to add to queue, or discard + let previous = stack.pop().unwrap(); + if previous.timestamp == el.timestamp { + // Only rollback can have the same timestamp, so here we do nothing and simply + // double check the invariants + assert!(!previous.rollback); + assert!(el.rollback); + assert!(previous.rw_flag); + assert!(el.rw_flag); + assert_eq!(previous.tx_number_in_block, el.tx_number_in_block); + assert_eq!(previous.shard_id, el.shard_id); + assert_eq!(previous.address, el.address); + assert_eq!(previous.key, el.key); + assert_eq!(previous.written_value, el.written_value); + assert_eq!(previous.is_service, el.is_service); + continue; + } else { + // The event on the stack has not been rolled back. It must be a different event, + // with a different timestamp. + assert!(!el.rollback); + stack.push(*el); + + // cleanup some fields + // flags are conventions + let sorted_log_query = LogQuery { + timestamp: Timestamp(0), + tx_number_in_block: previous.tx_number_in_block, + aux_byte: 0, + shard_id: previous.shard_id, + address: previous.address, + key: previous.key, + read_value: U256::zero(), + written_value: previous.written_value, + rw_flag: false, + rollback: false, + is_service: previous.is_service, + }; + + net_history.push(sorted_log_query); + } + } + } + + // In case the stack is non-empty, then the last element of it has not been rolled back. + if let Some(previous) = stack.pop() { + // cleanup some fields + // flags are conventions + let sorted_log_query = LogQuery { + timestamp: Timestamp(0), + tx_number_in_block: previous.tx_number_in_block, + aux_byte: 0, + shard_id: previous.shard_id, + address: previous.address, + key: previous.key, + read_value: U256::zero(), + written_value: previous.written_value, + rw_flag: false, + rollback: false, + is_service: previous.is_service, + }; + + net_history.push(sorted_log_query); + } + + net_history + } + + fn events_and_l1_messages_from_history( + history: &[Box], + ) -> (Vec, Vec) { + let mut tmp = HashMap::::with_capacity(history.len()); + + // note that we only use "forward" part and discard the rollbacks at the end, + // since if rollbacks of parents were not appended anywhere we just still keep them + for el in history { + // we are time ordered here in terms of rollbacks + if tmp.get(&el.timestamp.0).is_some() { + assert!(el.rollback); + tmp.remove(&el.timestamp.0); + } else { + assert!(!el.rollback); + tmp.insert(el.timestamp.0, **el); + } + } + + // naturally sorted by timestamp + let mut keys: Vec<_> = tmp.keys().cloned().collect(); + keys.sort_unstable(); + + let mut events = vec![]; + let mut l1_messages = vec![]; + + for k in keys.into_iter() { + let el = tmp.remove(&k).unwrap(); + let LogQuery { + shard_id, + is_service, + tx_number_in_block, + address, + key, + written_value, + aux_byte, + .. + } = el; + + let event = EventMessage { + shard_id, + is_first: is_service, + tx_number_in_block, + address, + key, + value: written_value, + }; + + if aux_byte == EVENT_AUX_BYTE { + events.push(event); + } else { + l1_messages.push(event); + } + } + + (events, l1_messages) + } + + pub(crate) fn get_size(&self) -> usize { + self.frames_stack.get_size() + } + + pub fn get_history_size(&self) -> usize { + self.frames_stack.get_history_size() + } + + pub fn delete_history(&mut self) { + self.frames_stack.delete_history(); + } +} + +impl EventSink for InMemoryEventSink { + // when we enter a new frame we should remember all our current applications and rollbacks + // when we exit the current frame then if we did panic we should concatenate all current + // forward and rollback cases + + fn add_partial_query(&mut self, _monotonic_cycle_counter: u32, mut query: LogQuery) { + assert!(query.rw_flag); + assert!(query.aux_byte == EVENT_AUX_BYTE || query.aux_byte == L1_MESSAGE_AUX_BYTE); + assert!(!query.rollback); + + // just append to rollbacks and a full history + + self.frames_stack + .push_forward(Box::new(query), query.timestamp); + // we do not need it explicitly here, but let's be consistent with circuit counterpart + query.rollback = true; + self.frames_stack + .push_rollback(Box::new(query), query.timestamp); + } + + fn start_frame(&mut self, timestamp: Timestamp) { + self.frames_stack.push_frame(timestamp) + } + + fn finish_frame(&mut self, panicked: bool, timestamp: Timestamp) { + // if we panic then we append forward and rollbacks to the forward of parent, + // otherwise we place rollbacks of child before rollbacks of the parent + if panicked { + self.frames_stack.move_rollback_to_forward( + |q| q.address != *BOOTLOADER_FORMAL_ADDRESS || q.aux_byte != EVENT_AUX_BYTE, + timestamp, + ); + } + self.frames_stack.merge_frame(timestamp); + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/events.rs b/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/events.rs new file mode 100644 index 000000000000..eed8fee4ac86 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/events.rs @@ -0,0 +1,146 @@ +use zk_evm_1_4_0::{ethereum_types::Address, reference_impls::event_sink::EventMessage}; +use zksync_types::{L1BatchNumber, VmEvent, EVENT_WRITER_ADDRESS, H256}; +use zksync_utils::{be_chunks_to_h256_words, h256_to_account_address}; + +#[derive(Clone)] +pub(crate) struct SolidityLikeEvent { + pub(crate) shard_id: u8, + pub(crate) tx_number_in_block: u16, + pub(crate) address: Address, + pub(crate) topics: Vec<[u8; 32]>, + pub(crate) data: Vec, +} + +impl SolidityLikeEvent { + pub(crate) fn into_vm_event(self, block_number: L1BatchNumber) -> VmEvent { + VmEvent { + location: (block_number, self.tx_number_in_block as u32), + address: self.address, + indexed_topics: be_chunks_to_h256_words(self.topics), + value: self.data, + } + } +} + +fn merge_events_inner(events: Vec) -> Vec { + let mut result = vec![]; + let mut current: Option<(usize, u32, SolidityLikeEvent)> = None; + + for message in events.into_iter() { + if !message.is_first { + let EventMessage { + shard_id, + is_first: _, + tx_number_in_block, + address, + key, + value, + } = message; + + if let Some((mut remaining_data_length, mut remaining_topics, mut event)) = + current.take() + { + if event.address != address + || event.shard_id != shard_id + || event.tx_number_in_block != tx_number_in_block + { + continue; + } + let mut data_0 = [0u8; 32]; + let mut data_1 = [0u8; 32]; + key.to_big_endian(&mut data_0); + value.to_big_endian(&mut data_1); + for el in [data_0, data_1].iter() { + if remaining_topics != 0 { + event.topics.push(*el); + remaining_topics -= 1; + } else if remaining_data_length != 0 { + if remaining_data_length >= 32 { + event.data.extend_from_slice(el); + remaining_data_length -= 32; + } else { + event.data.extend_from_slice(&el[..remaining_data_length]); + remaining_data_length = 0; + } + } + } + + if remaining_data_length != 0 || remaining_topics != 0 { + current = Some((remaining_data_length, remaining_topics, event)) + } else { + result.push(event); + } + } + } else { + // start new one. First take the old one only if it's well formed + if let Some((remaining_data_length, remaining_topics, event)) = current.take() { + if remaining_data_length == 0 && remaining_topics == 0 { + result.push(event); + } + } + + let EventMessage { + shard_id, + is_first: _, + tx_number_in_block, + address, + key, + value, + } = message; + // split key as our internal marker. Ignore higher bits + let mut num_topics = key.0[0] as u32; + let mut data_length = (key.0[0] >> 32) as usize; + let mut buffer = [0u8; 32]; + value.to_big_endian(&mut buffer); + + let (topics, data) = if num_topics == 0 && data_length == 0 { + (vec![], vec![]) + } else if num_topics == 0 { + data_length -= 32; + (vec![], buffer.to_vec()) + } else { + num_topics -= 1; + (vec![buffer], vec![]) + }; + + let new_event = SolidityLikeEvent { + shard_id, + tx_number_in_block, + address, + topics, + data, + }; + + current = Some((data_length, num_topics, new_event)) + } + } + + // add the last one + if let Some((remaining_data_length, remaining_topics, event)) = current.take() { + if remaining_data_length == 0 && remaining_topics == 0 { + result.push(event); + } + } + + result +} + +pub(crate) fn merge_events(events: Vec) -> Vec { + let raw_events = merge_events_inner(events); + + raw_events + .into_iter() + .filter(|e| e.address == EVENT_WRITER_ADDRESS) + .map(|event| { + // The events writer events where the first topic is the actual address of the event and the rest of the topics are real topics + let address = h256_to_account_address(&H256(event.topics[0])); + let topics = event.topics.into_iter().skip(1).collect(); + + SolidityLikeEvent { + topics, + address, + ..event + } + }) + .collect() +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/history_recorder.rs b/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/history_recorder.rs new file mode 100644 index 000000000000..90d0c868ea33 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/history_recorder.rs @@ -0,0 +1,811 @@ +use std::{collections::HashMap, fmt::Debug, hash::Hash}; + +use zk_evm_1_4_0::{ + aux_structures::Timestamp, + vm_state::PrimitiveValue, + zkevm_opcode_defs::{self}, +}; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_types::{StorageKey, U256}; +use zksync_utils::{h256_to_u256, u256_to_h256}; + +pub(crate) type MemoryWithHistory = HistoryRecorder; +pub(crate) type IntFrameManagerWithHistory = HistoryRecorder, H>; + +// Within the same cycle, timestamps in range `timestamp..timestamp+TIME_DELTA_PER_CYCLE-1` +// can be used. This can sometimes violate monotonicity of the timestamp within the +// same cycle, so it should be normalized. +#[inline] +fn normalize_timestamp(timestamp: Timestamp) -> Timestamp { + let timestamp = timestamp.0; + + // Making sure it is divisible by `TIME_DELTA_PER_CYCLE` + Timestamp(timestamp - timestamp % zkevm_opcode_defs::TIME_DELTA_PER_CYCLE) +} + +/// Accepts history item as its parameter and applies it. +pub trait WithHistory { + type HistoryRecord; + type ReturnValue; + + // Applies an action and returns the action that would + // rollback its effect as well as some returned value + fn apply_historic_record( + &mut self, + item: Self::HistoryRecord, + ) -> (Self::HistoryRecord, Self::ReturnValue); +} + +type EventList = Vec<(Timestamp, ::HistoryRecord)>; + +/// Controls if rolling back is possible or not. +/// Either [HistoryEnabled] or [HistoryDisabled]. +pub trait HistoryMode: private::Sealed + Debug + Clone + Default { + type History: Default; + + fn clone_history(history: &Self::History) -> Self::History + where + T::HistoryRecord: Clone; + fn mutate_history)>( + recorder: &mut HistoryRecorder, + f: F, + ); + fn borrow_history) -> R, R>( + recorder: &HistoryRecorder, + f: F, + default: R, + ) -> R; +} + +mod private { + pub trait Sealed {} + impl Sealed for super::HistoryEnabled {} + impl Sealed for super::HistoryDisabled {} +} + +// derives require that all type parameters implement the trait, which is why +// HistoryEnabled/Disabled derive so many traits even though they mostly don't +// exist at runtime. + +/// A data structure with this parameter can be rolled back. +/// See also: [HistoryDisabled] +#[derive(Debug, Clone, Default, PartialEq)] +pub struct HistoryEnabled; + +/// A data structure with this parameter cannot be rolled back. +/// It won't even have rollback methods. +/// See also: [HistoryEnabled] +#[derive(Debug, Clone, Default)] +pub struct HistoryDisabled; + +impl HistoryMode for HistoryEnabled { + type History = EventList; + + fn clone_history(history: &Self::History) -> Self::History + where + T::HistoryRecord: Clone, + { + history.clone() + } + fn mutate_history)>( + recorder: &mut HistoryRecorder, + f: F, + ) { + f(&mut recorder.inner, &mut recorder.history) + } + fn borrow_history) -> R, R>( + recorder: &HistoryRecorder, + f: F, + _: R, + ) -> R { + f(&recorder.history) + } +} + +impl HistoryMode for HistoryDisabled { + type History = (); + + fn clone_history(_: &Self::History) -> Self::History {} + fn mutate_history)>( + _: &mut HistoryRecorder, + _: F, + ) { + } + fn borrow_history) -> R, R>( + _: &HistoryRecorder, + _: F, + default: R, + ) -> R { + default + } +} + +/// A struct responsible for tracking history for +/// a component that is passed as a generic parameter to it (`inner`). +#[derive(Default)] +pub struct HistoryRecorder { + inner: T, + history: H::History, +} + +impl PartialEq for HistoryRecorder +where + T::HistoryRecord: PartialEq, +{ + fn eq(&self, other: &Self) -> bool { + self.inner == other.inner + && self.borrow_history(|h1| other.borrow_history(|h2| h1 == h2, true), true) + } +} + +impl Debug for HistoryRecorder +where + T::HistoryRecord: Debug, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut debug_struct = f.debug_struct("HistoryRecorder"); + debug_struct.field("inner", &self.inner); + self.borrow_history( + |h| { + debug_struct.field("history", h); + }, + (), + ); + debug_struct.finish() + } +} + +impl Clone for HistoryRecorder +where + T::HistoryRecord: Clone, + H: HistoryMode, +{ + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + history: H::clone_history(&self.history), + } + } +} + +impl HistoryRecorder { + pub fn from_inner(inner: T) -> Self { + Self { + inner, + history: Default::default(), + } + } + + pub fn inner(&self) -> &T { + &self.inner + } + + /// If history exists, modify it using `f`. + pub fn mutate_history)>(&mut self, f: F) { + H::mutate_history(self, f); + } + + /// If history exists, feed it into `f`. Otherwise return `default`. + pub fn borrow_history) -> R, R>(&self, f: F, default: R) -> R { + H::borrow_history(self, f, default) + } + + pub fn apply_historic_record( + &mut self, + item: T::HistoryRecord, + timestamp: Timestamp, + ) -> T::ReturnValue { + let (reversed_item, return_value) = self.inner.apply_historic_record(item); + + self.mutate_history(|_, history| { + let last_recorded_timestamp = history.last().map(|(t, _)| *t).unwrap_or(Timestamp(0)); + let timestamp = normalize_timestamp(timestamp); + assert!( + last_recorded_timestamp <= timestamp, + "Timestamps are not monotonic" + ); + history.push((timestamp, reversed_item)); + }); + + return_value + } + + /// Deletes all the history for its component, making + /// its current state irreversible + pub fn delete_history(&mut self) { + self.mutate_history(|_, h| h.clear()) + } +} + +impl HistoryRecorder { + pub fn history(&self) -> &Vec<(Timestamp, T::HistoryRecord)> { + &self.history + } + + pub(crate) fn rollback_to_timestamp(&mut self, timestamp: Timestamp) { + loop { + let should_undo = self + .history + .last() + .map(|(item_timestamp, _)| *item_timestamp >= timestamp) + .unwrap_or(false); + if !should_undo { + break; + } + + let (_, item_to_apply) = self.history.pop().unwrap(); + self.inner.apply_historic_record(item_to_apply); + } + } +} + +#[derive(Debug, Clone, PartialEq)] +pub enum VectorHistoryEvent { + Push(X), + Pop, +} + +impl WithHistory for Vec { + type HistoryRecord = VectorHistoryEvent; + type ReturnValue = Option; + fn apply_historic_record( + &mut self, + item: VectorHistoryEvent, + ) -> (Self::HistoryRecord, Self::ReturnValue) { + match item { + VectorHistoryEvent::Pop => { + // Note, that here we assume that the users + // will check themselves whether this vector is empty + // prior to popping from it. + let poped_item = self.pop().unwrap(); + + (VectorHistoryEvent::Push(poped_item), Some(poped_item)) + } + VectorHistoryEvent::Push(x) => { + self.push(x); + + (VectorHistoryEvent::Pop, None) + } + } + } +} + +impl HistoryRecorder, H> { + pub fn push(&mut self, elem: T, timestamp: Timestamp) { + self.apply_historic_record(VectorHistoryEvent::Push(elem), timestamp); + } + + pub fn pop(&mut self, timestamp: Timestamp) -> T { + self.apply_historic_record(VectorHistoryEvent::Pop, timestamp) + .unwrap() + } + + pub fn len(&self) -> usize { + self.inner.len() + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct HashMapHistoryEvent { + pub key: K, + pub value: Option, +} + +impl WithHistory for HashMap { + type HistoryRecord = HashMapHistoryEvent; + type ReturnValue = Option; + fn apply_historic_record( + &mut self, + item: Self::HistoryRecord, + ) -> (Self::HistoryRecord, Self::ReturnValue) { + let HashMapHistoryEvent { key, value } = item; + + let prev_value = match value { + Some(x) => self.insert(key, x), + None => self.remove(&key), + }; + + ( + HashMapHistoryEvent { + key, + value: prev_value.clone(), + }, + prev_value, + ) + } +} + +impl HistoryRecorder, H> { + pub fn insert(&mut self, key: K, value: V, timestamp: Timestamp) -> Option { + self.apply_historic_record( + HashMapHistoryEvent { + key, + value: Some(value), + }, + timestamp, + ) + } + + pub(crate) fn remove(&mut self, key: K, timestamp: Timestamp) -> Option { + self.apply_historic_record(HashMapHistoryEvent { key, value: None }, timestamp) + } +} + +/// A stack of stacks. The inner stacks are called frames. +/// +/// Does not support popping from the outer stack. Instead, the outer stack can +/// push its topmost frame's contents onto the previous frame. +#[derive(Debug, Clone, PartialEq)] +pub struct FramedStack { + data: Vec, + frame_start_indices: Vec, +} + +impl Default for FramedStack { + fn default() -> Self { + // We typically require at least the first frame to be there + // since the last user-provided frame might be reverted + Self { + data: vec![], + frame_start_indices: vec![0], + } + } +} + +#[derive(Debug, Clone, PartialEq)] +pub enum FramedStackEvent { + Push(T), + Pop, + PushFrame(usize), + MergeFrame, +} + +impl WithHistory for FramedStack { + type HistoryRecord = FramedStackEvent; + type ReturnValue = (); + + fn apply_historic_record( + &mut self, + item: Self::HistoryRecord, + ) -> (Self::HistoryRecord, Self::ReturnValue) { + use FramedStackEvent::*; + match item { + Push(x) => { + self.data.push(x); + (Pop, ()) + } + Pop => { + let x = self.data.pop().unwrap(); + (Push(x), ()) + } + PushFrame(i) => { + self.frame_start_indices.push(i); + (MergeFrame, ()) + } + MergeFrame => { + let pos = self.frame_start_indices.pop().unwrap(); + (PushFrame(pos), ()) + } + } + } +} + +impl FramedStack { + fn push_frame(&self) -> FramedStackEvent { + FramedStackEvent::PushFrame(self.data.len()) + } + + pub fn current_frame(&self) -> &[T] { + &self.data[*self.frame_start_indices.last().unwrap()..self.data.len()] + } + + fn len(&self) -> usize { + self.frame_start_indices.len() + } + + /// Returns the amount of memory taken up by the stored items + pub fn get_size(&self) -> usize { + self.data.len() * std::mem::size_of::() + } +} + +impl HistoryRecorder, H> { + pub fn push_to_frame(&mut self, x: T, timestamp: Timestamp) { + self.apply_historic_record(FramedStackEvent::Push(x), timestamp); + } + pub fn clear_frame(&mut self, timestamp: Timestamp) { + let start = *self.inner.frame_start_indices.last().unwrap(); + while self.inner.data.len() > start { + self.apply_historic_record(FramedStackEvent::Pop, timestamp); + } + } + pub fn extend_frame(&mut self, items: impl IntoIterator, timestamp: Timestamp) { + for x in items { + self.push_to_frame(x, timestamp); + } + } + pub fn push_frame(&mut self, timestamp: Timestamp) { + self.apply_historic_record(self.inner.push_frame(), timestamp); + } + pub fn merge_frame(&mut self, timestamp: Timestamp) { + self.apply_historic_record(FramedStackEvent::MergeFrame, timestamp); + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct AppDataFrameManagerWithHistory { + forward: HistoryRecorder, H>, + rollback: HistoryRecorder, H>, +} + +impl Default for AppDataFrameManagerWithHistory { + fn default() -> Self { + Self { + forward: Default::default(), + rollback: Default::default(), + } + } +} + +impl AppDataFrameManagerWithHistory { + pub(crate) fn delete_history(&mut self) { + self.forward.delete_history(); + self.rollback.delete_history(); + } + + pub(crate) fn push_forward(&mut self, item: T, timestamp: Timestamp) { + self.forward.push_to_frame(item, timestamp); + } + pub(crate) fn push_rollback(&mut self, item: T, timestamp: Timestamp) { + self.rollback.push_to_frame(item, timestamp); + } + pub(crate) fn push_frame(&mut self, timestamp: Timestamp) { + self.forward.push_frame(timestamp); + self.rollback.push_frame(timestamp); + } + pub(crate) fn merge_frame(&mut self, timestamp: Timestamp) { + self.forward.merge_frame(timestamp); + self.rollback.merge_frame(timestamp); + } + + pub(crate) fn len(&self) -> usize { + self.forward.inner.len() + } + pub(crate) fn forward(&self) -> &FramedStack { + &self.forward.inner + } + pub(crate) fn rollback(&self) -> &FramedStack { + &self.rollback.inner + } + + /// Returns the amount of memory taken up by the stored items + pub(crate) fn get_size(&self) -> usize { + self.forward().get_size() + self.rollback().get_size() + } + + pub(crate) fn get_history_size(&self) -> usize { + (self.forward.borrow_history(|h| h.len(), 0) + self.rollback.borrow_history(|h| h.len(), 0)) + * std::mem::size_of::< as WithHistory>::HistoryRecord>() + } +} + +impl AppDataFrameManagerWithHistory { + pub(crate) fn move_rollback_to_forward bool>( + &mut self, + filter: F, + timestamp: Timestamp, + ) { + for x in self.rollback.inner.current_frame().iter().rev() { + if filter(x) { + self.forward.push_to_frame(x.clone(), timestamp); + } + } + self.rollback.clear_frame(timestamp); + } +} + +impl AppDataFrameManagerWithHistory { + pub(crate) fn rollback_to_timestamp(&mut self, timestamp: Timestamp) { + self.forward.rollback_to_timestamp(timestamp); + self.rollback.rollback_to_timestamp(timestamp); + } +} + +const PRIMITIVE_VALUE_EMPTY: PrimitiveValue = PrimitiveValue::empty(); +const PAGE_SUBDIVISION_LEN: usize = 64; + +#[derive(Debug, Default, Clone)] +struct MemoryPage { + root: Vec>>, +} + +impl MemoryPage { + fn get(&self, slot: usize) -> &PrimitiveValue { + self.root + .get(slot / PAGE_SUBDIVISION_LEN) + .and_then(|inner| inner.as_ref()) + .map(|leaf| &leaf[slot % PAGE_SUBDIVISION_LEN]) + .unwrap_or(&PRIMITIVE_VALUE_EMPTY) + } + fn set(&mut self, slot: usize, value: PrimitiveValue) -> PrimitiveValue { + let root_index = slot / PAGE_SUBDIVISION_LEN; + let leaf_index = slot % PAGE_SUBDIVISION_LEN; + + if self.root.len() <= root_index { + self.root.resize_with(root_index + 1, || None); + } + let node = &mut self.root[root_index]; + + if let Some(leaf) = node { + let old = leaf[leaf_index]; + leaf[leaf_index] = value; + old + } else { + let mut leaf = [PrimitiveValue::empty(); PAGE_SUBDIVISION_LEN]; + leaf[leaf_index] = value; + self.root[root_index] = Some(Box::new(leaf)); + PrimitiveValue::empty() + } + } + + fn get_size(&self) -> usize { + self.root.iter().filter_map(|x| x.as_ref()).count() + * PAGE_SUBDIVISION_LEN + * std::mem::size_of::() + } +} + +impl PartialEq for MemoryPage { + fn eq(&self, other: &Self) -> bool { + for slot in 0..self.root.len().max(other.root.len()) * PAGE_SUBDIVISION_LEN { + if self.get(slot) != other.get(slot) { + return false; + } + } + true + } +} + +#[derive(Debug, Default, Clone)] +pub struct MemoryWrapper { + memory: Vec, +} + +impl PartialEq for MemoryWrapper { + fn eq(&self, other: &Self) -> bool { + let empty_page = MemoryPage::default(); + let empty_pages = std::iter::repeat(&empty_page); + self.memory + .iter() + .chain(empty_pages.clone()) + .zip(other.memory.iter().chain(empty_pages)) + .take(self.memory.len().max(other.memory.len())) + .all(|(a, b)| a == b) + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct MemoryHistoryRecord { + pub page: usize, + pub slot: usize, + pub set_value: PrimitiveValue, +} + +impl MemoryWrapper { + pub fn ensure_page_exists(&mut self, page: usize) { + if self.memory.len() <= page { + // We don't need to record such events in history + // because all these vectors will be empty + self.memory.resize_with(page + 1, MemoryPage::default); + } + } + + pub fn dump_page_content_as_u256_words( + &self, + page_number: u32, + range: std::ops::Range, + ) -> Vec { + if let Some(page) = self.memory.get(page_number as usize) { + let mut result = vec![]; + for i in range { + result.push(*page.get(i as usize)); + } + result + } else { + vec![PrimitiveValue::empty(); range.len()] + } + } + + pub fn read_slot(&self, page: usize, slot: usize) -> &PrimitiveValue { + self.memory + .get(page) + .map(|page| page.get(slot)) + .unwrap_or(&PRIMITIVE_VALUE_EMPTY) + } + + pub fn get_size(&self) -> usize { + self.memory.iter().map(|page| page.get_size()).sum() + } +} + +impl WithHistory for MemoryWrapper { + type HistoryRecord = MemoryHistoryRecord; + type ReturnValue = PrimitiveValue; + + fn apply_historic_record( + &mut self, + item: MemoryHistoryRecord, + ) -> (Self::HistoryRecord, Self::ReturnValue) { + let MemoryHistoryRecord { + page, + slot, + set_value, + } = item; + + self.ensure_page_exists(page); + let page_handle = self.memory.get_mut(page).unwrap(); + let prev_value = page_handle.set(slot, set_value); + + let undo = MemoryHistoryRecord { + page, + slot, + set_value: prev_value, + }; + + (undo, prev_value) + } +} + +impl HistoryRecorder { + pub fn write_to_memory( + &mut self, + page: usize, + slot: usize, + value: PrimitiveValue, + timestamp: Timestamp, + ) -> PrimitiveValue { + self.apply_historic_record( + MemoryHistoryRecord { + page, + slot, + set_value: value, + }, + timestamp, + ) + } + + pub fn clear_page(&mut self, page: usize, timestamp: Timestamp) { + self.mutate_history(|inner, history| { + if let Some(page_handle) = inner.memory.get(page) { + for (i, x) in page_handle.root.iter().enumerate() { + if let Some(slots) = x { + for (j, value) in slots.iter().enumerate() { + if *value != PrimitiveValue::empty() { + history.push(( + timestamp, + MemoryHistoryRecord { + page, + slot: PAGE_SUBDIVISION_LEN * i + j, + set_value: *value, + }, + )) + } + } + } + } + inner.memory[page] = MemoryPage::default(); + } + }); + } +} + +#[derive(Debug)] +pub struct StorageWrapper { + storage_ptr: StoragePtr, +} + +impl StorageWrapper { + pub fn new(storage_ptr: StoragePtr) -> Self { + Self { storage_ptr } + } + + pub fn get_ptr(&self) -> StoragePtr { + self.storage_ptr.clone() + } + + pub fn read_from_storage(&self, key: &StorageKey) -> U256 { + h256_to_u256(self.storage_ptr.borrow_mut().read_value(key)) + } +} + +#[derive(Debug, Clone)] +pub struct StorageHistoryRecord { + pub key: StorageKey, + pub value: U256, +} + +impl WithHistory for StorageWrapper { + type HistoryRecord = StorageHistoryRecord; + type ReturnValue = U256; + + fn apply_historic_record( + &mut self, + item: Self::HistoryRecord, + ) -> (Self::HistoryRecord, Self::ReturnValue) { + let prev_value = h256_to_u256( + self.storage_ptr + .borrow_mut() + .set_value(item.key, u256_to_h256(item.value)), + ); + + let reverse_item = StorageHistoryRecord { + key: item.key, + value: prev_value, + }; + + (reverse_item, prev_value) + } +} + +impl HistoryRecorder, H> { + pub fn read_from_storage(&self, key: &StorageKey) -> U256 { + self.inner.read_from_storage(key) + } + + pub fn write_to_storage(&mut self, key: StorageKey, value: U256, timestamp: Timestamp) -> U256 { + self.apply_historic_record(StorageHistoryRecord { key, value }, timestamp) + } + + /// Returns a pointer to the storage. + /// Note, that any changes done to the storage via this pointer + /// will NOT be recorded as its history. + pub fn get_ptr(&self) -> StoragePtr { + self.inner.get_ptr() + } +} + +#[cfg(test)] +mod tests { + use zk_evm_1_4_0::{aux_structures::Timestamp, vm_state::PrimitiveValue}; + use zksync_types::U256; + + use crate::vm_boojum_integration::{ + old_vm::history_recorder::{HistoryRecorder, MemoryWrapper}, + HistoryDisabled, + }; + + #[test] + fn memory_equality() { + let mut a: HistoryRecorder = Default::default(); + let mut b = a.clone(); + let nonzero = U256::from_dec_str("123").unwrap(); + let different_value = U256::from_dec_str("1234").unwrap(); + + let write = |memory: &mut HistoryRecorder, value| { + memory.write_to_memory( + 17, + 34, + PrimitiveValue { + value, + is_pointer: false, + }, + Timestamp::empty(), + ); + }; + + assert_eq!(a, b); + + write(&mut b, nonzero); + assert_ne!(a, b); + + write(&mut a, different_value); + assert_ne!(a, b); + + write(&mut a, nonzero); + assert_eq!(a, b); + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/memory.rs b/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/memory.rs new file mode 100644 index 000000000000..8229727b6dd9 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/memory.rs @@ -0,0 +1,327 @@ +use zk_evm_1_4_0::{ + abstractions::{Memory, MemoryType}, + aux_structures::{MemoryPage, MemoryQuery, Timestamp}, + vm_state::PrimitiveValue, + zkevm_opcode_defs::FatPointer, +}; +use zksync_types::U256; + +use crate::vm_boojum_integration::old_vm::{ + history_recorder::{ + FramedStack, HistoryEnabled, HistoryMode, IntFrameManagerWithHistory, MemoryWithHistory, + MemoryWrapper, WithHistory, + }, + oracles::OracleWithHistory, + utils::{aux_heap_page_from_base, heap_page_from_base, stack_page_from_base}, +}; + +#[derive(Debug, Clone, PartialEq)] +pub struct SimpleMemory { + memory: MemoryWithHistory, + observable_pages: IntFrameManagerWithHistory, +} + +impl Default for SimpleMemory { + fn default() -> Self { + let mut memory: MemoryWithHistory = Default::default(); + memory.mutate_history(|_, h| h.reserve(607)); + Self { + memory, + observable_pages: Default::default(), + } + } +} + +impl OracleWithHistory for SimpleMemory { + fn rollback_to_timestamp(&mut self, timestamp: Timestamp) { + self.memory.rollback_to_timestamp(timestamp); + self.observable_pages.rollback_to_timestamp(timestamp); + } +} + +impl SimpleMemory { + pub fn populate(&mut self, elements: Vec<(u32, Vec)>, timestamp: Timestamp) { + for (page, values) in elements.into_iter() { + for (i, value) in values.into_iter().enumerate() { + let value = PrimitiveValue { + value, + is_pointer: false, + }; + self.memory + .write_to_memory(page as usize, i, value, timestamp); + } + } + } + + pub fn populate_page( + &mut self, + page: usize, + elements: Vec<(usize, U256)>, + timestamp: Timestamp, + ) { + elements.into_iter().for_each(|(offset, value)| { + let value = PrimitiveValue { + value, + is_pointer: false, + }; + + self.memory.write_to_memory(page, offset, value, timestamp); + }); + } + + pub fn dump_page_content_as_u256_words( + &self, + page: u32, + range: std::ops::Range, + ) -> Vec { + self.memory + .inner() + .dump_page_content_as_u256_words(page, range) + .into_iter() + .map(|v| v.value) + .collect() + } + + pub fn read_slot(&self, page: usize, slot: usize) -> &PrimitiveValue { + self.memory.inner().read_slot(page, slot) + } + + // This method should be used with relatively small lengths, since + // we don't heavily optimize here for cases with long lengths + pub fn read_unaligned_bytes(&self, page: usize, start: usize, length: usize) -> Vec { + if length == 0 { + return vec![]; + } + + let end = start + length - 1; + + let mut current_word = start / 32; + let mut result = vec![]; + while current_word * 32 <= end { + let word_value = self.read_slot(page, current_word).value; + let word_value = { + let mut bytes: Vec = vec![0u8; 32]; + word_value.to_big_endian(&mut bytes); + bytes + }; + + result.extend(extract_needed_bytes_from_word( + word_value, + current_word, + start, + end, + )); + + current_word += 1; + } + + assert_eq!(result.len(), length); + + result + } + + pub(crate) fn get_size(&self) -> usize { + // Hashmap memory overhead is neglected. + let memory_size = self.memory.inner().get_size(); + let observable_pages_size = self.observable_pages.inner().get_size(); + + memory_size + observable_pages_size + } + + pub fn get_history_size(&self) -> usize { + let memory_size = self.memory.borrow_history(|h| h.len(), 0) + * std::mem::size_of::<::HistoryRecord>(); + let observable_pages_size = self.observable_pages.borrow_history(|h| h.len(), 0) + * std::mem::size_of::< as WithHistory>::HistoryRecord>(); + + memory_size + observable_pages_size + } + + pub fn delete_history(&mut self) { + self.memory.delete_history(); + self.observable_pages.delete_history(); + } +} + +impl Memory for SimpleMemory { + fn execute_partial_query( + &mut self, + _monotonic_cycle_counter: u32, + mut query: MemoryQuery, + ) -> MemoryQuery { + match query.location.memory_type { + MemoryType::Stack => {} + MemoryType::Heap | MemoryType::AuxHeap => { + // The following assertion works fine even when doing a read + // from heap through pointer, since `value_is_pointer` can only be set to + // `true` during memory writes. + assert!( + !query.value_is_pointer, + "Pointers can only be stored on stack" + ); + } + MemoryType::FatPointer => { + assert!(!query.rw_flag); + assert!( + !query.value_is_pointer, + "Pointers can only be stored on stack" + ); + } + MemoryType::Code => { + unreachable!("code should be through specialized query"); + } + } + + let page = query.location.page.0 as usize; + let slot = query.location.index.0 as usize; + + if query.rw_flag { + self.memory.write_to_memory( + page, + slot, + PrimitiveValue { + value: query.value, + is_pointer: query.value_is_pointer, + }, + query.timestamp, + ); + } else { + let current_value = self.read_slot(page, slot); + query.value = current_value.value; + query.value_is_pointer = current_value.is_pointer; + } + + query + } + + fn specialized_code_query( + &mut self, + _monotonic_cycle_counter: u32, + mut query: MemoryQuery, + ) -> MemoryQuery { + assert_eq!(query.location.memory_type, MemoryType::Code); + assert!( + !query.value_is_pointer, + "Pointers are not used for decommmits" + ); + + let page = query.location.page.0 as usize; + let slot = query.location.index.0 as usize; + + if query.rw_flag { + self.memory.write_to_memory( + page, + slot, + PrimitiveValue { + value: query.value, + is_pointer: query.value_is_pointer, + }, + query.timestamp, + ); + } else { + let current_value = self.read_slot(page, slot); + query.value = current_value.value; + query.value_is_pointer = current_value.is_pointer; + } + + query + } + + fn read_code_query( + &self, + _monotonic_cycle_counter: u32, + mut query: MemoryQuery, + ) -> MemoryQuery { + assert_eq!(query.location.memory_type, MemoryType::Code); + assert!( + !query.value_is_pointer, + "Pointers are not used for decommmits" + ); + assert!(!query.rw_flag, "Only read queries can be processed"); + + let page = query.location.page.0 as usize; + let slot = query.location.index.0 as usize; + + let current_value = self.read_slot(page, slot); + query.value = current_value.value; + query.value_is_pointer = current_value.is_pointer; + + query + } + + fn start_global_frame( + &mut self, + _current_base_page: MemoryPage, + new_base_page: MemoryPage, + calldata_fat_pointer: FatPointer, + timestamp: Timestamp, + ) { + // Besides the calldata page, we also formally include the current stack + // page, heap page and aux heap page. + // The code page will be always left observable, so we don't include it here. + self.observable_pages.push_frame(timestamp); + self.observable_pages.extend_frame( + vec![ + calldata_fat_pointer.memory_page, + stack_page_from_base(new_base_page).0, + heap_page_from_base(new_base_page).0, + aux_heap_page_from_base(new_base_page).0, + ], + timestamp, + ); + } + + fn finish_global_frame( + &mut self, + base_page: MemoryPage, + returndata_fat_pointer: FatPointer, + timestamp: Timestamp, + ) { + // Safe to unwrap here, since `finish_global_frame` is never called with empty stack + let current_observable_pages = self.observable_pages.inner().current_frame(); + let returndata_page = returndata_fat_pointer.memory_page; + + for &page in current_observable_pages { + // If the page's number is greater than or equal to the `base_page`, + // it means that it was created by the internal calls of this contract. + // We need to add this check as the calldata pointer is also part of the + // observable pages. + if page >= base_page.0 && page != returndata_page { + self.memory.clear_page(page as usize, timestamp); + } + } + + self.observable_pages.clear_frame(timestamp); + self.observable_pages.merge_frame(timestamp); + + self.observable_pages + .push_to_frame(returndata_page, timestamp); + } +} + +// It is expected that there is some intersection between `[word_number*32..word_number*32+31]` and `[start, end]` +fn extract_needed_bytes_from_word( + word_value: Vec, + word_number: usize, + start: usize, + end: usize, +) -> Vec { + let word_start = word_number * 32; + let word_end = word_start + 31; // Note, that at `word_start + 32` a new word already starts + + let intersection_left = std::cmp::max(word_start, start); + let intersection_right = std::cmp::min(word_end, end); + + if intersection_right < intersection_left { + vec![] + } else { + let start_bytes = intersection_left - word_start; + let to_take = intersection_right - intersection_left + 1; + + word_value + .into_iter() + .skip(start_bytes) + .take(to_take) + .collect() + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/mod.rs b/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/mod.rs new file mode 100644 index 000000000000..afade1984614 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/mod.rs @@ -0,0 +1,8 @@ +/// This module contains the parts from old VM implementation, which were not changed during the vm implementation. +/// It should be refactored and removed in the future. +pub(crate) mod event_sink; +pub(crate) mod events; +pub(crate) mod history_recorder; +pub(crate) mod memory; +pub(crate) mod oracles; +pub(crate) mod utils; diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/oracles/decommitter.rs b/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/oracles/decommitter.rs new file mode 100644 index 000000000000..6ff63e17ce00 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/oracles/decommitter.rs @@ -0,0 +1,236 @@ +use std::{collections::HashMap, fmt::Debug}; + +use zk_evm_1_4_0::{ + abstractions::{DecommittmentProcessor, Memory, MemoryType}, + aux_structures::{ + DecommittmentQuery, MemoryIndex, MemoryLocation, MemoryPage, MemoryQuery, Timestamp, + }, +}; +use zksync_state::{ReadStorage, StoragePtr}; +use zksync_types::U256; +use zksync_utils::{bytecode::bytecode_len_in_words, bytes_to_be_words, u256_to_h256}; + +use super::OracleWithHistory; +use crate::vm_boojum_integration::old_vm::history_recorder::{ + HistoryEnabled, HistoryMode, HistoryRecorder, WithHistory, +}; + +/// The main job of the DecommiterOracle is to implement the DecommitmentProcessor trait - that is +/// used by the VM to 'load' bytecodes into memory. +#[derive(Debug)] +pub struct DecommitterOracle { + /// Pointer that enables to read contract bytecodes from the database. + storage: StoragePtr, + /// The cache of bytecodes that the bootloader "knows", but that are not necessarily in the database. + /// And it is also used as a database cache. + pub known_bytecodes: HistoryRecorder>, H>, + /// Stores pages of memory where certain code hashes have already been decommitted. + /// It is expected that they all are present in the DB. + // `decommitted_code_hashes` history is necessary + pub decommitted_code_hashes: HistoryRecorder, HistoryEnabled>, + /// Stores history of decommitment requests. + decommitment_requests: HistoryRecorder, H>, +} + +impl DecommitterOracle { + pub fn new(storage: StoragePtr) -> Self { + Self { + storage, + known_bytecodes: HistoryRecorder::default(), + decommitted_code_hashes: HistoryRecorder::default(), + decommitment_requests: HistoryRecorder::default(), + } + } + + /// Gets the bytecode for a given hash (either from storage, or from 'known_bytecodes' that were populated by `populate` method). + /// Panics if bytecode doesn't exist. + pub fn get_bytecode(&mut self, hash: U256, timestamp: Timestamp) -> Vec { + let entry = self.known_bytecodes.inner().get(&hash); + + match entry { + Some(x) => x.clone(), + None => { + // It is ok to panic here, since the decommitter is never called directly by + // the users and always called by the VM. VM will never let decommit the + // code hash which we didn't previously claim to know the preimage of. + let value = self + .storage + .borrow_mut() + .load_factory_dep(u256_to_h256(hash)) + .expect("Trying to decode unexisting hash"); + + let value = bytes_to_be_words(value); + self.known_bytecodes.insert(hash, value.clone(), timestamp); + value + } + } + } + + /// Adds additional bytecodes. They will take precedent over the bytecodes from storage. + pub fn populate(&mut self, bytecodes: Vec<(U256, Vec)>, timestamp: Timestamp) { + for (hash, bytecode) in bytecodes { + self.known_bytecodes.insert(hash, bytecode, timestamp); + } + } + + pub fn get_used_bytecode_hashes(&self) -> Vec { + self.decommitted_code_hashes + .inner() + .iter() + .map(|item| *item.0) + .collect() + } + + pub fn get_decommitted_bytecodes_after_timestamp(&self, timestamp: Timestamp) -> usize { + // Note, that here we rely on the fact that for each used bytecode + // there is one and only one corresponding event in the history of it. + self.decommitted_code_hashes + .history() + .iter() + .rev() + .take_while(|(t, _)| *t >= timestamp) + .count() + } + + pub fn get_decommitted_code_hashes_with_history( + &self, + ) -> &HistoryRecorder, HistoryEnabled> { + &self.decommitted_code_hashes + } + + /// Returns the storage handle. Used only in tests. + pub fn get_storage(&self) -> StoragePtr { + self.storage.clone() + } + + /// Measures the amount of memory used by this Oracle (used for metrics only). + pub(crate) fn get_size(&self) -> usize { + // Hashmap memory overhead is neglected. + let known_bytecodes_size = self + .known_bytecodes + .inner() + .iter() + .map(|(_, value)| value.len() * std::mem::size_of::()) + .sum::(); + let decommitted_code_hashes_size = + self.decommitted_code_hashes.inner().len() * std::mem::size_of::<(U256, u32)>(); + + known_bytecodes_size + decommitted_code_hashes_size + } + + pub(crate) fn get_history_size(&self) -> usize { + let known_bytecodes_stack_size = self.known_bytecodes.borrow_history(|h| h.len(), 0) + * std::mem::size_of::<> as WithHistory>::HistoryRecord>(); + let known_bytecodes_heap_size = self.known_bytecodes.borrow_history( + |h| { + h.iter() + .map(|(_, event)| { + if let Some(bytecode) = event.value.as_ref() { + bytecode.len() * std::mem::size_of::() + } else { + 0 + } + }) + .sum::() + }, + 0, + ); + let decommitted_code_hashes_size = + self.decommitted_code_hashes.borrow_history(|h| h.len(), 0) + * std::mem::size_of::< as WithHistory>::HistoryRecord>(); + + known_bytecodes_stack_size + known_bytecodes_heap_size + decommitted_code_hashes_size + } + + pub fn delete_history(&mut self) { + self.decommitted_code_hashes.delete_history(); + self.known_bytecodes.delete_history(); + self.decommitment_requests.delete_history(); + } +} + +impl OracleWithHistory for DecommitterOracle { + fn rollback_to_timestamp(&mut self, timestamp: Timestamp) { + self.decommitted_code_hashes + .rollback_to_timestamp(timestamp); + self.known_bytecodes.rollback_to_timestamp(timestamp); + self.decommitment_requests.rollback_to_timestamp(timestamp); + } +} + +impl DecommittmentProcessor + for DecommitterOracle +{ + /// Loads a given bytecode hash into memory (see trait description for more details). + fn decommit_into_memory( + &mut self, + monotonic_cycle_counter: u32, + mut partial_query: DecommittmentQuery, + memory: &mut M, + ) -> Result< + ( + zk_evm_1_4_0::aux_structures::DecommittmentQuery, + Option>, + ), + anyhow::Error, + > { + self.decommitment_requests.push((), partial_query.timestamp); + // First - check if we didn't fetch this bytecode in the past. + // If we did - we can just return the page that we used before (as the memory is readonly). + if let Some(memory_page) = self + .decommitted_code_hashes + .inner() + .get(&partial_query.hash) + .copied() + { + partial_query.is_fresh = false; + partial_query.memory_page = MemoryPage(memory_page); + partial_query.decommitted_length = + bytecode_len_in_words(&u256_to_h256(partial_query.hash)); + + Ok((partial_query, None)) + } else { + // We are fetching a fresh bytecode that we didn't read before. + let values = self.get_bytecode(partial_query.hash, partial_query.timestamp); + let page_to_use = partial_query.memory_page; + let timestamp = partial_query.timestamp; + partial_query.decommitted_length = values.len() as u16; + partial_query.is_fresh = true; + + // Create a template query, that we'll use for writing into memory. + // value & index are set to 0 - as they will be updated in the inner loop below. + let mut tmp_q = MemoryQuery { + timestamp, + location: MemoryLocation { + memory_type: MemoryType::Code, + page: page_to_use, + index: MemoryIndex(0), + }, + value: U256::zero(), + value_is_pointer: false, + rw_flag: true, + }; + self.decommitted_code_hashes + .insert(partial_query.hash, page_to_use.0, timestamp); + + // Copy the bytecode (that is stored in 'values' Vec) into the memory page. + if B { + for (i, value) in values.iter().enumerate() { + tmp_q.location.index = MemoryIndex(i as u32); + tmp_q.value = *value; + memory.specialized_code_query(monotonic_cycle_counter, tmp_q); + } + // If we're in the witness mode - we also have to return the values. + Ok((partial_query, Some(values))) + } else { + for (i, value) in values.into_iter().enumerate() { + tmp_q.location.index = MemoryIndex(i as u32); + tmp_q.value = value; + memory.specialized_code_query(monotonic_cycle_counter, tmp_q); + } + + Ok((partial_query, None)) + } + } + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/oracles/mod.rs b/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/oracles/mod.rs new file mode 100644 index 000000000000..3f8d2d0f1383 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/oracles/mod.rs @@ -0,0 +1,8 @@ +use zk_evm_1_4_0::aux_structures::Timestamp; + +pub(crate) mod decommitter; +pub(crate) mod precompile; + +pub(crate) trait OracleWithHistory { + fn rollback_to_timestamp(&mut self, timestamp: Timestamp); +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/oracles/precompile.rs b/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/oracles/precompile.rs new file mode 100644 index 000000000000..0fc1108ead85 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/oracles/precompile.rs @@ -0,0 +1,114 @@ +use std::convert::TryFrom; + +use zk_evm_1_4_0::{ + abstractions::{Memory, PrecompileCyclesWitness, PrecompilesProcessor}, + aux_structures::{LogQuery, MemoryQuery, Timestamp}, + zk_evm_abstractions::precompiles::{ecrecover, keccak256, sha256, PrecompileAddress}, +}; + +use super::OracleWithHistory; +use crate::vm_boojum_integration::old_vm::history_recorder::{ + HistoryEnabled, HistoryMode, HistoryRecorder, +}; + +/// Wrap of DefaultPrecompilesProcessor that store queue +/// of timestamp when precompiles are called to be executed. +/// Number of precompiles per block is strictly limited, +/// saving timestamps allows us to check the exact number +/// of log queries, that were used during the tx execution. +#[derive(Debug, Clone)] +pub struct PrecompilesProcessorWithHistory { + pub timestamp_history: HistoryRecorder, H>, + pub precompile_cycles_history: HistoryRecorder, H>, +} + +impl Default for PrecompilesProcessorWithHistory { + fn default() -> Self { + Self { + timestamp_history: Default::default(), + precompile_cycles_history: Default::default(), + } + } +} + +impl OracleWithHistory for PrecompilesProcessorWithHistory { + fn rollback_to_timestamp(&mut self, timestamp: Timestamp) { + self.timestamp_history.rollback_to_timestamp(timestamp); + self.precompile_cycles_history + .rollback_to_timestamp(timestamp); + } +} + +impl PrecompilesProcessorWithHistory { + pub fn get_timestamp_history(&self) -> &Vec { + self.timestamp_history.inner() + } + + pub fn delete_history(&mut self) { + self.timestamp_history.delete_history(); + self.precompile_cycles_history.delete_history(); + } +} + +impl PrecompilesProcessor for PrecompilesProcessorWithHistory { + fn start_frame(&mut self) { + // there are no precompiles to rollback, do nothing + } + + fn execute_precompile( + &mut self, + monotonic_cycle_counter: u32, + query: LogQuery, + memory: &mut M, + ) -> Option<(Vec, Vec, PrecompileCyclesWitness)> { + // In the next line we same `query.timestamp` as both + // an operation in the history of precompiles processor and + // the time when this operation occurred. + // While slightly weird, it is done for consistency with other oracles + // where operations and timestamp have different types. + self.timestamp_history + .push(query.timestamp, query.timestamp); + + let address_low = u16::from_le_bytes([query.address.0[19], query.address.0[18]]); + if let Ok(precompile_address) = PrecompileAddress::try_from(address_low) { + let rounds = match precompile_address { + PrecompileAddress::Keccak256 => { + // pure function call, non-revertable + keccak256::keccak256_rounds_function::( + monotonic_cycle_counter, + query, + memory, + ) + .0 + } + PrecompileAddress::SHA256 => { + // pure function call, non-revertable + sha256::sha256_rounds_function::( + monotonic_cycle_counter, + query, + memory, + ) + .0 + } + PrecompileAddress::Ecrecover => { + // pure function call, non-revertable + ecrecover::ecrecover_function::( + monotonic_cycle_counter, + query, + memory, + ) + .0 + } + }; + + self.precompile_cycles_history + .push((precompile_address, rounds), query.timestamp); + }; + + None + } + + fn finish_frame(&mut self, _panicked: bool) { + // there are no revertible precompile yes, so we are ok + } +} diff --git a/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/storage.rs b/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/oracles/storage.rs similarity index 99% rename from core/lib/multivm/src/versions/vm_latest/old_vm/oracles/storage.rs rename to core/lib/multivm/src/versions/vm_boojum_integration/old_vm/oracles/storage.rs index b2c471832e46..1c14706de87a 100644 --- a/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/storage.rs +++ b/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/oracles/storage.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::vm_latest::old_vm::history_recorder::{ +use crate::vm_boojum_integration::old_vm::history_recorder::{ AppDataFrameManagerWithHistory, HashMapHistoryEvent, HistoryEnabled, HistoryMode, HistoryRecorder, StorageWrapper, WithHistory, }; diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/utils.rs b/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/utils.rs new file mode 100644 index 000000000000..342cc64ea2ac --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/old_vm/utils.rs @@ -0,0 +1,221 @@ +use zk_evm_1_4_0::{ + aux_structures::{MemoryPage, Timestamp}, + vm_state::PrimitiveValue, + zkevm_opcode_defs::{ + decoding::{AllowedPcOrImm, EncodingModeProduction, VmEncodingMode}, + FatPointer, RET_IMPLICIT_RETURNDATA_PARAMS_REGISTER, + }, +}; +use zksync_state::WriteStorage; +use zksync_system_constants::L1_GAS_PER_PUBDATA_BYTE; +use zksync_types::{Address, U256}; + +use crate::vm_boojum_integration::{ + old_vm::memory::SimpleMemory, types::internals::ZkSyncVmState, HistoryMode, +}; + +#[derive(Debug, Clone)] +pub(crate) enum VmExecutionResult { + Ok(Vec), + Revert(Vec), + Panic, + MostLikelyDidNotFinish(Address, u16), +} + +pub(crate) const fn stack_page_from_base(base: MemoryPage) -> MemoryPage { + MemoryPage(base.0 + 1) +} + +pub(crate) const fn heap_page_from_base(base: MemoryPage) -> MemoryPage { + MemoryPage(base.0 + 2) +} + +pub(crate) const fn aux_heap_page_from_base(base: MemoryPage) -> MemoryPage { + MemoryPage(base.0 + 3) +} + +pub(crate) trait FixedLengthIterator<'a, I: 'a, const N: usize>: Iterator +where + Self: 'a, +{ + fn next(&mut self) -> Option<::Item> { + ::next(self) + } +} + +pub(crate) trait IntoFixedLengthByteIterator { + type IntoIter: FixedLengthIterator<'static, u8, N>; + fn into_le_iter(self) -> Self::IntoIter; + fn into_be_iter(self) -> Self::IntoIter; +} + +pub(crate) struct FixedBufferValueIterator { + iter: std::array::IntoIter, +} + +impl Iterator for FixedBufferValueIterator { + type Item = T; + fn next(&mut self) -> Option { + self.iter.next() + } +} + +impl FixedLengthIterator<'static, T, N> + for FixedBufferValueIterator +{ +} + +impl IntoFixedLengthByteIterator<32> for U256 { + type IntoIter = FixedBufferValueIterator; + fn into_le_iter(self) -> Self::IntoIter { + let mut buffer = [0u8; 32]; + self.to_little_endian(&mut buffer); + + FixedBufferValueIterator { + iter: IntoIterator::into_iter(buffer), + } + } + + fn into_be_iter(self) -> Self::IntoIter { + let mut buffer = [0u8; 32]; + self.to_big_endian(&mut buffer); + + FixedBufferValueIterator { + iter: IntoIterator::into_iter(buffer), + } + } +} + +/// Receives sorted slice of timestamps. +/// Returns count of timestamps that are greater than or equal to `from_timestamp`. +/// Works in O(log(sorted_timestamps.len())). +pub(crate) fn precompile_calls_count_after_timestamp( + sorted_timestamps: &[Timestamp], + from_timestamp: Timestamp, +) -> usize { + sorted_timestamps.len() - sorted_timestamps.partition_point(|t| *t < from_timestamp) +} + +pub(crate) fn eth_price_per_pubdata_byte(l1_gas_price: u64) -> u64 { + // This value will typically be a lot less than u64 + // unless the gas price on L1 goes beyond tens of millions of gwei + l1_gas_price * (L1_GAS_PER_PUBDATA_BYTE as u64) +} + +pub(crate) fn vm_may_have_ended_inner( + vm: &ZkSyncVmState, +) -> Option { + let execution_has_ended = vm.execution_has_ended(); + + let r1 = vm.local_state.registers[RET_IMPLICIT_RETURNDATA_PARAMS_REGISTER as usize]; + let current_address = vm.local_state.callstack.get_current_stack().this_address; + + let outer_eh_location = >::PcOrImm::MAX.as_u64(); + match ( + execution_has_ended, + vm.local_state.callstack.get_current_stack().pc.as_u64(), + ) { + (true, 0) => { + let returndata = dump_memory_page_using_primitive_value(&vm.memory, r1); + + Some(VmExecutionResult::Ok(returndata)) + } + (false, _) => None, + (true, l) if l == outer_eh_location => { + // check `r1,r2,r3` + if vm.local_state.flags.overflow_or_less_than_flag { + Some(VmExecutionResult::Panic) + } else { + let returndata = dump_memory_page_using_primitive_value(&vm.memory, r1); + Some(VmExecutionResult::Revert(returndata)) + } + } + (_, a) => Some(VmExecutionResult::MostLikelyDidNotFinish( + current_address, + a as u16, + )), + } +} + +pub(crate) fn dump_memory_page_using_primitive_value( + memory: &SimpleMemory, + ptr: PrimitiveValue, +) -> Vec { + if !ptr.is_pointer { + return vec![]; + } + let fat_ptr = FatPointer::from_u256(ptr.value); + dump_memory_page_using_fat_pointer(memory, fat_ptr) +} + +pub(crate) fn dump_memory_page_using_fat_pointer( + memory: &SimpleMemory, + fat_ptr: FatPointer, +) -> Vec { + dump_memory_page_by_offset_and_length( + memory, + fat_ptr.memory_page, + (fat_ptr.start + fat_ptr.offset) as usize, + (fat_ptr.length - fat_ptr.offset) as usize, + ) +} + +pub(crate) fn dump_memory_page_by_offset_and_length( + memory: &SimpleMemory, + page: u32, + offset: usize, + length: usize, +) -> Vec { + assert!(offset < (1u32 << 24) as usize); + assert!(length < (1u32 << 24) as usize); + let mut dump = Vec::with_capacity(length); + if length == 0 { + return dump; + } + + let first_word = offset / 32; + let end_byte = offset + length; + let mut last_word = end_byte / 32; + if end_byte % 32 != 0 { + last_word += 1; + } + + let unalignment = offset % 32; + + let page_part = + memory.dump_page_content_as_u256_words(page, (first_word as u32)..(last_word as u32)); + + let mut is_first = true; + let mut remaining = length; + for word in page_part.into_iter() { + let it = word.into_be_iter(); + if is_first { + is_first = false; + let it = it.skip(unalignment); + for next in it { + if remaining > 0 { + dump.push(next); + remaining -= 1; + } + } + } else { + for next in it { + if remaining > 0 { + dump.push(next); + remaining -= 1; + } + } + } + } + + assert_eq!( + dump.len(), + length, + "tried to dump with offset {}, length {}, got a bytestring of length {}", + offset, + length, + dump.len() + ); + + dump +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/oracles/mod.rs b/core/lib/multivm/src/versions/vm_boojum_integration/oracles/mod.rs new file mode 100644 index 000000000000..b21c842572fe --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/oracles/mod.rs @@ -0,0 +1 @@ +pub(crate) mod storage; diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/oracles/storage.rs b/core/lib/multivm/src/versions/vm_boojum_integration/oracles/storage.rs new file mode 100644 index 000000000000..1ea8c7822e18 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/oracles/storage.rs @@ -0,0 +1,511 @@ +use std::collections::HashMap; + +use zk_evm_1_4_0::{ + abstractions::{RefundType, RefundedAmounts, Storage as VmStorageOracle}, + aux_structures::{LogQuery, Timestamp}, + zkevm_opcode_defs::system_params::INITIAL_STORAGE_WRITE_PUBDATA_BYTES, +}; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_types::{ + utils::storage_key_for_eth_balance, + writes::{ + compression::compress_with_best_strategy, BYTES_PER_DERIVED_KEY, + BYTES_PER_ENUMERATION_INDEX, + }, + AccountTreeId, Address, StorageKey, StorageLogQueryType, BOOTLOADER_ADDRESS, U256, +}; +use zksync_utils::u256_to_h256; + +use crate::vm_boojum_integration::{ + old_vm::{ + history_recorder::{ + AppDataFrameManagerWithHistory, HashMapHistoryEvent, HistoryEnabled, HistoryMode, + HistoryRecorder, StorageWrapper, VectorHistoryEvent, WithHistory, + }, + oracles::OracleWithHistory, + }, + utils::logs::StorageLogQuery, +}; + +// While the storage does not support different shards, it was decided to write the +// code of the StorageOracle with the shard parameters in mind. +pub(crate) fn triplet_to_storage_key(_shard_id: u8, address: Address, key: U256) -> StorageKey { + StorageKey::new(AccountTreeId::new(address), u256_to_h256(key)) +} + +pub(crate) fn storage_key_of_log(query: &LogQuery) -> StorageKey { + triplet_to_storage_key(query.shard_id, query.address, query.key) +} + +#[derive(Debug)] +pub struct StorageOracle { + // Access to the persistent storage. Please note that it + // is used only for read access. All the actual writes happen + // after the execution ended. + pub(crate) storage: HistoryRecorder, H>, + + pub(crate) frames_stack: AppDataFrameManagerWithHistory, H>, + + // The changes that have been paid for in previous transactions. + // It is a mapping from storage key to the number of *bytes* that was paid by the user + // to cover this slot. + pub(crate) pre_paid_changes: HistoryRecorder, H>, + + // The changes that have been paid for in the current transaction + pub(crate) paid_changes: HistoryRecorder, H>, + + // The map that contains all the first values read from storage for each slot. + // While formally it does not have to be rolled back, we still do it to avoid memory bloat + // for unused slots. + pub(crate) initial_values: HistoryRecorder, H>, + + // Storage refunds that oracle has returned in `estimate_refunds_for_write`. + pub(crate) returned_refunds: HistoryRecorder, H>, + + // Keeps track of storage keys that were ever written to. + pub(crate) written_keys: HistoryRecorder, HistoryEnabled>, + // Keeps track of storage keys that were ever read. + pub(crate) read_keys: HistoryRecorder, HistoryEnabled>, +} + +impl OracleWithHistory for StorageOracle { + fn rollback_to_timestamp(&mut self, timestamp: Timestamp) { + self.storage.rollback_to_timestamp(timestamp); + self.frames_stack.rollback_to_timestamp(timestamp); + self.pre_paid_changes.rollback_to_timestamp(timestamp); + self.paid_changes.rollback_to_timestamp(timestamp); + self.initial_values.rollback_to_timestamp(timestamp); + self.returned_refunds.rollback_to_timestamp(timestamp); + self.written_keys.rollback_to_timestamp(timestamp); + self.read_keys.rollback_to_timestamp(timestamp); + } +} + +impl StorageOracle { + pub fn new(storage: StoragePtr) -> Self { + Self { + storage: HistoryRecorder::from_inner(StorageWrapper::new(storage)), + frames_stack: Default::default(), + pre_paid_changes: Default::default(), + paid_changes: Default::default(), + initial_values: Default::default(), + returned_refunds: Default::default(), + written_keys: Default::default(), + read_keys: Default::default(), + } + } + + pub fn delete_history(&mut self) { + self.storage.delete_history(); + self.frames_stack.delete_history(); + self.pre_paid_changes.delete_history(); + self.paid_changes.delete_history(); + self.initial_values.delete_history(); + self.returned_refunds.delete_history(); + self.written_keys.delete_history(); + self.read_keys.delete_history(); + } + + fn is_storage_key_free(&self, key: &StorageKey) -> bool { + key.address() == &zksync_system_constants::SYSTEM_CONTEXT_ADDRESS + || *key == storage_key_for_eth_balance(&BOOTLOADER_ADDRESS) + } + + fn get_initial_value(&self, storage_key: &StorageKey) -> Option { + self.initial_values.inner().get(storage_key).copied() + } + + fn set_initial_value(&mut self, storage_key: &StorageKey, value: U256, timestamp: Timestamp) { + if !self.initial_values.inner().contains_key(storage_key) { + self.initial_values.insert(*storage_key, value, timestamp); + } + } + + fn read_value(&mut self, mut query: LogQuery) -> LogQuery { + let key = triplet_to_storage_key(query.shard_id, query.address, query.key); + + if !self.read_keys.inner().contains_key(&key) { + self.read_keys.insert(key, (), query.timestamp); + } + let current_value = self.storage.read_from_storage(&key); + + query.read_value = current_value; + + self.set_initial_value(&key, current_value, query.timestamp); + + self.frames_stack.push_forward( + Box::new(StorageLogQuery { + log_query: query, + log_type: StorageLogQueryType::Read, + }), + query.timestamp, + ); + + query + } + + fn write_value(&mut self, query: LogQuery) -> LogQuery { + let key = triplet_to_storage_key(query.shard_id, query.address, query.key); + if !self.written_keys.inner().contains_key(&key) { + self.written_keys.insert(key, (), query.timestamp); + } + let current_value = + self.storage + .write_to_storage(key, query.written_value, query.timestamp); + + let is_initial_write = self.storage.get_ptr().borrow_mut().is_write_initial(&key); + let log_query_type = if is_initial_write { + StorageLogQueryType::InitialWrite + } else { + StorageLogQueryType::RepeatedWrite + }; + + self.set_initial_value(&key, current_value, query.timestamp); + + let mut storage_log_query = StorageLogQuery { + log_query: query, + log_type: log_query_type, + }; + self.frames_stack + .push_forward(Box::new(storage_log_query), query.timestamp); + storage_log_query.log_query.rollback = true; + self.frames_stack + .push_rollback(Box::new(storage_log_query), query.timestamp); + storage_log_query.log_query.rollback = false; + + query + } + + // Returns the amount of funds that has been already paid for writes into the storage slot + fn prepaid_for_write(&self, storage_key: &StorageKey) -> u32 { + self.paid_changes + .inner() + .get(storage_key) + .copied() + .unwrap_or_else(|| { + self.pre_paid_changes + .inner() + .get(storage_key) + .copied() + .unwrap_or(0) + }) + } + + // Remembers the changes that have been paid for in the current transaction. + // It also returns how much pubdata did the user pay for and how much was actually published. + pub(crate) fn save_paid_changes(&mut self, timestamp: Timestamp) -> u32 { + let mut published = 0; + + let modified_keys = self + .paid_changes + .inner() + .iter() + .map(|(k, v)| (*k, *v)) + .collect::>(); + + for (key, _) in modified_keys { + // It is expected that for each slot for which we have paid changes, there is some + // first slot value already read. + let first_slot_value = self.initial_values.inner().get(&key).copied().unwrap(); + + // This is the value has been written to the storage slot at the end. + let current_slot_value = self.storage.read_from_storage(&key); + + let required_pubdata = + self.base_price_for_write(&key, first_slot_value, current_slot_value); + + // We assume that `prepaid_for_slot` represents both the number of pubdata published and the number of bytes paid by the previous transactions + // as they should be identical. + let prepaid_for_slot = self + .pre_paid_changes + .inner() + .get(&key) + .copied() + .unwrap_or_default(); + + published += required_pubdata.saturating_sub(prepaid_for_slot); + + // We remove the slot from the paid changes and move to the pre-paid changes as + // the transaction ends. + self.paid_changes.remove(key, timestamp); + self.pre_paid_changes + .insert(key, prepaid_for_slot.max(required_pubdata), timestamp); + } + + published + } + + fn base_price_for_write_query(&self, query: &LogQuery) -> u32 { + let storage_key = storage_key_of_log(query); + + let initial_value = self + .get_initial_value(&storage_key) + .unwrap_or(self.storage.read_from_storage(&storage_key)); + + self.base_price_for_write(&storage_key, initial_value, query.written_value) + } + + pub(crate) fn base_price_for_write( + &self, + storage_key: &StorageKey, + prev_value: U256, + new_value: U256, + ) -> u32 { + if self.is_storage_key_free(storage_key) || prev_value == new_value { + return 0; + } + + let is_initial_write = self + .storage + .get_ptr() + .borrow_mut() + .is_write_initial(storage_key); + + get_pubdata_price_bytes(prev_value, new_value, is_initial_write) + } + + // Returns the price of the update in terms of pubdata bytes. + // TODO (SMA-1701): update VM to accept gas instead of pubdata. + fn value_update_price(&mut self, query: &LogQuery) -> u32 { + let storage_key = storage_key_of_log(query); + + let base_cost = self.base_price_for_write_query(query); + + let initial_value = self + .get_initial_value(&storage_key) + .unwrap_or(self.storage.read_from_storage(&storage_key)); + + self.set_initial_value(&storage_key, initial_value, query.timestamp); + + let already_paid = self.prepaid_for_write(&storage_key); + + if base_cost <= already_paid { + // Some other transaction has already paid for this slot, no need to pay anything + 0u32 + } else { + base_cost - already_paid + } + } + + /// Returns storage log queries from current frame where `log.log_query.timestamp >= from_timestamp`. + pub(crate) fn storage_log_queries_after_timestamp( + &self, + from_timestamp: Timestamp, + ) -> &[Box] { + let logs = self.frames_stack.forward().current_frame(); + + // Select all of the last elements where `l.log_query.timestamp >= from_timestamp`. + // Note, that using binary search here is dangerous, because the logs are not sorted by timestamp. + logs.rsplit(|l| l.log_query.timestamp < from_timestamp) + .next() + .unwrap_or(&[]) + } + + pub(crate) fn get_final_log_queries(&self) -> Vec { + assert_eq!( + self.frames_stack.len(), + 1, + "VM finished execution in unexpected state" + ); + + self.frames_stack + .forward() + .current_frame() + .iter() + .map(|x| **x) + .collect() + } + + pub(crate) fn get_size(&self) -> usize { + let frames_stack_size = self.frames_stack.get_size(); + let paid_changes_size = + self.paid_changes.inner().len() * std::mem::size_of::<(StorageKey, u32)>(); + + frames_stack_size + paid_changes_size + } + + pub(crate) fn get_history_size(&self) -> usize { + let storage_size = self.storage.borrow_history(|h| h.len(), 0) + * std::mem::size_of::< as WithHistory>::HistoryRecord>(); + let frames_stack_size = self.frames_stack.get_history_size(); + let paid_changes_size = self.paid_changes.borrow_history(|h| h.len(), 0) + * std::mem::size_of::< as WithHistory>::HistoryRecord>(); + storage_size + frames_stack_size + paid_changes_size + } +} + +impl VmStorageOracle for StorageOracle { + // Perform a storage read/write access by taking an partially filled query + // and returning filled query and cold/warm marker for pricing purposes + fn execute_partial_query( + &mut self, + _monotonic_cycle_counter: u32, + mut query: LogQuery, + ) -> LogQuery { + //``` + // tracing::trace!( + // "execute partial query cyc {:?} addr {:?} key {:?}, rw {:?}, wr {:?}, tx {:?}", + // _monotonic_cycle_counter, + // query.address, + // query.key, + // query.rw_flag, + // query.written_value, + // query.tx_number_in_block + // ); + //``` + assert!(!query.rollback); + if query.rw_flag { + // The number of bytes that have been compensated by the user to perform this write + let storage_key = storage_key_of_log(&query); + let read_value = self.storage.read_from_storage(&storage_key); + query.read_value = read_value; + + // It is considered that the user has paid for the whole base price for the writes + let to_pay_by_user = self.base_price_for_write_query(&query); + let prepaid = self.prepaid_for_write(&storage_key); + + if to_pay_by_user > prepaid { + self.paid_changes.apply_historic_record( + HashMapHistoryEvent { + key: storage_key, + value: Some(to_pay_by_user), + }, + query.timestamp, + ); + } + self.write_value(query) + } else { + self.read_value(query) + } + } + + // We can return the size of the refund before each storage query. + // Note, that while the `RefundType` allows to provide refunds both in + // `ergs` and `pubdata`, only refunds in pubdata will be compensated for the users + fn estimate_refunds_for_write( + &mut self, // to avoid any hacks inside, like prefetch + _monotonic_cycle_counter: u32, + partial_query: &LogQuery, + ) -> RefundType { + let storage_key = storage_key_of_log(partial_query); + let mut partial_query = *partial_query; + let read_value = self.storage.read_from_storage(&storage_key); + partial_query.read_value = read_value; + + let price_to_pay = self + .value_update_price(&partial_query) + .min(INITIAL_STORAGE_WRITE_PUBDATA_BYTES as u32); + + let refund = RefundType::RepeatedWrite(RefundedAmounts { + ergs: 0, + // `INITIAL_STORAGE_WRITE_PUBDATA_BYTES` is the default amount of pubdata bytes the user pays for. + pubdata_bytes: (INITIAL_STORAGE_WRITE_PUBDATA_BYTES as u32) - price_to_pay, + }); + self.returned_refunds.apply_historic_record( + VectorHistoryEvent::Push(refund.pubdata_refund()), + partial_query.timestamp, + ); + + refund + } + + // Indicate a start of execution frame for rollback purposes + fn start_frame(&mut self, timestamp: Timestamp) { + self.frames_stack.push_frame(timestamp); + } + + // Indicate that execution frame went out from the scope, so we can + // log the history and either rollback immediately or keep records to rollback later + fn finish_frame(&mut self, timestamp: Timestamp, panicked: bool) { + // If we panic then we append forward and rollbacks to the forward of parent, + // otherwise we place rollbacks of child before rollbacks of the parent + if panicked { + // perform actual rollback + for query in self.frames_stack.rollback().current_frame().iter().rev() { + let read_value = match query.log_type { + StorageLogQueryType::Read => { + // Having Read logs in rollback is not possible + tracing::warn!("Read log in rollback queue {:?}", query); + continue; + } + StorageLogQueryType::InitialWrite | StorageLogQueryType::RepeatedWrite => { + query.log_query.read_value + } + }; + + let LogQuery { written_value, .. } = query.log_query; + let key = triplet_to_storage_key( + query.log_query.shard_id, + query.log_query.address, + query.log_query.key, + ); + let current_value = self.storage.write_to_storage( + key, + // NOTE, that since it is a rollback query, + // the `read_value` is being set + read_value, timestamp, + ); + + // Additional validation that the current value was correct + // Unwrap is safe because the return value from `write_inner` is the previous value in this leaf. + // It is impossible to set leaf value to `None` + assert_eq!(current_value, written_value); + } + + self.frames_stack + .move_rollback_to_forward(|_| true, timestamp); + } + self.frames_stack.merge_frame(timestamp); + } +} + +/// Returns the number of bytes needed to publish a slot. +// Since we need to publish the state diffs onchain, for each of the updated storage slot +// we basically need to publish the following pair: `()`. +// For key we use the following optimization: +// - The first time we publish it, we use 32 bytes. +// Then, we remember a 8-byte id for this slot and assign it to it. We call this initial write. +// - The second time we publish it, we will use the 4/5 byte representation of this 8-byte instead of the 32 +// bytes of the entire key. +// For value compression, we use a metadata byte which holds the length of the value and the operation from the +// previous state to the new state, and the compressed value. The maximum for this is 33 bytes. +// Total bytes for initial writes then becomes 65 bytes and repeated writes becomes 38 bytes. +fn get_pubdata_price_bytes(initial_value: U256, final_value: U256, is_initial: bool) -> u32 { + // TODO (SMA-1702): take into account the content of the log query, i.e. values that contain mostly zeroes + // should cost less. + + let compressed_value_size = + compress_with_best_strategy(initial_value, final_value).len() as u32; + + if is_initial { + (BYTES_PER_DERIVED_KEY as u32) + compressed_value_size + } else { + (BYTES_PER_ENUMERATION_INDEX as u32) + compressed_value_size + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_get_pubdata_price_bytes() { + let initial_value = U256::default(); + let final_value = U256::from(92122); + let is_initial = true; + + let compression_len = 4; + + let initial_bytes_price = get_pubdata_price_bytes(initial_value, final_value, is_initial); + let repeated_bytes_price = get_pubdata_price_bytes(initial_value, final_value, !is_initial); + + assert_eq!( + initial_bytes_price, + (compression_len + BYTES_PER_DERIVED_KEY as usize) as u32 + ); + assert_eq!( + repeated_bytes_price, + (compression_len + BYTES_PER_ENUMERATION_INDEX as usize) as u32 + ); + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/bootloader.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/bootloader.rs new file mode 100644 index 000000000000..0ee3b811b4ca --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/bootloader.rs @@ -0,0 +1,56 @@ +use zksync_types::U256; + +use crate::{ + interface::{ExecutionResult, Halt, TxExecutionMode, VmExecutionMode, VmInterface}, + vm_boojum_integration::{ + constants::BOOTLOADER_HEAP_PAGE, + tests::{ + tester::VmTesterBuilder, + utils::{get_bootloader, verify_required_memory, BASE_SYSTEM_CONTRACTS}, + }, + HistoryEnabled, + }, +}; + +#[test] +fn test_dummy_bootloader() { + let mut base_system_contracts = BASE_SYSTEM_CONTRACTS.clone(); + base_system_contracts.bootloader = get_bootloader("dummy"); + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_base_system_smart_contracts(base_system_contracts) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .build(); + + let result = vm.vm.execute(VmExecutionMode::Batch); + assert!(!result.result.is_failed()); + + let correct_first_cell = U256::from_str_radix("123123123", 16).unwrap(); + verify_required_memory( + &vm.vm.state, + vec![(correct_first_cell, BOOTLOADER_HEAP_PAGE, 0)], + ); +} + +#[test] +fn test_bootloader_out_of_gas() { + let mut base_system_contracts = BASE_SYSTEM_CONTRACTS.clone(); + base_system_contracts.bootloader = get_bootloader("dummy"); + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_base_system_smart_contracts(base_system_contracts) + .with_gas_limit(10) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .build(); + + let res = vm.vm.execute(VmExecutionMode::Batch); + + assert!(matches!( + res.result, + ExecutionResult::Halt { + reason: Halt::BootloaderOutOfGas + } + )); +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/bytecode_publishing.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/bytecode_publishing.rs new file mode 100644 index 000000000000..ad1b0f26036e --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/bytecode_publishing.rs @@ -0,0 +1,43 @@ +use zksync_types::event::extract_long_l2_to_l1_messages; +use zksync_utils::bytecode::compress_bytecode; + +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_boojum_integration::{ + tests::{ + tester::{DeployContractsTx, TxType, VmTesterBuilder}, + utils::read_test_contract, + }, + HistoryEnabled, + }, +}; + +#[test] +fn test_bytecode_publishing() { + // In this test, we aim to ensure that the contents of the compressed bytecodes + // are included as part of the L2->L1 long messages + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let counter = read_test_contract(); + let account = &mut vm.rich_accounts[0]; + + let compressed_bytecode = compress_bytecode(&counter).unwrap(); + + let DeployContractsTx { tx, .. } = account.get_deploy_tx(&counter, None, TxType::L2); + vm.vm.push_transaction(tx); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert!(!result.result.is_failed(), "Transaction wasn't successful"); + + vm.vm.execute(VmExecutionMode::Batch); + + let state = vm.vm.get_current_execution_state(); + let long_messages = extract_long_l2_to_l1_messages(&state.events); + assert!( + long_messages.contains(&compressed_bytecode), + "Bytecode not published" + ); +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/call_tracer.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/call_tracer.rs new file mode 100644 index 000000000000..e9df4fa80ff0 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/call_tracer.rs @@ -0,0 +1,92 @@ +use std::sync::Arc; + +use once_cell::sync::OnceCell; +use zksync_types::{Address, Execute}; + +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + tracers::CallTracer, + vm_boojum_integration::{ + constants::BLOCK_GAS_LIMIT, + tests::{ + tester::VmTesterBuilder, + utils::{read_max_depth_contract, read_test_contract}, + }, + HistoryEnabled, ToTracerPointer, + }, +}; + +// This test is ultra slow, so it's ignored by default. +#[test] +#[ignore] +fn test_max_depth() { + let contarct = read_max_depth_contract(); + let address = Address::random(); + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_random_rich_accounts(1) + .with_deployer() + .with_gas_limit(BLOCK_GAS_LIMIT) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_custom_contracts(vec![(contarct, address, true)]) + .build(); + + let account = &mut vm.rich_accounts[0]; + let tx = account.get_l2_tx_for_execute( + Execute { + contract_address: address, + calldata: vec![], + value: Default::default(), + factory_deps: None, + }, + None, + ); + + let result = Arc::new(OnceCell::new()); + let call_tracer = CallTracer::new(result.clone()).into_tracer_pointer(); + vm.vm.push_transaction(tx); + let res = vm.vm.inspect(call_tracer.into(), VmExecutionMode::OneTx); + assert!(result.get().is_some()); + assert!(res.result.is_failed()); +} + +#[test] +fn test_basic_behavior() { + let contarct = read_test_contract(); + let address = Address::random(); + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_random_rich_accounts(1) + .with_deployer() + .with_gas_limit(BLOCK_GAS_LIMIT) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_custom_contracts(vec![(contarct, address, true)]) + .build(); + + let increment_by_6_calldata = + "7cf5dab00000000000000000000000000000000000000000000000000000000000000006"; + + let account = &mut vm.rich_accounts[0]; + let tx = account.get_l2_tx_for_execute( + Execute { + contract_address: address, + calldata: hex::decode(increment_by_6_calldata).unwrap(), + value: Default::default(), + factory_deps: None, + }, + None, + ); + + let result = Arc::new(OnceCell::new()); + let call_tracer = CallTracer::new(result.clone()).into_tracer_pointer(); + vm.vm.push_transaction(tx); + let res = vm.vm.inspect(call_tracer.into(), VmExecutionMode::OneTx); + + let call_tracer_result = result.get().unwrap(); + + assert_eq!(call_tracer_result.len(), 1); + // Expect that there are a plenty of subcalls underneath. + let subcall = &call_tracer_result[0].calls; + assert!(subcall.len() > 10); + assert!(!res.result.is_failed()); +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/circuits.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/circuits.rs new file mode 100644 index 000000000000..7d429b225136 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/circuits.rs @@ -0,0 +1,64 @@ +use zkevm_test_harness_1_4_0::geometry_config::get_geometry_config; +use zksync_types::{Address, Execute, U256}; + +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_boojum_integration::{constants::BLOCK_GAS_LIMIT, tests::tester::VmTesterBuilder, HistoryEnabled}, +}; + +// Checks that estimated number of circuits for simple transfer doesn't differ much +// from hardcoded expected value. +#[test] +fn test_circuits() { + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_random_rich_accounts(1) + .with_deployer() + .with_gas_limit(BLOCK_GAS_LIMIT) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .build(); + + let account = &mut vm.rich_accounts[0]; + let tx = account.get_l2_tx_for_execute( + Execute { + contract_address: Address::random(), + calldata: Vec::new(), + value: U256::from(1u8), + factory_deps: None, + }, + None, + ); + vm.vm.push_transaction(tx); + let res = vm.vm.inspect(Default::default(), VmExecutionMode::OneTx); + + let statistic = res.statistics.circuit_statistic; + // Check `circuit_statistic`. + assert!(statistic.main_vm > f32::EPSILON); + assert!(statistic.ram_permutation > f32::EPSILON); + assert!(statistic.storage_application > f32::EPSILON); + assert!(statistic.storage_sorter > f32::EPSILON); + assert!(statistic.code_decommitter > f32::EPSILON); + assert!(statistic.code_decommitter_sorter > f32::EPSILON); + assert!(statistic.log_demuxer > f32::EPSILON); + assert!(statistic.events_sorter > f32::EPSILON); + assert!(statistic.keccak256 > f32::EPSILON); + // Single `ecrecover` should be used to validate tx signature. + assert_eq!( + statistic.ecrecover, + 1.0 / get_geometry_config().cycles_per_ecrecover_circuit as f32 + ); + // `sha256` shouldn't be used. + assert_eq!(statistic.sha256, 0.0); + + const EXPECTED_CIRCUITS_USED: f32 = 4.6363; + let delta = (statistic.total_f32() - EXPECTED_CIRCUITS_USED) / EXPECTED_CIRCUITS_USED; + + if delta.abs() > 0.1 { + panic!( + "Estimation differs from expected result by too much: {}%, expected value: {}, got {}", + delta * 100.0, + EXPECTED_CIRCUITS_USED, + statistic.total_f32(), + ); + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/default_aa.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/default_aa.rs new file mode 100644 index 000000000000..a8c20cfebc1d --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/default_aa.rs @@ -0,0 +1,76 @@ +use zksync_system_constants::L2_ETH_TOKEN_ADDRESS; +use zksync_types::{ + get_code_key, get_known_code_key, get_nonce_key, + system_contracts::{DEPLOYMENT_NONCE_INCREMENT, TX_NONCE_INCREMENT}, + AccountTreeId, U256, +}; +use zksync_utils::u256_to_h256; + +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_boojum_integration::{ + tests::{ + tester::{DeployContractsTx, TxType, VmTesterBuilder}, + utils::{get_balance, read_test_contract, verify_required_storage}, + }, + HistoryEnabled, + }, +}; + +#[test] +fn test_default_aa_interaction() { + // In this test, we aim to test whether a simple account interaction (without any fee logic) + // will work. The account will try to deploy a simple contract from integration tests. + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let counter = read_test_contract(); + let account = &mut vm.rich_accounts[0]; + let DeployContractsTx { + tx, + bytecode_hash, + address, + } = account.get_deploy_tx(&counter, None, TxType::L2); + let maximal_fee = tx.gas_limit() * vm.vm.batch_env.base_fee(); + + vm.vm.push_transaction(tx); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert!(!result.result.is_failed(), "Transaction wasn't successful"); + + vm.vm.execute(VmExecutionMode::Batch); + vm.vm.get_current_execution_state(); + + // Both deployment and ordinary nonce should be incremented by one. + let account_nonce_key = get_nonce_key(&account.address); + let expected_nonce = TX_NONCE_INCREMENT + DEPLOYMENT_NONCE_INCREMENT; + + // The code hash of the deployed contract should be marked as republished. + let known_codes_key = get_known_code_key(&bytecode_hash); + + // The contract should be deployed successfully. + let account_code_key = get_code_key(&address); + + let expected_slots = vec![ + (u256_to_h256(expected_nonce), account_nonce_key), + (u256_to_h256(U256::from(1u32)), known_codes_key), + (bytecode_hash, account_code_key), + ]; + + verify_required_storage(&vm.vm.state, expected_slots); + + let expected_fee = maximal_fee + - U256::from(result.refunds.gas_refunded) * U256::from(vm.vm.batch_env.base_fee()); + let operator_balance = get_balance( + AccountTreeId::new(L2_ETH_TOKEN_ADDRESS), + &vm.fee_account, + vm.vm.state.storage.storage.get_ptr(), + ); + + assert_eq!( + operator_balance, expected_fee, + "Operator did not receive his fee" + ); +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/gas_limit.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/gas_limit.rs new file mode 100644 index 000000000000..30a65097111d --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/gas_limit.rs @@ -0,0 +1,47 @@ +use zksync_types::{fee::Fee, Execute}; + +use crate::{ + interface::{TxExecutionMode, VmInterface}, + vm_boojum_integration::{ + constants::{BOOTLOADER_HEAP_PAGE, TX_DESCRIPTION_OFFSET, TX_GAS_LIMIT_OFFSET}, + tests::tester::VmTesterBuilder, + HistoryDisabled, + }, +}; + +/// Checks that `TX_GAS_LIMIT_OFFSET` constant is correct. +#[test] +fn test_tx_gas_limit_offset() { + let mut vm = VmTesterBuilder::new(HistoryDisabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let gas_limit = 9999.into(); + let tx = vm.rich_accounts[0].get_l2_tx_for_execute( + Execute { + contract_address: Default::default(), + calldata: vec![], + value: Default::default(), + factory_deps: None, + }, + Some(Fee { + gas_limit, + ..Default::default() + }), + ); + + vm.vm.push_transaction(tx); + + let gas_limit_from_memory = vm + .vm + .state + .memory + .read_slot( + BOOTLOADER_HEAP_PAGE as usize, + TX_DESCRIPTION_OFFSET + TX_GAS_LIMIT_OFFSET, + ) + .value; + assert_eq!(gas_limit_from_memory, gas_limit); +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/get_used_contracts.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/get_used_contracts.rs new file mode 100644 index 000000000000..25aab0871f14 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/get_used_contracts.rs @@ -0,0 +1,109 @@ +use std::collections::{HashMap, HashSet}; + +use itertools::Itertools; +use zksync_state::WriteStorage; +use zksync_system_constants::CONTRACT_DEPLOYER_ADDRESS; +use zksync_test_account::Account; +use zksync_types::{Execute, U256}; +use zksync_utils::{bytecode::hash_bytecode, h256_to_u256}; + +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_boojum_integration::{ + tests::{ + tester::{TxType, VmTesterBuilder}, + utils::{read_test_contract, BASE_SYSTEM_CONTRACTS}, + }, + HistoryDisabled, Vm, + }, + HistoryMode, +}; + +#[test] +fn test_get_used_contracts() { + let mut vm = VmTesterBuilder::new(HistoryDisabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .build(); + + assert!(known_bytecodes_without_aa_code(&vm.vm).is_empty()); + + // create and push and execute some not-empty factory deps transaction with success status + // to check that get_used_contracts() updates + let contract_code = read_test_contract(); + let mut account = Account::random(); + let tx = account.get_deploy_tx(&contract_code, None, TxType::L1 { serial_id: 0 }); + vm.vm.push_transaction(tx.tx.clone()); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert!(!result.result.is_failed()); + + assert!(vm + .vm + .get_used_contracts() + .contains(&h256_to_u256(tx.bytecode_hash))); + + // Note: Default_AA will be in the list of used contracts if l2 tx is used + assert_eq!( + vm.vm + .get_used_contracts() + .into_iter() + .collect::>(), + known_bytecodes_without_aa_code(&vm.vm) + .keys() + .cloned() + .collect::>() + ); + + // create push and execute some non-empty factory deps transaction that fails + // (known_bytecodes will be updated but we expect get_used_contracts() to not be updated) + + let calldata = [1, 2, 3]; + let big_calldata: Vec = calldata + .iter() + .cycle() + .take(calldata.len() * 1024) + .cloned() + .collect(); + let account2 = Account::random(); + let tx2 = account2.get_l1_tx( + Execute { + contract_address: CONTRACT_DEPLOYER_ADDRESS, + calldata: big_calldata, + value: Default::default(), + factory_deps: Some(vec![vec![1; 32]]), + }, + 1, + ); + + vm.vm.push_transaction(tx2.clone()); + + let res2 = vm.vm.execute(VmExecutionMode::OneTx); + + assert!(res2.result.is_failed()); + + for factory_dep in tx2.execute.factory_deps.unwrap() { + let hash = hash_bytecode(&factory_dep); + let hash_to_u256 = h256_to_u256(hash); + assert!(known_bytecodes_without_aa_code(&vm.vm) + .keys() + .contains(&hash_to_u256)); + assert!(!vm.vm.get_used_contracts().contains(&hash_to_u256)); + } +} + +fn known_bytecodes_without_aa_code( + vm: &Vm, +) -> HashMap> { + let mut known_bytecodes_without_aa_code = vm + .state + .decommittment_processor + .known_bytecodes + .inner() + .clone(); + + known_bytecodes_without_aa_code + .remove(&h256_to_u256(BASE_SYSTEM_CONTRACTS.default_aa.hash)) + .unwrap(); + + known_bytecodes_without_aa_code +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/invalid_bytecode.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/invalid_bytecode.rs new file mode 100644 index 000000000000..079e6d61b6c2 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/invalid_bytecode.rs @@ -0,0 +1,120 @@ +use zksync_types::H256; +use zksync_utils::h256_to_u256; + +use crate::vm_boojum_integration::tests::tester::VmTesterBuilder; +use crate::vm_boojum_integration::types::inputs::system_env::TxExecutionMode; +use crate::vm_boojum_integration::{HistoryEnabled, TxRevertReason}; + +// TODO this test requires a lot of hacks for bypassing the bytecode checks in the VM. +// Port it later, it's not significant. for now + +#[test] +fn test_invalid_bytecode() { + let mut vm_builder = VmTesterBuilder::new(HistoryEnabled) + .with_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1); + let mut storage = vm_builder.take_storage(); + let mut vm = vm_builder.build(&mut storage); + + let block_gas_per_pubdata = vm_test_env + .block_context + .context + .block_gas_price_per_pubdata(); + + let mut test_vm_with_custom_bytecode_hash = + |bytecode_hash: H256, expected_revert_reason: Option| { + let mut oracle_tools = + OracleTools::new(vm_test_env.storage_ptr.as_mut(), HistoryEnabled); + + let (encoded_tx, predefined_overhead) = get_l1_tx_with_custom_bytecode_hash( + h256_to_u256(bytecode_hash), + block_gas_per_pubdata as u32, + ); + + run_vm_with_custom_factory_deps( + &mut oracle_tools, + vm_test_env.block_context.context, + &vm_test_env.block_properties, + encoded_tx, + predefined_overhead, + expected_revert_reason, + ); + }; + + let failed_to_mark_factory_deps = |msg: &str, data: Vec| { + TxRevertReason::FailedToMarkFactoryDependencies(VmRevertReason::General { + msg: msg.to_string(), + data, + }) + }; + + // Here we provide the correctly-formatted bytecode hash of + // odd length, so it should work. + test_vm_with_custom_bytecode_hash( + H256([ + 1, 0, 0, 1, 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, + ]), + None, + ); + + // Here we provide correctly formatted bytecode of even length, so + // it should fail. + test_vm_with_custom_bytecode_hash( + H256([ + 1, 0, 2, 2, 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, + ]), + Some(failed_to_mark_factory_deps( + "Code length in words must be odd", + vec![ + 8, 195, 121, 160, 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, 32, 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, 32, 67, 111, 100, 101, 32, 108, 101, 110, + 103, 116, 104, 32, 105, 110, 32, 119, 111, 114, 100, 115, 32, 109, 117, 115, 116, + 32, 98, 101, 32, 111, 100, 100, + ], + )), + ); + + // Here we provide incorrectly formatted bytecode of odd length, so + // it should fail. + test_vm_with_custom_bytecode_hash( + H256([ + 1, 1, 0, 1, 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, + ]), + Some(failed_to_mark_factory_deps( + "Incorrectly formatted bytecodeHash", + vec![ + 8, 195, 121, 160, 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, 32, 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, 34, 73, 110, 99, 111, 114, 114, 101, 99, + 116, 108, 121, 32, 102, 111, 114, 109, 97, 116, 116, 101, 100, 32, 98, 121, 116, + 101, 99, 111, 100, 101, 72, 97, 115, 104, 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, + ], + )), + ); + + // Here we provide incorrectly formatted bytecode of odd length, so + // it should fail. + test_vm_with_custom_bytecode_hash( + H256([ + 2, 0, 0, 1, 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, + ]), + Some(failed_to_mark_factory_deps( + "Incorrectly formatted bytecodeHash", + vec![ + 8, 195, 121, 160, 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, 32, 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, 34, 73, 110, 99, 111, 114, 114, 101, 99, + 116, 108, 121, 32, 102, 111, 114, 109, 97, 116, 116, 101, 100, 32, 98, 121, 116, + 101, 99, 111, 100, 101, 72, 97, 115, 104, 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, + ], + )), + ); +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/is_write_initial.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/is_write_initial.rs new file mode 100644 index 000000000000..bf56aa2b816d --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/is_write_initial.rs @@ -0,0 +1,48 @@ +use zksync_state::ReadStorage; +use zksync_types::get_nonce_key; + +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_boojum_integration::{ + tests::{ + tester::{Account, TxType, VmTesterBuilder}, + utils::read_test_contract, + }, + HistoryDisabled, + }, +}; + +#[test] +fn test_is_write_initial_behaviour() { + // In this test, we check result of `is_write_initial` at different stages. + // The main idea is to check that `is_write_initial` storage uses the correct cache for initial_writes and doesn't + // messed up it with the repeated writes during the one batch execution. + + let mut account = Account::random(); + let mut vm = VmTesterBuilder::new(HistoryDisabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_rich_accounts(vec![account.clone()]) + .build(); + + let nonce_key = get_nonce_key(&account.address); + // Check that the next write to the nonce key will be initial. + assert!(vm + .storage + .as_ref() + .borrow_mut() + .is_write_initial(&nonce_key)); + + let contract_code = read_test_contract(); + let tx = account.get_deploy_tx(&contract_code, None, TxType::L2).tx; + + vm.vm.push_transaction(tx); + vm.vm.execute(VmExecutionMode::OneTx); + + // Check that `is_write_initial` still returns true for the nonce key. + assert!(vm + .storage + .as_ref() + .borrow_mut() + .is_write_initial(&nonce_key)); +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/l1_tx_execution.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/l1_tx_execution.rs new file mode 100644 index 000000000000..b547f346d28c --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/l1_tx_execution.rs @@ -0,0 +1,139 @@ +use zksync_system_constants::BOOTLOADER_ADDRESS; +use zksync_types::{ + get_code_key, get_known_code_key, + l2_to_l1_log::{L2ToL1Log, UserL2ToL1Log}, + storage_writes_deduplicator::StorageWritesDeduplicator, + U256, +}; +use zksync_utils::u256_to_h256; + +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_boojum_integration::{ + tests::{ + tester::{TxType, VmTesterBuilder}, + utils::{read_test_contract, verify_required_storage, BASE_SYSTEM_CONTRACTS}, + }, + types::internals::TransactionData, + HistoryEnabled, + }, +}; + +#[test] +fn test_l1_tx_execution() { + // In this test, we try to execute a contract deployment from L1 + // Here instead of marking code hash via the bootloader means, we will be + // using L1->L2 communication, the same it would likely be done during the priority mode. + + // There are always at least 7 initial writes here, because we pay fees from l1: + // - totalSupply of ETH token + // - balance of the refund recipient + // - balance of the bootloader + // - tx_rolling hash + // - rolling hash of L2->L1 logs + // - transaction number in block counter + // - L2->L1 log counter in L1Messenger + + // TODO(PLA-537): right now we are using 4 slots instead of 7 due to 0 fee for transaction. + let basic_initial_writes = 4; + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_base_system_smart_contracts(BASE_SYSTEM_CONTRACTS.clone()) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let contract_code = read_test_contract(); + let account = &mut vm.rich_accounts[0]; + let deploy_tx = account.get_deploy_tx(&contract_code, None, TxType::L1 { serial_id: 1 }); + let tx_data: TransactionData = deploy_tx.tx.clone().into(); + + let required_l2_to_l1_logs: Vec<_> = vec![L2ToL1Log { + shard_id: 0, + is_service: true, + tx_number_in_block: 0, + sender: BOOTLOADER_ADDRESS, + key: tx_data.tx_hash(0.into()), + value: u256_to_h256(U256::from(1u32)), + }] + .into_iter() + .map(UserL2ToL1Log) + .collect(); + + vm.vm.push_transaction(deploy_tx.tx.clone()); + + let res = vm.vm.execute(VmExecutionMode::OneTx); + + // The code hash of the deployed contract should be marked as republished. + let known_codes_key = get_known_code_key(&deploy_tx.bytecode_hash); + + // The contract should be deployed successfully. + let account_code_key = get_code_key(&deploy_tx.address); + + let expected_slots = vec![ + (u256_to_h256(U256::from(1u32)), known_codes_key), + (deploy_tx.bytecode_hash, account_code_key), + ]; + assert!(!res.result.is_failed()); + + verify_required_storage(&vm.vm.state, expected_slots); + + assert_eq!(res.logs.user_l2_to_l1_logs, required_l2_to_l1_logs); + + let tx = account.get_test_contract_transaction( + deploy_tx.address, + true, + None, + false, + TxType::L1 { serial_id: 0 }, + ); + vm.vm.push_transaction(tx); + let res = vm.vm.execute(VmExecutionMode::OneTx); + let storage_logs = res.logs.storage_logs; + let res = StorageWritesDeduplicator::apply_on_empty_state(&storage_logs); + + // Tx panicked + assert_eq!(res.initial_storage_writes - basic_initial_writes, 0); + + let tx = account.get_test_contract_transaction( + deploy_tx.address, + false, + None, + false, + TxType::L1 { serial_id: 0 }, + ); + vm.vm.push_transaction(tx.clone()); + let res = vm.vm.execute(VmExecutionMode::OneTx); + let storage_logs = res.logs.storage_logs; + let res = StorageWritesDeduplicator::apply_on_empty_state(&storage_logs); + // We changed one slot inside contract + assert_eq!(res.initial_storage_writes - basic_initial_writes, 1); + + // No repeated writes + let repeated_writes = res.repeated_storage_writes; + assert_eq!(res.repeated_storage_writes, 0); + + vm.vm.push_transaction(tx); + let storage_logs = vm.vm.execute(VmExecutionMode::OneTx).logs.storage_logs; + let res = StorageWritesDeduplicator::apply_on_empty_state(&storage_logs); + // We do the same storage write, it will be deduplicated, so still 4 initial write and 0 repeated + assert_eq!(res.initial_storage_writes - basic_initial_writes, 1); + assert_eq!(res.repeated_storage_writes, repeated_writes); + + let tx = account.get_test_contract_transaction( + deploy_tx.address, + false, + Some(10.into()), + false, + TxType::L1 { serial_id: 1 }, + ); + vm.vm.push_transaction(tx); + let result = vm.vm.execute(VmExecutionMode::OneTx); + // Method is not payable tx should fail + assert!(result.result.is_failed(), "The transaction should fail"); + + let res = StorageWritesDeduplicator::apply_on_empty_state(&result.logs.storage_logs); + // There are only basic initial writes + assert_eq!(res.initial_storage_writes - basic_initial_writes, 2); +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/l2_blocks.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/l2_blocks.rs new file mode 100644 index 000000000000..b26cc09e0577 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/l2_blocks.rs @@ -0,0 +1,437 @@ +//! +//! Tests for the bootloader +//! The description for each of the tests can be found in the corresponding `.yul` file. +//! + +use zk_evm_1_4_0::aux_structures::Timestamp; +use zksync_state::WriteStorage; +use zksync_system_constants::REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE; +use zksync_types::{ + block::{pack_block_info, MiniblockHasher}, + AccountTreeId, Execute, ExecuteTransactionCommon, L1BatchNumber, L1TxCommonData, + MiniblockNumber, ProtocolVersionId, StorageKey, Transaction, H160, H256, + SYSTEM_CONTEXT_ADDRESS, SYSTEM_CONTEXT_BLOCK_INFO_POSITION, + SYSTEM_CONTEXT_CURRENT_L2_BLOCK_INFO_POSITION, SYSTEM_CONTEXT_CURRENT_TX_ROLLING_HASH_POSITION, + U256, +}; +use zksync_utils::{h256_to_u256, u256_to_h256}; + +use crate::{ + interface::{ExecutionResult, Halt, L2BlockEnv, TxExecutionMode, VmExecutionMode, VmInterface}, + vm_boojum_integration::{ + constants::{ + BOOTLOADER_HEAP_PAGE, TX_OPERATOR_L2_BLOCK_INFO_OFFSET, + TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO, + }, + tests::tester::{default_l1_batch, VmTesterBuilder}, + utils::l2_blocks::get_l2_block_hash_key, + HistoryEnabled, Vm, + }, + HistoryMode, +}; + +fn get_l1_noop() -> Transaction { + Transaction { + common_data: ExecuteTransactionCommon::L1(L1TxCommonData { + sender: H160::random(), + gas_limit: U256::from(2000000u32), + gas_per_pubdata_limit: REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE.into(), + ..Default::default() + }), + execute: Execute { + contract_address: H160::zero(), + calldata: vec![], + value: U256::zero(), + factory_deps: None, + }, + received_timestamp_ms: 0, + raw_bytes: None, + } +} + +#[test] +fn test_l2_block_initialization_timestamp() { + // This test checks that the L2 block initialization works correctly. + // Here we check that that the first block must have timestamp that is greater or equal to the timestamp + // of the current batch. + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + // Override the timestamp of the current miniblock to be 0. + vm.vm.bootloader_state.push_l2_block(L2BlockEnv { + number: 1, + timestamp: 0, + prev_block_hash: MiniblockHasher::legacy_hash(MiniblockNumber(0)), + max_virtual_blocks_to_create: 1, + }); + let l1_tx = get_l1_noop(); + + vm.vm.push_transaction(l1_tx); + let res = vm.vm.execute(VmExecutionMode::OneTx); + + assert_eq!( + res.result, + ExecutionResult::Halt {reason: Halt::FailedToSetL2Block("The timestamp of the L2 block must be greater than or equal to the timestamp of the current batch".to_string())} + ); +} + +#[test] +fn test_l2_block_initialization_number_non_zero() { + // This test checks that the L2 block initialization works correctly. + // Here we check that the first miniblock number can not be zero. + + let l1_batch = default_l1_batch(L1BatchNumber(1)); + let first_l2_block = L2BlockEnv { + number: 0, + timestamp: l1_batch.timestamp, + prev_block_hash: MiniblockHasher::legacy_hash(MiniblockNumber(0)), + max_virtual_blocks_to_create: 1, + }; + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_l1_batch_env(l1_batch) + .with_random_rich_accounts(1) + .build(); + + let l1_tx = get_l1_noop(); + + vm.vm.push_transaction(l1_tx); + + let timestamp = Timestamp(vm.vm.state.local_state.timestamp); + set_manual_l2_block_info(&mut vm.vm, 0, first_l2_block, timestamp); + + let res = vm.vm.execute(VmExecutionMode::OneTx); + + assert_eq!( + res.result, + ExecutionResult::Halt { + reason: Halt::FailedToSetL2Block( + "L2 block number is never expected to be zero".to_string() + ) + } + ); +} + +fn test_same_l2_block( + expected_error: Option, + override_timestamp: Option, + override_prev_block_hash: Option, +) { + let mut l1_batch = default_l1_batch(L1BatchNumber(1)); + l1_batch.timestamp = 1; + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_l1_batch_env(l1_batch) + .with_random_rich_accounts(1) + .build(); + + let l1_tx = get_l1_noop(); + vm.vm.push_transaction(l1_tx.clone()); + let res = vm.vm.execute(VmExecutionMode::OneTx); + assert!(!res.result.is_failed()); + + let mut current_l2_block = vm.vm.batch_env.first_l2_block; + + if let Some(timestamp) = override_timestamp { + current_l2_block.timestamp = timestamp; + } + if let Some(prev_block_hash) = override_prev_block_hash { + current_l2_block.prev_block_hash = prev_block_hash; + } + + if (None, None) == (override_timestamp, override_prev_block_hash) { + current_l2_block.max_virtual_blocks_to_create = 0; + } + + vm.vm.push_transaction(l1_tx); + let timestamp = Timestamp(vm.vm.state.local_state.timestamp); + set_manual_l2_block_info(&mut vm.vm, 1, current_l2_block, timestamp); + + let result = vm.vm.execute(VmExecutionMode::OneTx); + + if let Some(err) = expected_error { + assert_eq!(result.result, ExecutionResult::Halt { reason: err }); + } else { + assert_eq!(result.result, ExecutionResult::Success { output: vec![] }); + } +} + +#[test] +fn test_l2_block_same_l2_block() { + // This test aims to test the case when there are multiple transactions inside the same L2 block. + + // Case 1: Incorrect timestamp + test_same_l2_block( + Some(Halt::FailedToSetL2Block( + "The timestamp of the same L2 block must be same".to_string(), + )), + Some(0), + None, + ); + + // Case 2: Incorrect previous block hash + test_same_l2_block( + Some(Halt::FailedToSetL2Block( + "The previous hash of the same L2 block must be same".to_string(), + )), + None, + Some(H256::zero()), + ); + + // Case 3: Correct continuation of the same L2 block + test_same_l2_block(None, None, None); +} + +fn test_new_l2_block( + first_l2_block: L2BlockEnv, + overriden_second_block_number: Option, + overriden_second_block_timestamp: Option, + overriden_second_block_prev_block_hash: Option, + expected_error: Option, +) { + let mut l1_batch = default_l1_batch(L1BatchNumber(1)); + l1_batch.timestamp = 1; + l1_batch.first_l2_block = first_l2_block; + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_l1_batch_env(l1_batch) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let l1_tx = get_l1_noop(); + + // Firstly we execute the first transaction + vm.vm.push_transaction(l1_tx.clone()); + vm.vm.execute(VmExecutionMode::OneTx); + + let mut second_l2_block = vm.vm.batch_env.first_l2_block; + second_l2_block.number += 1; + second_l2_block.timestamp += 1; + second_l2_block.prev_block_hash = vm.vm.bootloader_state.last_l2_block().get_hash(); + + if let Some(block_number) = overriden_second_block_number { + second_l2_block.number = block_number; + } + if let Some(timestamp) = overriden_second_block_timestamp { + second_l2_block.timestamp = timestamp; + } + if let Some(prev_block_hash) = overriden_second_block_prev_block_hash { + second_l2_block.prev_block_hash = prev_block_hash; + } + + vm.vm.bootloader_state.push_l2_block(second_l2_block); + + vm.vm.push_transaction(l1_tx); + + let result = vm.vm.execute(VmExecutionMode::OneTx); + if let Some(err) = expected_error { + assert_eq!(result.result, ExecutionResult::Halt { reason: err }); + } else { + assert_eq!(result.result, ExecutionResult::Success { output: vec![] }); + } +} + +#[test] +fn test_l2_block_new_l2_block() { + // This test is aimed to cover potential issue + + let correct_first_block = L2BlockEnv { + number: 1, + timestamp: 1, + prev_block_hash: MiniblockHasher::legacy_hash(MiniblockNumber(0)), + max_virtual_blocks_to_create: 1, + }; + + // Case 1: Block number increasing by more than 1 + test_new_l2_block( + correct_first_block, + Some(3), + None, + None, + Some(Halt::FailedToSetL2Block( + "Invalid new L2 block number".to_string(), + )), + ); + + // Case 2: Timestamp not increasing + test_new_l2_block( + correct_first_block, + None, + Some(1), + None, + Some(Halt::FailedToSetL2Block("The timestamp of the new L2 block must be greater than the timestamp of the previous L2 block".to_string())), + ); + + // Case 3: Incorrect previous block hash + test_new_l2_block( + correct_first_block, + None, + None, + Some(H256::zero()), + Some(Halt::FailedToSetL2Block( + "The current L2 block hash is incorrect".to_string(), + )), + ); + + // Case 4: Correct new block + test_new_l2_block(correct_first_block, None, None, None, None); +} + +#[allow(clippy::too_many_arguments)] +fn test_first_in_batch( + miniblock_timestamp: u64, + miniblock_number: u32, + pending_txs_hash: H256, + batch_timestamp: u64, + new_batch_timestamp: u64, + batch_number: u32, + proposed_block: L2BlockEnv, + expected_error: Option, +) { + let mut l1_batch = default_l1_batch(L1BatchNumber(1)); + l1_batch.number += 1; + l1_batch.timestamp = new_batch_timestamp; + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_l1_batch_env(l1_batch) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + let l1_tx = get_l1_noop(); + + // Setting the values provided. + let storage_ptr = vm.vm.state.storage.storage.get_ptr(); + let miniblock_info_slot = StorageKey::new( + AccountTreeId::new(SYSTEM_CONTEXT_ADDRESS), + SYSTEM_CONTEXT_CURRENT_L2_BLOCK_INFO_POSITION, + ); + let pending_txs_hash_slot = StorageKey::new( + AccountTreeId::new(SYSTEM_CONTEXT_ADDRESS), + SYSTEM_CONTEXT_CURRENT_TX_ROLLING_HASH_POSITION, + ); + let batch_info_slot = StorageKey::new( + AccountTreeId::new(SYSTEM_CONTEXT_ADDRESS), + SYSTEM_CONTEXT_BLOCK_INFO_POSITION, + ); + let prev_block_hash_position = get_l2_block_hash_key(miniblock_number - 1); + + storage_ptr.borrow_mut().set_value( + miniblock_info_slot, + u256_to_h256(pack_block_info( + miniblock_number as u64, + miniblock_timestamp, + )), + ); + storage_ptr + .borrow_mut() + .set_value(pending_txs_hash_slot, pending_txs_hash); + storage_ptr.borrow_mut().set_value( + batch_info_slot, + u256_to_h256(pack_block_info(batch_number as u64, batch_timestamp)), + ); + storage_ptr.borrow_mut().set_value( + prev_block_hash_position, + MiniblockHasher::legacy_hash(MiniblockNumber(miniblock_number - 1)), + ); + + // In order to skip checks from the Rust side of the VM, we firstly use some definitely correct L2 block info. + // And then override it with the user-provided value + + let last_l2_block = vm.vm.bootloader_state.last_l2_block(); + let new_l2_block = L2BlockEnv { + number: last_l2_block.number + 1, + timestamp: last_l2_block.timestamp + 1, + prev_block_hash: last_l2_block.get_hash(), + max_virtual_blocks_to_create: last_l2_block.max_virtual_blocks_to_create, + }; + + vm.vm.bootloader_state.push_l2_block(new_l2_block); + vm.vm.push_transaction(l1_tx); + let timestamp = Timestamp(vm.vm.state.local_state.timestamp); + set_manual_l2_block_info(&mut vm.vm, 0, proposed_block, timestamp); + + let result = vm.vm.execute(VmExecutionMode::OneTx); + if let Some(err) = expected_error { + assert_eq!(result.result, ExecutionResult::Halt { reason: err }); + } else { + assert_eq!(result.result, ExecutionResult::Success { output: vec![] }); + } +} + +#[test] +fn test_l2_block_first_in_batch() { + let prev_block_hash = MiniblockHasher::legacy_hash(MiniblockNumber(0)); + let prev_block_hash = MiniblockHasher::new(MiniblockNumber(1), 1, prev_block_hash) + .finalize(ProtocolVersionId::latest()); + test_first_in_batch( + 1, + 1, + H256::zero(), + 1, + 2, + 1, + L2BlockEnv { + number: 2, + timestamp: 2, + prev_block_hash, + max_virtual_blocks_to_create: 1, + }, + None, + ); + + let prev_block_hash = MiniblockHasher::legacy_hash(MiniblockNumber(0)); + let prev_block_hash = MiniblockHasher::new(MiniblockNumber(1), 8, prev_block_hash) + .finalize(ProtocolVersionId::latest()); + test_first_in_batch( + 8, + 1, + H256::zero(), + 5, + 12, + 1, + L2BlockEnv { + number: 2, + timestamp: 9, + prev_block_hash, + max_virtual_blocks_to_create: 1, + }, + Some(Halt::FailedToSetL2Block("The timestamp of the L2 block must be greater than or equal to the timestamp of the current batch".to_string())), + ); +} + +fn set_manual_l2_block_info( + vm: &mut Vm, + tx_number: usize, + block_info: L2BlockEnv, + timestamp: Timestamp, +) { + let fictive_miniblock_position = + TX_OPERATOR_L2_BLOCK_INFO_OFFSET + TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO * tx_number; + + vm.state.memory.populate_page( + BOOTLOADER_HEAP_PAGE as usize, + vec![ + (fictive_miniblock_position, block_info.number.into()), + (fictive_miniblock_position + 1, block_info.timestamp.into()), + ( + fictive_miniblock_position + 2, + h256_to_u256(block_info.prev_block_hash), + ), + ( + fictive_miniblock_position + 3, + block_info.max_virtual_blocks_to_create.into(), + ), + ], + timestamp, + ) +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/mod.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/mod.rs new file mode 100644 index 000000000000..95377232b3e3 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/mod.rs @@ -0,0 +1,22 @@ +mod bootloader; +mod default_aa; +// TODO - fix this test +// mod invalid_bytecode; +mod bytecode_publishing; +mod call_tracer; +mod circuits; +mod gas_limit; +mod get_used_contracts; +mod is_write_initial; +mod l1_tx_execution; +mod l2_blocks; +mod nonce_holder; +mod precompiles; +mod refunds; +mod require_eip712; +mod rollbacks; +mod simple_execution; +mod tester; +mod tracing_execution_error; +mod upgrade; +mod utils; diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/nonce_holder.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/nonce_holder.rs new file mode 100644 index 000000000000..44ba3e4e323a --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/nonce_holder.rs @@ -0,0 +1,188 @@ +use zksync_types::{Execute, Nonce}; + +use crate::{ + interface::{ + ExecutionResult, Halt, TxExecutionMode, TxRevertReason, VmExecutionMode, VmInterface, + VmRevertReason, + }, + vm_boojum_integration::{ + tests::{ + tester::{Account, VmTesterBuilder}, + utils::read_nonce_holder_tester, + }, + types::internals::TransactionData, + HistoryEnabled, + }, +}; + +pub enum NonceHolderTestMode { + SetValueUnderNonce, + IncreaseMinNonceBy5, + IncreaseMinNonceTooMuch, + LeaveNonceUnused, + IncreaseMinNonceBy1, + SwitchToArbitraryOrdering, +} + +impl From for u8 { + fn from(mode: NonceHolderTestMode) -> u8 { + match mode { + NonceHolderTestMode::SetValueUnderNonce => 0, + NonceHolderTestMode::IncreaseMinNonceBy5 => 1, + NonceHolderTestMode::IncreaseMinNonceTooMuch => 2, + NonceHolderTestMode::LeaveNonceUnused => 3, + NonceHolderTestMode::IncreaseMinNonceBy1 => 4, + NonceHolderTestMode::SwitchToArbitraryOrdering => 5, + } + } +} + +#[test] +fn test_nonce_holder() { + let mut account = Account::random(); + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_deployer() + .with_custom_contracts(vec![( + read_nonce_holder_tester().to_vec(), + account.address, + true, + )]) + .with_rich_accounts(vec![account.clone()]) + .build(); + + let mut run_nonce_test = |nonce: u32, + test_mode: NonceHolderTestMode, + error_message: Option, + comment: &'static str| { + // In this test we have to reset VM state after each test case. Because once bootloader failed during the validation of the transaction, + // it will fail again and again. At the same time we have to keep the same storage, because we want to keep the nonce holder contract state. + // The easiest way in terms of lifetimes is to reuse vm_builder to achieve it. + vm.reset_state(true); + let mut transaction_data: TransactionData = account + .get_l2_tx_for_execute_with_nonce( + Execute { + contract_address: account.address, + calldata: vec![12], + value: Default::default(), + factory_deps: None, + }, + None, + Nonce(nonce), + ) + .into(); + + transaction_data.signature = vec![test_mode.into()]; + vm.vm.push_raw_transaction(transaction_data, 0, 0, true); + let result = vm.vm.execute(VmExecutionMode::OneTx); + + if let Some(msg) = error_message { + let expected_error = + TxRevertReason::Halt(Halt::ValidationFailed(VmRevertReason::General { + msg, + data: vec![], + })); + let ExecutionResult::Halt { reason } = result.result else { + panic!("Expected revert, got {:?}", result.result); + }; + assert_eq!( + reason.to_string(), + expected_error.to_string(), + "{}", + comment + ); + } else { + assert!(!result.result.is_failed(), "{}", comment); + } + }; + // Test 1: trying to set value under non sequential nonce value. + run_nonce_test( + 1u32, + NonceHolderTestMode::SetValueUnderNonce, + Some("Previous nonce has not been used".to_string()), + "Allowed to set value under non sequential value", + ); + + // Test 2: increase min nonce by 1 with sequential nonce ordering: + run_nonce_test( + 0u32, + NonceHolderTestMode::IncreaseMinNonceBy1, + None, + "Failed to increment nonce by 1 for sequential account", + ); + + // Test 3: correctly set value under nonce with sequential nonce ordering: + run_nonce_test( + 1u32, + NonceHolderTestMode::SetValueUnderNonce, + None, + "Failed to set value under nonce sequential value", + ); + + // Test 5: migrate to the arbitrary nonce ordering: + run_nonce_test( + 2u32, + NonceHolderTestMode::SwitchToArbitraryOrdering, + None, + "Failed to switch to arbitrary ordering", + ); + + // Test 6: increase min nonce by 5 + run_nonce_test( + 6u32, + NonceHolderTestMode::IncreaseMinNonceBy5, + None, + "Failed to increase min nonce by 5", + ); + + // Test 7: since the nonces in range [6,10] are no longer allowed, the + // tx with nonce 10 should not be allowed + run_nonce_test( + 10u32, + NonceHolderTestMode::IncreaseMinNonceBy5, + Some("Reusing the same nonce twice".to_string()), + "Allowed to reuse nonce below the minimal one", + ); + + // Test 8: we should be able to use nonce 13 + run_nonce_test( + 13u32, + NonceHolderTestMode::SetValueUnderNonce, + None, + "Did not allow to use unused nonce 10", + ); + + // Test 9: we should not be able to reuse nonce 13 + run_nonce_test( + 13u32, + NonceHolderTestMode::IncreaseMinNonceBy5, + Some("Reusing the same nonce twice".to_string()), + "Allowed to reuse the same nonce twice", + ); + + // Test 10: we should be able to simply use nonce 14, while bumping the minimal nonce by 5 + run_nonce_test( + 14u32, + NonceHolderTestMode::IncreaseMinNonceBy5, + None, + "Did not allow to use a bumped nonce", + ); + + // Test 11: Do not allow bumping nonce by too much + run_nonce_test( + 16u32, + NonceHolderTestMode::IncreaseMinNonceTooMuch, + Some("The value for incrementing the nonce is too high".to_string()), + "Allowed for incrementing min nonce too much", + ); + + // Test 12: Do not allow not setting a nonce as used + run_nonce_test( + 16u32, + NonceHolderTestMode::LeaveNonceUnused, + Some("The nonce was not set as used".to_string()), + "Allowed to leave nonce as unused", + ); +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/precompiles.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/precompiles.rs new file mode 100644 index 000000000000..516331d574f4 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/precompiles.rs @@ -0,0 +1,136 @@ +use zk_evm_1_4_0::zk_evm_abstractions::precompiles::PrecompileAddress; +use zksync_types::{Address, Execute}; + +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_boojum_integration::{ + constants::BLOCK_GAS_LIMIT, + tests::{tester::VmTesterBuilder, utils::read_precompiles_contract}, + HistoryEnabled, + }, +}; + +#[test] +fn test_keccak() { + // Execute special transaction and check that at least 1000 keccak calls were made. + let contract = read_precompiles_contract(); + let address = Address::random(); + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_random_rich_accounts(1) + .with_deployer() + .with_gas_limit(BLOCK_GAS_LIMIT) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_custom_contracts(vec![(contract, address, true)]) + .build(); + + // calldata for `doKeccak(1000)`. + let keccak1000_calldata = + "370f20ac00000000000000000000000000000000000000000000000000000000000003e8"; + + let account = &mut vm.rich_accounts[0]; + let tx = account.get_l2_tx_for_execute( + Execute { + contract_address: address, + calldata: hex::decode(keccak1000_calldata).unwrap(), + value: Default::default(), + factory_deps: None, + }, + None, + ); + vm.vm.push_transaction(tx); + let _ = vm.vm.inspect(Default::default(), VmExecutionMode::OneTx); + + let keccak_count = vm + .vm + .state + .precompiles_processor + .precompile_cycles_history + .inner() + .iter() + .filter(|(precompile, _)| precompile == &PrecompileAddress::Keccak256) + .count(); + + assert!(keccak_count >= 1000); +} + +#[test] +fn test_sha256() { + // Execute special transaction and check that at least 1000 sha256 calls were made. + let contract = read_precompiles_contract(); + let address = Address::random(); + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_random_rich_accounts(1) + .with_deployer() + .with_gas_limit(BLOCK_GAS_LIMIT) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_custom_contracts(vec![(contract, address, true)]) + .build(); + + // calldata for `doSha256(1000)`. + let sha1000_calldata = + "5d0b4fb500000000000000000000000000000000000000000000000000000000000003e8"; + + let account = &mut vm.rich_accounts[0]; + let tx = account.get_l2_tx_for_execute( + Execute { + contract_address: address, + calldata: hex::decode(sha1000_calldata).unwrap(), + value: Default::default(), + factory_deps: None, + }, + None, + ); + vm.vm.push_transaction(tx); + let _ = vm.vm.inspect(Default::default(), VmExecutionMode::OneTx); + + let sha_count = vm + .vm + .state + .precompiles_processor + .precompile_cycles_history + .inner() + .iter() + .filter(|(precompile, _)| precompile == &PrecompileAddress::SHA256) + .count(); + + assert!(sha_count >= 1000); +} + +#[test] +fn test_ecrecover() { + // Execute simple transfer and check that exactly 1 ecrecover call was made (it's done during tx validation). + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_random_rich_accounts(1) + .with_deployer() + .with_gas_limit(BLOCK_GAS_LIMIT) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .build(); + + let account = &mut vm.rich_accounts[0]; + let tx = account.get_l2_tx_for_execute( + Execute { + contract_address: account.address, + calldata: Vec::new(), + value: Default::default(), + factory_deps: None, + }, + None, + ); + vm.vm.push_transaction(tx); + let _ = vm.vm.inspect(Default::default(), VmExecutionMode::OneTx); + + let ecrecover_count = vm + .vm + .state + .precompiles_processor + .precompile_cycles_history + .inner() + .iter() + .filter(|(precompile, _)| precompile == &PrecompileAddress::Ecrecover) + .count(); + + assert_eq!(ecrecover_count, 1); +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/refunds.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/refunds.rs new file mode 100644 index 000000000000..521bd81f2ef4 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/refunds.rs @@ -0,0 +1,167 @@ +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_boojum_integration::{ + tests::{ + tester::{DeployContractsTx, TxType, VmTesterBuilder}, + utils::read_test_contract, + }, + types::internals::TransactionData, + HistoryEnabled, + }, +}; + +#[test] +fn test_predetermined_refunded_gas() { + // In this test, we compare the execution of the bootloader with the predefined + // refunded gas and without them + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + let l1_batch = vm.vm.batch_env.clone(); + + let counter = read_test_contract(); + let account = &mut vm.rich_accounts[0]; + + let DeployContractsTx { + tx, + bytecode_hash: _, + address: _, + } = account.get_deploy_tx(&counter, None, TxType::L2); + vm.vm.push_transaction(tx.clone()); + let result = vm.vm.execute(VmExecutionMode::OneTx); + + assert!(!result.result.is_failed()); + + // If the refund provided by the operator or the final refund are the 0 + // there is no impact of the operator's refund at all and so this test does not + // make much sense. + assert!( + result.refunds.operator_suggested_refund > 0, + "The operator's refund is 0" + ); + assert!(result.refunds.gas_refunded > 0, "The final refund is 0"); + + let result_without_predefined_refunds = vm.vm.execute(VmExecutionMode::Batch); + let mut current_state_without_predefined_refunds = vm.vm.get_current_execution_state(); + assert!(!result_without_predefined_refunds.result.is_failed(),); + + // Here we want to provide the same refund from the operator and check that it's the correct one. + // We execute the whole block without refund tracer, because refund tracer will eventually override the provided refund. + // But the overall result should be the same + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_l1_batch_env(l1_batch.clone()) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_rich_accounts(vec![account.clone()]) + .build(); + + let tx: TransactionData = tx.into(); + let block_gas_per_pubdata_byte = vm.vm.batch_env.block_gas_price_per_pubdata(); + // Overhead + let overhead = tx.overhead_gas(block_gas_per_pubdata_byte as u32); + vm.vm + .push_raw_transaction(tx.clone(), overhead, result.refunds.gas_refunded, true); + + let result_with_predefined_refunds = vm.vm.execute(VmExecutionMode::Batch); + let mut current_state_with_predefined_refunds = vm.vm.get_current_execution_state(); + + assert!(!result_with_predefined_refunds.result.is_failed()); + + // We need to sort these lists as those are flattened from HashMaps + current_state_with_predefined_refunds + .used_contract_hashes + .sort(); + current_state_without_predefined_refunds + .used_contract_hashes + .sort(); + + assert_eq!( + current_state_with_predefined_refunds.events, + current_state_without_predefined_refunds.events + ); + + assert_eq!( + current_state_with_predefined_refunds.user_l2_to_l1_logs, + current_state_without_predefined_refunds.user_l2_to_l1_logs + ); + + assert_eq!( + current_state_with_predefined_refunds.system_logs, + current_state_without_predefined_refunds.system_logs + ); + + assert_eq!( + current_state_with_predefined_refunds.storage_log_queries, + current_state_without_predefined_refunds.storage_log_queries + ); + assert_eq!( + current_state_with_predefined_refunds.used_contract_hashes, + current_state_without_predefined_refunds.used_contract_hashes + ); + + // In this test we put the different refund from the operator. + // We still can't use the refund tracer, because it will override the refund. + // But we can check that the logs and events have changed. + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_l1_batch_env(l1_batch) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_rich_accounts(vec![account.clone()]) + .build(); + + let changed_operator_suggested_refund = result.refunds.gas_refunded + 1000; + vm.vm + .push_raw_transaction(tx, overhead, changed_operator_suggested_refund, true); + let result = vm.vm.execute(VmExecutionMode::Batch); + let mut current_state_with_changed_predefined_refunds = vm.vm.get_current_execution_state(); + + assert!(!result.result.is_failed()); + current_state_with_changed_predefined_refunds + .used_contract_hashes + .sort(); + current_state_without_predefined_refunds + .used_contract_hashes + .sort(); + + assert_eq!( + current_state_with_changed_predefined_refunds.events.len(), + current_state_without_predefined_refunds.events.len() + ); + + assert_ne!( + current_state_with_changed_predefined_refunds.events, + current_state_without_predefined_refunds.events + ); + + assert_eq!( + current_state_with_changed_predefined_refunds.user_l2_to_l1_logs, + current_state_without_predefined_refunds.user_l2_to_l1_logs + ); + + assert_ne!( + current_state_with_changed_predefined_refunds.system_logs, + current_state_without_predefined_refunds.system_logs + ); + + assert_eq!( + current_state_with_changed_predefined_refunds + .storage_log_queries + .len(), + current_state_without_predefined_refunds + .storage_log_queries + .len() + ); + + assert_ne!( + current_state_with_changed_predefined_refunds.storage_log_queries, + current_state_without_predefined_refunds.storage_log_queries + ); + assert_eq!( + current_state_with_changed_predefined_refunds.used_contract_hashes, + current_state_without_predefined_refunds.used_contract_hashes + ); +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/require_eip712.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/require_eip712.rs new file mode 100644 index 000000000000..90c3206b24bf --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/require_eip712.rs @@ -0,0 +1,165 @@ +use std::convert::TryInto; + +use ethabi::Token; +use zksync_eth_signer::{raw_ethereum_tx::TransactionParameters, EthereumSigner}; +use zksync_system_constants::L2_ETH_TOKEN_ADDRESS; +use zksync_types::{ + fee::Fee, l2::L2Tx, transaction_request::TransactionRequest, + utils::storage_key_for_standard_token_balance, AccountTreeId, Address, Eip712Domain, Execute, + L2ChainId, Nonce, Transaction, U256, +}; + +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_boojum_integration::{ + tests::{ + tester::{Account, VmTester, VmTesterBuilder}, + utils::read_many_owners_custom_account_contract, + }, + HistoryDisabled, + }, +}; + +impl VmTester { + pub(crate) fn get_eth_balance(&mut self, address: Address) -> U256 { + let key = storage_key_for_standard_token_balance( + AccountTreeId::new(L2_ETH_TOKEN_ADDRESS), + &address, + ); + self.vm.state.storage.storage.read_from_storage(&key) + } +} + +// TODO refactor this test it use too much internal details of the VM +#[tokio::test] +/// This test deploys 'buggy' account abstraction code, and then tries accessing it both with legacy +/// and EIP712 transactions. +/// Currently we support both, but in the future, we should allow only EIP712 transactions to access the AA accounts. +async fn test_require_eip712() { + // Use 3 accounts: + // - private_address - EOA account, where we have the key + // - account_address - AA account, where the contract is deployed + // - beneficiary - an EOA account, where we'll try to transfer the tokens. + let account_abstraction = Account::random(); + let mut private_account = Account::random(); + let beneficiary = Account::random(); + + let (bytecode, contract) = read_many_owners_custom_account_contract(); + let mut vm = VmTesterBuilder::new(HistoryDisabled) + .with_empty_in_memory_storage() + .with_custom_contracts(vec![(bytecode, account_abstraction.address, true)]) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_rich_accounts(vec![account_abstraction.clone(), private_account.clone()]) + .build(); + + assert_eq!(vm.get_eth_balance(beneficiary.address), U256::from(0)); + + let chain_id: u32 = 270; + + // First, let's set the owners of the AA account to the private_address. + // (so that messages signed by private_address, are authorized to act on behalf of the AA account). + let set_owners_function = contract.function("setOwners").unwrap(); + let encoded_input = set_owners_function + .encode_input(&[Token::Array(vec![Token::Address(private_account.address)])]) + .unwrap(); + + let tx = private_account.get_l2_tx_for_execute( + Execute { + contract_address: account_abstraction.address, + calldata: encoded_input, + value: Default::default(), + factory_deps: None, + }, + None, + ); + + vm.vm.push_transaction(tx); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert!(!result.result.is_failed()); + + let private_account_balance = vm.get_eth_balance(private_account.address); + + // And now let's do the transfer from the 'account abstraction' to 'beneficiary' (using 'legacy' transaction). + // Normally this would not work - unless the operator is malicious. + let aa_raw_tx = TransactionParameters { + nonce: U256::from(0), + to: Some(beneficiary.address), + gas: U256::from(100000000), + gas_price: Some(U256::from(10000000)), + value: U256::from(888000088), + data: vec![], + chain_id: 270, + transaction_type: None, + access_list: None, + max_fee_per_gas: U256::from(1000000000), + max_priority_fee_per_gas: U256::from(1000000000), + }; + + let aa_tx = private_account.sign_legacy_tx(aa_raw_tx).await; + let (tx_request, hash) = TransactionRequest::from_bytes(&aa_tx, L2ChainId::from(270)).unwrap(); + + let mut l2_tx: L2Tx = L2Tx::from_request(tx_request, 10000).unwrap(); + l2_tx.set_input(aa_tx, hash); + // Pretend that operator is malicious and sets the initiator to the AA account. + l2_tx.common_data.initiator_address = account_abstraction.address; + let transaction: Transaction = l2_tx.try_into().unwrap(); + + vm.vm.push_transaction(transaction); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert!(!result.result.is_failed()); + assert_eq!( + vm.get_eth_balance(beneficiary.address), + U256::from(888000088) + ); + // Make sure that the tokens were transferred from the AA account. + assert_eq!( + private_account_balance, + vm.get_eth_balance(private_account.address) + ); + + // // Now send the 'classic' EIP712 transaction + let tx_712 = L2Tx::new( + beneficiary.address, + vec![], + Nonce(1), + Fee { + gas_limit: U256::from(1000000000), + max_fee_per_gas: U256::from(1000000000), + max_priority_fee_per_gas: U256::from(1000000000), + gas_per_pubdata_limit: U256::from(1000000000), + }, + account_abstraction.address, + U256::from(28374938), + None, + Default::default(), + ); + + let transaction_request: TransactionRequest = tx_712.into(); + + let domain = Eip712Domain::new(L2ChainId::from(chain_id)); + let signature = private_account + .get_pk_signer() + .sign_typed_data(&domain, &transaction_request) + .await + .unwrap(); + let encoded_tx = transaction_request.get_signed_bytes(&signature, L2ChainId::from(chain_id)); + + let (aa_txn_request, aa_hash) = + TransactionRequest::from_bytes(&encoded_tx, L2ChainId::from(chain_id)).unwrap(); + + let mut l2_tx = L2Tx::from_request(aa_txn_request, 100000).unwrap(); + l2_tx.set_input(encoded_tx, aa_hash); + + let transaction: Transaction = l2_tx.try_into().unwrap(); + vm.vm.push_transaction(transaction); + vm.vm.execute(VmExecutionMode::OneTx); + + assert_eq!( + vm.get_eth_balance(beneficiary.address), + U256::from(916375026) + ); + assert_eq!( + private_account_balance, + vm.get_eth_balance(private_account.address) + ); +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/rollbacks.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/rollbacks.rs new file mode 100644 index 000000000000..3d3127f8428b --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/rollbacks.rs @@ -0,0 +1,263 @@ +use ethabi::Token; +use zksync_contracts::{get_loadnext_contract, test_contracts::LoadnextContractExecutionParams}; +use zksync_state::WriteStorage; +use zksync_types::{get_nonce_key, Execute, U256}; + +use crate::{ + interface::{ + dyn_tracers::vm_1_4_0::DynTracer, + tracer::{TracerExecutionStatus, TracerExecutionStopReason}, + TxExecutionMode, VmExecutionMode, VmInterface, VmInterfaceHistoryEnabled, + }, + vm_boojum_integration::{ + tests::{ + tester::{DeployContractsTx, TransactionTestInfo, TxModifier, TxType, VmTesterBuilder}, + utils::read_test_contract, + }, + types::internals::ZkSyncVmState, + BootloaderState, HistoryEnabled, HistoryMode, SimpleMemory, ToTracerPointer, VmTracer, + }, +}; + +#[test] +fn test_vm_rollbacks() { + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let mut account = vm.rich_accounts[0].clone(); + let counter = read_test_contract(); + let tx_0 = account.get_deploy_tx(&counter, None, TxType::L2).tx; + let tx_1 = account.get_deploy_tx(&counter, None, TxType::L2).tx; + let tx_2 = account.get_deploy_tx(&counter, None, TxType::L2).tx; + + let result_without_rollbacks = vm.execute_and_verify_txs(&vec![ + TransactionTestInfo::new_processed(tx_0.clone(), false), + TransactionTestInfo::new_processed(tx_1.clone(), false), + TransactionTestInfo::new_processed(tx_2.clone(), false), + ]); + + // reset vm + vm.reset_with_empty_storage(); + + let result_with_rollbacks = vm.execute_and_verify_txs(&vec![ + TransactionTestInfo::new_rejected(tx_0.clone(), TxModifier::WrongSignatureLength.into()), + TransactionTestInfo::new_rejected(tx_0.clone(), TxModifier::WrongMagicValue.into()), + TransactionTestInfo::new_rejected(tx_0.clone(), TxModifier::WrongSignature.into()), + // The correct nonce is 0, this tx will fail + TransactionTestInfo::new_rejected(tx_2.clone(), TxModifier::WrongNonce.into()), + // This tx will succeed + TransactionTestInfo::new_processed(tx_0.clone(), false), + // The correct nonce is 1, this tx will fail + TransactionTestInfo::new_rejected(tx_0.clone(), TxModifier::NonceReused.into()), + // The correct nonce is 1, this tx will fail + TransactionTestInfo::new_rejected(tx_2.clone(), TxModifier::WrongNonce.into()), + // This tx will succeed + TransactionTestInfo::new_processed(tx_1, false), + // The correct nonce is 2, this tx will fail + TransactionTestInfo::new_rejected(tx_0.clone(), TxModifier::NonceReused.into()), + // This tx will succeed + TransactionTestInfo::new_processed(tx_2.clone(), false), + // This tx will fail + TransactionTestInfo::new_rejected(tx_2, TxModifier::NonceReused.into()), + TransactionTestInfo::new_rejected(tx_0, TxModifier::NonceReused.into()), + ]); + + assert_eq!(result_without_rollbacks, result_with_rollbacks); +} + +#[test] +fn test_vm_loadnext_rollbacks() { + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + let mut account = vm.rich_accounts[0].clone(); + + let loadnext_contract = get_loadnext_contract(); + let loadnext_constructor_data = &[Token::Uint(U256::from(100))]; + let DeployContractsTx { + tx: loadnext_deploy_tx, + address, + .. + } = account.get_deploy_tx_with_factory_deps( + &loadnext_contract.bytecode, + Some(loadnext_constructor_data), + loadnext_contract.factory_deps.clone(), + TxType::L2, + ); + + let loadnext_tx_1 = account.get_l2_tx_for_execute( + Execute { + contract_address: address, + calldata: LoadnextContractExecutionParams { + reads: 100, + writes: 100, + events: 100, + hashes: 500, + recursive_calls: 10, + deploys: 60, + } + .to_bytes(), + value: Default::default(), + factory_deps: None, + }, + None, + ); + + let loadnext_tx_2 = account.get_l2_tx_for_execute( + Execute { + contract_address: address, + calldata: LoadnextContractExecutionParams { + reads: 100, + writes: 100, + events: 100, + hashes: 500, + recursive_calls: 10, + deploys: 60, + } + .to_bytes(), + value: Default::default(), + factory_deps: None, + }, + None, + ); + + let result_without_rollbacks = vm.execute_and_verify_txs(&vec![ + TransactionTestInfo::new_processed(loadnext_deploy_tx.clone(), false), + TransactionTestInfo::new_processed(loadnext_tx_1.clone(), false), + TransactionTestInfo::new_processed(loadnext_tx_2.clone(), false), + ]); + + // reset vm + vm.reset_with_empty_storage(); + + let result_with_rollbacks = vm.execute_and_verify_txs(&vec![ + TransactionTestInfo::new_processed(loadnext_deploy_tx.clone(), false), + TransactionTestInfo::new_processed(loadnext_tx_1.clone(), true), + TransactionTestInfo::new_rejected( + loadnext_deploy_tx.clone(), + TxModifier::NonceReused.into(), + ), + TransactionTestInfo::new_processed(loadnext_tx_1, false), + TransactionTestInfo::new_processed(loadnext_tx_2.clone(), true), + TransactionTestInfo::new_processed(loadnext_tx_2.clone(), true), + TransactionTestInfo::new_rejected(loadnext_deploy_tx, TxModifier::NonceReused.into()), + TransactionTestInfo::new_processed(loadnext_tx_2, false), + ]); + + assert_eq!(result_without_rollbacks, result_with_rollbacks); +} + +// Testing tracer that does not allow the recursion to go deeper than a certain limit +struct MaxRecursionTracer { + max_recursion_depth: usize, +} + +/// Tracer responsible for calculating the number of storage invocations and +/// stopping the VM execution if the limit is reached. +impl DynTracer> for MaxRecursionTracer {} + +impl VmTracer for MaxRecursionTracer { + fn finish_cycle( + &mut self, + state: &mut ZkSyncVmState, + _bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + let current_depth = state.local_state.callstack.depth(); + + if current_depth > self.max_recursion_depth { + TracerExecutionStatus::Stop(TracerExecutionStopReason::Finish) + } else { + TracerExecutionStatus::Continue + } + } +} + +#[test] +fn test_layered_rollback() { + // This test checks that the layered rollbacks work correctly, i.e. + // the rollback by the operator will always revert all the changes + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let account = &mut vm.rich_accounts[0]; + let loadnext_contract = get_loadnext_contract().bytecode; + + let DeployContractsTx { + tx: deploy_tx, + address, + .. + } = account.get_deploy_tx( + &loadnext_contract, + Some(&[Token::Uint(0.into())]), + TxType::L2, + ); + vm.vm.push_transaction(deploy_tx); + let deployment_res = vm.vm.execute(VmExecutionMode::OneTx); + assert!(!deployment_res.result.is_failed(), "transaction failed"); + + let loadnext_transaction = account.get_loadnext_transaction( + address, + LoadnextContractExecutionParams { + writes: 1, + recursive_calls: 20, + ..LoadnextContractExecutionParams::empty() + }, + TxType::L2, + ); + + let nonce_val = vm + .vm + .state + .storage + .storage + .read_from_storage(&get_nonce_key(&account.address)); + + vm.vm.make_snapshot(); + + vm.vm.push_transaction(loadnext_transaction.clone()); + vm.vm.inspect( + MaxRecursionTracer { + max_recursion_depth: 15, + } + .into_tracer_pointer() + .into(), + VmExecutionMode::OneTx, + ); + + let nonce_val2 = vm + .vm + .state + .storage + .storage + .read_from_storage(&get_nonce_key(&account.address)); + + // The tracer stopped after the validation has passed, so nonce has already been increased + assert_eq!(nonce_val + U256::one(), nonce_val2, "nonce did not change"); + + vm.vm.rollback_to_the_latest_snapshot(); + + let nonce_val_after_rollback = vm + .vm + .state + .storage + .storage + .read_from_storage(&get_nonce_key(&account.address)); + + assert_eq!( + nonce_val, nonce_val_after_rollback, + "nonce changed after rollback" + ); + + vm.vm.push_transaction(loadnext_transaction); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert!(!result.result.is_failed(), "transaction must not fail"); +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/simple_execution.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/simple_execution.rs new file mode 100644 index 000000000000..fc94e2c71526 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/simple_execution.rs @@ -0,0 +1,81 @@ +use crate::{ + interface::{ExecutionResult, VmExecutionMode, VmInterface}, + vm_boojum_integration::{ + tests::tester::{TxType, VmTesterBuilder}, + HistoryDisabled, + }, +}; + +#[test] +fn estimate_fee() { + let mut vm_tester = VmTesterBuilder::new(HistoryDisabled) + .with_empty_in_memory_storage() + .with_deployer() + .with_random_rich_accounts(1) + .build(); + + vm_tester.deploy_test_contract(); + let account = &mut vm_tester.rich_accounts[0]; + + let tx = account.get_test_contract_transaction( + vm_tester.test_contract.unwrap(), + false, + Default::default(), + false, + TxType::L2, + ); + + vm_tester.vm.push_transaction(tx); + + let result = vm_tester.vm.execute(VmExecutionMode::OneTx); + assert!(matches!(result.result, ExecutionResult::Success { .. })); +} + +#[test] +fn simple_execute() { + let mut vm_tester = VmTesterBuilder::new(HistoryDisabled) + .with_empty_in_memory_storage() + .with_deployer() + .with_random_rich_accounts(1) + .build(); + + vm_tester.deploy_test_contract(); + + let account = &mut vm_tester.rich_accounts[0]; + + let tx1 = account.get_test_contract_transaction( + vm_tester.test_contract.unwrap(), + false, + Default::default(), + false, + TxType::L1 { serial_id: 1 }, + ); + + let tx2 = account.get_test_contract_transaction( + vm_tester.test_contract.unwrap(), + true, + Default::default(), + false, + TxType::L1 { serial_id: 1 }, + ); + + let tx3 = account.get_test_contract_transaction( + vm_tester.test_contract.unwrap(), + false, + Default::default(), + false, + TxType::L1 { serial_id: 1 }, + ); + let vm = &mut vm_tester.vm; + vm.push_transaction(tx1); + vm.push_transaction(tx2); + vm.push_transaction(tx3); + let tx = vm.execute(VmExecutionMode::OneTx); + assert!(matches!(tx.result, ExecutionResult::Success { .. })); + let tx = vm.execute(VmExecutionMode::OneTx); + assert!(matches!(tx.result, ExecutionResult::Revert { .. })); + let tx = vm.execute(VmExecutionMode::OneTx); + assert!(matches!(tx.result, ExecutionResult::Success { .. })); + let block_tip = vm.execute(VmExecutionMode::Batch); + assert!(matches!(block_tip.result, ExecutionResult::Success { .. })); +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/tester/inner_state.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/tester/inner_state.rs new file mode 100644 index 000000000000..24f31c5a9393 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/tester/inner_state.rs @@ -0,0 +1,130 @@ +use std::collections::HashMap; + +use zk_evm_1_4_0::{aux_structures::Timestamp, vm_state::VmLocalState}; +use zksync_state::WriteStorage; +use zksync_types::{StorageKey, StorageLogQuery, StorageValue, U256}; + +use crate::{ + vm_boojum_integration::{ + old_vm::{ + event_sink::InMemoryEventSink, + history_recorder::{AppDataFrameManagerWithHistory, HistoryRecorder}, + }, + HistoryEnabled, HistoryMode, SimpleMemory, Vm, + }, + HistoryMode as CommonHistoryMode, +}; + +#[derive(Clone, Debug)] +pub(crate) struct ModifiedKeysMap(HashMap); + +// We consider hashmaps to be equal even if there is a key +// that is not present in one but has zero value in another. +impl PartialEq for ModifiedKeysMap { + fn eq(&self, other: &Self) -> bool { + for (key, value) in self.0.iter() { + if *value != other.0.get(key).cloned().unwrap_or_default() { + return false; + } + } + for (key, value) in other.0.iter() { + if *value != self.0.get(key).cloned().unwrap_or_default() { + return false; + } + } + true + } +} + +#[derive(Clone, PartialEq, Debug)] +pub(crate) struct DecommitterTestInnerState { + /// There is no way to "truly" compare the storage pointer, + /// so we just compare the modified keys. This is reasonable enough. + pub(crate) modified_storage_keys: ModifiedKeysMap, + pub(crate) known_bytecodes: HistoryRecorder>, H>, + pub(crate) decommitted_code_hashes: HistoryRecorder, HistoryEnabled>, +} + +#[derive(Clone, PartialEq, Debug)] +pub(crate) struct StorageOracleInnerState { + /// There is no way to "truly" compare the storage pointer, + /// so we just compare the modified keys. This is reasonable enough. + pub(crate) modified_storage_keys: ModifiedKeysMap, + + pub(crate) frames_stack: AppDataFrameManagerWithHistory, H>, + + pub(crate) pre_paid_changes: HistoryRecorder, H>, + pub(crate) paid_changes: HistoryRecorder, H>, + pub(crate) initial_values: HistoryRecorder, H>, + pub(crate) returned_refunds: HistoryRecorder, H>, +} + +#[derive(Clone, PartialEq, Debug)] +pub(crate) struct PrecompileProcessorTestInnerState { + pub(crate) timestamp_history: HistoryRecorder, H>, +} + +/// A struct that encapsulates the state of the VM's oracles +/// The state is to be used in tests. +#[derive(Clone, PartialEq, Debug)] +pub(crate) struct VmInstanceInnerState { + event_sink: InMemoryEventSink, + precompile_processor_state: PrecompileProcessorTestInnerState, + memory: SimpleMemory, + decommitter_state: DecommitterTestInnerState, + storage_oracle_state: StorageOracleInnerState, + local_state: VmLocalState, +} + +impl Vm { + // Dump inner state of the VM. + pub(crate) fn dump_inner_state(&self) -> VmInstanceInnerState { + let event_sink = self.state.event_sink.clone(); + let precompile_processor_state = PrecompileProcessorTestInnerState { + timestamp_history: self.state.precompiles_processor.timestamp_history.clone(), + }; + let memory = self.state.memory.clone(); + let decommitter_state = DecommitterTestInnerState { + modified_storage_keys: ModifiedKeysMap( + self.state + .decommittment_processor + .get_storage() + .borrow() + .modified_storage_keys() + .clone(), + ), + known_bytecodes: self.state.decommittment_processor.known_bytecodes.clone(), + decommitted_code_hashes: self + .state + .decommittment_processor + .get_decommitted_code_hashes_with_history() + .clone(), + }; + let storage_oracle_state = StorageOracleInnerState { + modified_storage_keys: ModifiedKeysMap( + self.state + .storage + .storage + .get_ptr() + .borrow() + .modified_storage_keys() + .clone(), + ), + frames_stack: self.state.storage.frames_stack.clone(), + pre_paid_changes: self.state.storage.pre_paid_changes.clone(), + paid_changes: self.state.storage.paid_changes.clone(), + initial_values: self.state.storage.initial_values.clone(), + returned_refunds: self.state.storage.returned_refunds.clone(), + }; + let local_state = self.state.local_state.clone(); + + VmInstanceInnerState { + event_sink, + precompile_processor_state, + memory, + decommitter_state, + storage_oracle_state, + local_state, + } + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/tester/mod.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/tester/mod.rs new file mode 100644 index 000000000000..dfe8905a7e08 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/tester/mod.rs @@ -0,0 +1,7 @@ +pub(crate) use transaction_test_info::{ExpectedError, TransactionTestInfo, TxModifier}; +pub(crate) use vm_tester::{default_l1_batch, InMemoryStorageView, VmTester, VmTesterBuilder}; +pub(crate) use zksync_test_account::{Account, DeployContractsTx, TxType}; + +mod inner_state; +mod transaction_test_info; +mod vm_tester; diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/tester/transaction_test_info.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/tester/transaction_test_info.rs new file mode 100644 index 000000000000..4d6572fe78a2 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/tester/transaction_test_info.rs @@ -0,0 +1,217 @@ +use zksync_types::{ExecuteTransactionCommon, Transaction}; + +use crate::{ + interface::{ + CurrentExecutionState, ExecutionResult, Halt, TxRevertReason, VmExecutionMode, + VmExecutionResultAndLogs, VmInterface, VmInterfaceHistoryEnabled, VmRevertReason, + }, + vm_boojum_integration::{tests::tester::vm_tester::VmTester, HistoryEnabled}, +}; + +#[derive(Debug, Clone)] +pub(crate) enum TxModifier { + WrongSignatureLength, + WrongSignature, + WrongMagicValue, + WrongNonce, + NonceReused, +} + +#[derive(Debug, Clone)] +pub(crate) enum TxExpectedResult { + Rejected { error: ExpectedError }, + Processed { rollback: bool }, +} + +#[derive(Debug, Clone)] +pub(crate) struct TransactionTestInfo { + tx: Transaction, + result: TxExpectedResult, +} + +#[derive(Debug, Clone)] +pub(crate) struct ExpectedError { + pub(crate) revert_reason: TxRevertReason, + pub(crate) modifier: Option, +} + +impl From for ExpectedError { + fn from(value: TxModifier) -> Self { + let revert_reason = match value { + TxModifier::WrongSignatureLength => { + Halt::ValidationFailed(VmRevertReason::General { + msg: "Signature length is incorrect".to_string(), + data: vec![ + 8, 195, 121, 160, 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, 32, 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, 29, 83, 105, 103, 110, 97, 116, 117, 114, 101, 32, + 108, 101, 110, 103, 116, 104, 32, 105, 115, 32, 105, 110, 99, 111, 114, 114, 101, 99, + 116, 0, 0, 0, + ], + }) + } + TxModifier::WrongSignature => { + Halt::ValidationFailed(VmRevertReason::General { + msg: "Account validation returned invalid magic value. Most often this means that the signature is incorrect".to_string(), + data: vec![], + }) + } + TxModifier::WrongMagicValue => { + Halt::ValidationFailed(VmRevertReason::General { + msg: "v is neither 27 nor 28".to_string(), + data: vec![ + 8, 195, 121, 160, 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, 32, 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, 22, 118, 32, 105, 115, 32, 110, 101, 105, 116, 104, + 101, 114, 32, 50, 55, 32, 110, 111, 114, 32, 50, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }) + + } + TxModifier::WrongNonce => { + Halt::ValidationFailed(VmRevertReason::General { + msg: "Incorrect nonce".to_string(), + data: vec![ + 8, 195, 121, 160, 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, 32, 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, 15, 73, 110, 99, 111, 114, 114, 101, 99, 116, 32, 110, + 111, 110, 99, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }) + } + TxModifier::NonceReused => { + Halt::ValidationFailed(VmRevertReason::General { + msg: "Reusing the same nonce twice".to_string(), + data: vec![ + 8, 195, 121, 160, 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, 32, 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, 28, 82, 101, 117, 115, 105, 110, 103, 32, 116, 104, + 101, 32, 115, 97, 109, 101, 32, 110, 111, 110, 99, 101, 32, 116, 119, 105, 99, 101, 0, + 0, 0, 0, + ], + }) + } + }; + + ExpectedError { + revert_reason: TxRevertReason::Halt(revert_reason), + modifier: Some(value), + } + } +} + +impl TransactionTestInfo { + pub(crate) fn new_rejected( + mut transaction: Transaction, + expected_error: ExpectedError, + ) -> Self { + transaction.common_data = match transaction.common_data { + ExecuteTransactionCommon::L2(mut data) => { + if let Some(modifier) = &expected_error.modifier { + match modifier { + TxModifier::WrongSignatureLength => { + data.signature = data.signature[..data.signature.len() - 20].to_vec() + } + TxModifier::WrongSignature => data.signature = vec![27u8; 65], + TxModifier::WrongMagicValue => data.signature = vec![1u8; 65], + TxModifier::WrongNonce => { + // Do not need to modify signature for nonce error + } + TxModifier::NonceReused => { + // Do not need to modify signature for nonce error + } + } + } + ExecuteTransactionCommon::L2(data) + } + _ => panic!("L1 transactions are not supported"), + }; + + Self { + tx: transaction, + result: TxExpectedResult::Rejected { + error: expected_error, + }, + } + } + + pub(crate) fn new_processed(transaction: Transaction, should_be_rollbacked: bool) -> Self { + Self { + tx: transaction, + result: TxExpectedResult::Processed { + rollback: should_be_rollbacked, + }, + } + } + + fn verify_result(&self, result: &VmExecutionResultAndLogs) { + match &self.result { + TxExpectedResult::Rejected { error } => match &result.result { + ExecutionResult::Success { .. } => { + panic!("Transaction should be reverted {:?}", self.tx.nonce()) + } + ExecutionResult::Revert { output } => match &error.revert_reason { + TxRevertReason::TxReverted(expected) => { + assert_eq!(output, expected) + } + _ => { + panic!("Error types mismatch"); + } + }, + ExecutionResult::Halt { reason } => match &error.revert_reason { + TxRevertReason::Halt(expected) => { + assert_eq!(reason, expected) + } + _ => { + panic!("Error types mismatch"); + } + }, + }, + TxExpectedResult::Processed { .. } => { + assert!(!result.result.is_failed()); + } + } + } + + fn should_rollback(&self) -> bool { + match &self.result { + TxExpectedResult::Rejected { .. } => true, + TxExpectedResult::Processed { rollback } => *rollback, + } + } +} + +impl VmTester { + pub(crate) fn execute_and_verify_txs( + &mut self, + txs: &[TransactionTestInfo], + ) -> CurrentExecutionState { + for tx_test_info in txs { + self.execute_tx_and_verify(tx_test_info.clone()); + } + self.vm.execute(VmExecutionMode::Batch); + let mut state = self.vm.get_current_execution_state(); + state.used_contract_hashes.sort(); + state + } + + pub(crate) fn execute_tx_and_verify( + &mut self, + tx_test_info: TransactionTestInfo, + ) -> VmExecutionResultAndLogs { + let inner_state_before = self.vm.dump_inner_state(); + self.vm.make_snapshot(); + self.vm.push_transaction(tx_test_info.tx.clone()); + let result = self.vm.execute(VmExecutionMode::OneTx); + tx_test_info.verify_result(&result); + if tx_test_info.should_rollback() { + self.vm.rollback_to_the_latest_snapshot(); + let inner_state_after = self.vm.dump_inner_state(); + assert_eq!( + inner_state_before, inner_state_after, + "Inner state before and after rollback should be equal" + ); + } + result + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/tester/vm_tester.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/tester/vm_tester.rs new file mode 100644 index 000000000000..30bf9535eb8b --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/tester/vm_tester.rs @@ -0,0 +1,295 @@ +use std::marker::PhantomData; + +use zksync_contracts::BaseSystemContracts; +use zksync_state::{InMemoryStorage, StoragePtr, StorageView, WriteStorage}; +use zksync_types::{ + block::MiniblockHasher, + get_code_key, get_is_account_key, + helpers::unix_timestamp_ms, + utils::{deployed_address_create, storage_key_for_eth_balance}, + Address, L1BatchNumber, L2ChainId, MiniblockNumber, Nonce, ProtocolVersionId, U256, +}; +use zksync_utils::{bytecode::hash_bytecode, u256_to_h256}; + +use crate::{ + interface::{ + L1BatchEnv, L2Block, L2BlockEnv, SystemEnv, TxExecutionMode, VmExecutionMode, VmInterface, + }, + vm_boojum_integration::{ + constants::BLOCK_GAS_LIMIT, + tests::{ + tester::{Account, TxType}, + utils::read_test_contract, + }, + utils::l2_blocks::load_last_l2_block, + Vm, + }, + HistoryMode, +}; + +pub(crate) type InMemoryStorageView = StorageView; + +pub(crate) struct VmTester { + pub(crate) vm: Vm, + pub(crate) storage: StoragePtr, + pub(crate) fee_account: Address, + pub(crate) deployer: Option, + pub(crate) test_contract: Option
, + pub(crate) rich_accounts: Vec, + pub(crate) custom_contracts: Vec, + _phantom: std::marker::PhantomData, +} + +impl VmTester { + pub(crate) fn deploy_test_contract(&mut self) { + let contract = read_test_contract(); + let tx = self + .deployer + .as_mut() + .expect("You have to initialize builder with deployer") + .get_deploy_tx(&contract, None, TxType::L2) + .tx; + let nonce = tx.nonce().unwrap().0.into(); + self.vm.push_transaction(tx); + self.vm.execute(VmExecutionMode::OneTx); + let deployed_address = + deployed_address_create(self.deployer.as_ref().unwrap().address, nonce); + self.test_contract = Some(deployed_address); + } + + pub(crate) fn reset_with_empty_storage(&mut self) { + self.storage = StorageView::new(get_empty_storage()).to_rc_ptr(); + self.reset_state(false); + } + + /// Reset the state of the VM to the initial state. + /// If `use_latest_l2_block` is true, then the VM will use the latest L2 block from storage, + /// otherwise it will use the first L2 block of l1 batch env + pub(crate) fn reset_state(&mut self, use_latest_l2_block: bool) { + for account in self.rich_accounts.iter_mut() { + account.nonce = Nonce(0); + make_account_rich(self.storage.clone(), account); + } + if let Some(deployer) = &self.deployer { + make_account_rich(self.storage.clone(), deployer); + } + + if !self.custom_contracts.is_empty() { + println!("Inserting custom contracts is not yet supported") + // insert_contracts(&mut self.storage, &self.custom_contracts); + } + + let mut l1_batch = self.vm.batch_env.clone(); + if use_latest_l2_block { + let last_l2_block = load_last_l2_block(self.storage.clone()).unwrap_or(L2Block { + number: 0, + timestamp: 0, + hash: MiniblockHasher::legacy_hash(MiniblockNumber(0)), + }); + l1_batch.first_l2_block = L2BlockEnv { + number: last_l2_block.number + 1, + timestamp: std::cmp::max(last_l2_block.timestamp + 1, l1_batch.timestamp), + prev_block_hash: last_l2_block.hash, + max_virtual_blocks_to_create: 1, + }; + } + + let vm = Vm::new(l1_batch, self.vm.system_env.clone(), self.storage.clone()); + + if self.test_contract.is_some() { + self.deploy_test_contract(); + } + + self.vm = vm; + } +} + +pub(crate) type ContractsToDeploy = (Vec, Address, bool); + +pub(crate) struct VmTesterBuilder { + storage: Option, + l1_batch_env: Option, + system_env: SystemEnv, + deployer: Option, + rich_accounts: Vec, + custom_contracts: Vec, + _phantom: PhantomData, +} + +impl Clone for VmTesterBuilder { + fn clone(&self) -> Self { + Self { + storage: None, + l1_batch_env: self.l1_batch_env.clone(), + system_env: self.system_env.clone(), + deployer: self.deployer.clone(), + rich_accounts: self.rich_accounts.clone(), + custom_contracts: self.custom_contracts.clone(), + _phantom: PhantomData, + } + } +} + +#[allow(dead_code)] +impl VmTesterBuilder { + pub(crate) fn new(_: H) -> Self { + Self { + storage: None, + l1_batch_env: None, + system_env: SystemEnv { + zk_porter_available: false, + version: ProtocolVersionId::latest(), + base_system_smart_contracts: BaseSystemContracts::playground(), + gas_limit: BLOCK_GAS_LIMIT, + execution_mode: TxExecutionMode::VerifyExecute, + default_validation_computational_gas_limit: BLOCK_GAS_LIMIT, + chain_id: L2ChainId::from(270), + }, + deployer: None, + rich_accounts: vec![], + custom_contracts: vec![], + _phantom: PhantomData, + } + } + + pub(crate) fn with_l1_batch_env(mut self, l1_batch_env: L1BatchEnv) -> Self { + self.l1_batch_env = Some(l1_batch_env); + self + } + + pub(crate) fn with_system_env(mut self, system_env: SystemEnv) -> Self { + self.system_env = system_env; + self + } + + pub(crate) fn with_storage(mut self, storage: InMemoryStorage) -> Self { + self.storage = Some(storage); + self + } + + pub(crate) fn with_base_system_smart_contracts( + mut self, + base_system_smart_contracts: BaseSystemContracts, + ) -> Self { + self.system_env.base_system_smart_contracts = base_system_smart_contracts; + self + } + + pub(crate) fn with_gas_limit(mut self, gas_limit: u32) -> Self { + self.system_env.gas_limit = gas_limit; + self + } + + pub(crate) fn with_execution_mode(mut self, execution_mode: TxExecutionMode) -> Self { + self.system_env.execution_mode = execution_mode; + self + } + + pub(crate) fn with_empty_in_memory_storage(mut self) -> Self { + self.storage = Some(get_empty_storage()); + self + } + + pub(crate) fn with_random_rich_accounts(mut self, number: u32) -> Self { + for _ in 0..number { + let account = Account::random(); + self.rich_accounts.push(account); + } + self + } + + pub(crate) fn with_rich_accounts(mut self, accounts: Vec) -> Self { + self.rich_accounts.extend(accounts); + self + } + + pub(crate) fn with_deployer(mut self) -> Self { + let deployer = Account::random(); + self.deployer = Some(deployer); + self + } + + pub(crate) fn with_custom_contracts(mut self, contracts: Vec) -> Self { + self.custom_contracts = contracts; + self + } + + pub(crate) fn build(self) -> VmTester { + let l1_batch_env = self + .l1_batch_env + .unwrap_or_else(|| default_l1_batch(L1BatchNumber(1))); + + let mut raw_storage = self.storage.unwrap_or_else(get_empty_storage); + insert_contracts(&mut raw_storage, &self.custom_contracts); + let storage_ptr = StorageView::new(raw_storage).to_rc_ptr(); + for account in self.rich_accounts.iter() { + make_account_rich(storage_ptr.clone(), account); + } + if let Some(deployer) = &self.deployer { + make_account_rich(storage_ptr.clone(), deployer); + } + let fee_account = l1_batch_env.fee_account; + + let vm = Vm::new(l1_batch_env, self.system_env, storage_ptr.clone()); + + VmTester { + vm, + storage: storage_ptr, + fee_account, + deployer: self.deployer, + test_contract: None, + rich_accounts: self.rich_accounts.clone(), + custom_contracts: self.custom_contracts.clone(), + _phantom: PhantomData, + } + } +} + +pub(crate) fn default_l1_batch(number: L1BatchNumber) -> L1BatchEnv { + let timestamp = unix_timestamp_ms(); + L1BatchEnv { + previous_batch_hash: None, + number, + timestamp, + l1_gas_price: 50_000_000_000, // 50 gwei + fair_l2_gas_price: 250_000_000, // 0.25 gwei + fee_account: Address::random(), + enforced_base_fee: None, + first_l2_block: L2BlockEnv { + number: 1, + timestamp, + prev_block_hash: MiniblockHasher::legacy_hash(MiniblockNumber(0)), + max_virtual_blocks_to_create: 100, + }, + } +} + +pub(crate) fn make_account_rich(storage: StoragePtr, account: &Account) { + let key = storage_key_for_eth_balance(&account.address); + storage + .as_ref() + .borrow_mut() + .set_value(key, u256_to_h256(U256::from(10u64.pow(19)))); +} + +pub(crate) fn get_empty_storage() -> InMemoryStorage { + InMemoryStorage::with_system_contracts(hash_bytecode) +} + +// Inserts the contracts into the test environment, bypassing the +// deployer system contract. Besides the reference to storage +// it accepts a `contracts` tuple of information about the contract +// and whether or not it is an account. +fn insert_contracts(raw_storage: &mut InMemoryStorage, contracts: &[ContractsToDeploy]) { + for (contract, address, is_account) in contracts { + let deployer_code_key = get_code_key(address); + raw_storage.set_value(deployer_code_key, hash_bytecode(contract)); + + if *is_account { + let is_account_key = get_is_account_key(address); + raw_storage.set_value(is_account_key, u256_to_h256(1_u32.into())); + } + + raw_storage.store_factory_dep(hash_bytecode(contract), contract.clone()); + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/tracing_execution_error.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/tracing_execution_error.rs new file mode 100644 index 000000000000..8c538dcf9bf2 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/tracing_execution_error.rs @@ -0,0 +1,54 @@ +use zksync_types::{Execute, H160}; + +use crate::{ + interface::{TxExecutionMode, TxRevertReason, VmRevertReason}, + vm_boojum_integration::{ + tests::{ + tester::{ExpectedError, TransactionTestInfo, VmTesterBuilder}, + utils::{get_execute_error_calldata, read_error_contract, BASE_SYSTEM_CONTRACTS}, + }, + HistoryEnabled, + }, +}; + +#[test] +fn test_tracing_of_execution_errors() { + let contract_address = H160::random(); + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_base_system_smart_contracts(BASE_SYSTEM_CONTRACTS.clone()) + .with_custom_contracts(vec![(read_error_contract(), contract_address, false)]) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_deployer() + .with_random_rich_accounts(1) + .build(); + + let account = &mut vm.rich_accounts[0]; + + let tx = account.get_l2_tx_for_execute( + Execute { + contract_address, + calldata: get_execute_error_calldata(), + value: Default::default(), + factory_deps: Some(vec![]), + }, + None, + ); + + vm.execute_tx_and_verify(TransactionTestInfo::new_rejected( + tx, + ExpectedError { + revert_reason: TxRevertReason::TxReverted(VmRevertReason::General { + msg: "short".to_string(), + data: vec![ + 8, 195, 121, 160, 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, 32, 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, 5, 115, 104, 111, 114, 116, + 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, + ], + }), + modifier: None, + }, + )); +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/upgrade.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/upgrade.rs new file mode 100644 index 000000000000..4442d7c4082d --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/upgrade.rs @@ -0,0 +1,362 @@ +use zk_evm_1_4_0::aux_structures::Timestamp; +use zksync_contracts::{deployer_contract, load_contract, load_sys_contract, read_bytecode}; +use zksync_state::WriteStorage; +use zksync_test_account::TxType; +use zksync_types::{ + ethabi::{Contract, Token}, + get_code_key, get_known_code_key, + protocol_version::ProtocolUpgradeTxCommonData, + Address, Execute, ExecuteTransactionCommon, Transaction, COMPLEX_UPGRADER_ADDRESS, + CONTRACT_DEPLOYER_ADDRESS, CONTRACT_FORCE_DEPLOYER_ADDRESS, H160, H256, + REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE, U256, +}; +use zksync_utils::{bytecode::hash_bytecode, bytes_to_be_words, h256_to_u256, u256_to_h256}; + +use super::utils::read_test_contract; +use crate::{ + interface::{ + ExecutionResult, Halt, TxExecutionMode, VmExecutionMode, VmInterface, + VmInterfaceHistoryEnabled, + }, + vm_boojum_integration::{ + tests::{tester::VmTesterBuilder, utils::verify_required_storage}, + HistoryEnabled, + }, +}; + +/// In this test we ensure that the requirements for protocol upgrade transactions are enforced by the bootloader: +/// - This transaction must be the only one in block +/// - If present, this transaction must be the first one in block +#[test] +fn test_protocol_upgrade_is_first() { + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let bytecode_hash = hash_bytecode(&read_test_contract()); + vm.vm + .storage + .borrow_mut() + .set_value(get_known_code_key(&bytecode_hash), u256_to_h256(1.into())); + + // Here we just use some random transaction of protocol upgrade type: + let protocol_upgrade_transaction = get_forced_deploy_tx(&[ForceDeployment { + // The bytecode hash to put on an address + bytecode_hash, + // The address on which to deploy the bytecodehash to + address: H160::random(), + // Whether to run the constructor on the force deployment + call_constructor: false, + // The value with which to initialize a contract + value: U256::zero(), + // The constructor calldata + input: vec![], + }]); + + // Another random upgrade transaction + let another_protocol_upgrade_transaction = get_forced_deploy_tx(&[ForceDeployment { + // The bytecode hash to put on an address + bytecode_hash, + // The address on which to deploy the bytecodehash to + address: H160::random(), + // Whether to run the constructor on the force deployment + call_constructor: false, + // The value with which to initialize a contract + value: U256::zero(), + // The constructor calldata + input: vec![], + }]); + + let normal_l1_transaction = vm.rich_accounts[0] + .get_deploy_tx(&read_test_contract(), None, TxType::L1 { serial_id: 0 }) + .tx; + + let expected_error = + Halt::UnexpectedVMBehavior("Assertion error: Protocol upgrade tx not first".to_string()); + + vm.vm.make_snapshot(); + // Test 1: there must be only one system transaction in block + vm.vm.push_transaction(protocol_upgrade_transaction.clone()); + vm.vm.push_transaction(normal_l1_transaction.clone()); + vm.vm.push_transaction(another_protocol_upgrade_transaction); + + vm.vm.execute(VmExecutionMode::OneTx); + vm.vm.execute(VmExecutionMode::OneTx); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert_eq!( + result.result, + ExecutionResult::Halt { + reason: expected_error.clone() + } + ); + + // Test 2: the protocol upgrade tx must be the first one in block + vm.vm.rollback_to_the_latest_snapshot(); + vm.vm.make_snapshot(); + vm.vm.push_transaction(normal_l1_transaction.clone()); + vm.vm.push_transaction(protocol_upgrade_transaction.clone()); + + vm.vm.execute(VmExecutionMode::OneTx); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert_eq!( + result.result, + ExecutionResult::Halt { + reason: expected_error + } + ); + + vm.vm.rollback_to_the_latest_snapshot(); + vm.vm.make_snapshot(); + vm.vm.push_transaction(protocol_upgrade_transaction); + vm.vm.push_transaction(normal_l1_transaction); + + vm.vm.execute(VmExecutionMode::OneTx); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert!(!result.result.is_failed()); +} + +/// In this test we try to test how force deployments could be done via protocol upgrade transactions. +#[test] +fn test_force_deploy_upgrade() { + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let storage_view = vm.storage.clone(); + let bytecode_hash = hash_bytecode(&read_test_contract()); + + let known_code_key = get_known_code_key(&bytecode_hash); + // It is generally expected that all the keys will be set as known prior to the protocol upgrade. + storage_view + .borrow_mut() + .set_value(known_code_key, u256_to_h256(1.into())); + drop(storage_view); + + let address_to_deploy = H160::random(); + // Here we just use some random transaction of protocol upgrade type: + let transaction = get_forced_deploy_tx(&[ForceDeployment { + // The bytecode hash to put on an address + bytecode_hash, + // The address on which to deploy the bytecodehash to + address: address_to_deploy, + // Whether to run the constructor on the force deployment + call_constructor: false, + // The value with which to initialize a contract + value: U256::zero(), + // The constructor calldata + input: vec![], + }]); + + vm.vm.push_transaction(transaction); + + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert!( + !result.result.is_failed(), + "The force upgrade was not successful" + ); + + let expected_slots = vec![(bytecode_hash, get_code_key(&address_to_deploy))]; + + // Verify that the bytecode has been set correctly + verify_required_storage(&vm.vm.state, expected_slots); +} + +/// Here we show how the work with the complex upgrader could be done +#[test] +fn test_complex_upgrader() { + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let storage_view = vm.storage.clone(); + + let bytecode_hash = hash_bytecode(&read_complex_upgrade()); + let msg_sender_test_hash = hash_bytecode(&read_msg_sender_test()); + + // Let's assume that the bytecode for the implementation of the complex upgrade + // is already deployed in some address in userspace + let upgrade_impl = H160::random(); + let account_code_key = get_code_key(&upgrade_impl); + + storage_view + .borrow_mut() + .set_value(get_known_code_key(&bytecode_hash), u256_to_h256(1.into())); + storage_view.borrow_mut().set_value( + get_known_code_key(&msg_sender_test_hash), + u256_to_h256(1.into()), + ); + storage_view + .borrow_mut() + .set_value(account_code_key, bytecode_hash); + drop(storage_view); + + vm.vm.state.decommittment_processor.populate( + vec![ + ( + h256_to_u256(bytecode_hash), + bytes_to_be_words(read_complex_upgrade()), + ), + ( + h256_to_u256(msg_sender_test_hash), + bytes_to_be_words(read_msg_sender_test()), + ), + ], + Timestamp(0), + ); + + let address_to_deploy1 = H160::random(); + let address_to_deploy2 = H160::random(); + + let transaction = get_complex_upgrade_tx( + upgrade_impl, + address_to_deploy1, + address_to_deploy2, + bytecode_hash, + ); + + vm.vm.push_transaction(transaction); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert!( + !result.result.is_failed(), + "The force upgrade was not successful" + ); + + let expected_slots = vec![ + (bytecode_hash, get_code_key(&address_to_deploy1)), + (bytecode_hash, get_code_key(&address_to_deploy2)), + ]; + + // Verify that the bytecode has been set correctly + verify_required_storage(&vm.vm.state, expected_slots); +} + +#[derive(Debug, Clone)] +struct ForceDeployment { + // The bytecode hash to put on an address + bytecode_hash: H256, + // The address on which to deploy the bytecodehash to + address: Address, + // Whether to run the constructor on the force deployment + call_constructor: bool, + // The value with which to initialize a contract + value: U256, + // The constructor calldata + input: Vec, +} + +fn get_forced_deploy_tx(deployment: &[ForceDeployment]) -> Transaction { + let deployer = deployer_contract(); + let contract_function = deployer.function("forceDeployOnAddresses").unwrap(); + + let encoded_deployments: Vec<_> = deployment + .iter() + .map(|deployment| { + Token::Tuple(vec![ + Token::FixedBytes(deployment.bytecode_hash.as_bytes().to_vec()), + Token::Address(deployment.address), + Token::Bool(deployment.call_constructor), + Token::Uint(deployment.value), + Token::Bytes(deployment.input.clone()), + ]) + }) + .collect(); + + let params = [Token::Array(encoded_deployments)]; + + let calldata = contract_function + .encode_input(¶ms) + .expect("failed to encode parameters"); + + let execute = Execute { + contract_address: CONTRACT_DEPLOYER_ADDRESS, + calldata, + factory_deps: None, + value: U256::zero(), + }; + + Transaction { + common_data: ExecuteTransactionCommon::ProtocolUpgrade(ProtocolUpgradeTxCommonData { + sender: CONTRACT_FORCE_DEPLOYER_ADDRESS, + gas_limit: U256::from(200_000_000u32), + gas_per_pubdata_limit: REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE.into(), + ..Default::default() + }), + execute, + received_timestamp_ms: 0, + raw_bytes: None, + } +} + +// Returns the transaction that performs a complex protocol upgrade. +// The first param is the address of the implementation of the complex upgrade +// in user-space, while the next 3 params are params of the implenentaiton itself +// For the explanatation for the parameters, please refer to: +// etc/contracts-test-data/complex-upgrade/complex-upgrade.sol +fn get_complex_upgrade_tx( + implementation_address: Address, + address1: Address, + address2: Address, + bytecode_hash: H256, +) -> Transaction { + let impl_contract = get_complex_upgrade_abi(); + let impl_function = impl_contract.function("someComplexUpgrade").unwrap(); + let impl_calldata = impl_function + .encode_input(&[ + Token::Address(address1), + Token::Address(address2), + Token::FixedBytes(bytecode_hash.as_bytes().to_vec()), + ]) + .unwrap(); + + let complex_upgrader = get_complex_upgrader_abi(); + let upgrade_function = complex_upgrader.function("upgrade").unwrap(); + let complex_upgrader_calldata = upgrade_function + .encode_input(&[ + Token::Address(implementation_address), + Token::Bytes(impl_calldata), + ]) + .unwrap(); + + let execute = Execute { + contract_address: COMPLEX_UPGRADER_ADDRESS, + calldata: complex_upgrader_calldata, + factory_deps: None, + value: U256::zero(), + }; + + Transaction { + common_data: ExecuteTransactionCommon::ProtocolUpgrade(ProtocolUpgradeTxCommonData { + sender: CONTRACT_FORCE_DEPLOYER_ADDRESS, + gas_limit: U256::from(200_000_000u32), + gas_per_pubdata_limit: REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE.into(), + ..Default::default() + }), + execute, + received_timestamp_ms: 0, + raw_bytes: None, + } +} + +fn read_complex_upgrade() -> Vec { + read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/complex-upgrade/complex-upgrade.sol/ComplexUpgrade.json") +} + +fn read_msg_sender_test() -> Vec { + read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/complex-upgrade/msg-sender.sol/MsgSenderTest.json") +} + +fn get_complex_upgrade_abi() -> Contract { + load_contract( + "etc/contracts-test-data/artifacts-zk/contracts/complex-upgrade/complex-upgrade.sol/ComplexUpgrade.json" + ) +} + +fn get_complex_upgrader_abi() -> Contract { + load_sys_contract("ComplexUpgrader") +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tests/utils.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tests/utils.rs new file mode 100644 index 000000000000..2dd8e2350eb4 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tests/utils.rs @@ -0,0 +1,111 @@ +use ethabi::Contract; +use once_cell::sync::Lazy; +use zksync_contracts::{ + load_contract, read_bytecode, read_zbin_bytecode, BaseSystemContracts, SystemContractCode, +}; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_types::{ + utils::storage_key_for_standard_token_balance, AccountTreeId, Address, StorageKey, H256, U256, +}; +use zksync_utils::{bytecode::hash_bytecode, bytes_to_be_words, h256_to_u256, u256_to_h256}; + +use crate::vm_boojum_integration::{ + tests::tester::InMemoryStorageView, types::internals::ZkSyncVmState, HistoryMode, +}; + +pub(crate) static BASE_SYSTEM_CONTRACTS: Lazy = + Lazy::new(BaseSystemContracts::load_from_disk); + +// Probably make it a part of vm tester +pub(crate) fn verify_required_storage( + state: &ZkSyncVmState, + required_values: Vec<(H256, StorageKey)>, +) { + for (required_value, key) in required_values { + let current_value = state.storage.storage.read_from_storage(&key); + + assert_eq!( + u256_to_h256(current_value), + required_value, + "Invalid value at key {key:?}" + ); + } +} + +pub(crate) fn verify_required_memory( + state: &ZkSyncVmState, + required_values: Vec<(U256, u32, u32)>, +) { + for (required_value, memory_page, cell) in required_values { + let current_value = state + .memory + .read_slot(memory_page as usize, cell as usize) + .value; + assert_eq!(current_value, required_value); + } +} + +pub(crate) fn get_balance( + token_id: AccountTreeId, + account: &Address, + main_storage: StoragePtr, +) -> U256 { + let key = storage_key_for_standard_token_balance(token_id, account); + h256_to_u256(main_storage.borrow_mut().read_value(&key)) +} + +pub(crate) fn read_test_contract() -> Vec { + read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/counter/counter.sol/Counter.json") +} + +pub(crate) fn get_bootloader(test: &str) -> SystemContractCode { + let bootloader_code = read_zbin_bytecode(format!( + "contracts/system-contracts/bootloader/tests/artifacts/{}.yul.zbin", + test + )); + + let bootloader_hash = hash_bytecode(&bootloader_code); + SystemContractCode { + code: bytes_to_be_words(bootloader_code), + hash: bootloader_hash, + } +} + +pub(crate) fn read_nonce_holder_tester() -> Vec { + read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/custom-account/nonce-holder-test.sol/NonceHolderTest.json") +} + +pub(crate) fn read_error_contract() -> Vec { + read_bytecode( + "etc/contracts-test-data/artifacts-zk/contracts/error/error.sol/SimpleRequire.json", + ) +} + +pub(crate) fn get_execute_error_calldata() -> Vec { + let test_contract = load_contract( + "etc/contracts-test-data/artifacts-zk/contracts/error/error.sol/SimpleRequire.json", + ); + + let function = test_contract.function("require_short").unwrap(); + + function + .encode_input(&[]) + .expect("failed to encode parameters") +} + +pub(crate) fn read_many_owners_custom_account_contract() -> (Vec, Contract) { + let path = "etc/contracts-test-data/artifacts-zk/contracts/custom-account/many-owners-custom-account.sol/ManyOwnersCustomAccount.json"; + (read_bytecode(path), load_contract(path)) +} + +pub(crate) fn read_max_depth_contract() -> Vec { + read_zbin_bytecode( + "core/tests/ts-integration/contracts/zkasm/artifacts/deep_stak.zkasm/deep_stak.zkasm.zbin", + ) +} + +pub(crate) fn read_precompiles_contract() -> Vec { + read_bytecode( + "etc/contracts-test-data/artifacts-zk/contracts/precompiles/precompiles.sol/Precompiles.json", + ) +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tracers/circuits_capacity.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tracers/circuits_capacity.rs new file mode 100644 index 000000000000..5ba932a2a102 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tracers/circuits_capacity.rs @@ -0,0 +1,67 @@ +use zkevm_test_harness_1_4_0::{geometry_config::get_geometry_config, toolset::GeometryConfig}; +use zksync_types::circuit::{CircuitCycleStatistic, CircuitStatistic}; + +// "Rich addressing" opcodes are opcodes that can write their return value/read the input onto the stack +// and so take 1-2 RAM permutations more than an average opcode. +// In the worst case, a rich addressing may take 3 ram permutations +// (1 for reading the opcode, 1 for writing input value, 1 for writing output value). +pub(crate) const RICH_ADDRESSING_OPCODE_RAM_CYCLES: u32 = 3; + +pub(crate) const AVERAGE_OPCODE_RAM_CYCLES: u32 = 1; + +pub(crate) const STORAGE_READ_RAM_CYCLES: u32 = 1; +pub(crate) const STORAGE_READ_LOG_DEMUXER_CYCLES: u32 = 1; +pub(crate) const STORAGE_READ_STORAGE_SORTER_CYCLES: u32 = 1; +pub(crate) const STORAGE_READ_STORAGE_APPLICATION_CYCLES: u32 = 1; + +pub(crate) const EVENT_RAM_CYCLES: u32 = 1; +pub(crate) const EVENT_LOG_DEMUXER_CYCLES: u32 = 2; +pub(crate) const EVENT_EVENTS_SORTER_CYCLES: u32 = 2; + +pub(crate) const STORAGE_WRITE_RAM_CYCLES: u32 = 1; +pub(crate) const STORAGE_WRITE_LOG_DEMUXER_CYCLES: u32 = 2; +pub(crate) const STORAGE_WRITE_STORAGE_SORTER_CYCLES: u32 = 2; +pub(crate) const STORAGE_WRITE_STORAGE_APPLICATION_CYCLES: u32 = 2; + +pub(crate) const FAR_CALL_RAM_CYCLES: u32 = 1; +pub(crate) const FAR_CALL_STORAGE_SORTER_CYCLES: u32 = 1; +pub(crate) const FAR_CALL_CODE_DECOMMITTER_SORTER_CYCLES: u32 = 1; + +// 5 RAM permutations, because: 1 to read opcode + 2 reads + 2 writes. +// 2 reads and 2 writes are needed because unaligned access is implemented with +// aligned queries. +pub(crate) const UMA_WRITE_RAM_CYCLES: u32 = 5; + +// 3 RAM permutations, because: 1 to read opcode + 2 reads. +// 2 reads are needed because unaligned access is implemented with aligned queries. +pub(crate) const UMA_READ_RAM_CYCLES: u32 = 3; + +pub(crate) const PRECOMPILE_RAM_CYCLES: u32 = 1; +pub(crate) const PRECOMPILE_LOG_DEMUXER_CYCLES: u32 = 1; + +const GEOMETRY_CONFIG: GeometryConfig = get_geometry_config(); + +pub(crate) fn circuit_statistic_from_cycles(cycles: CircuitCycleStatistic) -> CircuitStatistic { + CircuitStatistic { + main_vm: cycles.main_vm_cycles as f32 / GEOMETRY_CONFIG.cycles_per_vm_snapshot as f32, + ram_permutation: cycles.ram_permutation_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_ram_permutation as f32, + storage_application: cycles.storage_application_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_storage_application as f32, + storage_sorter: cycles.storage_sorter_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_storage_sorter as f32, + code_decommitter: cycles.code_decommitter_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_code_decommitter as f32, + code_decommitter_sorter: cycles.code_decommitter_sorter_cycles as f32 + / GEOMETRY_CONFIG.cycles_code_decommitter_sorter as f32, + log_demuxer: cycles.log_demuxer_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_log_demuxer as f32, + events_sorter: cycles.events_sorter_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_events_or_l1_messages_sorter as f32, + keccak256: cycles.keccak256_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_keccak256_circuit as f32, + ecrecover: cycles.ecrecover_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_ecrecover_circuit as f32, + sha256: cycles.sha256_cycles as f32 / GEOMETRY_CONFIG.cycles_per_sha256_circuit as f32, + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tracers/circuits_tracer.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tracers/circuits_tracer.rs new file mode 100644 index 000000000000..27f4cc6db00f --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tracers/circuits_tracer.rs @@ -0,0 +1,233 @@ +use std::marker::PhantomData; + +use zk_evm_1_4_0::{ + tracing::{BeforeExecutionData, VmLocalStateData}, + zk_evm_abstractions::precompiles::PrecompileAddress, + zkevm_opcode_defs::{LogOpcode, Opcode, UMAOpcode}, +}; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_types::circuit::CircuitCycleStatistic; + +use super::circuits_capacity::*; +use crate::{ + interface::{dyn_tracers::vm_1_4_0::DynTracer, tracer::TracerExecutionStatus}, + vm_boojum_integration::{ + bootloader_state::BootloaderState, + old_vm::{history_recorder::HistoryMode, memory::SimpleMemory}, + tracers::traits::VmTracer, + types::internals::ZkSyncVmState, + }, +}; + +/// Tracer responsible for collecting information about refunds. +#[derive(Debug)] +pub(crate) struct CircuitsTracer { + pub(crate) statistics: CircuitCycleStatistic, + last_decommitment_history_entry_checked: Option, + last_written_keys_history_entry_checked: Option, + last_read_keys_history_entry_checked: Option, + last_precompile_inner_entry_checked: Option, + _phantom_data: PhantomData<(S, H)>, +} + +impl DynTracer> for CircuitsTracer { + fn before_execution( + &mut self, + _state: VmLocalStateData<'_>, + data: BeforeExecutionData, + _memory: &SimpleMemory, + _storage: StoragePtr, + ) { + self.statistics.main_vm_cycles += 1; + + match data.opcode.variant.opcode { + Opcode::Nop(_) + | Opcode::Add(_) + | Opcode::Sub(_) + | Opcode::Mul(_) + | Opcode::Div(_) + | Opcode::Jump(_) + | Opcode::Binop(_) + | Opcode::Shift(_) + | Opcode::Ptr(_) => { + self.statistics.ram_permutation_cycles += RICH_ADDRESSING_OPCODE_RAM_CYCLES; + } + Opcode::Context(_) | Opcode::Ret(_) | Opcode::NearCall(_) => { + self.statistics.ram_permutation_cycles += AVERAGE_OPCODE_RAM_CYCLES; + } + Opcode::Log(LogOpcode::StorageRead) => { + self.statistics.ram_permutation_cycles += STORAGE_READ_RAM_CYCLES; + self.statistics.log_demuxer_cycles += STORAGE_READ_LOG_DEMUXER_CYCLES; + self.statistics.storage_sorter_cycles += STORAGE_READ_STORAGE_SORTER_CYCLES; + } + Opcode::Log(LogOpcode::StorageWrite) => { + self.statistics.ram_permutation_cycles += STORAGE_WRITE_RAM_CYCLES; + self.statistics.log_demuxer_cycles += STORAGE_WRITE_LOG_DEMUXER_CYCLES; + self.statistics.storage_sorter_cycles += STORAGE_WRITE_STORAGE_SORTER_CYCLES; + } + Opcode::Log(LogOpcode::ToL1Message) | Opcode::Log(LogOpcode::Event) => { + self.statistics.ram_permutation_cycles += EVENT_RAM_CYCLES; + self.statistics.log_demuxer_cycles += EVENT_LOG_DEMUXER_CYCLES; + self.statistics.events_sorter_cycles += EVENT_EVENTS_SORTER_CYCLES; + } + Opcode::Log(LogOpcode::PrecompileCall) => { + self.statistics.ram_permutation_cycles += PRECOMPILE_RAM_CYCLES; + self.statistics.log_demuxer_cycles += PRECOMPILE_LOG_DEMUXER_CYCLES; + } + Opcode::FarCall(_) => { + self.statistics.ram_permutation_cycles += FAR_CALL_RAM_CYCLES; + self.statistics.code_decommitter_sorter_cycles += + FAR_CALL_CODE_DECOMMITTER_SORTER_CYCLES; + self.statistics.storage_sorter_cycles += FAR_CALL_STORAGE_SORTER_CYCLES; + } + Opcode::UMA(UMAOpcode::AuxHeapWrite | UMAOpcode::HeapWrite) => { + self.statistics.ram_permutation_cycles += UMA_WRITE_RAM_CYCLES; + } + Opcode::UMA( + UMAOpcode::AuxHeapRead | UMAOpcode::HeapRead | UMAOpcode::FatPointerRead, + ) => { + self.statistics.ram_permutation_cycles += UMA_READ_RAM_CYCLES; + } + Opcode::Invalid(_) => unreachable!(), // invalid opcodes are never executed + }; + } +} + +impl VmTracer for CircuitsTracer { + fn initialize_tracer(&mut self, state: &mut ZkSyncVmState) { + self.last_decommitment_history_entry_checked = Some( + state + .decommittment_processor + .decommitted_code_hashes + .history() + .len(), + ); + + self.last_written_keys_history_entry_checked = + Some(state.storage.written_keys.history().len()); + + self.last_read_keys_history_entry_checked = Some(state.storage.read_keys.history().len()); + + self.last_precompile_inner_entry_checked = Some( + state + .precompiles_processor + .precompile_cycles_history + .inner() + .len(), + ); + } + + fn finish_cycle( + &mut self, + state: &mut ZkSyncVmState, + _bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + self.trace_decommitments(state); + self.trace_storage_writes(state); + self.trace_storage_reads(state); + self.trace_precompile_calls(state); + + TracerExecutionStatus::Continue + } +} + +impl CircuitsTracer { + pub(crate) fn new() -> Self { + Self { + statistics: CircuitCycleStatistic::new(), + last_decommitment_history_entry_checked: None, + last_written_keys_history_entry_checked: None, + last_read_keys_history_entry_checked: None, + last_precompile_inner_entry_checked: None, + _phantom_data: Default::default(), + } + } + + fn trace_decommitments(&mut self, state: &ZkSyncVmState) { + let last_decommitment_history_entry_checked = self + .last_decommitment_history_entry_checked + .expect("Value must be set during init"); + let history = state + .decommittment_processor + .decommitted_code_hashes + .history(); + for (_, history_event) in &history[last_decommitment_history_entry_checked..] { + // We assume that only insertions may happen during a single VM inspection. + assert!(history_event.value.is_none()); + let bytecode_len = state + .decommittment_processor + .known_bytecodes + .inner() + .get(&history_event.key) + .expect("Bytecode must be known at this point") + .len(); + + // Each cycle of `CodeDecommitter` processes 2 words. + // If the number of words in bytecode is odd, then number of cycles must be rounded up. + let decommitter_cycles_used = (bytecode_len + 1) / 2; + self.statistics.code_decommitter_cycles += decommitter_cycles_used as u32; + } + self.last_decommitment_history_entry_checked = Some(history.len()); + } + + fn trace_storage_writes(&mut self, state: &ZkSyncVmState) { + let last_writes_history_entry_checked = self + .last_written_keys_history_entry_checked + .expect("Value must be set during init"); + let history = state.storage.written_keys.history(); + for (_, history_event) in &history[last_writes_history_entry_checked..] { + // We assume that only insertions may happen during a single VM inspection. + assert!(history_event.value.is_none()); + + self.statistics.storage_application_cycles += STORAGE_WRITE_STORAGE_APPLICATION_CYCLES; + } + self.last_written_keys_history_entry_checked = Some(history.len()); + } + + fn trace_storage_reads(&mut self, state: &ZkSyncVmState) { + let last_reads_history_entry_checked = self + .last_read_keys_history_entry_checked + .expect("Value must be set during init"); + let history = state.storage.read_keys.history(); + for (_, history_event) in &history[last_reads_history_entry_checked..] { + // We assume that only insertions may happen during a single VM inspection. + assert!(history_event.value.is_none()); + + // If the slot is already written to, then we've already taken 2 cycles into account. + if !state + .storage + .written_keys + .inner() + .contains_key(&history_event.key) + { + self.statistics.storage_application_cycles += + STORAGE_READ_STORAGE_APPLICATION_CYCLES; + } + } + self.last_read_keys_history_entry_checked = Some(history.len()); + } + + fn trace_precompile_calls(&mut self, state: &ZkSyncVmState) { + let last_precompile_inner_entry_checked = self + .last_precompile_inner_entry_checked + .expect("Value must be set during init"); + let inner = state + .precompiles_processor + .precompile_cycles_history + .inner(); + for (precompile, cycles) in &inner[last_precompile_inner_entry_checked..] { + match precompile { + PrecompileAddress::Ecrecover => { + self.statistics.ecrecover_cycles += *cycles as u32; + } + PrecompileAddress::SHA256 => { + self.statistics.sha256_cycles += *cycles as u32; + } + PrecompileAddress::Keccak256 => { + self.statistics.keccak256_cycles += *cycles as u32; + } + }; + } + self.last_precompile_inner_entry_checked = Some(inner.len()); + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tracers/default_tracers.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tracers/default_tracers.rs new file mode 100644 index 000000000000..01b21d809509 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tracers/default_tracers.rs @@ -0,0 +1,311 @@ +use std::{ + fmt::{Debug, Formatter}, + marker::PhantomData, +}; + +use zk_evm_1_4_0::{ + aux_structures::Timestamp, + tracing::{ + AfterDecodingData, AfterExecutionData, BeforeExecutionData, Tracer, VmLocalStateData, + }, + vm_state::VmLocalState, + witness_trace::DummyTracer, + zkevm_opcode_defs::{decoding::EncodingModeProduction, Opcode, RetOpcode}, +}; +use zksync_state::{StoragePtr, WriteStorage}; + +use super::PubdataTracer; +use crate::{ + interface::{ + tracer::{TracerExecutionStopReason, VmExecutionStopReason}, + traits::tracers::dyn_tracers::vm_1_4_0::DynTracer, + types::tracer::TracerExecutionStatus, + Halt, VmExecutionMode, + }, + vm_boojum_integration::{ + bootloader_state::{utils::apply_l2_block, BootloaderState}, + constants::BOOTLOADER_HEAP_PAGE, + old_vm::{history_recorder::HistoryMode, memory::SimpleMemory}, + tracers::{ + dispatcher::TracerDispatcher, + utils::{ + computational_gas_price, gas_spent_on_bytecodes_and_long_messages_this_opcode, + print_debug_if_needed, VmHook, + }, + CircuitsTracer, RefundsTracer, ResultTracer, + }, + types::internals::ZkSyncVmState, + VmTracer, + }, +}; + +/// Default tracer for the VM. It manages the other tracers execution and stop the vm when needed. +pub(crate) struct DefaultExecutionTracer { + tx_has_been_processed: bool, + execution_mode: VmExecutionMode, + + pub(crate) gas_spent_on_bytecodes_and_long_messages: u32, + // Amount of gas used during account validation. + pub(crate) computational_gas_used: u32, + // Maximum number of gas that we're allowed to use during account validation. + tx_validation_gas_limit: u32, + in_account_validation: bool, + final_batch_info_requested: bool, + pub(crate) result_tracer: ResultTracer, + // This tracer is designed specifically for calculating refunds. Its separation from the custom tracer + // ensures static dispatch, enhancing performance by avoiding dynamic dispatch overhead. + // Additionally, being an internal tracer, it saves the results directly to `VmResultAndLogs`. + pub(crate) refund_tracer: Option>, + // The pubdata tracer is responsible for inserting the pubdata packing information into the bootloader + // memory at the end of the batch. Its separation from the custom tracer + // ensures static dispatch, enhancing performance by avoiding dynamic dispatch overhead. + pub(crate) pubdata_tracer: Option>, + pub(crate) dispatcher: TracerDispatcher, + ret_from_the_bootloader: Option, + // This tracer tracks what opcodes were executed and calculates how much circuits will be generated. + // It only takes into account circuits that are generated for actual execution. It doesn't + // take into account e.g circuits produced by the initial bootloader memory commitment. + pub(crate) circuits_tracer: CircuitsTracer, + + storage: StoragePtr, + _phantom: PhantomData, +} + +impl DefaultExecutionTracer { + pub(crate) fn new( + computational_gas_limit: u32, + execution_mode: VmExecutionMode, + dispatcher: TracerDispatcher, + storage: StoragePtr, + refund_tracer: Option>, + pubdata_tracer: Option>, + ) -> Self { + Self { + tx_has_been_processed: false, + execution_mode, + gas_spent_on_bytecodes_and_long_messages: 0, + computational_gas_used: 0, + tx_validation_gas_limit: computational_gas_limit, + in_account_validation: false, + final_batch_info_requested: false, + result_tracer: ResultTracer::new(execution_mode), + refund_tracer, + dispatcher, + pubdata_tracer, + ret_from_the_bootloader: None, + circuits_tracer: CircuitsTracer::new(), + storage, + _phantom: PhantomData, + } + } + + pub(crate) fn tx_has_been_processed(&self) -> bool { + self.tx_has_been_processed + } + + pub(crate) fn validation_run_out_of_gas(&self) -> bool { + self.computational_gas_used > self.tx_validation_gas_limit + } + + pub(crate) fn gas_spent_on_pubdata(&self, vm_local_state: &VmLocalState) -> u32 { + self.gas_spent_on_bytecodes_and_long_messages + vm_local_state.spent_pubdata_counter + } + + fn set_fictive_l2_block( + &mut self, + state: &mut ZkSyncVmState, + bootloader_state: &mut BootloaderState, + ) { + let current_timestamp = Timestamp(state.local_state.timestamp); + let txs_index = bootloader_state.free_tx_index(); + let l2_block = bootloader_state.insert_fictive_l2_block(); + let mut memory = vec![]; + apply_l2_block(&mut memory, l2_block, txs_index); + state + .memory + .populate_page(BOOTLOADER_HEAP_PAGE as usize, memory, current_timestamp); + self.final_batch_info_requested = false; + } + + fn should_stop_execution(&self) -> TracerExecutionStatus { + match self.execution_mode { + VmExecutionMode::OneTx if self.tx_has_been_processed() => { + return TracerExecutionStatus::Stop(TracerExecutionStopReason::Finish); + } + VmExecutionMode::Bootloader if self.ret_from_the_bootloader == Some(RetOpcode::Ok) => { + return TracerExecutionStatus::Stop(TracerExecutionStopReason::Finish); + } + _ => {} + }; + if self.validation_run_out_of_gas() { + return TracerExecutionStatus::Stop(TracerExecutionStopReason::Abort( + Halt::ValidationOutOfGas, + )); + } + TracerExecutionStatus::Continue + } +} + +impl Debug for DefaultExecutionTracer { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("DefaultExecutionTracer").finish() + } +} + +/// The default tracer for the VM manages all other tracers. For the sake of optimization, these tracers are statically dispatched. +/// At the same time, the boilerplate for calling these tracers for all tracer calls is quite extensive. +/// This macro is used to reduce the boilerplate. +/// +/// Usage: +/// ``` +/// dispatch_tracers!( +/// self.after_decoding(state, data, memory) +/// ); +/// ``` +/// Whenever a new tracer is added, it should be added to the macro call. +/// +/// The macro passes the function call to all tracers. +macro_rules! dispatch_tracers { + ($self:ident.$function:ident($( $params:expr ),*)) => { + $self.result_tracer.$function($( $params ),*); + $self.dispatcher.$function($( $params ),*); + if let Some(tracer) = &mut $self.refund_tracer { + tracer.$function($( $params ),*); + } + if let Some(tracer) = &mut $self.pubdata_tracer { + tracer.$function($( $params ),*); + } + $self.circuits_tracer.$function($( $params ),*); + }; +} + +impl Tracer for DefaultExecutionTracer { + const CALL_BEFORE_DECODING: bool = false; + const CALL_AFTER_DECODING: bool = true; + const CALL_BEFORE_EXECUTION: bool = true; + const CALL_AFTER_EXECUTION: bool = true; + type SupportedMemory = SimpleMemory; + + fn before_decoding( + &mut self, + _state: VmLocalStateData<'_, 8, EncodingModeProduction>, + _memory: &Self::SupportedMemory, + ) { + } + + fn after_decoding( + &mut self, + state: VmLocalStateData<'_>, + data: AfterDecodingData, + memory: &Self::SupportedMemory, + ) { + dispatch_tracers!(self.after_decoding(state, data, memory)); + } + + fn before_execution( + &mut self, + state: VmLocalStateData<'_>, + data: BeforeExecutionData, + memory: &Self::SupportedMemory, + ) { + if self.in_account_validation { + self.computational_gas_used = self + .computational_gas_used + .saturating_add(computational_gas_price(state, &data)); + } + + let hook = VmHook::from_opcode_memory(&state, &data); + print_debug_if_needed(&hook, &state, memory); + + match hook { + VmHook::TxHasEnded => self.tx_has_been_processed = true, + VmHook::NoValidationEntered => self.in_account_validation = false, + VmHook::AccountValidationEntered => self.in_account_validation = true, + VmHook::FinalBatchInfo => self.final_batch_info_requested = true, + _ => {} + } + + self.gas_spent_on_bytecodes_and_long_messages += + gas_spent_on_bytecodes_and_long_messages_this_opcode(&state, &data); + + dispatch_tracers!(self.before_execution(state, data, memory, self.storage.clone())); + } + + fn after_execution( + &mut self, + state: VmLocalStateData<'_>, + data: AfterExecutionData, + memory: &Self::SupportedMemory, + ) { + if let VmExecutionMode::Bootloader = self.execution_mode { + let (next_opcode, _, _) = zk_evm_1_4_0::vm_state::read_and_decode( + state.vm_local_state, + memory, + &mut DummyTracer, + self, + ); + if current_frame_is_bootloader(state.vm_local_state) { + if let Opcode::Ret(ret) = next_opcode.inner.variant.opcode { + self.ret_from_the_bootloader = Some(ret); + } + } + } + + dispatch_tracers!(self.after_execution(state, data, memory, self.storage.clone())); + } +} + +impl DefaultExecutionTracer { + pub(crate) fn initialize_tracer(&mut self, state: &mut ZkSyncVmState) { + dispatch_tracers!(self.initialize_tracer(state)); + } + + pub(crate) fn finish_cycle( + &mut self, + state: &mut ZkSyncVmState, + bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + if self.final_batch_info_requested { + self.set_fictive_l2_block(state, bootloader_state) + } + + let mut result = self.result_tracer.finish_cycle(state, bootloader_state); + if let Some(refund_tracer) = &mut self.refund_tracer { + result = refund_tracer + .finish_cycle(state, bootloader_state) + .stricter(&result); + } + result = self + .dispatcher + .finish_cycle(state, bootloader_state) + .stricter(&result); + if let Some(pubdata_tracer) = &mut self.pubdata_tracer { + result = pubdata_tracer + .finish_cycle(state, bootloader_state) + .stricter(&result); + } + + result = self + .circuits_tracer + .finish_cycle(state, bootloader_state) + .stricter(&result); + + result.stricter(&self.should_stop_execution()) + } + + pub(crate) fn after_vm_execution( + &mut self, + state: &mut ZkSyncVmState, + bootloader_state: &BootloaderState, + stop_reason: VmExecutionStopReason, + ) { + dispatch_tracers!(self.after_vm_execution(state, bootloader_state, stop_reason.clone())); + } +} + +fn current_frame_is_bootloader(local_state: &VmLocalState) -> bool { + // The current frame is bootloader if the call stack depth is 1. + // Some of the near calls inside the bootloader can be out of gas, which is totally normal behavior + // and it shouldn't result in `is_bootloader_out_of_gas` becoming true. + local_state.callstack.inner.len() == 1 +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tracers/dispatcher.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tracers/dispatcher.rs new file mode 100644 index 000000000000..11262c4d7665 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tracers/dispatcher.rs @@ -0,0 +1,126 @@ +use zk_evm_1_4_0::tracing::{ + AfterDecodingData, AfterExecutionData, BeforeExecutionData, VmLocalStateData, +}; +use zksync_state::{StoragePtr, WriteStorage}; + +use crate::{ + interface::{ + dyn_tracers::vm_1_4_0::DynTracer, + tracer::{TracerExecutionStatus, VmExecutionStopReason}, + }, + vm_boojum_integration::{ + BootloaderState, HistoryMode, SimpleMemory, TracerPointer, VmTracer, ZkSyncVmState, + }, +}; + +/// Tracer dispatcher is a tracer that can dispatch calls to multiple tracers. +pub struct TracerDispatcher { + tracers: Vec>, +} + +impl TracerDispatcher { + pub fn new(tracers: Vec>) -> Self { + Self { tracers } + } +} + +impl From> for TracerDispatcher { + fn from(value: TracerPointer) -> Self { + Self { + tracers: vec![value], + } + } +} + +impl From>> for TracerDispatcher { + fn from(value: Vec>) -> Self { + Self { tracers: value } + } +} + +impl Default for TracerDispatcher { + fn default() -> Self { + Self { tracers: vec![] } + } +} + +impl DynTracer> for TracerDispatcher { + #[inline(always)] + fn before_decoding(&mut self, _state: VmLocalStateData<'_>, _memory: &SimpleMemory) { + for tracer in self.tracers.iter_mut() { + tracer.before_decoding(_state, _memory); + } + } + + #[inline(always)] + fn after_decoding( + &mut self, + _state: VmLocalStateData<'_>, + _data: AfterDecodingData, + _memory: &SimpleMemory, + ) { + for tracer in self.tracers.iter_mut() { + tracer.after_decoding(_state, _data, _memory); + } + } + + #[inline(always)] + fn before_execution( + &mut self, + _state: VmLocalStateData<'_>, + _data: BeforeExecutionData, + _memory: &SimpleMemory, + _storage: StoragePtr, + ) { + for tracer in self.tracers.iter_mut() { + tracer.before_execution(_state, _data, _memory, _storage.clone()); + } + } + + #[inline(always)] + fn after_execution( + &mut self, + _state: VmLocalStateData<'_>, + _data: AfterExecutionData, + _memory: &SimpleMemory, + _storage: StoragePtr, + ) { + for tracer in self.tracers.iter_mut() { + tracer.after_execution(_state, _data, _memory, _storage.clone()); + } + } +} + +impl VmTracer for TracerDispatcher { + fn initialize_tracer(&mut self, _state: &mut ZkSyncVmState) { + for tracer in self.tracers.iter_mut() { + tracer.initialize_tracer(_state); + } + } + + /// Run after each vm execution cycle + #[inline(always)] + fn finish_cycle( + &mut self, + _state: &mut ZkSyncVmState, + _bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + let mut result = TracerExecutionStatus::Continue; + for tracer in self.tracers.iter_mut() { + result = result.stricter(&tracer.finish_cycle(_state, _bootloader_state)); + } + result + } + + /// Run after the vm execution + fn after_vm_execution( + &mut self, + _state: &mut ZkSyncVmState, + _bootloader_state: &BootloaderState, + _stop_reason: VmExecutionStopReason, + ) { + for tracer in self.tracers.iter_mut() { + tracer.after_vm_execution(_state, _bootloader_state, _stop_reason.clone()); + } + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tracers/mod.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tracers/mod.rs new file mode 100644 index 000000000000..fe916e19e8ca --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tracers/mod.rs @@ -0,0 +1,16 @@ +pub(crate) use circuits_tracer::CircuitsTracer; +pub(crate) use default_tracers::DefaultExecutionTracer; +pub(crate) use pubdata_tracer::PubdataTracer; +pub(crate) use refunds::RefundsTracer; +pub(crate) use result_tracer::ResultTracer; + +pub(crate) mod circuits_tracer; +pub(crate) mod default_tracers; +pub(crate) mod pubdata_tracer; +pub(crate) mod refunds; +pub(crate) mod result_tracer; + +pub(crate) mod circuits_capacity; +pub mod dispatcher; +pub(crate) mod traits; +pub(crate) mod utils; diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tracers/pubdata_tracer.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tracers/pubdata_tracer.rs new file mode 100644 index 000000000000..55a58ccd1b03 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tracers/pubdata_tracer.rs @@ -0,0 +1,212 @@ +use std::marker::PhantomData; + +use zk_evm_1_4_0::{ + aux_structures::Timestamp, + tracing::{BeforeExecutionData, VmLocalStateData}, +}; +use zkevm_test_harness_1_4_0::witness::sort_storage_access::sort_storage_access_queries; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_types::{ + event::{ + extract_bytecode_publication_requests_from_l1_messenger, + extract_l2tol1logs_from_l1_messenger, extract_long_l2_to_l1_messages, L1MessengerL2ToL1Log, + }, + writes::StateDiffRecord, + AccountTreeId, StorageKey, L1_MESSENGER_ADDRESS, +}; +use zksync_utils::{h256_to_u256, u256_to_bytes_be, u256_to_h256}; + +use crate::{ + interface::{ + dyn_tracers::vm_1_4_0::DynTracer, + tracer::{TracerExecutionStatus, TracerExecutionStopReason}, + types::inputs::L1BatchEnv, + VmExecutionMode, + }, + vm_boojum_integration::{ + bootloader_state::{utils::apply_pubdata_to_memory, BootloaderState}, + constants::BOOTLOADER_HEAP_PAGE, + old_vm::{history_recorder::HistoryMode, memory::SimpleMemory}, + tracers::{traits::VmTracer, utils::VmHook}, + types::internals::{PubdataInput, ZkSyncVmState}, + utils::logs::collect_events_and_l1_system_logs_after_timestamp, + StorageOracle, + }, +}; + +/// Tracer responsible for collecting information about refunds. +#[derive(Debug, Clone)] +pub(crate) struct PubdataTracer { + l1_batch_env: L1BatchEnv, + pubdata_info_requested: bool, + execution_mode: VmExecutionMode, + _phantom_data: PhantomData, +} + +impl PubdataTracer { + pub(crate) fn new(l1_batch_env: L1BatchEnv, execution_mode: VmExecutionMode) -> Self { + Self { + l1_batch_env, + pubdata_info_requested: false, + execution_mode, + _phantom_data: Default::default(), + } + } +} + +impl PubdataTracer { + // Packs part of L1 Messenger total pubdata that corresponds to + // `L2toL1Logs` sent in the block + fn get_total_user_logs( + &self, + state: &ZkSyncVmState, + ) -> Vec { + let (all_generated_events, _) = collect_events_and_l1_system_logs_after_timestamp( + state, + &self.l1_batch_env, + Timestamp(0), + ); + extract_l2tol1logs_from_l1_messenger(&all_generated_events) + } + + // Packs part of L1 Messenger total pubdata that corresponds to + // Messages sent in the block + fn get_total_l1_messenger_messages( + &self, + state: &ZkSyncVmState, + ) -> Vec> { + let (all_generated_events, _) = collect_events_and_l1_system_logs_after_timestamp( + state, + &self.l1_batch_env, + Timestamp(0), + ); + + extract_long_l2_to_l1_messages(&all_generated_events) + } + + // Packs part of L1 Messenger total pubdata that corresponds to + // Bytecodes needed to be published on L1 + fn get_total_published_bytecodes( + &self, + state: &ZkSyncVmState, + ) -> Vec> { + let (all_generated_events, _) = collect_events_and_l1_system_logs_after_timestamp( + state, + &self.l1_batch_env, + Timestamp(0), + ); + + let bytecode_publication_requests = + extract_bytecode_publication_requests_from_l1_messenger(&all_generated_events); + + bytecode_publication_requests + .iter() + .map(|bytecode_publication_request| { + state + .decommittment_processor + .known_bytecodes + .inner() + .get(&h256_to_u256(bytecode_publication_request.bytecode_hash)) + .unwrap() + .iter() + .flat_map(u256_to_bytes_be) + .collect() + }) + .collect() + } + + // Packs part of L1Messenger total pubdata that corresponds to + // State diffs needed to be published on L1 + fn get_state_diffs(storage: &StorageOracle) -> Vec { + sort_storage_access_queries( + storage + .storage_log_queries_after_timestamp(Timestamp(0)) + .iter() + .map(|log| &log.log_query), + ) + .1 + .into_iter() + .filter(|log| log.rw_flag) + .filter(|log| log.read_value != log.written_value) + .filter(|log| log.address != L1_MESSENGER_ADDRESS) + .map(|log| StateDiffRecord { + address: log.address, + key: log.key, + derived_key: log.derive_final_address(), + enumeration_index: storage + .storage + .get_ptr() + .borrow_mut() + .get_enumeration_index(&StorageKey::new( + AccountTreeId::new(log.address), + u256_to_h256(log.key), + )) + .unwrap_or_default(), + initial_value: log.read_value, + final_value: log.written_value, + }) + .collect() + } + + fn build_pubdata_input(&self, state: &ZkSyncVmState) -> PubdataInput { + PubdataInput { + user_logs: self.get_total_user_logs(state), + l2_to_l1_messages: self.get_total_l1_messenger_messages(state), + published_bytecodes: self.get_total_published_bytecodes(state), + state_diffs: Self::get_state_diffs(&state.storage), + } + } +} + +impl DynTracer> for PubdataTracer { + fn before_execution( + &mut self, + state: VmLocalStateData<'_>, + data: BeforeExecutionData, + _memory: &SimpleMemory, + _storage: StoragePtr, + ) { + let hook = VmHook::from_opcode_memory(&state, &data); + if let VmHook::PubdataRequested = hook { + self.pubdata_info_requested = true; + } + } +} + +impl VmTracer for PubdataTracer { + fn finish_cycle( + &mut self, + state: &mut ZkSyncVmState, + bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + if !matches!(self.execution_mode, VmExecutionMode::Batch) { + // We do not provide the pubdata when executing the block tip or a single transaction + if self.pubdata_info_requested { + return TracerExecutionStatus::Stop(TracerExecutionStopReason::Finish); + } else { + return TracerExecutionStatus::Continue; + } + } + + if self.pubdata_info_requested { + let pubdata_input = self.build_pubdata_input(state); + + // Save the pubdata for the future initial bootloader memory building + bootloader_state.set_pubdata_input(pubdata_input.clone()); + + // Apply the pubdata to the current memory + let mut memory_to_apply = vec![]; + + apply_pubdata_to_memory(&mut memory_to_apply, pubdata_input); + state.memory.populate_page( + BOOTLOADER_HEAP_PAGE as usize, + memory_to_apply, + Timestamp(state.local_state.timestamp), + ); + + self.pubdata_info_requested = false; + } + + TracerExecutionStatus::Continue + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tracers/refunds.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tracers/refunds.rs new file mode 100644 index 000000000000..a4e7295eca81 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tracers/refunds.rs @@ -0,0 +1,352 @@ +use std::marker::PhantomData; + +use vise::{Buckets, EncodeLabelSet, EncodeLabelValue, Family, Histogram, Metrics}; +use zk_evm_1_4_0::{ + aux_structures::Timestamp, + tracing::{BeforeExecutionData, VmLocalStateData}, + vm_state::VmLocalState, +}; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_system_constants::{PUBLISH_BYTECODE_OVERHEAD, SYSTEM_CONTEXT_ADDRESS}; +use zksync_types::{ + event::{extract_long_l2_to_l1_messages, extract_published_bytecodes}, + l2_to_l1_log::L2ToL1Log, + L1BatchNumber, U256, +}; +use zksync_utils::{bytecode::bytecode_len_in_bytes, ceil_div_u256, u256_to_h256}; + +use crate::{ + interface::{ + traits::tracers::dyn_tracers::vm_1_4_0::DynTracer, types::tracer::TracerExecutionStatus, + L1BatchEnv, Refunds, + }, + vm_boojum_integration::{ + bootloader_state::BootloaderState, + constants::{BOOTLOADER_HEAP_PAGE, OPERATOR_REFUNDS_OFFSET, TX_GAS_LIMIT_OFFSET}, + old_vm::{ + events::merge_events, history_recorder::HistoryMode, memory::SimpleMemory, + utils::eth_price_per_pubdata_byte, + }, + tracers::{ + traits::VmTracer, + utils::{ + gas_spent_on_bytecodes_and_long_messages_this_opcode, get_vm_hook_params, VmHook, + }, + }, + types::internals::ZkSyncVmState, + utils::fee::get_batch_base_fee, + }, +}; + +/// Tracer responsible for collecting information about refunds. +#[derive(Debug, Clone)] +pub(crate) struct RefundsTracer { + // Some(x) means that the bootloader has asked the operator + // to provide the refund the user, where `x` is the refund proposed + // by the bootloader itself. + pending_operator_refund: Option, + refund_gas: u32, + operator_refund: Option, + timestamp_initial: Timestamp, + timestamp_before_cycle: Timestamp, + gas_remaining_before: u32, + spent_pubdata_counter_before: u32, + gas_spent_on_bytecodes_and_long_messages: u32, + l1_batch: L1BatchEnv, + pubdata_published: u32, + _phantom: PhantomData, +} + +impl RefundsTracer { + pub(crate) fn new(l1_batch: L1BatchEnv) -> Self { + Self { + pending_operator_refund: None, + refund_gas: 0, + operator_refund: None, + timestamp_initial: Timestamp(0), + timestamp_before_cycle: Timestamp(0), + gas_remaining_before: 0, + spent_pubdata_counter_before: 0, + gas_spent_on_bytecodes_and_long_messages: 0, + l1_batch, + pubdata_published: 0, + _phantom: PhantomData, + } + } +} + +impl RefundsTracer { + fn requested_refund(&self) -> Option { + self.pending_operator_refund + } + + fn set_refund_as_done(&mut self) { + self.pending_operator_refund = None; + } + + fn block_overhead_refund(&mut self) -> u32 { + 0 + } + + pub(crate) fn get_refunds(&self) -> Refunds { + Refunds { + gas_refunded: self.refund_gas, + operator_suggested_refund: self.operator_refund.unwrap_or_default(), + } + } + + pub(crate) fn tx_body_refund( + &self, + bootloader_refund: u32, + gas_spent_on_pubdata: u32, + tx_gas_limit: u32, + current_ergs_per_pubdata_byte: u32, + pubdata_published: u32, + ) -> u32 { + let total_gas_spent = tx_gas_limit - bootloader_refund; + + let gas_spent_on_computation = total_gas_spent + .checked_sub(gas_spent_on_pubdata) + .unwrap_or_else(|| { + tracing::error!( + "Gas spent on pubdata is greater than total gas spent. On pubdata: {}, total: {}", + gas_spent_on_pubdata, + total_gas_spent + ); + 0 + }); + + // For now, bootloader charges only for base fee. + let effective_gas_price = get_batch_base_fee(&self.l1_batch); + + let bootloader_eth_price_per_pubdata_byte = + U256::from(effective_gas_price) * U256::from(current_ergs_per_pubdata_byte); + + let fair_eth_price_per_pubdata_byte = U256::from(eth_price_per_pubdata_byte( + self.l1_batch.fee_input.l1_gas_price(), + )); + + // For now, L1 originated transactions are allowed to pay less than fair fee per pubdata, + // so we should take it into account. + let eth_price_per_pubdata_byte_for_calculation = std::cmp::min( + bootloader_eth_price_per_pubdata_byte, + fair_eth_price_per_pubdata_byte, + ); + + let fair_fee_eth = U256::from(gas_spent_on_computation) + * U256::from(self.l1_batch.fee_input.fair_l2_gas_price()) + + U256::from(pubdata_published) * eth_price_per_pubdata_byte_for_calculation; + let pre_paid_eth = U256::from(tx_gas_limit) * U256::from(effective_gas_price); + let refund_eth = pre_paid_eth.checked_sub(fair_fee_eth).unwrap_or_else(|| { + tracing::error!( + "Fair fee is greater than pre paid. Fair fee: {} wei, pre paid: {} wei", + fair_fee_eth, + pre_paid_eth + ); + U256::zero() + }); + + ceil_div_u256(refund_eth, effective_gas_price.into()).as_u32() + } + + pub(crate) fn gas_spent_on_pubdata(&self, vm_local_state: &VmLocalState) -> u32 { + self.gas_spent_on_bytecodes_and_long_messages + vm_local_state.spent_pubdata_counter + } + + pub(crate) fn pubdata_published(&self) -> u32 { + self.pubdata_published + } +} + +impl DynTracer> for RefundsTracer { + fn before_execution( + &mut self, + state: VmLocalStateData<'_>, + data: BeforeExecutionData, + memory: &SimpleMemory, + _storage: StoragePtr, + ) { + self.timestamp_before_cycle = Timestamp(state.vm_local_state.timestamp); + let hook = VmHook::from_opcode_memory(&state, &data); + match hook { + VmHook::NotifyAboutRefund => self.refund_gas = get_vm_hook_params(memory)[0].as_u32(), + VmHook::AskOperatorForRefund => { + self.pending_operator_refund = Some(get_vm_hook_params(memory)[0].as_u32()) + } + _ => {} + } + + self.gas_spent_on_bytecodes_and_long_messages += + gas_spent_on_bytecodes_and_long_messages_this_opcode(&state, &data); + } +} + +impl VmTracer for RefundsTracer { + fn initialize_tracer(&mut self, state: &mut ZkSyncVmState) { + self.timestamp_initial = Timestamp(state.local_state.timestamp); + self.gas_remaining_before = state.local_state.callstack.current.ergs_remaining; + self.spent_pubdata_counter_before = state.local_state.spent_pubdata_counter; + } + + fn finish_cycle( + &mut self, + state: &mut ZkSyncVmState, + bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelValue, EncodeLabelSet)] + #[metrics(label = "type", rename_all = "snake_case")] + enum RefundType { + Bootloader, + Operator, + } + + const PERCENT_BUCKETS: Buckets = Buckets::values(&[ + 5.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 120.0, + ]); + + #[derive(Debug, Metrics)] + #[metrics(prefix = "vm_boojum_integration")] + struct RefundMetrics { + #[metrics(buckets = PERCENT_BUCKETS)] + refund: Family>, + #[metrics(buckets = PERCENT_BUCKETS)] + refund_diff: Histogram, + } + + #[vise::register] + static METRICS: vise::Global = vise::Global::new(); + + // This means that the bootloader has informed the system (usually via `VMHooks`) - that some gas + // should be refunded back (see `askOperatorForRefund` in `bootloader.yul` for details). + if let Some(bootloader_refund) = self.requested_refund() { + assert!( + self.operator_refund.is_none(), + "Operator was asked for refund two times" + ); + let gas_spent_on_pubdata = + self.gas_spent_on_pubdata(&state.local_state) - self.spent_pubdata_counter_before; + + let current_tx_index = bootloader_state.current_tx(); + let tx_description_offset = + bootloader_state.get_tx_description_offset(current_tx_index); + let tx_gas_limit = state + .memory + .read_slot( + BOOTLOADER_HEAP_PAGE as usize, + tx_description_offset + TX_GAS_LIMIT_OFFSET, + ) + .value + .as_u32(); + + let used_published_storage_slots = state + .storage + .save_paid_changes(Timestamp(state.local_state.timestamp)); + + let pubdata_published = pubdata_published( + state, + used_published_storage_slots, + self.timestamp_initial, + self.l1_batch.number, + ); + + self.pubdata_published = pubdata_published; + let current_ergs_per_pubdata_byte = state.local_state.current_ergs_per_pubdata_byte; + let tx_body_refund = self.tx_body_refund( + bootloader_refund, + gas_spent_on_pubdata, + tx_gas_limit, + current_ergs_per_pubdata_byte, + pubdata_published, + ); + + if tx_body_refund < bootloader_refund { + tracing::error!( + "Suggested tx body refund is less than bootloader refund. Tx body refund: {tx_body_refund}, \ + bootloader refund: {bootloader_refund}" + ); + } + + let refund_to_propose = tx_body_refund + self.block_overhead_refund(); + + let refund_slot = OPERATOR_REFUNDS_OFFSET + current_tx_index; + + // Writing the refund into memory + state.memory.populate_page( + BOOTLOADER_HEAP_PAGE as usize, + vec![(refund_slot, refund_to_propose.into())], + self.timestamp_before_cycle, + ); + + bootloader_state.set_refund_for_current_tx(refund_to_propose); + self.operator_refund = Some(refund_to_propose); + self.set_refund_as_done(); + + if tx_gas_limit < bootloader_refund { + tracing::error!( + "Tx gas limit is less than bootloader refund. Tx gas limit: {tx_gas_limit}, \ + bootloader refund: {bootloader_refund}" + ); + } + if tx_gas_limit < refund_to_propose { + tracing::error!( + "Tx gas limit is less than operator refund. Tx gas limit: {tx_gas_limit}, \ + operator refund: {refund_to_propose}" + ); + } + + METRICS.refund[&RefundType::Bootloader] + .observe(bootloader_refund as f64 / tx_gas_limit as f64 * 100.0); + METRICS.refund[&RefundType::Operator] + .observe(refund_to_propose as f64 / tx_gas_limit as f64 * 100.0); + let refund_diff = + (refund_to_propose as f64 - bootloader_refund as f64) / tx_gas_limit as f64 * 100.0; + METRICS.refund_diff.observe(refund_diff); + } + TracerExecutionStatus::Continue + } +} + +/// Returns the given transactions' gas limit - by reading it directly from the VM memory. +pub(crate) fn pubdata_published( + state: &ZkSyncVmState, + storage_writes_pubdata_published: u32, + from_timestamp: Timestamp, + batch_number: L1BatchNumber, +) -> u32 { + let (raw_events, l1_messages) = state + .event_sink + .get_events_and_l2_l1_logs_after_timestamp(from_timestamp); + let events: Vec<_> = merge_events(raw_events) + .into_iter() + .map(|e| e.into_vm_event(batch_number)) + .collect(); + // For the first transaction in L1 batch there may be (it depends on the execution mode) an L2->L1 log + // that is sent by `SystemContext` in `setNewBlock`. It's a part of the L1 batch pubdata overhead and not the transaction itself. + let l2_l1_logs_bytes = (l1_messages + .into_iter() + .map(|log| L2ToL1Log { + shard_id: log.shard_id, + is_service: log.is_first, + tx_number_in_block: log.tx_number_in_block, + sender: log.address, + key: u256_to_h256(log.key), + value: u256_to_h256(log.value), + }) + .filter(|log| log.sender != SYSTEM_CONTEXT_ADDRESS) + .count() as u32) + * zk_evm_1_4_0::zkevm_opcode_defs::system_params::L1_MESSAGE_PUBDATA_BYTES; + let l2_l1_long_messages_bytes: u32 = extract_long_l2_to_l1_messages(&events) + .iter() + .map(|event| event.len() as u32) + .sum(); + + let published_bytecode_bytes: u32 = extract_published_bytecodes(&events) + .iter() + .map(|bytecodehash| bytecode_len_in_bytes(*bytecodehash) as u32 + PUBLISH_BYTECODE_OVERHEAD) + .sum(); + + storage_writes_pubdata_published + + l2_l1_logs_bytes + + l2_l1_long_messages_bytes + + published_bytecode_bytes +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tracers/result_tracer.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tracers/result_tracer.rs new file mode 100644 index 000000000000..2293273228b1 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tracers/result_tracer.rs @@ -0,0 +1,246 @@ +use std::marker::PhantomData; + +use zk_evm_1_4_0::{ + tracing::{AfterDecodingData, BeforeExecutionData, VmLocalStateData}, + vm_state::{ErrorFlags, VmLocalState}, + zkevm_opcode_defs::FatPointer, +}; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_types::U256; + +use crate::{ + interface::{ + tracer::VmExecutionStopReason, traits::tracers::dyn_tracers::vm_1_4_0::DynTracer, + types::tracer::TracerExecutionStopReason, ExecutionResult, Halt, TxRevertReason, + VmExecutionMode, VmRevertReason, + }, + vm_boojum_integration::{ + constants::{BOOTLOADER_HEAP_PAGE, RESULT_SUCCESS_FIRST_SLOT}, + old_vm::utils::{vm_may_have_ended_inner, VmExecutionResult}, + tracers::{ + traits::VmTracer, + utils::{get_vm_hook_params, read_pointer, VmHook}, + }, + types::internals::ZkSyncVmState, + BootloaderState, HistoryMode, SimpleMemory, + }, +}; + +#[derive(Debug, Clone)] +enum Result { + Error { error_reason: VmRevertReason }, + Success { return_data: Vec }, + Halt { reason: Halt }, +} + +/// Tracer responsible for handling the VM execution result. +#[derive(Debug, Clone)] +pub(crate) struct ResultTracer { + result: Option, + bootloader_out_of_gas: bool, + execution_mode: VmExecutionMode, + _phantom: PhantomData, +} + +impl ResultTracer { + pub(crate) fn new(execution_mode: VmExecutionMode) -> Self { + Self { + result: None, + bootloader_out_of_gas: false, + execution_mode, + _phantom: PhantomData, + } + } +} + +fn current_frame_is_bootloader(local_state: &VmLocalState) -> bool { + // The current frame is bootloader if the call stack depth is 1. + // Some of the near calls inside the bootloader can be out of gas, which is totally normal behavior + // and it shouldn't result in `is_bootloader_out_of_gas` becoming true. + local_state.callstack.inner.len() == 1 +} + +impl DynTracer> for ResultTracer { + fn after_decoding( + &mut self, + state: VmLocalStateData<'_>, + data: AfterDecodingData, + _memory: &SimpleMemory, + ) { + // We should check not only for the `NOT_ENOUGH_ERGS` flag but if the current frame is bootloader too. + if current_frame_is_bootloader(state.vm_local_state) + && data + .error_flags_accumulated + .contains(ErrorFlags::NOT_ENOUGH_ERGS) + { + self.bootloader_out_of_gas = true; + } + } + + fn before_execution( + &mut self, + state: VmLocalStateData<'_>, + data: BeforeExecutionData, + memory: &SimpleMemory, + _storage: StoragePtr, + ) { + let hook = VmHook::from_opcode_memory(&state, &data); + if let VmHook::ExecutionResult = hook { + let vm_hook_params = get_vm_hook_params(memory); + let success = vm_hook_params[0]; + let returndata_ptr = FatPointer::from_u256(vm_hook_params[1]); + let returndata = read_pointer(memory, returndata_ptr); + if success == U256::zero() { + self.result = Some(Result::Error { + // Tx has reverted, without bootloader error, we can simply parse the revert reason + error_reason: (VmRevertReason::from(returndata.as_slice())), + }); + } else { + self.result = Some(Result::Success { + return_data: returndata, + }); + } + } + } +} + +impl VmTracer for ResultTracer { + fn after_vm_execution( + &mut self, + state: &mut ZkSyncVmState, + bootloader_state: &BootloaderState, + stop_reason: VmExecutionStopReason, + ) { + match stop_reason { + // Vm has finished execution, we need to check the result of it + VmExecutionStopReason::VmFinished => { + self.vm_finished_execution(state); + } + // One of the tracers above has requested to stop the execution. + // If it was the correct stop we already have the result, + // otherwise it can be out of gas error + VmExecutionStopReason::TracerRequestedStop(reason) => { + match self.execution_mode { + VmExecutionMode::OneTx => { + self.vm_stopped_execution(state, bootloader_state, reason) + } + VmExecutionMode::Batch => self.vm_finished_execution(state), + VmExecutionMode::Bootloader => self.vm_finished_execution(state), + }; + } + } + } +} + +impl ResultTracer { + fn vm_finished_execution(&mut self, state: &ZkSyncVmState) { + let Some(result) = vm_may_have_ended_inner(state) else { + // The VM has finished execution, but the result is not yet available. + self.result = Some(Result::Success { + return_data: vec![], + }); + return; + }; + + // Check it's not inside tx + match result { + VmExecutionResult::Ok(output) => { + self.result = Some(Result::Success { + return_data: output, + }); + } + VmExecutionResult::Revert(output) => { + // Unlike `VmHook::ExecutionResult`, vm has completely finished and returned not only the revert reason, + // but with bytecode, which represents the type of error from the bootloader side + let revert_reason = TxRevertReason::parse_error(&output); + + match revert_reason { + TxRevertReason::TxReverted(reason) => { + self.result = Some(Result::Error { + error_reason: reason, + }); + } + TxRevertReason::Halt(halt) => { + self.result = Some(Result::Halt { reason: halt }); + } + }; + } + VmExecutionResult::Panic => { + if self.bootloader_out_of_gas { + self.result = Some(Result::Halt { + reason: Halt::BootloaderOutOfGas, + }); + } else { + self.result = Some(Result::Halt { + reason: Halt::VMPanic, + }); + } + } + VmExecutionResult::MostLikelyDidNotFinish(_, _) => { + unreachable!() + } + } + } + + fn vm_stopped_execution( + &mut self, + state: &ZkSyncVmState, + bootloader_state: &BootloaderState, + reason: TracerExecutionStopReason, + ) { + if let TracerExecutionStopReason::Abort(halt) = reason { + self.result = Some(Result::Halt { reason: halt }); + return; + } + + if self.bootloader_out_of_gas { + self.result = Some(Result::Halt { + reason: Halt::BootloaderOutOfGas, + }); + } else { + if self.result.is_some() { + return; + } + + let has_failed = tx_has_failed(state, bootloader_state.current_tx() as u32); + if has_failed { + self.result = Some(Result::Error { + error_reason: VmRevertReason::General { + msg: "Transaction reverted with empty reason. Possibly out of gas" + .to_string(), + data: vec![], + }, + }); + } else { + self.result = Some(self.result.clone().unwrap_or(Result::Success { + return_data: vec![], + })); + } + } + } + + pub(crate) fn into_result(self) -> ExecutionResult { + match self.result.unwrap() { + Result::Error { error_reason } => ExecutionResult::Revert { + output: error_reason, + }, + Result::Success { return_data } => ExecutionResult::Success { + output: return_data, + }, + Result::Halt { reason } => ExecutionResult::Halt { reason }, + } + } +} + +pub(crate) fn tx_has_failed( + state: &ZkSyncVmState, + tx_id: u32, +) -> bool { + let mem_slot = RESULT_SUCCESS_FIRST_SLOT + tx_id; + let mem_value = state + .memory + .read_slot(BOOTLOADER_HEAP_PAGE as usize, mem_slot as usize) + .value; + + mem_value == U256::zero() +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tracers/traits.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tracers/traits.rs new file mode 100644 index 000000000000..767f45c6050a --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tracers/traits.rs @@ -0,0 +1,47 @@ +use zksync_state::WriteStorage; + +use crate::{ + interface::{ + dyn_tracers::vm_1_4_0::DynTracer, + tracer::{TracerExecutionStatus, VmExecutionStopReason}, + }, + vm_boojum_integration::{ + bootloader_state::BootloaderState, + old_vm::{history_recorder::HistoryMode, memory::SimpleMemory}, + types::internals::ZkSyncVmState, + }, +}; + +pub type TracerPointer = Box>; + +/// Run tracer for collecting data during the vm execution cycles +pub trait VmTracer: DynTracer> { + /// Initialize the tracer before the vm execution + fn initialize_tracer(&mut self, _state: &mut ZkSyncVmState) {} + /// Run after each vm execution cycle + fn finish_cycle( + &mut self, + _state: &mut ZkSyncVmState, + _bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + TracerExecutionStatus::Continue + } + /// Run after the vm execution + fn after_vm_execution( + &mut self, + _state: &mut ZkSyncVmState, + _bootloader_state: &BootloaderState, + _stop_reason: VmExecutionStopReason, + ) { + } +} + +pub trait ToTracerPointer { + fn into_tracer_pointer(self) -> TracerPointer; +} + +impl + 'static> ToTracerPointer for T { + fn into_tracer_pointer(self) -> TracerPointer { + Box::new(self) + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/tracers/utils.rs b/core/lib/multivm/src/versions/vm_boojum_integration/tracers/utils.rs new file mode 100644 index 000000000000..58264d89c8ea --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/tracers/utils.rs @@ -0,0 +1,225 @@ +use zk_evm_1_4_0::{ + aux_structures::MemoryPage, + tracing::{BeforeExecutionData, VmLocalStateData}, + zkevm_opcode_defs::{ + FarCallABI, FarCallForwardPageType, FatPointer, LogOpcode, Opcode, UMAOpcode, + }, +}; +use zksync_system_constants::{ + ECRECOVER_PRECOMPILE_ADDRESS, KECCAK256_PRECOMPILE_ADDRESS, KNOWN_CODES_STORAGE_ADDRESS, + L1_MESSENGER_ADDRESS, SHA256_PRECOMPILE_ADDRESS, +}; +use zksync_types::U256; +use zksync_utils::u256_to_h256; + +use crate::vm_boojum_integration::{ + constants::{ + BOOTLOADER_HEAP_PAGE, VM_HOOK_PARAMS_COUNT, VM_HOOK_PARAMS_START_POSITION, VM_HOOK_POSITION, + }, + old_vm::{ + history_recorder::HistoryMode, + memory::SimpleMemory, + utils::{aux_heap_page_from_base, heap_page_from_base}, + }, +}; + +#[derive(Clone, Debug, Copy)] +pub(crate) enum VmHook { + AccountValidationEntered, + PaymasterValidationEntered, + NoValidationEntered, + ValidationStepEndeded, + TxHasEnded, + DebugLog, + DebugReturnData, + NoHook, + NearCallCatch, + AskOperatorForRefund, + NotifyAboutRefund, + ExecutionResult, + FinalBatchInfo, + // Hook used to signal that the final pubdata for a batch is requested. + PubdataRequested, +} + +impl VmHook { + pub(crate) fn from_opcode_memory( + state: &VmLocalStateData<'_>, + data: &BeforeExecutionData, + ) -> Self { + let opcode_variant = data.opcode.variant; + let heap_page = + heap_page_from_base(state.vm_local_state.callstack.current.base_memory_page).0; + + let src0_value = data.src0_value.value; + + let fat_ptr = FatPointer::from_u256(src0_value); + + let value = data.src1_value.value; + + // Only `UMA` opcodes in the bootloader serve for vm hooks + if !matches!(opcode_variant.opcode, Opcode::UMA(UMAOpcode::HeapWrite)) + || heap_page != BOOTLOADER_HEAP_PAGE + || fat_ptr.offset != VM_HOOK_POSITION * 32 + { + return Self::NoHook; + } + + match value.as_u32() { + 0 => Self::AccountValidationEntered, + 1 => Self::PaymasterValidationEntered, + 2 => Self::NoValidationEntered, + 3 => Self::ValidationStepEndeded, + 4 => Self::TxHasEnded, + 5 => Self::DebugLog, + 6 => Self::DebugReturnData, + 7 => Self::NearCallCatch, + 8 => Self::AskOperatorForRefund, + 9 => Self::NotifyAboutRefund, + 10 => Self::ExecutionResult, + 11 => Self::FinalBatchInfo, + 12 => Self::PubdataRequested, + _ => panic!("Unknown hook: {}", value.as_u32()), + } + } +} + +pub(crate) fn get_debug_log( + state: &VmLocalStateData<'_>, + memory: &SimpleMemory, +) -> String { + let vm_hook_params: Vec<_> = get_vm_hook_params(memory) + .into_iter() + .map(u256_to_h256) + .collect(); + let msg = vm_hook_params[0].as_bytes().to_vec(); + let data = vm_hook_params[1].as_bytes().to_vec(); + + let msg = String::from_utf8(msg).expect("Invalid debug message"); + let data = U256::from_big_endian(&data); + + // For long data, it is better to use hex-encoding for greater readability + let data_str = if data > U256::from(u64::max_value()) { + let mut bytes = [0u8; 32]; + data.to_big_endian(&mut bytes); + format!("0x{}", hex::encode(bytes)) + } else { + data.to_string() + }; + + let tx_id = state.vm_local_state.tx_number_in_block; + + format!("Bootloader transaction {}: {} {}", tx_id, msg, data_str) +} + +/// Reads the memory slice represented by the fat pointer. +/// Note, that the fat pointer must point to the accessible memory (i.e. not cleared up yet). +pub(crate) fn read_pointer( + memory: &SimpleMemory, + pointer: FatPointer, +) -> Vec { + let FatPointer { + offset, + length, + start, + memory_page, + } = pointer; + + // The actual bounds of the returndata ptr is [start+offset..start+length] + let mem_region_start = start + offset; + let mem_region_length = length - offset; + + memory.read_unaligned_bytes( + memory_page as usize, + mem_region_start as usize, + mem_region_length as usize, + ) +} + +/// Outputs the returndata for the latest call. +/// This is usually used to output the revert reason. +pub(crate) fn get_debug_returndata(memory: &SimpleMemory) -> String { + let vm_hook_params: Vec<_> = get_vm_hook_params(memory); + let returndata_ptr = FatPointer::from_u256(vm_hook_params[0]); + let returndata = read_pointer(memory, returndata_ptr); + + format!("0x{}", hex::encode(returndata)) +} + +/// Accepts a vm hook and, if it requires to output some debug log, outputs it. +pub(crate) fn print_debug_if_needed( + hook: &VmHook, + state: &VmLocalStateData<'_>, + memory: &SimpleMemory, +) { + let log = match hook { + VmHook::DebugLog => get_debug_log(state, memory), + VmHook::DebugReturnData => get_debug_returndata(memory), + _ => return, + }; + + tracing::trace!("{}", log); +} + +pub(crate) fn computational_gas_price( + state: VmLocalStateData<'_>, + data: &BeforeExecutionData, +) -> u32 { + // We calculate computational gas used as a raw price for opcode plus cost for precompiles. + // This calculation is incomplete as it misses decommitment and memory growth costs. + // To calculate decommitment cost we need an access to decommitter oracle which is missing in tracer now. + // Memory growth calculation is complex and it will require different logic for different opcodes (`FarCall`, `Ret`, `UMA`). + let base_price = data.opcode.inner.variant.ergs_price(); + let precompile_price = match data.opcode.variant.opcode { + Opcode::Log(LogOpcode::PrecompileCall) => { + let address = state.vm_local_state.callstack.current.this_address; + + if address == KECCAK256_PRECOMPILE_ADDRESS + || address == SHA256_PRECOMPILE_ADDRESS + || address == ECRECOVER_PRECOMPILE_ADDRESS + { + data.src1_value.value.low_u32() + } else { + 0 + } + } + _ => 0, + }; + base_price + precompile_price +} + +pub(crate) fn gas_spent_on_bytecodes_and_long_messages_this_opcode( + state: &VmLocalStateData<'_>, + data: &BeforeExecutionData, +) -> u32 { + if data.opcode.variant.opcode == Opcode::Log(LogOpcode::PrecompileCall) { + let current_stack = state.vm_local_state.callstack.get_current_stack(); + // Trace for precompile calls from `KNOWN_CODES_STORAGE_ADDRESS` and `L1_MESSENGER_ADDRESS` that burn some gas. + // Note, that if there is less gas left than requested to burn it will be burnt anyway. + if current_stack.this_address == KNOWN_CODES_STORAGE_ADDRESS + || current_stack.this_address == L1_MESSENGER_ADDRESS + { + std::cmp::min(data.src1_value.value.as_u32(), current_stack.ergs_remaining) + } else { + 0 + } + } else { + 0 + } +} + +pub(crate) fn get_calldata_page_via_abi(far_call_abi: &FarCallABI, base_page: MemoryPage) -> u32 { + match far_call_abi.forwarding_mode { + FarCallForwardPageType::ForwardFatPointer => { + far_call_abi.memory_quasi_fat_pointer.memory_page + } + FarCallForwardPageType::UseAuxHeap => aux_heap_page_from_base(base_page).0, + FarCallForwardPageType::UseHeap => heap_page_from_base(base_page).0, + } +} +pub(crate) fn get_vm_hook_params(memory: &SimpleMemory) -> Vec { + memory.dump_page_content_as_u256_words( + BOOTLOADER_HEAP_PAGE, + VM_HOOK_PARAMS_START_POSITION..VM_HOOK_PARAMS_START_POSITION + VM_HOOK_PARAMS_COUNT, + ) +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/types/internals/mod.rs b/core/lib/multivm/src/versions/vm_boojum_integration/types/internals/mod.rs new file mode 100644 index 000000000000..7dc60ec5b0fb --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/types/internals/mod.rs @@ -0,0 +1,9 @@ +pub(crate) use pubdata::PubdataInput; +pub(crate) use snapshot::VmSnapshot; +pub(crate) use transaction_data::TransactionData; +pub(crate) use vm_state::new_vm_state; +pub use vm_state::ZkSyncVmState; +mod pubdata; +mod snapshot; +mod transaction_data; +mod vm_state; diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/types/internals/pubdata.rs b/core/lib/multivm/src/versions/vm_boojum_integration/types/internals/pubdata.rs new file mode 100644 index 000000000000..5451201c5bcf --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/types/internals/pubdata.rs @@ -0,0 +1,124 @@ +use zksync_types::{ + event::L1MessengerL2ToL1Log, + writes::{compress_state_diffs, StateDiffRecord}, +}; + +/// Struct based on which the pubdata blob is formed +#[derive(Debug, Clone, Default)] +pub(crate) struct PubdataInput { + pub(crate) user_logs: Vec, + pub(crate) l2_to_l1_messages: Vec>, + pub(crate) published_bytecodes: Vec>, + pub(crate) state_diffs: Vec, +} + +impl PubdataInput { + pub(crate) fn build_pubdata(self, with_uncompressed_state_diffs: bool) -> Vec { + let mut l1_messenger_pubdata = vec![]; + + let PubdataInput { + user_logs, + l2_to_l1_messages, + published_bytecodes, + state_diffs, + } = self; + + // Encoding user L2->L1 logs. + // Format: `[(numberOfL2ToL1Logs as u32) || l2tol1logs[1] || ... || l2tol1logs[n]]` + l1_messenger_pubdata.extend((user_logs.len() as u32).to_be_bytes()); + for l2tol1log in user_logs { + l1_messenger_pubdata.extend(l2tol1log.packed_encoding()); + } + + // Encoding L2->L1 messages + // Format: `[(numberOfMessages as u32) || (messages[1].len() as u32) || messages[1] || ... || (messages[n].len() as u32) || messages[n]]` + l1_messenger_pubdata.extend((l2_to_l1_messages.len() as u32).to_be_bytes()); + for message in l2_to_l1_messages { + l1_messenger_pubdata.extend((message.len() as u32).to_be_bytes()); + l1_messenger_pubdata.extend(message); + } + + // Encoding bytecodes + // Format: `[(numberOfBytecodes as u32) || (bytecodes[1].len() as u32) || bytecodes[1] || ... || (bytecodes[n].len() as u32) || bytecodes[n]]` + l1_messenger_pubdata.extend((published_bytecodes.len() as u32).to_be_bytes()); + for bytecode in published_bytecodes { + l1_messenger_pubdata.extend((bytecode.len() as u32).to_be_bytes()); + l1_messenger_pubdata.extend(bytecode); + } + + // Encoding state diffs + // Format: `[size of compressed state diffs u32 || compressed state diffs || (# state diffs: initial + repeated) as u32 || sorted state diffs by ]` + let state_diffs_compressed = compress_state_diffs(state_diffs.clone()); + l1_messenger_pubdata.extend(state_diffs_compressed); + + if with_uncompressed_state_diffs { + l1_messenger_pubdata.extend((state_diffs.len() as u32).to_be_bytes()); + for state_diff in state_diffs { + l1_messenger_pubdata.extend(state_diff.encode_padded()); + } + } + + l1_messenger_pubdata + } +} + +#[cfg(test)] +mod tests { + use zksync_system_constants::{ACCOUNT_CODE_STORAGE_ADDRESS, BOOTLOADER_ADDRESS}; + use zksync_utils::u256_to_h256; + + use super::*; + + #[test] + fn test_basic_pubdata_building() { + // Just using some constant addresses for tests + let addr1 = BOOTLOADER_ADDRESS; + let addr2 = ACCOUNT_CODE_STORAGE_ADDRESS; + + let user_logs = vec![L1MessengerL2ToL1Log { + l2_shard_id: 0, + is_service: false, + tx_number_in_block: 0, + sender: addr1, + key: 1.into(), + value: 128.into(), + }]; + + let l2_to_l1_messages = vec![hex::decode("deadbeef").unwrap()]; + + let published_bytecodes = vec![hex::decode("aaaabbbb").unwrap()]; + + // For covering more cases, we have two state diffs: + // One with enumeration index present (and so it is a repeated write) and the one without it. + let state_diffs = vec![ + StateDiffRecord { + address: addr2, + key: 155.into(), + derived_key: u256_to_h256(125.into()).0, + enumeration_index: 12, + initial_value: 11.into(), + final_value: 12.into(), + }, + StateDiffRecord { + address: addr2, + key: 156.into(), + derived_key: u256_to_h256(126.into()).0, + enumeration_index: 0, + initial_value: 0.into(), + final_value: 14.into(), + }, + ]; + + let input = PubdataInput { + user_logs, + l2_to_l1_messages, + published_bytecodes, + state_diffs, + }; + + let pubdata = + ethabi::encode(&[ethabi::Token::Bytes(input.build_pubdata(true))])[32..].to_vec(); + + assert_eq!(hex::encode(pubdata), "00000000000000000000000000000000000000000000000000000000000002c700000001000000000000000000000000000000000000000000008001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000100000004deadbeef0000000100000004aaaabbbb0100002a040001000000000000000000000000000000000000000000000000000000000000007e090e0000000c0901000000020000000000000000000000000000000000008002000000000000000000000000000000000000000000000000000000000000009b000000000000000000000000000000000000000000000000000000000000007d000000000000000c000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008002000000000000000000000000000000000000000000000000000000000000009c000000000000000000000000000000000000000000000000000000000000007e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/types/internals/snapshot.rs b/core/lib/multivm/src/versions/vm_boojum_integration/types/internals/snapshot.rs new file mode 100644 index 000000000000..f1aa1a333595 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/types/internals/snapshot.rs @@ -0,0 +1,11 @@ +use zk_evm_1_4_0::vm_state::VmLocalState; + +use crate::vm_boojum_integration::bootloader_state::BootloaderStateSnapshot; + +/// A snapshot of the VM that holds enough information to +/// rollback the VM to some historical state. +#[derive(Debug, Clone)] +pub(crate) struct VmSnapshot { + pub(crate) local_state: VmLocalState, + pub(crate) bootloader_state: BootloaderStateSnapshot, +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/types/internals/transaction_data.rs b/core/lib/multivm/src/versions/vm_boojum_integration/types/internals/transaction_data.rs new file mode 100644 index 000000000000..81d967029f64 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/types/internals/transaction_data.rs @@ -0,0 +1,358 @@ +use std::convert::TryInto; + +use zksync_types::{ + ethabi::{encode, Address, Token}, + fee::{encoding_len, Fee}, + l1::is_l1_tx_type, + l2::{L2Tx, TransactionType}, + transaction_request::{PaymasterParams, TransactionRequest}, + Bytes, Execute, ExecuteTransactionCommon, L2ChainId, L2TxCommonData, Nonce, Transaction, H256, + U256, +}; +use zksync_utils::{address_to_h256, bytecode::hash_bytecode, bytes_to_be_words, h256_to_u256}; + +use crate::vm_boojum_integration::{ + constants::MAX_GAS_PER_PUBDATA_BYTE, + utils::overhead::{get_amortized_overhead, OverheadCoefficients}, +}; + +/// This structure represents the data that is used by +/// the Bootloader to describe the transaction. +#[derive(Debug, Default, Clone)] +pub(crate) struct TransactionData { + pub(crate) tx_type: u8, + pub(crate) from: Address, + pub(crate) to: Address, + pub(crate) gas_limit: U256, + pub(crate) pubdata_price_limit: U256, + pub(crate) max_fee_per_gas: U256, + pub(crate) max_priority_fee_per_gas: U256, + pub(crate) paymaster: Address, + pub(crate) nonce: U256, + pub(crate) value: U256, + // The reserved fields that are unique for different types of transactions. + // E.g. nonce is currently used in all transaction, but it should not be mandatory + // in the long run. + pub(crate) reserved: [U256; 4], + pub(crate) data: Vec, + pub(crate) signature: Vec, + // The factory deps provided with the transaction. + // Note that *only hashes* of these bytecodes are signed by the user + // and they are used in the ABI encoding of the struct. + // TODO: include this into the tx signature as part of SMA-1010 + pub(crate) factory_deps: Vec>, + pub(crate) paymaster_input: Vec, + pub(crate) reserved_dynamic: Vec, + pub(crate) raw_bytes: Option>, +} + +impl From for TransactionData { + fn from(execute_tx: Transaction) -> Self { + match execute_tx.common_data { + ExecuteTransactionCommon::L2(common_data) => { + let nonce = U256::from_big_endian(&common_data.nonce.to_be_bytes()); + + let should_check_chain_id = if matches!( + common_data.transaction_type, + TransactionType::LegacyTransaction + ) && common_data.extract_chain_id().is_some() + { + U256([1, 0, 0, 0]) + } else { + U256::zero() + }; + + // Ethereum transactions do not sign gas per pubdata limit, and so for them we need to use + // some default value. We use the maximum possible value that is allowed by the bootloader + // (i.e. we can not use u64::MAX, because the bootloader requires gas per pubdata for such + // transactions to be higher than `MAX_GAS_PER_PUBDATA_BYTE`). + let gas_per_pubdata_limit = if common_data.transaction_type.is_ethereum_type() { + MAX_GAS_PER_PUBDATA_BYTE.into() + } else { + common_data.fee.gas_per_pubdata_limit + }; + + TransactionData { + tx_type: (common_data.transaction_type as u32) as u8, + from: common_data.initiator_address, + to: execute_tx.execute.contract_address, + gas_limit: common_data.fee.gas_limit, + pubdata_price_limit: gas_per_pubdata_limit, + max_fee_per_gas: common_data.fee.max_fee_per_gas, + max_priority_fee_per_gas: common_data.fee.max_priority_fee_per_gas, + paymaster: common_data.paymaster_params.paymaster, + nonce, + value: execute_tx.execute.value, + reserved: [ + should_check_chain_id, + U256::zero(), + U256::zero(), + U256::zero(), + ], + data: execute_tx.execute.calldata, + signature: common_data.signature, + factory_deps: execute_tx.execute.factory_deps.unwrap_or_default(), + paymaster_input: common_data.paymaster_params.paymaster_input, + reserved_dynamic: vec![], + raw_bytes: execute_tx.raw_bytes.map(|a| a.0), + } + } + ExecuteTransactionCommon::L1(common_data) => { + let refund_recipient = h256_to_u256(address_to_h256(&common_data.refund_recipient)); + TransactionData { + tx_type: common_data.tx_format() as u8, + from: common_data.sender, + to: execute_tx.execute.contract_address, + gas_limit: common_data.gas_limit, + pubdata_price_limit: common_data.gas_per_pubdata_limit, + // It doesn't matter what we put here, since + // the bootloader does not charge anything + max_fee_per_gas: common_data.max_fee_per_gas, + max_priority_fee_per_gas: U256::zero(), + paymaster: Address::default(), + nonce: U256::from(common_data.serial_id.0), // priority op ID + value: execute_tx.execute.value, + reserved: [ + common_data.to_mint, + refund_recipient, + U256::zero(), + U256::zero(), + ], + data: execute_tx.execute.calldata, + // The signature isn't checked for L1 transactions so we don't care + signature: vec![], + factory_deps: execute_tx.execute.factory_deps.unwrap_or_default(), + paymaster_input: vec![], + reserved_dynamic: vec![], + raw_bytes: None, + } + } + ExecuteTransactionCommon::ProtocolUpgrade(common_data) => { + let refund_recipient = h256_to_u256(address_to_h256(&common_data.refund_recipient)); + TransactionData { + tx_type: common_data.tx_format() as u8, + from: common_data.sender, + to: execute_tx.execute.contract_address, + gas_limit: common_data.gas_limit, + pubdata_price_limit: common_data.gas_per_pubdata_limit, + // It doesn't matter what we put here, since + // the bootloader does not charge anything + max_fee_per_gas: common_data.max_fee_per_gas, + max_priority_fee_per_gas: U256::zero(), + paymaster: Address::default(), + nonce: U256::from(common_data.upgrade_id as u16), + value: execute_tx.execute.value, + reserved: [ + common_data.to_mint, + refund_recipient, + U256::zero(), + U256::zero(), + ], + data: execute_tx.execute.calldata, + // The signature isn't checked for L1 transactions so we don't care + signature: vec![], + factory_deps: execute_tx.execute.factory_deps.unwrap_or_default(), + paymaster_input: vec![], + reserved_dynamic: vec![], + raw_bytes: None, + } + } + } + } +} + +impl TransactionData { + pub(crate) fn abi_encode_with_custom_factory_deps( + self, + factory_deps_hashes: Vec, + ) -> Vec { + encode(&[Token::Tuple(vec![ + Token::Uint(U256::from_big_endian(&self.tx_type.to_be_bytes())), + Token::Address(self.from), + Token::Address(self.to), + Token::Uint(self.gas_limit), + Token::Uint(self.pubdata_price_limit), + Token::Uint(self.max_fee_per_gas), + Token::Uint(self.max_priority_fee_per_gas), + Token::Address(self.paymaster), + Token::Uint(self.nonce), + Token::Uint(self.value), + Token::FixedArray(self.reserved.iter().copied().map(Token::Uint).collect()), + Token::Bytes(self.data), + Token::Bytes(self.signature), + Token::Array(factory_deps_hashes.into_iter().map(Token::Uint).collect()), + Token::Bytes(self.paymaster_input), + Token::Bytes(self.reserved_dynamic), + ])]) + } + + pub(crate) fn abi_encode(self) -> Vec { + let factory_deps_hashes = self + .factory_deps + .iter() + .map(|dep| h256_to_u256(hash_bytecode(dep))) + .collect(); + self.abi_encode_with_custom_factory_deps(factory_deps_hashes) + } + + pub(crate) fn into_tokens(self) -> Vec { + let bytes = self.abi_encode(); + assert!(bytes.len() % 32 == 0); + + bytes_to_be_words(bytes) + } + + pub(crate) fn effective_gas_price_per_pubdata(&self, block_gas_price_per_pubdata: u32) -> u32 { + // It is enforced by the protocol that the L1 transactions always pay the exact amount of gas per pubdata + // as was supplied in the transaction. + if is_l1_tx_type(self.tx_type) { + self.pubdata_price_limit.as_u32() + } else { + block_gas_price_per_pubdata + } + } + + pub(crate) fn overhead_gas(&self, block_gas_price_per_pubdata: u32) -> u32 { + let total_gas_limit = self.gas_limit.as_u32(); + let gas_price_per_pubdata = + self.effective_gas_price_per_pubdata(block_gas_price_per_pubdata); + + let encoded_len = encoding_len( + self.data.len() as u64, + self.signature.len() as u64, + self.factory_deps.len() as u64, + self.paymaster_input.len() as u64, + self.reserved_dynamic.len() as u64, + ); + + let coefficients = OverheadCoefficients::from_tx_type(self.tx_type); + get_amortized_overhead( + total_gas_limit, + gas_price_per_pubdata, + encoded_len, + coefficients, + ) + } + + pub(crate) fn trusted_ergs_limit(&self, _block_gas_price_per_pubdata: u64) -> U256 { + // TODO (EVM-66): correctly calculate the trusted gas limit for a transaction + self.gas_limit + } + + pub(crate) fn tx_hash(&self, chain_id: L2ChainId) -> H256 { + if is_l1_tx_type(self.tx_type) { + return self.canonical_l1_tx_hash().unwrap(); + } + + let l2_tx: L2Tx = self.clone().try_into().unwrap(); + let transaction_request: TransactionRequest = l2_tx.into(); + + // It is assumed that the `TransactionData` always has all the necessary components to recover the hash. + transaction_request + .get_tx_hash(chain_id) + .expect("Could not recover L2 transaction hash") + } + + fn canonical_l1_tx_hash(&self) -> Result { + use zksync_types::web3::signing::keccak256; + + if !is_l1_tx_type(self.tx_type) { + return Err(TxHashCalculationError::CannotCalculateL1HashForL2Tx); + } + + let encoded_bytes = self.clone().abi_encode(); + + Ok(H256(keccak256(&encoded_bytes))) + } +} + +#[derive(Debug, Clone, Copy)] +pub(crate) enum TxHashCalculationError { + CannotCalculateL1HashForL2Tx, + CannotCalculateL2HashForL1Tx, +} + +impl TryInto for TransactionData { + type Error = TxHashCalculationError; + + fn try_into(self) -> Result { + if is_l1_tx_type(self.tx_type) { + return Err(TxHashCalculationError::CannotCalculateL2HashForL1Tx); + } + + let common_data = L2TxCommonData { + transaction_type: (self.tx_type as u32).try_into().unwrap(), + nonce: Nonce(self.nonce.as_u32()), + fee: Fee { + max_fee_per_gas: self.max_fee_per_gas, + max_priority_fee_per_gas: self.max_priority_fee_per_gas, + gas_limit: self.gas_limit, + gas_per_pubdata_limit: self.pubdata_price_limit, + }, + signature: self.signature, + input: None, + initiator_address: self.from, + paymaster_params: PaymasterParams { + paymaster: self.paymaster, + paymaster_input: self.paymaster_input, + }, + }; + let factory_deps = (!self.factory_deps.is_empty()).then_some(self.factory_deps); + let execute = Execute { + contract_address: self.to, + value: self.value, + calldata: self.data, + factory_deps, + }; + + Ok(L2Tx { + execute, + common_data, + received_timestamp_ms: 0, + raw_bytes: self.raw_bytes.map(Bytes::from), + }) + } +} + +#[cfg(test)] +mod tests { + use zksync_types::fee::encoding_len; + + use super::*; + + #[test] + fn test_consistency_with_encoding_length() { + let transaction = TransactionData { + tx_type: 113, + from: Address::random(), + to: Address::random(), + gas_limit: U256::from(1u32), + pubdata_price_limit: U256::from(1u32), + max_fee_per_gas: U256::from(1u32), + max_priority_fee_per_gas: U256::from(1u32), + paymaster: Address::random(), + nonce: U256::zero(), + value: U256::zero(), + // The reserved fields that are unique for different types of transactions. + // E.g. nonce is currently used in all transaction, but it should not be mandatory + // in the long run. + reserved: [U256::zero(); 4], + data: vec![0u8; 65], + signature: vec![0u8; 75], + // The factory deps provided with the transaction. + // Note that *only hashes* of these bytecodes are signed by the user + // and they are used in the ABI encoding of the struct. + // TODO: include this into the tx signature as part of SMA-1010 + factory_deps: vec![vec![0u8; 32], vec![1u8; 32]], + paymaster_input: vec![0u8; 85], + reserved_dynamic: vec![0u8; 32], + raw_bytes: None, + }; + + let assumed_encoded_len = encoding_len(65, 75, 2, 85, 32); + + let true_encoding_len = transaction.into_tokens().len(); + + assert_eq!(assumed_encoded_len, true_encoding_len); + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/types/internals/vm_state.rs b/core/lib/multivm/src/versions/vm_boojum_integration/types/internals/vm_state.rs new file mode 100644 index 000000000000..e3c233931f30 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/types/internals/vm_state.rs @@ -0,0 +1,181 @@ +use zk_evm_1_4_0::{ + aux_structures::{MemoryPage, Timestamp}, + block_properties::BlockProperties, + vm_state::{CallStackEntry, PrimitiveValue, VmState}, + witness_trace::DummyTracer, + zkevm_opcode_defs::{ + system_params::{BOOTLOADER_MAX_MEMORY, INITIAL_FRAME_FORMAL_EH_LOCATION}, + FatPointer, BOOTLOADER_BASE_PAGE, BOOTLOADER_CALLDATA_PAGE, BOOTLOADER_CODE_PAGE, + STARTING_BASE_PAGE, STARTING_TIMESTAMP, + }, +}; +use zkevm_test_harness_1_3_3::INITIAL_MONOTONIC_CYCLE_COUNTER; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_system_constants::BOOTLOADER_ADDRESS; +use zksync_types::{block::MiniblockHasher, Address, MiniblockNumber}; +use zksync_utils::h256_to_u256; + +use crate::{ + interface::{L1BatchEnv, L2Block, SystemEnv}, + vm_boojum_integration::{ + bootloader_state::BootloaderState, + constants::BOOTLOADER_HEAP_PAGE, + old_vm::{ + event_sink::InMemoryEventSink, + history_recorder::HistoryMode, + memory::SimpleMemory, + oracles::{ + decommitter::DecommitterOracle, precompile::PrecompilesProcessorWithHistory, + }, + }, + oracles::storage::StorageOracle, + types::l1_batch::bootloader_initial_memory, + utils::l2_blocks::{assert_next_block, load_last_l2_block}, + }, +}; + +pub type ZkSyncVmState = VmState< + StorageOracle, + SimpleMemory, + InMemoryEventSink, + PrecompilesProcessorWithHistory, + DecommitterOracle, + DummyTracer, +>; + +fn formal_calldata_abi() -> PrimitiveValue { + let fat_pointer = FatPointer { + offset: 0, + memory_page: BOOTLOADER_CALLDATA_PAGE, + start: 0, + length: 0, + }; + + PrimitiveValue { + value: fat_pointer.to_u256(), + is_pointer: true, + } +} + +/// Initialize the vm state and all necessary oracles +pub(crate) fn new_vm_state( + storage: StoragePtr, + system_env: &SystemEnv, + l1_batch_env: &L1BatchEnv, +) -> (ZkSyncVmState, BootloaderState) { + let last_l2_block = if let Some(last_l2_block) = load_last_l2_block(storage.clone()) { + last_l2_block + } else { + // This is the scenario of either the first L2 block ever or + // the first block after the upgrade for support of L2 blocks. + L2Block { + number: l1_batch_env.first_l2_block.number.saturating_sub(1), + timestamp: 0, + hash: MiniblockHasher::legacy_hash( + MiniblockNumber(l1_batch_env.first_l2_block.number) - 1, + ), + } + }; + + assert_next_block(&last_l2_block, &l1_batch_env.first_l2_block); + let first_l2_block = l1_batch_env.first_l2_block; + let storage_oracle: StorageOracle = StorageOracle::new(storage.clone()); + let mut memory = SimpleMemory::default(); + let event_sink = InMemoryEventSink::default(); + let precompiles_processor = PrecompilesProcessorWithHistory::::default(); + let mut decommittment_processor: DecommitterOracle = + DecommitterOracle::new(storage); + + decommittment_processor.populate( + vec![( + h256_to_u256(system_env.base_system_smart_contracts.default_aa.hash), + system_env + .base_system_smart_contracts + .default_aa + .code + .clone(), + )], + Timestamp(0), + ); + + memory.populate( + vec![( + BOOTLOADER_CODE_PAGE, + system_env + .base_system_smart_contracts + .bootloader + .code + .clone(), + )], + Timestamp(0), + ); + + let bootloader_initial_memory = bootloader_initial_memory(l1_batch_env); + memory.populate_page( + BOOTLOADER_HEAP_PAGE as usize, + bootloader_initial_memory.clone(), + Timestamp(0), + ); + + let mut vm = VmState::empty_state( + storage_oracle, + memory, + event_sink, + precompiles_processor, + decommittment_processor, + DummyTracer, + BlockProperties { + default_aa_code_hash: h256_to_u256( + system_env.base_system_smart_contracts.default_aa.hash, + ), + zkporter_is_available: system_env.zk_porter_available, + }, + ); + + vm.local_state.callstack.current.ergs_remaining = system_env.gas_limit; + + let initial_context = CallStackEntry { + this_address: BOOTLOADER_ADDRESS, + msg_sender: Address::zero(), + code_address: BOOTLOADER_ADDRESS, + base_memory_page: MemoryPage(BOOTLOADER_BASE_PAGE), + code_page: MemoryPage(BOOTLOADER_CODE_PAGE), + sp: 0, + pc: 0, + // Note, that since the results are written at the end of the memory + // it is needed to have the entire heap available from the beginning + heap_bound: BOOTLOADER_MAX_MEMORY, + aux_heap_bound: BOOTLOADER_MAX_MEMORY, + exception_handler_location: INITIAL_FRAME_FORMAL_EH_LOCATION, + ergs_remaining: system_env.gas_limit, + this_shard_id: 0, + caller_shard_id: 0, + code_shard_id: 0, + is_static: false, + is_local_frame: false, + context_u128_value: 0, + }; + + // We consider the contract that is being run as a bootloader + vm.push_bootloader_context(INITIAL_MONOTONIC_CYCLE_COUNTER - 1, initial_context); + vm.local_state.timestamp = STARTING_TIMESTAMP; + vm.local_state.memory_page_counter = STARTING_BASE_PAGE; + vm.local_state.monotonic_cycle_counter = INITIAL_MONOTONIC_CYCLE_COUNTER; + vm.local_state.current_ergs_per_pubdata_byte = 0; + vm.local_state.registers[0] = formal_calldata_abi(); + + // Deleting all the historical records brought by the initial + // initialization of the VM to make them permanent. + vm.decommittment_processor.delete_history(); + vm.event_sink.delete_history(); + vm.storage.delete_history(); + vm.memory.delete_history(); + vm.precompiles_processor.delete_history(); + let bootloader_state = BootloaderState::new( + system_env.execution_mode, + bootloader_initial_memory, + first_l2_block, + ); + + (vm, bootloader_state) +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/types/l1_batch.rs b/core/lib/multivm/src/versions/vm_boojum_integration/types/l1_batch.rs new file mode 100644 index 000000000000..386dc040099b --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/types/l1_batch.rs @@ -0,0 +1,43 @@ +use zksync_types::U256; +use zksync_utils::{address_to_u256, h256_to_u256}; + +use crate::{interface::L1BatchEnv, vm_boojum_integration::utils::fee::get_batch_base_fee}; + +const OPERATOR_ADDRESS_SLOT: usize = 0; +const PREV_BLOCK_HASH_SLOT: usize = 1; +const NEW_BLOCK_TIMESTAMP_SLOT: usize = 2; +const NEW_BLOCK_NUMBER_SLOT: usize = 3; +const L1_GAS_PRICE_SLOT: usize = 4; +const FAIR_L2_GAS_PRICE_SLOT: usize = 5; +const EXPECTED_BASE_FEE_SLOT: usize = 6; +const SHOULD_SET_NEW_BLOCK_SLOT: usize = 7; + +/// Returns the initial memory for the bootloader based on the current batch environment. +pub(crate) fn bootloader_initial_memory(l1_batch: &L1BatchEnv) -> Vec<(usize, U256)> { + let (prev_block_hash, should_set_new_block) = l1_batch + .previous_batch_hash + .map(|prev_block_hash| (h256_to_u256(prev_block_hash), U256::one())) + .unwrap_or_default(); + + let fee_input = l1_batch.fee_input.into_l1_pegged(); + + vec![ + ( + OPERATOR_ADDRESS_SLOT, + address_to_u256(&l1_batch.fee_account), + ), + (PREV_BLOCK_HASH_SLOT, prev_block_hash), + (NEW_BLOCK_TIMESTAMP_SLOT, U256::from(l1_batch.timestamp)), + (NEW_BLOCK_NUMBER_SLOT, U256::from(l1_batch.number.0)), + (L1_GAS_PRICE_SLOT, U256::from(fee_input.l1_gas_price)), + ( + FAIR_L2_GAS_PRICE_SLOT, + U256::from(fee_input.fair_l2_gas_price), + ), + ( + EXPECTED_BASE_FEE_SLOT, + U256::from(get_batch_base_fee(l1_batch)), + ), + (SHOULD_SET_NEW_BLOCK_SLOT, should_set_new_block), + ] +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/types/mod.rs b/core/lib/multivm/src/versions/vm_boojum_integration/types/mod.rs new file mode 100644 index 000000000000..a12005734abb --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/types/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod internals; +mod l1_batch; diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/utils/fee.rs b/core/lib/multivm/src/versions/vm_boojum_integration/utils/fee.rs new file mode 100644 index 000000000000..55c7d0894598 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/utils/fee.rs @@ -0,0 +1,53 @@ +//! Utility functions for vm +use zksync_types::fee_model::L1PeggedBatchFeeModelInput; +use zksync_utils::ceil_div; + +use crate::{ + vm_boojum_integration::{ + constants::MAX_GAS_PER_PUBDATA_BYTE, old_vm::utils::eth_price_per_pubdata_byte, + }, + vm_latest::L1BatchEnv, +}; + +/// Calculates the amount of gas required to publish one byte of pubdata +pub fn base_fee_to_gas_per_pubdata(l1_gas_price: u64, base_fee: u64) -> u64 { + let eth_price_per_pubdata_byte = eth_price_per_pubdata_byte(l1_gas_price); + + ceil_div(eth_price_per_pubdata_byte, base_fee) +} + +/// Calculates the base fee and gas per pubdata for the given L1 gas price. +pub(crate) fn derive_base_fee_and_gas_per_pubdata( + fee_input: L1PeggedBatchFeeModelInput, +) -> (u64, u64) { + let L1PeggedBatchFeeModelInput { + l1_gas_price, + fair_l2_gas_price, + } = fee_input; + let eth_price_per_pubdata_byte = eth_price_per_pubdata_byte(l1_gas_price); + + // The `baseFee` is set in such a way that it is always possible for a transaction to + // publish enough public data while compensating us for it. + let base_fee = std::cmp::max( + fair_l2_gas_price, + ceil_div(eth_price_per_pubdata_byte, MAX_GAS_PER_PUBDATA_BYTE), + ); + + ( + base_fee, + base_fee_to_gas_per_pubdata(l1_gas_price, base_fee), + ) +} + +pub(crate) fn get_batch_base_fee(l1_batch_env: &L1BatchEnv) -> u64 { + if let Some(base_fee) = l1_batch_env.enforced_base_fee { + return base_fee; + } + let (base_fee, _) = + derive_base_fee_and_gas_per_pubdata(l1_batch_env.fee_input.into_l1_pegged()); + base_fee +} + +pub(crate) fn get_batch_gas_per_pubdata(l1_batch_env: &L1BatchEnv) -> u64 { + derive_base_fee_and_gas_per_pubdata(l1_batch_env.fee_input.into_l1_pegged()).1 +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/utils/l2_blocks.rs b/core/lib/multivm/src/versions/vm_boojum_integration/utils/l2_blocks.rs new file mode 100644 index 000000000000..e5832f7f5879 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/utils/l2_blocks.rs @@ -0,0 +1,95 @@ +use zksync_state::{ReadStorage, StoragePtr}; +use zksync_system_constants::{ + SYSTEM_CONTEXT_ADDRESS, SYSTEM_CONTEXT_CURRENT_L2_BLOCK_HASHES_POSITION, + SYSTEM_CONTEXT_CURRENT_L2_BLOCK_INFO_POSITION, SYSTEM_CONTEXT_CURRENT_TX_ROLLING_HASH_POSITION, + SYSTEM_CONTEXT_STORED_L2_BLOCK_HASHES, +}; +use zksync_types::{ + block::unpack_block_info, web3::signing::keccak256, AccountTreeId, MiniblockNumber, StorageKey, + H256, U256, +}; +use zksync_utils::{h256_to_u256, u256_to_h256}; + +use crate::interface::{L2Block, L2BlockEnv}; + +pub(crate) fn get_l2_block_hash_key(block_number: u32) -> StorageKey { + let position = h256_to_u256(SYSTEM_CONTEXT_CURRENT_L2_BLOCK_HASHES_POSITION) + + U256::from(block_number % SYSTEM_CONTEXT_STORED_L2_BLOCK_HASHES); + StorageKey::new( + AccountTreeId::new(SYSTEM_CONTEXT_ADDRESS), + u256_to_h256(position), + ) +} + +pub(crate) fn assert_next_block(prev_block: &L2Block, next_block: &L2BlockEnv) { + if prev_block.number == 0 { + // Special case for the first block it can have the same timestamp as the previous block. + assert!(prev_block.timestamp <= next_block.timestamp); + } else { + assert_eq!(prev_block.number + 1, next_block.number); + assert!(prev_block.timestamp < next_block.timestamp); + } + assert_eq!(prev_block.hash, next_block.prev_block_hash); +} + +/// Returns the hash of the l2_block. +/// `txs_rolling_hash` of the l2_block is calculated the following way: +/// If the l2_block has 0 transactions, then `txs_rolling_hash` is equal to `H256::zero()`. +/// If the l2_block has i transactions, then `txs_rolling_hash` is equal to `H(H_{i-1}, H(tx_i))`, where +/// `H_{i-1}` is the `txs_rolling_hash` of the first i-1 transactions. +pub(crate) fn l2_block_hash( + l2_block_number: MiniblockNumber, + l2_block_timestamp: u64, + prev_l2_block_hash: H256, + txs_rolling_hash: H256, +) -> H256 { + let mut digest: [u8; 128] = [0u8; 128]; + U256::from(l2_block_number.0).to_big_endian(&mut digest[0..32]); + U256::from(l2_block_timestamp).to_big_endian(&mut digest[32..64]); + digest[64..96].copy_from_slice(prev_l2_block_hash.as_bytes()); + digest[96..128].copy_from_slice(txs_rolling_hash.as_bytes()); + + H256(keccak256(&digest)) +} + +/// Get last saved block from storage +pub fn load_last_l2_block(storage: StoragePtr) -> Option { + // Get block number and timestamp + let current_l2_block_info_key = StorageKey::new( + AccountTreeId::new(SYSTEM_CONTEXT_ADDRESS), + SYSTEM_CONTEXT_CURRENT_L2_BLOCK_INFO_POSITION, + ); + let mut storage_ptr = storage.borrow_mut(); + let current_l2_block_info = storage_ptr.read_value(¤t_l2_block_info_key); + let (block_number, block_timestamp) = unpack_block_info(h256_to_u256(current_l2_block_info)); + let block_number = block_number as u32; + if block_number == 0 { + // The block does not exist yet + return None; + } + + // Get previous block hash + let position = get_l2_block_hash_key(block_number - 1); + let prev_block_hash = storage_ptr.read_value(&position); + + // Get current tx rolling hash + let position = StorageKey::new( + AccountTreeId::new(SYSTEM_CONTEXT_ADDRESS), + SYSTEM_CONTEXT_CURRENT_TX_ROLLING_HASH_POSITION, + ); + let current_tx_rolling_hash = storage_ptr.read_value(&position); + + // Calculate current hash + let current_block_hash = l2_block_hash( + MiniblockNumber(block_number), + block_timestamp, + prev_block_hash, + current_tx_rolling_hash, + ); + + Some(L2Block { + number: block_number, + timestamp: block_timestamp, + hash: current_block_hash, + }) +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/utils/logs.rs b/core/lib/multivm/src/versions/vm_boojum_integration/utils/logs.rs new file mode 100644 index 000000000000..1507f2d5e22d --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/utils/logs.rs @@ -0,0 +1,38 @@ +use zk_evm_1_3_3::aux_structures::LogQuery; +use zk_evm_1_4_0::aux_structures::Timestamp; +use zksync_state::WriteStorage; +use zksync_types::{l2_to_l1_log::L2ToL1Log, StorageLogQueryType, VmEvent}; + +use crate::{ + glue::GlueInto, + interface::L1BatchEnv, + vm_boojum_integration::{ + old_vm::{events::merge_events, history_recorder::HistoryMode}, + types::internals::ZkSyncVmState, + }, +}; + +pub(crate) fn collect_events_and_l1_system_logs_after_timestamp( + vm_state: &ZkSyncVmState, + batch_env: &L1BatchEnv, + from_timestamp: Timestamp, +) -> (Vec, Vec) { + let (raw_events, l1_messages) = vm_state + .event_sink + .get_events_and_l2_l1_logs_after_timestamp(from_timestamp); + let events = merge_events(raw_events) + .into_iter() + .map(|e| e.into_vm_event(batch_env.number)) + .collect(); + ( + events, + l1_messages.into_iter().map(GlueInto::glue_into).collect(), + ) +} + +/// Log query, which handle initial and repeated writes to the storage +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) struct StorageLogQuery { + pub log_query: LogQuery, + pub log_type: StorageLogQueryType, +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/utils/mod.rs b/core/lib/multivm/src/versions/vm_boojum_integration/utils/mod.rs new file mode 100644 index 000000000000..0fb803de5d4e --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/utils/mod.rs @@ -0,0 +1,6 @@ +/// Utility functions for the VM. +pub mod fee; +pub mod l2_blocks; +pub(crate) mod logs; +pub mod overhead; +pub mod transaction_encoding; diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/utils/overhead.rs b/core/lib/multivm/src/versions/vm_boojum_integration/utils/overhead.rs new file mode 100644 index 000000000000..750d18940f5b --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/utils/overhead.rs @@ -0,0 +1,351 @@ +use zk_evm_1_4_0::zkevm_opcode_defs::system_params::MAX_TX_ERGS_LIMIT; +use zksync_system_constants::MAX_L2_TX_GAS_LIMIT; +use zksync_types::{l1::is_l1_tx_type, U256}; +use zksync_utils::ceil_div_u256; + +use crate::vm_boojum_integration::constants::{ + BLOCK_OVERHEAD_GAS, BLOCK_OVERHEAD_PUBDATA, BOOTLOADER_TX_ENCODING_SPACE, MAX_TXS_IN_BLOCK, +}; + +/// Derives the overhead for processing transactions in a block. +pub(crate) fn derive_overhead( + gas_limit: u32, + gas_price_per_pubdata: u32, + encoded_len: usize, + coefficients: OverheadCoefficients, +) -> u32 { + // Even if the gas limit is greater than the `MAX_TX_ERGS_LIMIT`, we assume that everything beyond `MAX_TX_ERGS_LIMIT` + // will be spent entirely on publishing bytecodes and so we derive the overhead solely based on the capped value + let gas_limit = std::cmp::min(MAX_TX_ERGS_LIMIT, gas_limit); + + // Using large `U256` type to avoid overflow + let max_block_overhead = U256::from(block_overhead_gas(gas_price_per_pubdata)); + let gas_limit = U256::from(gas_limit); + let encoded_len = U256::from(encoded_len); + + // The `MAX_TX_ERGS_LIMIT` is formed in a way that may fulfills a single-instance circuits + // if used in full. That is, within `MAX_TX_ERGS_LIMIT` it is possible to fully saturate all the single-instance + // circuits. + let overhead_for_single_instance_circuits = + ceil_div_u256(gas_limit * max_block_overhead, MAX_TX_ERGS_LIMIT.into()); + + // The overhead for occupying the bootloader memory + let overhead_for_length = ceil_div_u256( + encoded_len * max_block_overhead, + BOOTLOADER_TX_ENCODING_SPACE.into(), + ); + + // The overhead for occupying a single tx slot + let tx_slot_overhead = ceil_div_u256(max_block_overhead, MAX_TXS_IN_BLOCK.into()); + + // We use `ceil` here for formal reasons to allow easier approach for calculating the overhead in `O(1)` + // `let max_pubdata_in_tx = ceil_div_u256(gas_limit, gas_price_per_pubdata);` + + // The maximal potential overhead from pubdata + // TODO (EVM-67): possibly use overhead for pubdata + // ``` + // let pubdata_overhead = ceil_div_u256( + // max_pubdata_in_tx * max_block_overhead, + // MAX_PUBDATA_PER_BLOCK.into(), + // ); + //``` + + vec![ + (coefficients.ergs_limit_overhead_coeficient + * overhead_for_single_instance_circuits.as_u32() as f64) + .floor() as u32, + (coefficients.bootloader_memory_overhead_coeficient * overhead_for_length.as_u32() as f64) + .floor() as u32, + (coefficients.slot_overhead_coeficient * tx_slot_overhead.as_u32() as f64) as u32, + ] + .into_iter() + .max() + .unwrap() +} + +/// Contains the coefficients with which the overhead for transactions will be calculated. +/// All of the coefficients should be <= 1. There are here to provide a certain "discount" for normal transactions +/// at the risk of malicious transactions that may close the block prematurely. +/// IMPORTANT: to perform correct computations, `MAX_TX_ERGS_LIMIT / coefficients.ergs_limit_overhead_coeficient` MUST +/// result in an integer number +#[derive(Debug, Clone, Copy)] +pub struct OverheadCoefficients { + slot_overhead_coeficient: f64, + bootloader_memory_overhead_coeficient: f64, + ergs_limit_overhead_coeficient: f64, +} + +impl OverheadCoefficients { + // This method ensures that the parameters keep the required invariants + fn new_checked( + slot_overhead_coeficient: f64, + bootloader_memory_overhead_coeficient: f64, + ergs_limit_overhead_coeficient: f64, + ) -> Self { + assert!( + (MAX_TX_ERGS_LIMIT as f64 / ergs_limit_overhead_coeficient).round() + == MAX_TX_ERGS_LIMIT as f64 / ergs_limit_overhead_coeficient, + "MAX_TX_ERGS_LIMIT / ergs_limit_overhead_coeficient must be an integer" + ); + + Self { + slot_overhead_coeficient, + bootloader_memory_overhead_coeficient, + ergs_limit_overhead_coeficient, + } + } + + // L1->L2 do not receive any discounts + fn new_l1() -> Self { + OverheadCoefficients::new_checked(1.0, 1.0, 1.0) + } + + fn new_l2() -> Self { + OverheadCoefficients::new_checked( + 1.0, 1.0, + // For L2 transactions we allow a certain default discount with regard to the number of ergs. + // Multi-instance circuits can in theory be spawned infinite times, while projected future limitations + // on gas per pubdata allow for roughly 800k gas per L1 batch, so the rough trust "discount" on the proof's part + // to be paid by the users is 0.1. + 0.1, + ) + } + + /// Return the coefficients for the given transaction type + pub fn from_tx_type(tx_type: u8) -> Self { + if is_l1_tx_type(tx_type) { + Self::new_l1() + } else { + Self::new_l2() + } + } +} + +/// This method returns the overhead for processing the block +pub(crate) fn get_amortized_overhead( + total_gas_limit: u32, + gas_per_pubdata_byte_limit: u32, + encoded_len: usize, + coefficients: OverheadCoefficients, +) -> u32 { + // Using large U256 type to prevent overflows. + let overhead_for_block_gas = U256::from(block_overhead_gas(gas_per_pubdata_byte_limit)); + let total_gas_limit = U256::from(total_gas_limit); + let encoded_len = U256::from(encoded_len); + + // Derivation of overhead consists of 4 parts: + // 1. The overhead for taking up a transaction's slot. `(O1): O1 = 1 / MAX_TXS_IN_BLOCK` + // 2. The overhead for taking up the bootloader's memory `(O2): O2 = encoded_len / BOOTLOADER_TX_ENCODING_SPACE` + // 3. The overhead for possible usage of pubdata. `(O3): O3 = max_pubdata_in_tx / MAX_PUBDATA_PER_BLOCK` + // 4. The overhead for possible usage of all the single-instance circuits. `(O4): O4 = gas_limit / MAX_TX_ERGS_LIMIT` + // + // The maximum of these is taken to derive the part of the block's overhead to be paid by the users: + // + // `max_overhead = max(O1, O2, O3, O4)` + // `overhead_gas = ceil(max_overhead * overhead_for_block_gas)`. Thus, `overhead_gas` is a function of + // `tx_gas_limit`, `gas_per_pubdata_byte_limit` and `encoded_len`. + // + // While it is possible to derive the overhead with binary search in `O(log n)`, it is too expensive to be done + // on L1, so here is a reference implementation of finding the overhead for transaction in `O(1)`: + // + // Given `total_gas_limit = tx_gas_limit + overhead_gas`, we need to find `overhead_gas` and `tx_gas_limit`, such that: + // 1. `overhead_gas` is maximal possible (the operator is paid fairly) + // 2. `overhead_gas(tx_gas_limit, gas_per_pubdata_byte_limit, encoded_len) >= overhead_gas` (the user does not overpay) + // The third part boils to the following 4 inequalities (at least one of these must hold): + // `ceil(O1 * overhead_for_block_gas) >= overhead_gas` + // `ceil(O2 * overhead_for_block_gas) >= overhead_gas` + // `ceil(O3 * overhead_for_block_gas) >= overhead_gas` + // `ceil(O4 * overhead_for_block_gas) >= overhead_gas` + // + // Now, we need to solve each of these separately: + + // 1. The overhead for occupying a single tx slot is a constant: + let tx_slot_overhead = { + let tx_slot_overhead = + ceil_div_u256(overhead_for_block_gas, MAX_TXS_IN_BLOCK.into()).as_u32(); + (coefficients.slot_overhead_coeficient * tx_slot_overhead as f64).floor() as u32 + }; + + // 2. The overhead for occupying the bootloader memory can be derived from `encoded_len` + let overhead_for_length = { + let overhead_for_length = ceil_div_u256( + encoded_len * overhead_for_block_gas, + BOOTLOADER_TX_ENCODING_SPACE.into(), + ) + .as_u32(); + + (coefficients.bootloader_memory_overhead_coeficient * overhead_for_length as f64).floor() + as u32 + }; + //``` + // TODO (EVM-67): possibly include the overhead for pubdata. The formula below has not been properly maintained, + // since the pubdat is not published. If decided to use the pubdata overhead, it needs to be updated. + // 3. ceil(O3 * overhead_for_block_gas) >= overhead_gas + // O3 = max_pubdata_in_tx / MAX_PUBDATA_PER_BLOCK = ceil(gas_limit / gas_per_pubdata_byte_limit) / MAX_PUBDATA_PER_BLOCK + // >= (gas_limit / (gas_per_pubdata_byte_limit * MAX_PUBDATA_PER_BLOCK). Throwing off the `ceil`, while may provide marginally lower + // overhead to the operator, provides substantially easier formula to work with. + // + // For better clarity, let's denote gas_limit = GL, MAX_PUBDATA_PER_BLOCK = MP, gas_per_pubdata_byte_limit = EP, overhead_for_block_gas = OB, total_gas_limit = TL, overhead_gas = OE + // ceil(OB * (TL - OE) / (EP * MP)) >= OE + // + // OB * (TL - OE) / (MP * EP) > OE - 1 + // OB * (TL - OE) > (OE - 1) * EP * MP + // OB * TL + EP * MP > OE * EP * MP + OE * OB + // (OB * TL + EP * MP) / (EP * MP + OB) > OE + // OE = floor((OB * TL + EP * MP) / (EP * MP + OB)) with possible -1 if the division is without remainder + // let overhead_for_pubdata = { + // let numerator: U256 = overhead_for_block_gas * total_gas_limit + // + gas_per_pubdata_byte_limit * U256::from(MAX_PUBDATA_PER_BLOCK); + // let denominator = + // gas_per_pubdata_byte_limit * U256::from(MAX_PUBDATA_PER_BLOCK) + overhead_for_block_gas; + // + // // Corner case: if `total_gas_limit` = `gas_per_pubdata_byte_limit` = 0 + // // then the numerator will be 0 and subtracting 1 will cause a panic, so we just return a zero. + // if numerator.is_zero() { + // 0.into() + // } else { + // (numerator - 1) / denominator + // } + // }; + //``` + // 4. `K * ceil(O4 * overhead_for_block_gas) >= overhead_gas`, where K is the discount + // `O4 = gas_limit / MAX_TX_ERGS_LIMIT`. Using the notation from the previous equation: + // `ceil(OB * GL / MAX_TX_ERGS_LIMIT) >= (OE / K)` + // `ceil(OB * (TL - OE) / MAX_TX_ERGS_LIMIT) >= (OE/K)` + // `OB * (TL - OE) / MAX_TX_ERGS_LIMIT > (OE/K) - 1` + // `OB * (TL - OE) > (OE/K) * MAX_TX_ERGS_LIMIT - MAX_TX_ERGS_LIMIT` + // `OB * TL + MAX_TX_ERGS_LIMIT > OE * ( MAX_TX_ERGS_LIMIT/K + OB)` + // `OE = floor(OB * TL + MAX_TX_ERGS_LIMIT / (MAX_TX_ERGS_LIMIT/K + OB))`, with possible -1 if the division is without remainder + let overhead_for_gas = { + let numerator = overhead_for_block_gas * total_gas_limit + U256::from(MAX_TX_ERGS_LIMIT); + let denominator: U256 = U256::from( + (MAX_TX_ERGS_LIMIT as f64 / coefficients.ergs_limit_overhead_coeficient) as u64, + ) + overhead_for_block_gas; + + let overhead_for_gas = (numerator - 1) / denominator; + + overhead_for_gas.as_u32() + }; + + let overhead = vec![tx_slot_overhead, overhead_for_length, overhead_for_gas] + .into_iter() + .max() + // For the sake of consistency making sure that total_gas_limit >= max_overhead + .map(|max_overhead| std::cmp::min(max_overhead, total_gas_limit.as_u32())) + .unwrap(); + + let limit_after_deducting_overhead = total_gas_limit - overhead; + + // During double checking of the overhead, the bootloader will assume that the + // body of the transaction does not have any more than MAX_L2_TX_GAS_LIMIT ergs available to it. + if limit_after_deducting_overhead.as_u64() > MAX_L2_TX_GAS_LIMIT { + // We derive the same overhead that would exist for the MAX_L2_TX_GAS_LIMIT ergs + derive_overhead( + MAX_L2_TX_GAS_LIMIT as u32, + gas_per_pubdata_byte_limit, + encoded_len.as_usize(), + coefficients, + ) + } else { + overhead + } +} + +pub(crate) fn block_overhead_gas(gas_per_pubdata_byte: u32) -> u32 { + BLOCK_OVERHEAD_GAS + BLOCK_OVERHEAD_PUBDATA * gas_per_pubdata_byte +} + +#[cfg(test)] +mod tests { + + use super::*; + + // This method returns the maximum block overhead that can be charged from the user based on the binary search approach + pub(crate) fn get_maximal_allowed_overhead_bin_search( + total_gas_limit: u32, + gas_per_pubdata_byte_limit: u32, + encoded_len: usize, + coefficients: OverheadCoefficients, + ) -> u32 { + let mut left_bound = if MAX_TX_ERGS_LIMIT < total_gas_limit { + total_gas_limit - MAX_TX_ERGS_LIMIT + } else { + 0u32 + }; + // Safe cast: the gas_limit for a transaction can not be larger than 2^32 + let mut right_bound = total_gas_limit; + + // The closure returns whether a certain overhead would be accepted by the bootloader. + // It is accepted if the derived overhead (i.e. the actual overhead that the user has to pay) + // is >= than the overhead proposed by the operator. + let is_overhead_accepted = |suggested_overhead: u32| { + let derived_overhead = derive_overhead( + total_gas_limit - suggested_overhead, + gas_per_pubdata_byte_limit, + encoded_len, + coefficients, + ); + + derived_overhead >= suggested_overhead + }; + + // In order to find the maximal allowed overhead we are doing binary search + while left_bound + 1 < right_bound { + let mid = (left_bound + right_bound) / 2; + + if is_overhead_accepted(mid) { + left_bound = mid; + } else { + right_bound = mid; + } + } + + if is_overhead_accepted(right_bound) { + right_bound + } else { + left_bound + } + } + + #[test] + fn test_correctness_for_efficient_overhead() { + let test_params = |total_gas_limit: u32, + gas_per_pubdata: u32, + encoded_len: usize, + coefficients: OverheadCoefficients| { + let result_by_efficient_search = + get_amortized_overhead(total_gas_limit, gas_per_pubdata, encoded_len, coefficients); + + let result_by_binary_search = get_maximal_allowed_overhead_bin_search( + total_gas_limit, + gas_per_pubdata, + encoded_len, + coefficients, + ); + + assert_eq!(result_by_efficient_search, result_by_binary_search); + }; + + // Some arbitrary test + test_params(60_000_000, 800, 2900, OverheadCoefficients::new_l2()); + + // Very small parameters + test_params(0, 1, 12, OverheadCoefficients::new_l2()); + + // Relatively big parameters + let max_tx_overhead = derive_overhead( + MAX_TX_ERGS_LIMIT, + 5000, + 10000, + OverheadCoefficients::new_l2(), + ); + test_params( + MAX_TX_ERGS_LIMIT + max_tx_overhead, + 5000, + 10000, + OverheadCoefficients::new_l2(), + ); + + test_params(115432560, 800, 2900, OverheadCoefficients::new_l1()); + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/utils/transaction_encoding.rs b/core/lib/multivm/src/versions/vm_boojum_integration/utils/transaction_encoding.rs new file mode 100644 index 000000000000..0a447ac31db4 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/utils/transaction_encoding.rs @@ -0,0 +1,16 @@ +use zksync_types::Transaction; + +use crate::vm_boojum_integration::types::internals::TransactionData; + +/// Extension for transactions, specific for VM. Required for bypassing the orphan rule +pub trait TransactionVmExt { + /// Get the size of the transaction in tokens. + fn bootloader_encoding_size(&self) -> usize; +} + +impl TransactionVmExt for Transaction { + fn bootloader_encoding_size(&self) -> usize { + let transaction_data: TransactionData = self.clone().into(); + transaction_data.into_tokens().len() + } +} diff --git a/core/lib/multivm/src/versions/vm_boojum_integration/vm.rs b/core/lib/multivm/src/versions/vm_boojum_integration/vm.rs new file mode 100644 index 000000000000..9e897ac30709 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_boojum_integration/vm.rs @@ -0,0 +1,212 @@ +use zkevm_test_harness_1_4_0::witness::sort_storage_access::sort_storage_access_queries; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_types::{ + event::extract_l2tol1logs_from_l1_messenger, + l2_to_l1_log::{SystemL2ToL1Log, UserL2ToL1Log}, + Transaction, +}; +use zksync_utils::bytecode::CompressedBytecodeInfo; + +use super::constants::BOOTLOADER_BATCH_TIP_OVERHEAD; +use crate::{ + glue::GlueInto, + interface::{ + BootloaderMemory, BytecodeCompressionError, CurrentExecutionState, FinishedL1Batch, + L1BatchEnv, L2BlockEnv, SystemEnv, VmExecutionMode, VmExecutionResultAndLogs, VmInterface, + VmInterfaceHistoryEnabled, VmMemoryMetrics, + }, + vm_boojum_integration::{ + bootloader_state::BootloaderState, + old_vm::events::merge_events, + tracers::dispatcher::TracerDispatcher, + types::internals::{new_vm_state, VmSnapshot, ZkSyncVmState}, + }, + HistoryMode, +}; + +/// Main entry point for Virtual Machine integration. +/// The instance should process only one l1 batch +#[derive(Debug)] +pub struct Vm { + pub(crate) bootloader_state: BootloaderState, + // Current state and oracles of virtual machine + pub(crate) state: ZkSyncVmState, + pub(crate) storage: StoragePtr, + pub(crate) system_env: SystemEnv, + pub(crate) batch_env: L1BatchEnv, + // Snapshots for the current run + pub(crate) snapshots: Vec, + _phantom: std::marker::PhantomData, +} + +impl VmInterface for Vm { + type TracerDispatcher = TracerDispatcher; + + fn new(batch_env: L1BatchEnv, system_env: SystemEnv, storage: StoragePtr) -> Self { + let (state, bootloader_state) = new_vm_state(storage.clone(), &system_env, &batch_env); + Self { + bootloader_state, + state, + storage, + system_env, + batch_env, + snapshots: vec![], + _phantom: Default::default(), + } + } + + /// Push tx into memory for the future execution + fn push_transaction(&mut self, tx: Transaction) { + self.push_transaction_with_compression(tx, true); + } + + /// Execute VM with custom tracers. + fn inspect( + &mut self, + tracer: Self::TracerDispatcher, + execution_mode: VmExecutionMode, + ) -> VmExecutionResultAndLogs { + self.inspect_inner(tracer, execution_mode) + } + + /// Get current state of bootloader memory. + fn get_bootloader_memory(&self) -> BootloaderMemory { + self.bootloader_state.bootloader_memory() + } + + /// Get compressed bytecodes of the last executed transaction + fn get_last_tx_compressed_bytecodes(&self) -> Vec { + self.bootloader_state.get_last_tx_compressed_bytecodes() + } + + fn start_new_l2_block(&mut self, l2_block_env: L2BlockEnv) { + self.bootloader_state.start_new_l2_block(l2_block_env); + } + + /// Get current state of virtual machine. + /// This method should be used only after the batch execution. + /// Otherwise it can panic. + fn get_current_execution_state(&self) -> CurrentExecutionState { + let (deduplicated_events_logs, raw_events, l1_messages) = self.state.event_sink.flatten(); + let events: Vec<_> = merge_events(raw_events) + .into_iter() + .map(|e| e.into_vm_event(self.batch_env.number)) + .collect(); + + let user_l2_to_l1_logs = extract_l2tol1logs_from_l1_messenger(&events); + let system_logs = l1_messages + .into_iter() + .map(|log| SystemL2ToL1Log(log.glue_into())) + .collect(); + let total_log_queries = self.state.event_sink.get_log_queries() + + self + .state + .precompiles_processor + .get_timestamp_history() + .len() + + self.state.storage.get_final_log_queries().len(); + + let storage_log_queries = self.state.storage.get_final_log_queries(); + + let deduped_storage_log_queries = + sort_storage_access_queries(storage_log_queries.iter().map(|log| &log.log_query)).1; + + CurrentExecutionState { + events, + storage_log_queries: storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), + deduplicated_storage_log_queries: deduped_storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), + used_contract_hashes: self.get_used_contracts(), + user_l2_to_l1_logs: user_l2_to_l1_logs + .into_iter() + .map(|log| UserL2ToL1Log(log.into())) + .collect(), + system_logs, + total_log_queries, + cycles_used: self.state.local_state.monotonic_cycle_counter, + deduplicated_events_logs: deduplicated_events_logs + .into_iter() + .map(GlueInto::glue_into) + .collect(), + storage_refunds: self.state.storage.returned_refunds.inner().clone(), + } + } + + /// Execute transaction with optional bytecode compression. + + /// Inspect transaction with optional bytecode compression. + fn inspect_transaction_with_bytecode_compression( + &mut self, + tracer: Self::TracerDispatcher, + tx: Transaction, + with_compression: bool, + ) -> ( + Result<(), BytecodeCompressionError>, + VmExecutionResultAndLogs, + ) { + self.push_transaction_with_compression(tx, with_compression); + let result = self.inspect_inner(tracer, VmExecutionMode::OneTx); + if self.has_unpublished_bytecodes() { + ( + Err(BytecodeCompressionError::BytecodeCompressionFailed), + result, + ) + } else { + (Ok(()), result) + } + } + + fn record_vm_memory_metrics(&self) -> VmMemoryMetrics { + self.record_vm_memory_metrics_inner() + } + + fn has_enough_gas_for_batch_tip(&self) -> bool { + self.state.local_state.callstack.current.ergs_remaining >= BOOTLOADER_BATCH_TIP_OVERHEAD + } + + fn finish_batch(&mut self) -> FinishedL1Batch { + let result = self.execute(VmExecutionMode::Batch); + let execution_state = self.get_current_execution_state(); + let bootloader_memory = self.get_bootloader_memory(); + FinishedL1Batch { + block_tip_execution_result: result, + final_execution_state: execution_state, + final_bootloader_memory: Some(bootloader_memory), + pubdata_input: Some( + self.bootloader_state + .get_pubdata_information() + .clone() + .build_pubdata(false), + ), + } + } +} + +/// Methods of vm, which required some history manipulations +impl VmInterfaceHistoryEnabled for Vm { + /// Create snapshot of current vm state and push it into the memory + fn make_snapshot(&mut self) { + self.make_snapshot_inner() + } + + /// Rollback vm state to the latest snapshot and destroy the snapshot + fn rollback_to_the_latest_snapshot(&mut self) { + let snapshot = self + .snapshots + .pop() + .expect("Snapshot should be created before rolling it back"); + self.rollback_to_snapshot(snapshot); + } + + /// Pop the latest snapshot from the memory and destroy it + fn pop_snapshot_no_rollback(&mut self) { + self.snapshots + .pop() + .expect("Snapshot should be created before rolling it back"); + } +} diff --git a/core/lib/multivm/src/versions/vm_latest/bootloader_state/l2_block.rs b/core/lib/multivm/src/versions/vm_latest/bootloader_state/l2_block.rs index 146e8713c69e..70b6a2b866ee 100644 --- a/core/lib/multivm/src/versions/vm_latest/bootloader_state/l2_block.rs +++ b/core/lib/multivm/src/versions/vm_latest/bootloader_state/l2_block.rs @@ -19,10 +19,10 @@ pub(crate) struct BootloaderL2Block { pub(crate) timestamp: u64, pub(crate) txs_rolling_hash: H256, // The rolling hash of all the transactions in the miniblock pub(crate) prev_block_hash: H256, - // Number of the first l2 block tx in l1 batch + // Number of the first L2 block tx in L1 batch pub(crate) first_tx_index: usize, pub(crate) max_virtual_blocks_to_create: u32, - pub(super) txs: Vec, + pub(crate) txs: Vec, } impl BootloaderL2Block { diff --git a/core/lib/multivm/src/versions/vm_latest/bootloader_state/tx.rs b/core/lib/multivm/src/versions/vm_latest/bootloader_state/tx.rs index 21aee75b38b5..9f44d848a4ed 100644 --- a/core/lib/multivm/src/versions/vm_latest/bootloader_state/tx.rs +++ b/core/lib/multivm/src/versions/vm_latest/bootloader_state/tx.rs @@ -5,20 +5,20 @@ use crate::vm_latest::types::internals::TransactionData; /// Information about tx necessary for execution in bootloader. #[derive(Debug, Clone)] -pub(super) struct BootloaderTx { - pub(super) hash: H256, +pub(crate) struct BootloaderTx { + pub(crate) hash: H256, /// Encoded transaction - pub(super) encoded: Vec, + pub(crate) encoded: Vec, /// Compressed bytecodes, which has been published during this transaction - pub(super) compressed_bytecodes: Vec, + pub(crate) compressed_bytecodes: Vec, /// Refunds for this transaction - pub(super) refund: u32, + pub(crate) refund: u32, /// Gas overhead - pub(super) gas_overhead: u32, + pub(crate) gas_overhead: u32, /// Gas Limit for this transaction. It can be different from the gas limit inside the transaction - pub(super) trusted_gas_limit: U256, + pub(crate) trusted_gas_limit: U256, /// Offset of the tx in bootloader memory - pub(super) offset: usize, + pub(crate) offset: usize, } impl BootloaderTx { diff --git a/core/lib/multivm/src/versions/vm_latest/bootloader_state/utils.rs b/core/lib/multivm/src/versions/vm_latest/bootloader_state/utils.rs index 93ec255e7740..346c1bde5368 100644 --- a/core/lib/multivm/src/versions/vm_latest/bootloader_state/utils.rs +++ b/core/lib/multivm/src/versions/vm_latest/bootloader_state/utils.rs @@ -94,8 +94,8 @@ pub(crate) fn apply_l2_block( bootloader_l2_block: &BootloaderL2Block, txs_index: usize, ) { - // Since L2 block infos start from the TX_OPERATOR_L2_BLOCK_INFO_OFFSET and each - // L2 block info takes TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO slots, the position where the L2 block info + // Since L2 block information start from the `TX_OPERATOR_L2_BLOCK_INFO_OFFSET` and each + // L2 block info takes `TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO` slots, the position where the L2 block info // for this transaction needs to be written is: let block_position = diff --git a/core/lib/multivm/src/versions/vm_latest/constants.rs b/core/lib/multivm/src/versions/vm_latest/constants.rs index 44266344be61..5a12c0f2252e 100644 --- a/core/lib/multivm/src/versions/vm_latest/constants.rs +++ b/core/lib/multivm/src/versions/vm_latest/constants.rs @@ -1,20 +1,43 @@ -use zk_evm_1_4_0::aux_structures::MemoryPage; -pub use zk_evm_1_4_0::zkevm_opcode_defs::system_params::{ +use zk_evm_1_4_1::aux_structures::MemoryPage; +pub use zk_evm_1_4_1::zkevm_opcode_defs::system_params::{ ERGS_PER_CIRCUIT, INITIAL_STORAGE_WRITE_PUBDATA_BYTES, MAX_PUBDATA_PER_BLOCK, }; -use zksync_system_constants::{ - L1_GAS_PER_PUBDATA_BYTE, MAX_L2_TX_GAS_LIMIT, MAX_NEW_FACTORY_DEPS, MAX_TXS_IN_BLOCK, - USED_BOOTLOADER_MEMORY_WORDS, -}; +use zksync_system_constants::{MAX_L2_TX_GAS_LIMIT, MAX_NEW_FACTORY_DEPS}; use crate::vm_latest::old_vm::utils::heap_page_from_base; +/// The amount of ergs to be reserved at the end of the batch to ensure that it has enough ergs to verify compression, etc. +pub(crate) const BOOTLOADER_BATCH_TIP_OVERHEAD: u32 = 80_000_000; + +/// The size of the bootloader memory in bytes which is used by the protocol. +/// While the maximal possible size is a lot higher, we restrict ourselves to a certain limit to reduce +/// the requirements on RAM. +/// In this version of the VM the used bootloader memory bytes has increased from `2^24`` to `24_000_000`. +pub(crate) const USED_BOOTLOADER_MEMORY_BYTES: usize = 24_000_000; +pub(crate) const USED_BOOTLOADER_MEMORY_WORDS: usize = USED_BOOTLOADER_MEMORY_BYTES / 32; + +// This the number of pubdata such that it should be always possible to publish +// from a single transaction. Note, that these pubdata bytes include only bytes that are +// to be published inside the body of transaction (i.e. excluding of factory deps). +pub(crate) const GUARANTEED_PUBDATA_PER_L1_BATCH: u64 = 2500; + +// The users should always be able to provide `MAX_GAS_PER_PUBDATA_BYTE` gas per pubdata in their +// transactions so that they are able to send at least `GUARANTEED_PUBDATA_PER_L1_BATCH` bytes per +// transaction. +pub(crate) const MAX_GAS_PER_PUBDATA_BYTE: u64 = + MAX_L2_TX_GAS_LIMIT / GUARANTEED_PUBDATA_PER_L1_BATCH; + +// The maximal number of transactions in a single batch. +// In this version of the VM the limit has been increased from `1024` to to `10000`. +pub(crate) const MAX_TXS_IN_BATCH: usize = 10000; + /// Max cycles for a single transaction. pub const MAX_CYCLES_FOR_TX: u32 = u32::MAX; /// The first 32 slots are reserved for debugging purposes pub(crate) const DEBUG_SLOTS_OFFSET: usize = 8; pub(crate) const DEBUG_FIRST_SLOTS: usize = 32; + /// The next 33 slots are reserved for dealing with the paymaster context (1 slot for storing length + 32 slots for storing the actual context). pub(crate) const PAYMASTER_CONTEXT_SLOTS: usize = 32 + 1; /// The next PAYMASTER_CONTEXT_SLOTS + 7 slots free slots are needed before each tx, so that the @@ -32,7 +55,7 @@ const CURRENT_L2_TX_HASHES_SLOTS: usize = 2; const NEW_FACTORY_DEPS_RESERVED_SLOTS: usize = MAX_NEW_FACTORY_DEPS + 4; /// The operator can provide for each transaction the proposed minimal refund -pub(crate) const OPERATOR_REFUNDS_SLOTS: usize = MAX_TXS_IN_BLOCK; +pub(crate) const OPERATOR_REFUNDS_SLOTS: usize = MAX_TXS_IN_BATCH; pub(crate) const OPERATOR_REFUNDS_OFFSET: usize = DEBUG_SLOTS_OFFSET + DEBUG_FIRST_SLOTS @@ -41,10 +64,10 @@ pub(crate) const OPERATOR_REFUNDS_OFFSET: usize = DEBUG_SLOTS_OFFSET + NEW_FACTORY_DEPS_RESERVED_SLOTS; pub(crate) const TX_OVERHEAD_OFFSET: usize = OPERATOR_REFUNDS_OFFSET + OPERATOR_REFUNDS_SLOTS; -pub(crate) const TX_OVERHEAD_SLOTS: usize = MAX_TXS_IN_BLOCK; +pub(crate) const TX_OVERHEAD_SLOTS: usize = MAX_TXS_IN_BATCH; pub(crate) const TX_TRUSTED_GAS_LIMIT_OFFSET: usize = TX_OVERHEAD_OFFSET + TX_OVERHEAD_SLOTS; -pub(crate) const TX_TRUSTED_GAS_LIMIT_SLOTS: usize = MAX_TXS_IN_BLOCK; +pub(crate) const TX_TRUSTED_GAS_LIMIT_SLOTS: usize = MAX_TXS_IN_BATCH; pub(crate) const COMPRESSED_BYTECODES_SLOTS: usize = 32768; @@ -69,8 +92,8 @@ pub(crate) const BOOTLOADER_TX_DESCRIPTION_OFFSET: usize = OPERATOR_PROVIDED_L1_MESSENGER_PUBDATA_OFFSET + OPERATOR_PROVIDED_L1_MESSENGER_PUBDATA_SLOTS; /// The size of the bootloader memory dedicated to the encodings of transactions -pub const BOOTLOADER_TX_ENCODING_SPACE: u32 = - (USED_BOOTLOADER_MEMORY_WORDS - TX_DESCRIPTION_OFFSET - MAX_TXS_IN_BLOCK) as u32; +pub(crate) const BOOTLOADER_TX_ENCODING_SPACE: u32 = + (USED_BOOTLOADER_MEMORY_WORDS - TX_DESCRIPTION_OFFSET - MAX_TXS_IN_BATCH) as u32; // Size of the bootloader tx description in words pub(crate) const BOOTLOADER_TX_DESCRIPTION_SIZE: usize = 2; @@ -78,16 +101,13 @@ pub(crate) const BOOTLOADER_TX_DESCRIPTION_SIZE: usize = 2; /// The actual descriptions of transactions should start after the minor descriptions and a MAX_POSTOP_SLOTS /// free slots to allow postOp encoding. pub(crate) const TX_DESCRIPTION_OFFSET: usize = BOOTLOADER_TX_DESCRIPTION_OFFSET - + BOOTLOADER_TX_DESCRIPTION_SIZE * MAX_TXS_IN_BLOCK + + BOOTLOADER_TX_DESCRIPTION_SIZE * MAX_TXS_IN_BATCH + MAX_POSTOP_SLOTS; pub(crate) const TX_GAS_LIMIT_OFFSET: usize = 4; const INITIAL_BASE_PAGE: u32 = 8; pub const BOOTLOADER_HEAP_PAGE: u32 = heap_page_from_base(MemoryPage(INITIAL_BASE_PAGE)).0; -pub const BLOCK_OVERHEAD_GAS: u32 = 1200000; -pub const BLOCK_OVERHEAD_L1_GAS: u32 = 1000000; -pub const BLOCK_OVERHEAD_PUBDATA: u32 = BLOCK_OVERHEAD_L1_GAS / L1_GAS_PER_PUBDATA_BYTE; /// VM Hooks are used for communication between bootloader and tracers. /// The 'type' / 'opcode' is put into VM_HOOK_POSITION slot, @@ -98,17 +118,15 @@ pub const VM_HOOK_POSITION: u32 = RESULT_SUCCESS_FIRST_SLOT - 1; pub const VM_HOOK_PARAMS_COUNT: u32 = 2; pub const VM_HOOK_PARAMS_START_POSITION: u32 = VM_HOOK_POSITION - VM_HOOK_PARAMS_COUNT; -pub(crate) const MAX_MEM_SIZE_BYTES: u32 = 16777216; // 2^24 - /// Arbitrary space in memory closer to the end of the page pub const RESULT_SUCCESS_FIRST_SLOT: u32 = - (MAX_MEM_SIZE_BYTES - (MAX_TXS_IN_BLOCK as u32) * 32) / 32; + ((USED_BOOTLOADER_MEMORY_BYTES as u32) - (MAX_TXS_IN_BATCH as u32) * 32) / 32; /// How many gas bootloader is allowed to spend within one block. /// Note that this value doesn't correspond to the gas limit of any particular transaction /// (except for the fact that, of course, gas limit for each transaction should be <= `BLOCK_GAS_LIMIT`). pub const BLOCK_GAS_LIMIT: u32 = - zk_evm_1_4_0::zkevm_opcode_defs::system_params::VM_INITIAL_FRAME_ERGS; + zk_evm_1_4_1::zkevm_opcode_defs::system_params::VM_INITIAL_FRAME_ERGS; /// How many gas is allowed to spend on a single transaction in eth_call method pub const ETH_CALL_GAS_LIMIT: u32 = MAX_L2_TX_GAS_LIMIT as u32; @@ -121,7 +139,35 @@ pub(crate) const TX_OPERATOR_L2_BLOCK_INFO_OFFSET: usize = pub(crate) const TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO: usize = 4; pub(crate) const TX_OPERATOR_L2_BLOCK_INFO_SLOTS: usize = - (MAX_TXS_IN_BLOCK + 1) * TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO; + (MAX_TXS_IN_BATCH + 1) * TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO; pub(crate) const COMPRESSED_BYTECODES_OFFSET: usize = TX_OPERATOR_L2_BLOCK_INFO_OFFSET + TX_OPERATOR_L2_BLOCK_INFO_SLOTS; + +/// The maximal gas limit that gets passed into an L1->L2 transaction. +/// +/// It is equal to the `MAX_GAS_PER_TRANSACTION` in the bootloader. +/// We need to limit the number of gas that can be passed into the L1->L2 transaction due to the fact +/// that unlike L2 transactions they can not be rejected by the operator and must be executed. In turn, +/// this means that if a transaction spends more than `MAX_GAS_PER_TRANSACTION`, it use up all the limited resources of a batch. +/// +/// It the gas limit cap on Mailbox for a priority transactions should generally be low enough to never cross that boundary, since +/// artificially limiting the gas price is bad UX. However, during the transition between the pre-1.4.1 fee model and the 1.4.1 one, +/// we need to process such transactions somehow. +pub(crate) const PRIORITY_TX_MAX_GAS_LIMIT: usize = 80_000_000; + +/// The amount of gas to be charged for occupying a single slot of a transaction. +/// It is roughly equal to `80kk/MAX_TRANSACTIONS_PER_BATCH`, i.e. how many gas would an L1->L2 transaction +/// need to pay to compensate for the batch being closed. +/// While the derived formula is used for the worst case for L1->L2 transaction, it suits L2 transactions as well +/// and serves to compensate the operator for the fact that they need to process the transaction. In case batches start +/// getting often sealed due to the slot limit being reached, the L2 fair gas price will be increased. +pub(crate) const TX_SLOT_OVERHEAD_GAS: u32 = 10_000; + +/// The amount of gas to be charged for occupying a single byte of the bootloader's memory. +/// It is roughly equal to `80kk/BOOTLOADER_MEMORY_FOR_TXS`, i.e. how many gas would an L1->L2 transaction +/// need to pay to compensate for the batch being closed. +/// While the derived formula is used for the worst case for L1->L2 transaction, it suits L2 transactions as well +/// and serves to compensate the operator for the fact that they need to fill up the bootloader memory. In case batches start +/// getting often sealed due to the memory limit being reached, the L2 fair gas price will be increased. +pub(crate) const TX_MEMORY_OVERHEAD_GAS: u32 = 10; diff --git a/core/lib/multivm/src/versions/vm_latest/implementation/execution.rs b/core/lib/multivm/src/versions/vm_latest/implementation/execution.rs index a913ea3ed463..21e5b16cd2de 100644 --- a/core/lib/multivm/src/versions/vm_latest/implementation/execution.rs +++ b/core/lib/multivm/src/versions/vm_latest/implementation/execution.rs @@ -1,4 +1,4 @@ -use zk_evm_1_4_0::aux_structures::Timestamp; +use zk_evm_1_4_1::aux_structures::Timestamp; use zksync_state::WriteStorage; use crate::{ @@ -9,7 +9,8 @@ use crate::{ vm_latest::{ old_vm::utils::{vm_may_have_ended_inner, VmExecutionResult}, tracers::{ - dispatcher::TracerDispatcher, DefaultExecutionTracer, PubdataTracer, RefundsTracer, + circuits_capacity::circuit_statistic_from_cycles, dispatcher::TracerDispatcher, + DefaultExecutionTracer, PubdataTracer, RefundsTracer, }, vm::Vm, }, @@ -19,8 +20,9 @@ use crate::{ impl Vm { pub(crate) fn inspect_inner( &mut self, - dispatcher: TracerDispatcher, + dispatcher: TracerDispatcher, execution_mode: VmExecutionMode, + custom_pubdata_tracer: Option>, ) -> VmExecutionResultAndLogs { let mut enable_refund_tracer = false; if let VmExecutionMode::OneTx = execution_mode { @@ -29,8 +31,12 @@ impl Vm { enable_refund_tracer = true; } - let (_, result) = - self.inspect_and_collect_results(dispatcher, execution_mode, enable_refund_tracer); + let (_, result) = self.inspect_and_collect_results( + dispatcher, + execution_mode, + enable_refund_tracer, + custom_pubdata_tracer, + ); result } @@ -38,21 +44,22 @@ impl Vm { /// Collect the result from the default tracers. fn inspect_and_collect_results( &mut self, - dispatcher: TracerDispatcher, + dispatcher: TracerDispatcher, execution_mode: VmExecutionMode, with_refund_tracer: bool, + custom_pubdata_tracer: Option>, ) -> (VmExecutionStopReason, VmExecutionResultAndLogs) { let refund_tracers = with_refund_tracer.then_some(RefundsTracer::new(self.batch_env.clone())); - let mut tx_tracer: DefaultExecutionTracer = - DefaultExecutionTracer::new( - self.system_env.default_validation_computational_gas_limit, - execution_mode, - dispatcher, - self.storage.clone(), - refund_tracers, - Some(PubdataTracer::new(self.batch_env.clone(), execution_mode)), - ); + let mut tx_tracer: DefaultExecutionTracer = DefaultExecutionTracer::new( + self.system_env.default_validation_computational_gas_limit, + execution_mode, + dispatcher, + self.storage.clone(), + refund_tracers, + custom_pubdata_tracer + .or_else(|| Some(PubdataTracer::new(self.batch_env.clone(), execution_mode))), + ); let timestamp_initial = Timestamp(self.state.local_state.timestamp); let cycles_initial = self.state.local_state.monotonic_cycle_counter; @@ -80,6 +87,7 @@ impl Vm { spent_pubdata_counter_before, pubdata_published, logs.total_log_queries_count, + circuit_statistic_from_cycles(tx_tracer.circuits_tracer.statistics), ); let result = tx_tracer.result_tracer.into_result(); @@ -96,7 +104,7 @@ impl Vm { /// Execute vm with given tracers until the stop reason is reached. fn execute_with_default_tracer( &mut self, - tracer: &mut DefaultExecutionTracer, + tracer: &mut DefaultExecutionTracer, ) -> VmExecutionStopReason { tracer.initialize_tracer(&mut self.state); let result = loop { diff --git a/core/lib/multivm/src/versions/vm_latest/implementation/gas.rs b/core/lib/multivm/src/versions/vm_latest/implementation/gas.rs index 526eab76f07f..8b21e7aeca1a 100644 --- a/core/lib/multivm/src/versions/vm_latest/implementation/gas.rs +++ b/core/lib/multivm/src/versions/vm_latest/implementation/gas.rs @@ -20,7 +20,7 @@ impl Vm { pub(crate) fn calculate_computational_gas_used( &self, - tracer: &DefaultExecutionTracer, + tracer: &DefaultExecutionTracer, gas_remaining_before: u32, spent_pubdata_counter_before: u32, ) -> u32 { diff --git a/core/lib/multivm/src/versions/vm_latest/implementation/logs.rs b/core/lib/multivm/src/versions/vm_latest/implementation/logs.rs index 9e0817aa9394..99fa413938ac 100644 --- a/core/lib/multivm/src/versions/vm_latest/implementation/logs.rs +++ b/core/lib/multivm/src/versions/vm_latest/implementation/logs.rs @@ -1,4 +1,4 @@ -use zk_evm_1_4_0::aux_structures::Timestamp; +use zk_evm_1_4_1::aux_structures::Timestamp; use zksync_state::WriteStorage; use zksync_types::{ event::extract_l2tol1logs_from_l1_messenger, @@ -7,6 +7,7 @@ use zksync_types::{ }; use crate::{ + glue::GlueInto, interface::types::outputs::VmExecutionLogs, vm_latest::{old_vm::utils::precompile_calls_count_after_timestamp, utils::logs, vm::Vm}, HistoryMode, @@ -45,7 +46,10 @@ impl Vm { storage_logs_count + log_queries.len() + precompile_calls_count; VmExecutionLogs { - storage_logs, + storage_logs: storage_logs + .into_iter() + .map(|log| log.glue_into()) + .collect(), events, user_l2_to_l1_logs: user_logs .into_iter() @@ -66,7 +70,7 @@ impl Vm { logs::collect_events_and_l1_system_logs_after_timestamp( &self.state, &self.batch_env, - from_timestamp, + from_timestamp.glue_into(), ) } } diff --git a/core/lib/multivm/src/versions/vm_latest/implementation/snapshots.rs b/core/lib/multivm/src/versions/vm_latest/implementation/snapshots.rs index b6b452834388..6f27c031d09e 100644 --- a/core/lib/multivm/src/versions/vm_latest/implementation/snapshots.rs +++ b/core/lib/multivm/src/versions/vm_latest/implementation/snapshots.rs @@ -1,7 +1,7 @@ use std::time::Duration; use vise::{Buckets, EncodeLabelSet, EncodeLabelValue, Family, Histogram, Metrics}; -use zk_evm_1_4_0::aux_structures::Timestamp; +use zk_evm_1_4_1::aux_structures::Timestamp; use zksync_state::WriteStorage; use crate::vm_latest::{ @@ -36,8 +36,8 @@ impl Vm { pub(crate) fn make_snapshot_inner(&mut self) { self.snapshots.push(VmSnapshot { // Vm local state contains O(1) various parameters (registers/etc). - // The only "expensive" copying here is copying of the callstack. - // It will take O(callstack_depth) to copy it. + // The only "expensive" copying here is copying of the call stack. + // It will take `O(callstack_depth)` to copy it. // So it is generally recommended to get snapshots of the bootloader frame, // where the depth is 1. local_state: self.state.local_state.clone(), diff --git a/core/lib/multivm/src/versions/vm_latest/implementation/statistics.rs b/core/lib/multivm/src/versions/vm_latest/implementation/statistics.rs index 6af9ad041feb..0349b7d8cda0 100644 --- a/core/lib/multivm/src/versions/vm_latest/implementation/statistics.rs +++ b/core/lib/multivm/src/versions/vm_latest/implementation/statistics.rs @@ -1,6 +1,6 @@ -use zk_evm_1_4_0::aux_structures::Timestamp; +use zk_evm_1_4_1::aux_structures::Timestamp; use zksync_state::WriteStorage; -use zksync_types::U256; +use zksync_types::{circuit::CircuitStatistic, U256}; use crate::{ interface::{VmExecutionStatistics, VmMemoryMetrics}, @@ -18,12 +18,13 @@ impl Vm { &self, timestamp_initial: Timestamp, cycles_initial: u32, - tracer: &DefaultExecutionTracer, + tracer: &DefaultExecutionTracer, gas_remaining_before: u32, gas_remaining_after: u32, spent_pubdata_counter_before: u32, pubdata_published: u32, total_log_queries_count: usize, + circuit_statistic: CircuitStatistic, ) -> VmExecutionStatistics { let computational_gas_used = self.calculate_computational_gas_used( tracer, @@ -40,6 +41,7 @@ impl Vm { computational_gas_used, total_log_queries: total_log_queries_count, pubdata_published, + circuit_statistic, } } diff --git a/core/lib/multivm/src/versions/vm_latest/implementation/tx.rs b/core/lib/multivm/src/versions/vm_latest/implementation/tx.rs index 326be41c5ee7..d7d948c8b573 100644 --- a/core/lib/multivm/src/versions/vm_latest/implementation/tx.rs +++ b/core/lib/multivm/src/versions/vm_latest/implementation/tx.rs @@ -1,4 +1,4 @@ -use zk_evm_1_4_0::aux_structures::Timestamp; +use zk_evm_1_4_1::aux_structures::Timestamp; use zksync_state::WriteStorage; use zksync_types::{l1::is_l1_tx_type, Transaction}; @@ -38,8 +38,7 @@ impl Vm { .decommittment_processor .populate(codes_for_decommiter, timestamp); - let trusted_ergs_limit = - tx.trusted_ergs_limit(self.batch_env.block_gas_price_per_pubdata()); + let trusted_ergs_limit = tx.trusted_ergs_limit(); let memory = self.bootloader_state.push_tx( tx, @@ -61,8 +60,7 @@ impl Vm { with_compression: bool, ) { let tx: TransactionData = tx.into(); - let block_gas_per_pubdata_byte = self.batch_env.block_gas_price_per_pubdata(); - let overhead = tx.overhead_gas(block_gas_per_pubdata_byte as u32); + let overhead = tx.overhead_gas(); self.push_raw_transaction(tx, overhead, 0, with_compression); } } diff --git a/core/lib/multivm/src/versions/vm_latest/old_vm/event_sink.rs b/core/lib/multivm/src/versions/vm_latest/old_vm/event_sink.rs index 8e7f4d447b4d..7e3097aaeb44 100644 --- a/core/lib/multivm/src/versions/vm_latest/old_vm/event_sink.rs +++ b/core/lib/multivm/src/versions/vm_latest/old_vm/event_sink.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use itertools::Itertools; -use zk_evm_1_4_0::{ +use zk_evm_1_4_1::{ abstractions::EventSink, aux_structures::{LogQuery, Timestamp}, reference_impls::event_sink::EventMessage, @@ -54,7 +54,7 @@ impl InMemoryEventSink { pub fn log_queries_after_timestamp(&self, from_timestamp: Timestamp) -> &[Box] { let events = self.frames_stack.forward().current_frame(); - // Select all of the last elements where e.timestamp >= from_timestamp. + // Select all of the last elements where `e.timestamp >= from_timestamp`. // Note, that using binary search here is dangerous, because the logs are not sorted by timestamp. events .rsplit(|e| e.timestamp < from_timestamp) diff --git a/core/lib/multivm/src/versions/vm_latest/old_vm/events.rs b/core/lib/multivm/src/versions/vm_latest/old_vm/events.rs index eed8fee4ac86..fc97b6f4a419 100644 --- a/core/lib/multivm/src/versions/vm_latest/old_vm/events.rs +++ b/core/lib/multivm/src/versions/vm_latest/old_vm/events.rs @@ -1,4 +1,4 @@ -use zk_evm_1_4_0::{ethereum_types::Address, reference_impls::event_sink::EventMessage}; +use zk_evm_1_4_1::{ethereum_types::Address, reference_impls::event_sink::EventMessage}; use zksync_types::{L1BatchNumber, VmEvent, EVENT_WRITER_ADDRESS, H256}; use zksync_utils::{be_chunks_to_h256_words, h256_to_account_address}; diff --git a/core/lib/multivm/src/versions/vm_latest/old_vm/history_recorder.rs b/core/lib/multivm/src/versions/vm_latest/old_vm/history_recorder.rs index 83a22f35b4a1..d4c5b6367a9b 100644 --- a/core/lib/multivm/src/versions/vm_latest/old_vm/history_recorder.rs +++ b/core/lib/multivm/src/versions/vm_latest/old_vm/history_recorder.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, fmt::Debug, hash::Hash}; -use zk_evm_1_4_0::{ +use zk_evm_1_4_1::{ aux_structures::Timestamp, vm_state::PrimitiveValue, zkevm_opcode_defs::{self}, @@ -12,14 +12,14 @@ use zksync_utils::{h256_to_u256, u256_to_h256}; pub(crate) type MemoryWithHistory = HistoryRecorder; pub(crate) type IntFrameManagerWithHistory = HistoryRecorder, H>; -// Within the same cycle, timestamps in range timestamp..timestamp+TIME_DELTA_PER_CYCLE-1 +// Within the same cycle, timestamps in range `timestamp..timestamp+TIME_DELTA_PER_CYCLE-1` // can be used. This can sometimes violate monotonicity of the timestamp within the // same cycle, so it should be normalized. #[inline] fn normalize_timestamp(timestamp: Timestamp) -> Timestamp { let timestamp = timestamp.0; - // Making sure it is divisible by TIME_DELTA_PER_CYCLE + // Making sure it is divisible by `TIME_DELTA_PER_CYCLE` Timestamp(timestamp - timestamp % zkevm_opcode_defs::TIME_DELTA_PER_CYCLE) } @@ -770,7 +770,7 @@ impl HistoryRecorder, H> { #[cfg(test)] mod tests { - use zk_evm_1_4_0::{aux_structures::Timestamp, vm_state::PrimitiveValue}; + use zk_evm_1_4_1::{aux_structures::Timestamp, vm_state::PrimitiveValue}; use zksync_types::U256; use crate::vm_latest::{ diff --git a/core/lib/multivm/src/versions/vm_latest/old_vm/memory.rs b/core/lib/multivm/src/versions/vm_latest/old_vm/memory.rs index 5a7592ce9654..120ff43acffb 100644 --- a/core/lib/multivm/src/versions/vm_latest/old_vm/memory.rs +++ b/core/lib/multivm/src/versions/vm_latest/old_vm/memory.rs @@ -1,4 +1,4 @@ -use zk_evm_1_4_0::{ +use zk_evm_1_4_1::{ abstractions::{Memory, MemoryType}, aux_structures::{MemoryPage, MemoryQuery, Timestamp}, vm_state::PrimitiveValue, @@ -282,7 +282,7 @@ impl Memory for SimpleMemory { let returndata_page = returndata_fat_pointer.memory_page; for &page in current_observable_pages { - // If the page's number is greater than or equal to the base_page, + // If the page's number is greater than or equal to the `base_page`, // it means that it was created by the internal calls of this contract. // We need to add this check as the calldata pointer is also part of the // observable pages. @@ -299,7 +299,7 @@ impl Memory for SimpleMemory { } } -// It is expected that there is some intersection between [word_number*32..word_number*32+31] and [start, end] +// It is expected that there is some intersection between `[word_number*32..word_number*32+31]` and `[start, end]` fn extract_needed_bytes_from_word( word_value: Vec, word_number: usize, @@ -307,7 +307,7 @@ fn extract_needed_bytes_from_word( end: usize, ) -> Vec { let word_start = word_number * 32; - let word_end = word_start + 31; // Note, that at word_start + 32 a new word already starts + let word_end = word_start + 31; // Note, that at `word_start + 32` a new word already starts let intersection_left = std::cmp::max(word_start, start); let intersection_right = std::cmp::min(word_end, end); diff --git a/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/decommitter.rs b/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/decommitter.rs index 4a718917a21d..86e8f6f6da1e 100644 --- a/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/decommitter.rs +++ b/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/decommitter.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, fmt::Debug}; -use zk_evm_1_4_0::{ +use zk_evm_1_4_1::{ abstractions::{DecommittmentProcessor, Memory, MemoryType}, aux_structures::{ DecommittmentQuery, MemoryIndex, MemoryLocation, MemoryPage, MemoryQuery, Timestamp, @@ -14,7 +14,6 @@ use super::OracleWithHistory; use crate::vm_latest::old_vm::history_recorder::{ HistoryEnabled, HistoryMode, HistoryRecorder, WithHistory, }; - /// The main job of the DecommiterOracle is to implement the DecommittmentProcessor trait - that is /// used by the VM to 'load' bytecodes into memory. #[derive(Debug)] @@ -169,7 +168,7 @@ impl DecommittmentProcess memory: &mut M, ) -> Result< ( - zk_evm_1_4_0::aux_structures::DecommittmentQuery, + zk_evm_1_4_1::aux_structures::DecommittmentQuery, Option>, ), anyhow::Error, diff --git a/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/mod.rs b/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/mod.rs index 3f8d2d0f1383..7d463ad082be 100644 --- a/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/mod.rs +++ b/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/mod.rs @@ -1,4 +1,4 @@ -use zk_evm_1_4_0::aux_structures::Timestamp; +use zk_evm_1_4_1::aux_structures::Timestamp; pub(crate) mod decommitter; pub(crate) mod precompile; diff --git a/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/precompile.rs b/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/precompile.rs index 92b88e40fc95..8de51a9619df 100644 --- a/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/precompile.rs +++ b/core/lib/multivm/src/versions/vm_latest/old_vm/oracles/precompile.rs @@ -1,7 +1,9 @@ -use zk_evm_1_4_0::{ +use std::convert::TryFrom; + +use zk_evm_1_4_1::{ abstractions::{Memory, PrecompileCyclesWitness, PrecompilesProcessor}, aux_structures::{LogQuery, MemoryQuery, Timestamp}, - zk_evm_abstractions::precompiles::DefaultPrecompilesProcessor, + zk_evm_abstractions::precompiles::{ecrecover, keccak256, sha256, PrecompileAddress}, }; use super::OracleWithHistory; @@ -13,40 +15,44 @@ use crate::vm_latest::old_vm::history_recorder::{HistoryEnabled, HistoryMode, Hi /// saving timestamps allows us to check the exact number /// of log queries, that were used during the tx execution. #[derive(Debug, Clone)] -pub struct PrecompilesProcessorWithHistory { +pub struct PrecompilesProcessorWithHistory { pub timestamp_history: HistoryRecorder, H>, - pub default_precompiles_processor: DefaultPrecompilesProcessor, + pub precompile_cycles_history: HistoryRecorder, H>, } -impl Default for PrecompilesProcessorWithHistory { +impl Default for PrecompilesProcessorWithHistory { fn default() -> Self { Self { timestamp_history: Default::default(), - default_precompiles_processor: DefaultPrecompilesProcessor, + precompile_cycles_history: Default::default(), } } } -impl OracleWithHistory for PrecompilesProcessorWithHistory { +impl OracleWithHistory for PrecompilesProcessorWithHistory { fn rollback_to_timestamp(&mut self, timestamp: Timestamp) { self.timestamp_history.rollback_to_timestamp(timestamp); + self.precompile_cycles_history + .rollback_to_timestamp(timestamp); } } -impl PrecompilesProcessorWithHistory { +impl PrecompilesProcessorWithHistory { pub fn get_timestamp_history(&self) -> &Vec { self.timestamp_history.inner() } pub fn delete_history(&mut self) { self.timestamp_history.delete_history(); + self.precompile_cycles_history.delete_history(); } } -impl PrecompilesProcessor for PrecompilesProcessorWithHistory { +impl PrecompilesProcessor for PrecompilesProcessorWithHistory { fn start_frame(&mut self) { - self.default_precompiles_processor.start_frame(); + // there are no precompiles to rollback, do nothing } + fn execute_precompile( &mut self, monotonic_cycle_counter: u32, @@ -60,13 +66,47 @@ impl PrecompilesProcessor for PrecompilesProcesso // where operations and timestamp have different types. self.timestamp_history .push(query.timestamp, query.timestamp); - self.default_precompiles_processor.execute_precompile( - monotonic_cycle_counter, - query, - memory, - ) + + let address_low = u16::from_le_bytes([query.address.0[19], query.address.0[18]]); + if let Ok(precompile_address) = PrecompileAddress::try_from(address_low) { + let rounds = match precompile_address { + PrecompileAddress::Keccak256 => { + // pure function call, non-revertable + keccak256::keccak256_rounds_function::( + monotonic_cycle_counter, + query, + memory, + ) + .0 + } + PrecompileAddress::SHA256 => { + // pure function call, non-revertable + sha256::sha256_rounds_function::( + monotonic_cycle_counter, + query, + memory, + ) + .0 + } + PrecompileAddress::Ecrecover => { + // pure function call, non-revertable + ecrecover::ecrecover_function::( + monotonic_cycle_counter, + query, + memory, + ) + .0 + } + }; + + self.precompile_cycles_history + .push((precompile_address, rounds), query.timestamp); + }; + + None } + fn finish_frame(&mut self, _panicked: bool) { - self.default_precompiles_processor.finish_frame(_panicked); + // there are no revertible precompile yes, so we are ok } } diff --git a/core/lib/multivm/src/versions/vm_latest/old_vm/utils.rs b/core/lib/multivm/src/versions/vm_latest/old_vm/utils.rs index 1dbe82a81d4f..6320c6bcb1fe 100644 --- a/core/lib/multivm/src/versions/vm_latest/old_vm/utils.rs +++ b/core/lib/multivm/src/versions/vm_latest/old_vm/utils.rs @@ -1,4 +1,4 @@ -use zk_evm_1_4_0::{ +use zk_evm_1_4_1::{ aux_structures::{MemoryPage, Timestamp}, vm_state::PrimitiveValue, zkevm_opcode_defs::{ @@ -7,7 +7,6 @@ use zk_evm_1_4_0::{ }, }; use zksync_state::WriteStorage; -use zksync_system_constants::L1_GAS_PER_PUBDATA_BYTE; use zksync_types::{Address, U256}; use crate::vm_latest::{ @@ -96,12 +95,6 @@ pub(crate) fn precompile_calls_count_after_timestamp( sorted_timestamps.len() - sorted_timestamps.partition_point(|t| *t < from_timestamp) } -pub(crate) fn eth_price_per_pubdata_byte(l1_gas_price: u64) -> u64 { - // This value will typically be a lot less than u64 - // unless the gas price on L1 goes beyond tens of millions of gwei - l1_gas_price * (L1_GAS_PER_PUBDATA_BYTE as u64) -} - pub(crate) fn vm_may_have_ended_inner( vm: &ZkSyncVmState, ) -> Option { @@ -122,7 +115,7 @@ pub(crate) fn vm_may_have_ended_inner( } (false, _) => None, (true, l) if l == outer_eh_location => { - // check r1,r2,r3 + // check `r1,r2,r3` if vm.local_state.flags.overflow_or_less_than_flag { Some(VmExecutionResult::Panic) } else { diff --git a/core/lib/multivm/src/versions/vm_latest/oracles/storage.rs b/core/lib/multivm/src/versions/vm_latest/oracles/storage.rs index 2b6b5988e06e..07ec473624bf 100644 --- a/core/lib/multivm/src/versions/vm_latest/oracles/storage.rs +++ b/core/lib/multivm/src/versions/vm_latest/oracles/storage.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use zk_evm_1_4_0::{ +use zk_evm_1_4_1::{ abstractions::{RefundType, RefundedAmounts, Storage as VmStorageOracle}, aux_structures::{LogQuery, Timestamp}, zkevm_opcode_defs::system_params::INITIAL_STORAGE_WRITE_PUBDATA_BYTES, @@ -12,17 +12,22 @@ use zksync_types::{ compression::compress_with_best_strategy, BYTES_PER_DERIVED_KEY, BYTES_PER_ENUMERATION_INDEX, }, - AccountTreeId, Address, StorageKey, StorageLogQuery, StorageLogQueryType, BOOTLOADER_ADDRESS, - U256, + AccountTreeId, Address, StorageKey, StorageLogQueryType, BOOTLOADER_ADDRESS, U256, }; use zksync_utils::u256_to_h256; -use crate::vm_latest::old_vm::{ - history_recorder::{ - AppDataFrameManagerWithHistory, HashMapHistoryEvent, HistoryEnabled, HistoryMode, - HistoryRecorder, StorageWrapper, VectorHistoryEvent, WithHistory, +use crate::{ + glue::GlueInto, + vm_latest::{ + old_vm::{ + history_recorder::{ + AppDataFrameManagerWithHistory, HashMapHistoryEvent, HistoryEnabled, HistoryMode, + HistoryRecorder, StorageWrapper, VectorHistoryEvent, WithHistory, + }, + oracles::OracleWithHistory, + }, + utils::logs::StorageLogQuery, }, - oracles::OracleWithHistory, }; // While the storage does not support different shards, it was decided to write the @@ -53,12 +58,17 @@ pub struct StorageOracle { pub(crate) paid_changes: HistoryRecorder, H>, // The map that contains all the first values read from storage for each slot. - // While formally it does not have to be rollbackable, we still do it to avoid memory bloat + // While formally it does not have to be capable of rolling back, we still do it to avoid memory bloat // for unused slots. pub(crate) initial_values: HistoryRecorder, H>, // Storage refunds that oracle has returned in `estimate_refunds_for_write`. pub(crate) returned_refunds: HistoryRecorder, H>, + + // Keeps track of storage keys that were ever written to. + pub(crate) written_keys: HistoryRecorder, HistoryEnabled>, + // Keeps track of storage keys that were ever read. + pub(crate) read_keys: HistoryRecorder, HistoryEnabled>, } impl OracleWithHistory for StorageOracle { @@ -69,6 +79,8 @@ impl OracleWithHistory for StorageOracle { self.paid_changes.rollback_to_timestamp(timestamp); self.initial_values.rollback_to_timestamp(timestamp); self.returned_refunds.rollback_to_timestamp(timestamp); + self.written_keys.rollback_to_timestamp(timestamp); + self.read_keys.rollback_to_timestamp(timestamp); } } @@ -81,6 +93,8 @@ impl StorageOracle { paid_changes: Default::default(), initial_values: Default::default(), returned_refunds: Default::default(), + written_keys: Default::default(), + read_keys: Default::default(), } } @@ -91,6 +105,8 @@ impl StorageOracle { self.paid_changes.delete_history(); self.initial_values.delete_history(); self.returned_refunds.delete_history(); + self.written_keys.delete_history(); + self.read_keys.delete_history(); } fn is_storage_key_free(&self, key: &StorageKey) -> bool { @@ -108,8 +124,12 @@ impl StorageOracle { } } - pub fn read_value(&mut self, mut query: LogQuery) -> LogQuery { + fn read_value(&mut self, mut query: LogQuery) -> LogQuery { let key = triplet_to_storage_key(query.shard_id, query.address, query.key); + + if !self.read_keys.inner().contains_key(&key) { + self.read_keys.insert(key, (), query.timestamp); + } let current_value = self.storage.read_from_storage(&key); query.read_value = current_value; @@ -118,7 +138,7 @@ impl StorageOracle { self.frames_stack.push_forward( Box::new(StorageLogQuery { - log_query: query, + log_query: query.glue_into(), log_type: StorageLogQueryType::Read, }), query.timestamp, @@ -127,8 +147,11 @@ impl StorageOracle { query } - pub fn write_value(&mut self, query: LogQuery) -> LogQuery { + fn write_value(&mut self, query: LogQuery) -> LogQuery { let key = triplet_to_storage_key(query.shard_id, query.address, query.key); + if !self.written_keys.inner().contains_key(&key) { + self.written_keys.insert(key, (), query.timestamp); + } let current_value = self.storage .write_to_storage(key, query.written_value, query.timestamp); @@ -143,7 +166,7 @@ impl StorageOracle { self.set_initial_value(&key, current_value, query.timestamp); let mut storage_log_query = StorageLogQuery { - log_query: query, + log_query: query.glue_into(), log_type: log_query_type, }; self.frames_stack @@ -194,7 +217,7 @@ impl StorageOracle { let required_pubdata = self.base_price_for_write(&key, first_slot_value, current_slot_value); - // We assume that "prepaid_for_slot" represents both the number of pubdata published and the number of bytes paid by the previous transactions + // We assume that `prepaid_for_slot` represents both the number of pubdata published and the number of bytes paid by the previous transactions // as they should be identical. let prepaid_for_slot = self .pre_paid_changes @@ -274,9 +297,9 @@ impl StorageOracle { ) -> &[Box] { let logs = self.frames_stack.forward().current_frame(); - // Select all of the last elements where l.log_query.timestamp >= from_timestamp. + // Select all of the last elements where `l.log_query.timestamp >= from_timestamp`. // Note, that using binary search here is dangerous, because the logs are not sorted by timestamp. - logs.rsplit(|l| l.log_query.timestamp < from_timestamp) + logs.rsplit(|l| l.log_query.timestamp < from_timestamp.glue_into()) .next() .unwrap_or(&[]) } @@ -322,6 +345,7 @@ impl VmStorageOracle for StorageOracle { _monotonic_cycle_counter: u32, mut query: LogQuery, ) -> LogQuery { + // ``` // tracing::trace!( // "execute partial query cyc {:?} addr {:?} key {:?}, rw {:?}, wr {:?}, tx {:?}", // _monotonic_cycle_counter, @@ -331,6 +355,7 @@ impl VmStorageOracle for StorageOracle { // query.written_value, // query.tx_number_in_block // ); + // ``` assert!(!query.rollback); if query.rw_flag { // The number of bytes that have been compensated by the user to perform this write @@ -411,7 +436,7 @@ impl VmStorageOracle for StorageOracle { } }; - let LogQuery { written_value, .. } = query.log_query; + let LogQuery { written_value, .. } = query.log_query.glue_into(); let key = triplet_to_storage_key( query.log_query.shard_id, query.log_query.address, @@ -425,7 +450,7 @@ impl VmStorageOracle for StorageOracle { ); // Additional validation that the current value was correct - // Unwrap is safe because the return value from write_inner is the previous value in this leaf. + // Unwrap is safe because the return value from `write_inner` is the previous value in this leaf. // It is impossible to set leaf value to `None` assert_eq!(current_value, written_value); } @@ -439,7 +464,7 @@ impl VmStorageOracle for StorageOracle { /// Returns the number of bytes needed to publish a slot. // Since we need to publish the state diffs onchain, for each of the updated storage slot -// we basically need to publish the following pair: (). +// we basically need to publish the following pair: `()`. // For key we use the following optimization: // - The first time we publish it, we use 32 bytes. // Then, we remember a 8-byte id for this slot and assign it to it. We call this initial write. diff --git a/core/lib/multivm/src/versions/vm_latest/tests/block_tip.rs b/core/lib/multivm/src/versions/vm_latest/tests/block_tip.rs new file mode 100644 index 000000000000..fc6a2f26d6e5 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_latest/tests/block_tip.rs @@ -0,0 +1,284 @@ +use std::borrow::BorrowMut; + +use ethabi::Token; +use zk_evm_1_4_1::{ + aux_structures::Timestamp, zkevm_opcode_defs::system_params::MAX_PUBDATA_PER_BLOCK, +}; +use zksync_contracts::load_sys_contract; +use zksync_system_constants::{ + CONTRACT_FORCE_DEPLOYER_ADDRESS, KNOWN_CODES_STORAGE_ADDRESS, L1_MESSENGER_ADDRESS, +}; +use zksync_types::{ + commitment::SerializeCommitment, get_code_key, l2_to_l1_log::L2ToL1Log, + writes::StateDiffRecord, Address, Execute, H256, U256, +}; +use zksync_utils::{bytecode::hash_bytecode, bytes_to_be_words, h256_to_u256, u256_to_h256}; + +use super::utils::{get_complex_upgrade_abi, read_complex_upgrade}; +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_latest::{ + constants::BOOTLOADER_BATCH_TIP_OVERHEAD, + tests::tester::{get_empty_storage, InMemoryStorageView, VmTesterBuilder}, + tracers::PubdataTracer, + HistoryEnabled, TracerDispatcher, + }, +}; + +#[derive(Debug, Clone, Default)] +struct L1MessengerTestData { + l2_to_l1_logs: usize, + messages: Vec>, + bytecodes: Vec>, + state_diffs: Vec, +} + +struct MimicCallInfo { + to: Address, + who_to_mimic: Address, + data: Vec, +} + +fn populate_mimic_calls(data: L1MessengerTestData) -> Vec { + let complex_upgrade = get_complex_upgrade_abi(); + let l1_messenger = load_sys_contract("L1Messenger"); + + let logs_mimic_calls = (0..data.l2_to_l1_logs).map(|_| MimicCallInfo { + to: L1_MESSENGER_ADDRESS, + who_to_mimic: KNOWN_CODES_STORAGE_ADDRESS, + data: l1_messenger + .function("sendL2ToL1Log") + .unwrap() + .encode_input(&[ + Token::Bool(false), + Token::FixedBytes(H256::random().0.to_vec()), + Token::FixedBytes(H256::random().0.to_vec()), + ]) + .unwrap(), + }); + let messages_mimic_calls = data.messages.iter().map(|message| MimicCallInfo { + to: L1_MESSENGER_ADDRESS, + who_to_mimic: KNOWN_CODES_STORAGE_ADDRESS, + data: l1_messenger + .function("sendToL1") + .unwrap() + .encode_input(&[Token::Bytes(message.clone())]) + .unwrap(), + }); + let bytecodes_mimic_calls = data.bytecodes.iter().map(|bytecode| MimicCallInfo { + to: L1_MESSENGER_ADDRESS, + who_to_mimic: KNOWN_CODES_STORAGE_ADDRESS, + data: l1_messenger + .function("requestBytecodeL1Publication") + .unwrap() + .encode_input(&[Token::FixedBytes(hash_bytecode(bytecode).0.to_vec())]) + .unwrap(), + }); + + let encoded_calls = logs_mimic_calls + .chain(messages_mimic_calls) + .chain(bytecodes_mimic_calls) + .map(|call| { + Token::Tuple(vec![ + Token::Address(call.to), + Token::Address(call.who_to_mimic), + Token::Bytes(call.data), + ]) + }) + .collect::>(); + + complex_upgrade + .function("mimicCalls") + .unwrap() + .encode_input(&[Token::Array(encoded_calls)]) + .unwrap() +} + +fn execute_test(test_data: L1MessengerTestData) -> u32 { + let mut storage = get_empty_storage(); + let complex_upgrade_code = read_complex_upgrade(); + + // For this test we'll just put the bytecode onto the force deployer address + storage.borrow_mut().set_value( + get_code_key(&CONTRACT_FORCE_DEPLOYER_ADDRESS), + hash_bytecode(&complex_upgrade_code), + ); + storage + .borrow_mut() + .store_factory_dep(hash_bytecode(&complex_upgrade_code), complex_upgrade_code); + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_storage(storage) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let bytecodes = test_data + .bytecodes + .iter() + .map(|bytecode| { + let hash = hash_bytecode(bytecode); + let words = bytes_to_be_words(bytecode.clone()); + (h256_to_u256(hash), words) + }) + .collect(); + vm.vm + .state + .decommittment_processor + .populate(bytecodes, Timestamp(0)); + + let data = populate_mimic_calls(test_data.clone()); + let account = &mut vm.rich_accounts[0]; + let tx = account.get_l2_tx_for_execute( + Execute { + contract_address: CONTRACT_FORCE_DEPLOYER_ADDRESS, + calldata: data, + value: U256::zero(), + factory_deps: None, + }, + None, + ); + + vm.vm.push_transaction(tx); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert!(!result.result.is_failed(), "Transaction wasn't successful"); + + // Now we count how much ergs were spent at the end of the batch + // It is assumed that the top level frame is the bootloader + + let ergs_before = vm.vm.state.local_state.callstack.current.ergs_remaining; + + // We ensure that indeed the provided state diffs are used + let pubdata_tracer = PubdataTracer::::new_with_forced_state_diffs( + vm.vm.batch_env.clone(), + VmExecutionMode::Batch, + test_data.state_diffs, + ); + + let result = vm.vm.inspect_inner( + TracerDispatcher::default(), + VmExecutionMode::Batch, + Some(pubdata_tracer), + ); + + assert!(!result.result.is_failed(), "Batch wasn't successful"); + + let ergs_after = vm.vm.state.local_state.callstack.current.ergs_remaining; + + ergs_before - ergs_after +} + +fn generate_state_diffs( + repeated_writes: bool, + small_diff: bool, + number_of_state_diffs: usize, +) -> Vec { + (0..number_of_state_diffs) + .map(|i| { + let address = Address::from_low_u64_be(i as u64); + let key = U256::from(i); + let enumeration_index = if repeated_writes { i + 1 } else { 0 }; + + let (initial_value, final_value) = if small_diff { + // As small as it gets, one byte to denote zeroing out the value + (U256::from(1), U256::from(0)) + } else { + // As large as it gets + (U256::from(0), U256::from(2).pow(255.into())) + }; + + StateDiffRecord { + address, + key, + derived_key: u256_to_h256(i.into()).0, + enumeration_index: enumeration_index as u64, + initial_value, + final_value, + } + }) + .collect() +} + +#[test] +fn test_dry_run_upper_bound() { + // We are re-using the `ComplexUpgrade` contract as it already has the `mimicCall` functionality. + // To get the upper bound, we'll try to do the following: + // 1. Max number of logs. + // 2. Lots of small L2->L1 messages / one large L2->L1 message. + // 3. Lots of small bytecodes / one large bytecode. + // 4. Lots of storage slot updates. + + let max_logs = execute_test(L1MessengerTestData { + l2_to_l1_logs: L2ToL1Log::MIN_L2_L1_LOGS_TREE_SIZE, + ..Default::default() + }); + + let max_messages = execute_test(L1MessengerTestData { + // Each L2->L1 message is accompanied by a Log, so the max number of pubdata is bound by it + messages: vec![vec![0; 0]; MAX_PUBDATA_PER_BLOCK as usize / L2ToL1Log::SERIALIZED_SIZE], + ..Default::default() + }); + + let long_message = execute_test(L1MessengerTestData { + // Each L2->L1 message is accompanied by a Log, so the max number of pubdata is bound by it + messages: vec![vec![0; MAX_PUBDATA_PER_BLOCK as usize]; 1], + ..Default::default() + }); + + let max_bytecodes = execute_test(L1MessengerTestData { + // Each bytecode must be at least 32 bytes long + bytecodes: vec![vec![0; 32]; MAX_PUBDATA_PER_BLOCK as usize / 32], + ..Default::default() + }); + + let long_bytecode = execute_test(L1MessengerTestData { + // We have to add 48 since a valid bytecode must have an odd number of 32 byte words + bytecodes: vec![vec![0; MAX_PUBDATA_PER_BLOCK as usize + 48]; 1], + ..Default::default() + }); + + let lots_of_small_repeated_writes = execute_test(L1MessengerTestData { + // In theory each state diff can require only 5 bytes to be published (enum index + 4 bytes for the key) + state_diffs: generate_state_diffs(true, true, MAX_PUBDATA_PER_BLOCK as usize / 5), + ..Default::default() + }); + + let lots_of_big_repeated_writes = execute_test(L1MessengerTestData { + // Each big write will approximately require 32 bytes to encode + state_diffs: generate_state_diffs(true, false, MAX_PUBDATA_PER_BLOCK as usize / 32), + ..Default::default() + }); + + let lots_of_small_initial_writes = execute_test(L1MessengerTestData { + // Each initial write will take at least 32 bytes for derived key + 5 bytes for value + state_diffs: generate_state_diffs(false, true, MAX_PUBDATA_PER_BLOCK as usize / 37), + ..Default::default() + }); + + let lots_of_large_initial_writes = execute_test(L1MessengerTestData { + // Each big write will take at least 32 bytes for derived key + 32 bytes for value + state_diffs: generate_state_diffs(false, false, MAX_PUBDATA_PER_BLOCK as usize / 64), + ..Default::default() + }); + + let max_used_gas = vec![ + max_logs, + max_messages, + long_message, + max_bytecodes, + long_bytecode, + lots_of_small_repeated_writes, + lots_of_big_repeated_writes, + lots_of_small_initial_writes, + lots_of_large_initial_writes, + ] + .into_iter() + .max() + .unwrap(); + + // We use 2x overhead for the batch tip compared to the worst estimated scenario. + assert!( + max_used_gas * 2 <= BOOTLOADER_BATCH_TIP_OVERHEAD, + "BOOTLOADER_BATCH_TIP_OVERHEAD is too low" + ); +} diff --git a/core/lib/multivm/src/versions/vm_latest/tests/circuits.rs b/core/lib/multivm/src/versions/vm_latest/tests/circuits.rs new file mode 100644 index 000000000000..3821817135b0 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_latest/tests/circuits.rs @@ -0,0 +1,69 @@ +use zksync_types::{Address, Execute, U256}; + +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_latest::{constants::BLOCK_GAS_LIMIT, tests::tester::VmTesterBuilder, HistoryEnabled}, +}; + +// Checks that estimated number of circuits for simple transfer doesn't differ much +// from hardcoded expected value. +#[test] +fn test_circuits() { + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_random_rich_accounts(1) + .with_deployer() + .with_gas_limit(BLOCK_GAS_LIMIT) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .build(); + + let account = &mut vm.rich_accounts[0]; + let tx = account.get_l2_tx_for_execute( + Execute { + contract_address: Address::random(), + calldata: Vec::new(), + value: U256::from(1u8), + factory_deps: None, + }, + None, + ); + vm.vm.push_transaction(tx); + let res = vm.vm.inspect(Default::default(), VmExecutionMode::OneTx); + + let s = res.statistics.circuit_statistic; + // Check `circuit_statistic`. + const EXPECTED: [f32; 11] = [ + 1.1979, 0.1390, 1.5455, 0.0031, 1.0573, 0.00059, 0.00226, 0.00077, 0.1195, 0.1429, 0.0, + ]; + let actual = [ + (s.main_vm, "main_vm"), + (s.ram_permutation, "ram_permutation"), + (s.storage_application, "storage_application"), + (s.storage_sorter, "storage_sorter"), + (s.code_decommitter, "code_decommitter"), + (s.code_decommitter_sorter, "code_decommitter_sorter"), + (s.log_demuxer, "log_demuxer"), + (s.events_sorter, "events_sorter"), + (s.keccak256, "keccak256"), + (s.ecrecover, "ecrecover"), + (s.sha256, "sha256"), + ]; + for ((actual, name), expected) in actual.iter().zip(EXPECTED) { + if expected == 0.0 { + assert_eq!( + *actual, expected, + "Check failed for {}, expected {}, actual {}", + name, expected, actual + ); + } else { + let diff = (actual - expected) / expected; + assert!( + diff.abs() < 0.1, + "Check failed for {}, expected {}, actual {}", + name, + expected, + actual + ); + } + } +} diff --git a/core/lib/multivm/src/versions/vm_latest/tests/default_aa.rs b/core/lib/multivm/src/versions/vm_latest/tests/default_aa.rs index 7c951e313210..05e3e64f9c9a 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/default_aa.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/default_aa.rs @@ -13,6 +13,7 @@ use crate::{ tester::{DeployContractsTx, TxType, VmTesterBuilder}, utils::{get_balance, read_test_contract, verify_required_storage}, }, + utils::fee::get_batch_base_fee, HistoryEnabled, }, }; @@ -34,7 +35,7 @@ fn test_default_aa_interaction() { bytecode_hash, address, } = account.get_deploy_tx(&counter, None, TxType::L2); - let maximal_fee = tx.gas_limit() * vm.vm.batch_env.base_fee(); + let maximal_fee = tx.gas_limit() * get_batch_base_fee(&vm.vm.batch_env); vm.vm.push_transaction(tx); let result = vm.vm.execute(VmExecutionMode::OneTx); @@ -62,7 +63,8 @@ fn test_default_aa_interaction() { verify_required_storage(&vm.vm.state, expected_slots); let expected_fee = maximal_fee - - U256::from(result.refunds.gas_refunded) * U256::from(vm.vm.batch_env.base_fee()); + - U256::from(result.refunds.gas_refunded) + * U256::from(get_batch_base_fee(&vm.vm.batch_env)); let operator_balance = get_balance( AccountTreeId::new(L2_ETH_TOKEN_ADDRESS), &vm.fee_account, diff --git a/core/lib/multivm/src/versions/vm_latest/tests/get_used_contracts.rs b/core/lib/multivm/src/versions/vm_latest/tests/get_used_contracts.rs index b82057bef8b7..38a4d7cbb43c 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/get_used_contracts.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/get_used_contracts.rs @@ -29,7 +29,7 @@ fn test_get_used_contracts() { assert!(known_bytecodes_without_aa_code(&vm.vm).is_empty()); // create and push and execute some not-empty factory deps transaction with success status - // to check that get_used_contracts() updates + // to check that `get_used_contracts()` updates let contract_code = read_test_contract(); let mut account = Account::random(); let tx = account.get_deploy_tx(&contract_code, None, TxType::L1 { serial_id: 0 }); @@ -42,7 +42,7 @@ fn test_get_used_contracts() { .get_used_contracts() .contains(&h256_to_u256(tx.bytecode_hash))); - // Note: Default_AA will be in the list of used contracts if l2 tx is used + // Note: `Default_AA` will be in the list of used contracts if L2 tx is used assert_eq!( vm.vm .get_used_contracts() @@ -55,7 +55,7 @@ fn test_get_used_contracts() { ); // create push and execute some non-empty factory deps transaction that fails - // (known_bytecodes will be updated but we expect get_used_contracts() to not be updated) + // (`known_bytecodes` will be updated but we expect `get_used_contracts()` to not be updated) let calldata = [1, 2, 3]; let big_calldata: Vec = calldata diff --git a/core/lib/multivm/src/versions/vm_latest/tests/l1_tx_execution.rs b/core/lib/multivm/src/versions/vm_latest/tests/l1_tx_execution.rs index 4f61dd90fad7..fe2987d76ac5 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/l1_tx_execution.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/l1_tx_execution.rs @@ -1,9 +1,11 @@ -use zksync_system_constants::BOOTLOADER_ADDRESS; +use ethabi::Token; +use zksync_contracts::l1_messenger_contract; +use zksync_system_constants::{BOOTLOADER_ADDRESS, L1_MESSENGER_ADDRESS}; use zksync_types::{ get_code_key, get_known_code_key, l2_to_l1_log::{L2ToL1Log, UserL2ToL1Log}, storage_writes_deduplicator::StorageWritesDeduplicator, - U256, + Execute, ExecuteTransactionCommon, U256, }; use zksync_utils::u256_to_h256; @@ -26,13 +28,13 @@ fn test_l1_tx_execution() { // using L1->L2 communication, the same it would likely be done during the priority mode. // There are always at least 7 initial writes here, because we pay fees from l1: - // - totalSupply of ETH token + // - `totalSupply` of ETH token // - balance of the refund recipient // - balance of the bootloader - // - tx_rolling hash + // - `tx_rolling` hash // - rolling hash of L2->L1 logs // - transaction number in block counter - // - L2->L1 log counter in L1Messenger + // - L2->L1 log counter in `L1Messenger` // TODO(PLA-537): right now we are using 4 slots instead of 7 due to 0 fee for transaction. let basic_initial_writes = 4; @@ -137,3 +139,51 @@ fn test_l1_tx_execution() { // There are only basic initial writes assert_eq!(res.initial_storage_writes - basic_initial_writes, 2); } + +#[test] +fn test_l1_tx_execution_high_gas_limit() { + // In this test, we try to execute an L1->L2 transaction with a high gas limit. + // Usually priority transactions with dangerously gas limit should even pass the checks on the L1, + // however, they might pass during the transition period to the new fee model, so we check that we can safely process those. + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_base_system_smart_contracts(BASE_SYSTEM_CONTRACTS.clone()) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let account = &mut vm.rich_accounts[0]; + + let l1_messenger = l1_messenger_contract(); + + let contract_function = l1_messenger.function("sendToL1").unwrap(); + let params = [ + // Even a message of size 100k should not be able to be sent by a priority transaction + Token::Bytes(vec![0u8; 100_000]), + ]; + let calldata = contract_function.encode_input(¶ms).unwrap(); + + let mut tx = account.get_l1_tx( + Execute { + contract_address: L1_MESSENGER_ADDRESS, + value: 0.into(), + factory_deps: None, + calldata, + }, + 0, + ); + + if let ExecuteTransactionCommon::L1(data) = &mut tx.common_data { + // Using some large gas limit + data.gas_limit = 300_000_000.into(); + } else { + unreachable!() + }; + + vm.vm.push_transaction(tx); + + let res = vm.vm.execute(VmExecutionMode::OneTx); + + assert!(res.result.is_failed(), "The transaction should've failed"); +} diff --git a/core/lib/multivm/src/versions/vm_latest/tests/l2_blocks.rs b/core/lib/multivm/src/versions/vm_latest/tests/l2_blocks.rs index 1faeba9652f9..d103ebf7ebcb 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/l2_blocks.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/l2_blocks.rs @@ -3,7 +3,7 @@ //! The description for each of the tests can be found in the corresponding `.yul` file. //! -use zk_evm_1_4_0::aux_structures::Timestamp; +use zk_evm_1_4_1::aux_structures::Timestamp; use zksync_state::WriteStorage; use zksync_system_constants::REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE; use zksync_types::{ diff --git a/core/lib/multivm/src/versions/vm_latest/tests/mod.rs b/core/lib/multivm/src/versions/vm_latest/tests/mod.rs index ffb38dd3725a..a07608121bc1 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/mod.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/mod.rs @@ -1,15 +1,18 @@ mod bootloader; mod default_aa; // TODO - fix this test -// mod invalid_bytecode; +// `mod invalid_bytecode;` +mod block_tip; mod bytecode_publishing; mod call_tracer; +mod circuits; mod gas_limit; mod get_used_contracts; mod is_write_initial; mod l1_tx_execution; mod l2_blocks; mod nonce_holder; +mod precompiles; mod refunds; mod require_eip712; mod rollbacks; diff --git a/core/lib/multivm/src/versions/vm_latest/tests/nonce_holder.rs b/core/lib/multivm/src/versions/vm_latest/tests/nonce_holder.rs index 2de5e23bdd23..309e26120af3 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/nonce_holder.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/nonce_holder.rs @@ -59,7 +59,7 @@ fn test_nonce_holder() { comment: &'static str| { // In this test we have to reset VM state after each test case. Because once bootloader failed during the validation of the transaction, // it will fail again and again. At the same time we have to keep the same storage, because we want to keep the nonce holder contract state. - // The easiest way in terms of lifetimes is to reuse vm_builder to achieve it. + // The easiest way in terms of lifetimes is to reuse `vm_builder` to achieve it. vm.reset_state(true); let mut transaction_data: TransactionData = account .get_l2_tx_for_execute_with_nonce( diff --git a/core/lib/multivm/src/versions/vm_latest/tests/precompiles.rs b/core/lib/multivm/src/versions/vm_latest/tests/precompiles.rs new file mode 100644 index 000000000000..8556b17fd5bb --- /dev/null +++ b/core/lib/multivm/src/versions/vm_latest/tests/precompiles.rs @@ -0,0 +1,136 @@ +use zk_evm_1_4_1::zk_evm_abstractions::precompiles::PrecompileAddress; +use zksync_types::{Address, Execute}; + +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_latest::{ + constants::BLOCK_GAS_LIMIT, + tests::{tester::VmTesterBuilder, utils::read_precompiles_contract}, + HistoryEnabled, + }, +}; + +#[test] +fn test_keccak() { + // Execute special transaction and check that at least 1000 keccak calls were made. + let contract = read_precompiles_contract(); + let address = Address::random(); + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_random_rich_accounts(1) + .with_deployer() + .with_gas_limit(BLOCK_GAS_LIMIT) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_custom_contracts(vec![(contract, address, true)]) + .build(); + + // calldata for `doKeccak(1000)`. + let keccak1000_calldata = + "370f20ac00000000000000000000000000000000000000000000000000000000000003e8"; + + let account = &mut vm.rich_accounts[0]; + let tx = account.get_l2_tx_for_execute( + Execute { + contract_address: address, + calldata: hex::decode(keccak1000_calldata).unwrap(), + value: Default::default(), + factory_deps: None, + }, + None, + ); + vm.vm.push_transaction(tx); + let _ = vm.vm.inspect(Default::default(), VmExecutionMode::OneTx); + + let keccak_count = vm + .vm + .state + .precompiles_processor + .precompile_cycles_history + .inner() + .iter() + .filter(|(precompile, _)| precompile == &PrecompileAddress::Keccak256) + .count(); + + assert!(keccak_count >= 1000); +} + +#[test] +fn test_sha256() { + // Execute special transaction and check that at least 1000 `sha256` calls were made. + let contract = read_precompiles_contract(); + let address = Address::random(); + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_random_rich_accounts(1) + .with_deployer() + .with_gas_limit(BLOCK_GAS_LIMIT) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_custom_contracts(vec![(contract, address, true)]) + .build(); + + // calldata for `doSha256(1000)`. + let sha1000_calldata = + "5d0b4fb500000000000000000000000000000000000000000000000000000000000003e8"; + + let account = &mut vm.rich_accounts[0]; + let tx = account.get_l2_tx_for_execute( + Execute { + contract_address: address, + calldata: hex::decode(sha1000_calldata).unwrap(), + value: Default::default(), + factory_deps: None, + }, + None, + ); + vm.vm.push_transaction(tx); + let _ = vm.vm.inspect(Default::default(), VmExecutionMode::OneTx); + + let sha_count = vm + .vm + .state + .precompiles_processor + .precompile_cycles_history + .inner() + .iter() + .filter(|(precompile, _)| precompile == &PrecompileAddress::SHA256) + .count(); + + assert!(sha_count >= 1000); +} + +#[test] +fn test_ecrecover() { + // Execute simple transfer and check that exactly 1 `ecrecover` call was made (it's done during tx validation). + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_random_rich_accounts(1) + .with_deployer() + .with_gas_limit(BLOCK_GAS_LIMIT) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .build(); + + let account = &mut vm.rich_accounts[0]; + let tx = account.get_l2_tx_for_execute( + Execute { + contract_address: account.address, + calldata: Vec::new(), + value: Default::default(), + factory_deps: None, + }, + None, + ); + vm.vm.push_transaction(tx); + let _ = vm.vm.inspect(Default::default(), VmExecutionMode::OneTx); + + let ecrecover_count = vm + .vm + .state + .precompiles_processor + .precompile_cycles_history + .inner() + .iter() + .filter(|(precompile, _)| precompile == &PrecompileAddress::Ecrecover) + .count(); + + assert_eq!(ecrecover_count, 1); +} diff --git a/core/lib/multivm/src/versions/vm_latest/tests/refunds.rs b/core/lib/multivm/src/versions/vm_latest/tests/refunds.rs index dc1f4fe55bca..5662ee1fd665 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/refunds.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/refunds.rs @@ -60,9 +60,8 @@ fn test_predetermined_refunded_gas() { .build(); let tx: TransactionData = tx.into(); - let block_gas_per_pubdata_byte = vm.vm.batch_env.block_gas_price_per_pubdata(); // Overhead - let overhead = tx.overhead_gas(block_gas_per_pubdata_byte as u32); + let overhead = tx.overhead_gas(); vm.vm .push_raw_transaction(tx.clone(), overhead, result.refunds.gas_refunded, true); diff --git a/core/lib/multivm/src/versions/vm_latest/tests/require_eip712.rs b/core/lib/multivm/src/versions/vm_latest/tests/require_eip712.rs index c03e5fe64212..de4f27436afb 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/require_eip712.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/require_eip712.rs @@ -37,8 +37,8 @@ impl VmTester { /// Currently we support both, but in the future, we should allow only EIP712 transactions to access the AA accounts. async fn test_require_eip712() { // Use 3 accounts: - // - private_address - EOA account, where we have the key - // - account_address - AA account, where the contract is deployed + // - `private_address` - EOA account, where we have the key + // - `account_address` - AA account, where the contract is deployed // - beneficiary - an EOA account, where we'll try to transfer the tokens. let account_abstraction = Account::random(); let mut private_account = Account::random(); @@ -56,8 +56,8 @@ async fn test_require_eip712() { let chain_id: u32 = 270; - // First, let's set the owners of the AA account to the private_address. - // (so that messages signed by private_address, are authorized to act on behalf of the AA account). + // First, let's set the owners of the AA account to the `private_address`. + // (so that messages signed by `private_address`, are authorized to act on behalf of the AA account). let set_owners_function = contract.function("setOwners").unwrap(); let encoded_input = set_owners_function .encode_input(&[Token::Array(vec![Token::Address(private_account.address)])]) diff --git a/core/lib/multivm/src/versions/vm_latest/tests/rollbacks.rs b/core/lib/multivm/src/versions/vm_latest/tests/rollbacks.rs index 23c1ab49ad98..188941d74d77 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/rollbacks.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/rollbacks.rs @@ -5,7 +5,7 @@ use zksync_types::{get_nonce_key, Execute, U256}; use crate::{ interface::{ - dyn_tracers::vm_1_4_0::DynTracer, + dyn_tracers::vm_1_4_1::DynTracer, tracer::{TracerExecutionStatus, TracerExecutionStopReason}, TxExecutionMode, VmExecutionMode, VmInterface, VmInterfaceHistoryEnabled, }, diff --git a/core/lib/multivm/src/versions/vm_latest/tests/tester/inner_state.rs b/core/lib/multivm/src/versions/vm_latest/tests/tester/inner_state.rs index b82e995c2db3..dbe0afa33fa1 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/tester/inner_state.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/tester/inner_state.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use zk_evm_1_4_0::{aux_structures::Timestamp, vm_state::VmLocalState}; +use zk_evm_1_4_1::{aux_structures::Timestamp, vm_state::VmLocalState}; use zksync_state::WriteStorage; -use zksync_types::{StorageKey, StorageLogQuery, StorageValue, U256}; +use zksync_types::{StorageKey, StorageValue, U256}; use crate::{ vm_latest::{ @@ -10,6 +10,7 @@ use crate::{ event_sink::InMemoryEventSink, history_recorder::{AppDataFrameManagerWithHistory, HistoryRecorder}, }, + utils::logs::StorageLogQuery, HistoryEnabled, HistoryMode, SimpleMemory, Vm, }, HistoryMode as CommonHistoryMode, @@ -78,7 +79,7 @@ pub(crate) struct VmInstanceInnerState { impl Vm { // Dump inner state of the VM. - pub(crate) fn dump_inner_state(&self) -> VmInstanceInnerState { + pub(crate) fn dump_inner_state(&self) -> VmInstanceInnerState { let event_sink = self.state.event_sink.clone(); let precompile_processor_state = PrecompileProcessorTestInnerState { timestamp_history: self.state.precompiles_processor.timestamp_history.clone(), diff --git a/core/lib/multivm/src/versions/vm_latest/tests/tester/mod.rs b/core/lib/multivm/src/versions/vm_latest/tests/tester/mod.rs index dfe8905a7e08..c3cc5d8d9803 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/tester/mod.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/tester/mod.rs @@ -1,5 +1,7 @@ pub(crate) use transaction_test_info::{ExpectedError, TransactionTestInfo, TxModifier}; -pub(crate) use vm_tester::{default_l1_batch, InMemoryStorageView, VmTester, VmTesterBuilder}; +pub(crate) use vm_tester::{ + default_l1_batch, get_empty_storage, InMemoryStorageView, VmTester, VmTesterBuilder, +}; pub(crate) use zksync_test_account::{Account, DeployContractsTx, TxType}; mod inner_state; diff --git a/core/lib/multivm/src/versions/vm_latest/tests/tester/vm_tester.rs b/core/lib/multivm/src/versions/vm_latest/tests/tester/vm_tester.rs index 25f1361f14d0..0220ba4fc4d5 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/tester/vm_tester.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/tester/vm_tester.rs @@ -4,6 +4,7 @@ use zksync_contracts::BaseSystemContracts; use zksync_state::{InMemoryStorage, StoragePtr, StorageView, WriteStorage}; use zksync_types::{ block::MiniblockHasher, + fee_model::BatchFeeInput, get_code_key, get_is_account_key, helpers::unix_timestamp_ms, utils::{deployed_address_create, storage_key_for_eth_balance}, @@ -76,7 +77,7 @@ impl VmTester { if !self.custom_contracts.is_empty() { println!("Inserting custom contracts is not yet supported") - // insert_contracts(&mut self.storage, &self.custom_contracts); + // `insert_contracts(&mut self.storage, &self.custom_contracts);` } let mut l1_batch = self.vm.batch_env.clone(); @@ -251,8 +252,10 @@ pub(crate) fn default_l1_batch(number: L1BatchNumber) -> L1BatchEnv { previous_batch_hash: None, number, timestamp, - l1_gas_price: 50_000_000_000, // 50 gwei - fair_l2_gas_price: 250_000_000, // 0.25 gwei + fee_input: BatchFeeInput::l1_pegged( + 50_000_000_000, // 50 gwei + 250_000_000, // 0.25 gwei + ), fee_account: Address::random(), enforced_base_fee: None, first_l2_block: L2BlockEnv { diff --git a/core/lib/multivm/src/versions/vm_latest/tests/upgrade.rs b/core/lib/multivm/src/versions/vm_latest/tests/upgrade.rs index b5c493ca7075..8ab728e8ce38 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/upgrade.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/upgrade.rs @@ -1,5 +1,5 @@ -use zk_evm_1_4_0::aux_structures::Timestamp; -use zksync_contracts::{deployer_contract, load_contract, load_sys_contract, read_bytecode}; +use zk_evm_1_4_1::aux_structures::Timestamp; +use zksync_contracts::{deployer_contract, load_sys_contract, read_bytecode}; use zksync_state::WriteStorage; use zksync_test_account::TxType; use zksync_types::{ @@ -12,14 +12,17 @@ use zksync_types::{ }; use zksync_utils::{bytecode::hash_bytecode, bytes_to_be_words, h256_to_u256, u256_to_h256}; -use super::utils::read_test_contract; +use super::utils::{get_complex_upgrade_abi, read_test_contract}; use crate::{ interface::{ ExecutionResult, Halt, TxExecutionMode, VmExecutionMode, VmInterface, VmInterfaceHistoryEnabled, }, vm_latest::{ - tests::{tester::VmTesterBuilder, utils::verify_required_storage}, + tests::{ + tester::VmTesterBuilder, + utils::{read_complex_upgrade, verify_required_storage}, + }, HistoryEnabled, }, }; @@ -45,7 +48,7 @@ fn test_protocol_upgrade_is_first() { let protocol_upgrade_transaction = get_forced_deploy_tx(&[ForceDeployment { // The bytecode hash to put on an address bytecode_hash, - // The address on which to deploy the bytecodehash to + // The address on which to deploy the bytecode hash to address: H160::random(), // Whether to run the constructor on the force deployment call_constructor: false, @@ -59,7 +62,7 @@ fn test_protocol_upgrade_is_first() { let another_protocol_upgrade_transaction = get_forced_deploy_tx(&[ForceDeployment { // The bytecode hash to put on an address bytecode_hash, - // The address on which to deploy the bytecodehash to + // The address on which to deploy the bytecode hash to address: H160::random(), // Whether to run the constructor on the force deployment call_constructor: false, @@ -141,7 +144,7 @@ fn test_force_deploy_upgrade() { let transaction = get_forced_deploy_tx(&[ForceDeployment { // The bytecode hash to put on an address bytecode_hash, - // The address on which to deploy the bytecodehash to + // The address on which to deploy the bytecode hash to address: address_to_deploy, // Whether to run the constructor on the force deployment call_constructor: false, @@ -180,7 +183,7 @@ fn test_complex_upgrader() { let msg_sender_test_hash = hash_bytecode(&read_msg_sender_test()); // Let's assume that the bytecode for the implementation of the complex upgrade - // is already deployed in some address in userspace + // is already deployed in some address in user space let upgrade_impl = H160::random(); let account_code_key = get_code_key(&upgrade_impl); @@ -240,7 +243,7 @@ fn test_complex_upgrader() { struct ForceDeployment { // The bytecode hash to put on an address bytecode_hash: H256, - // The address on which to deploy the bytecodehash to + // The address on which to deploy the bytecode hash to address: Address, // Whether to run the constructor on the force deployment call_constructor: bool, @@ -295,8 +298,8 @@ fn get_forced_deploy_tx(deployment: &[ForceDeployment]) -> Transaction { // Returns the transaction that performs a complex protocol upgrade. // The first param is the address of the implementation of the complex upgrade -// in user-space, while the next 3 params are params of the implenentaiton itself -// For the explanatation for the parameters, please refer to: +// in user-space, while the next 3 params are params of the implementation itself +// For the explanation for the parameters, please refer to: // etc/contracts-test-data/complex-upgrade/complex-upgrade.sol fn get_complex_upgrade_tx( implementation_address: Address, @@ -343,20 +346,10 @@ fn get_complex_upgrade_tx( } } -fn read_complex_upgrade() -> Vec { - read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/complex-upgrade/complex-upgrade.sol/ComplexUpgrade.json") -} - fn read_msg_sender_test() -> Vec { read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/complex-upgrade/msg-sender.sol/MsgSenderTest.json") } -fn get_complex_upgrade_abi() -> Contract { - load_contract( - "etc/contracts-test-data/artifacts-zk/contracts/complex-upgrade/complex-upgrade.sol/ComplexUpgrade.json" - ) -} - fn get_complex_upgrader_abi() -> Contract { load_sys_contract("ComplexUpgrader") } diff --git a/core/lib/multivm/src/versions/vm_latest/tests/utils.rs b/core/lib/multivm/src/versions/vm_latest/tests/utils.rs index 6d3c5b32c05f..80d59ab709f5 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/utils.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/utils.rs @@ -60,8 +60,8 @@ pub(crate) fn read_test_contract() -> Vec { pub(crate) fn get_bootloader(test: &str) -> SystemContractCode { let bootloader_code = read_zbin_bytecode(format!( - "contracts/system-contracts/bootloader/tests/artifacts/{}.yul/{}.yul.zbin", - test, test + "contracts/system-contracts/bootloader/tests/artifacts/{}.yul.zbin", + test )); let bootloader_hash = hash_bytecode(&bootloader_code); @@ -103,3 +103,19 @@ pub(crate) fn read_max_depth_contract() -> Vec { "core/tests/ts-integration/contracts/zkasm/artifacts/deep_stak.zkasm/deep_stak.zkasm.zbin", ) } + +pub(crate) fn read_precompiles_contract() -> Vec { + read_bytecode( + "etc/contracts-test-data/artifacts-zk/contracts/precompiles/precompiles.sol/Precompiles.json", + ) +} + +pub(crate) fn read_complex_upgrade() -> Vec { + read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/complex-upgrade/complex-upgrade.sol/ComplexUpgrade.json") +} + +pub(crate) fn get_complex_upgrade_abi() -> Contract { + load_contract( + "etc/contracts-test-data/artifacts-zk/contracts/complex-upgrade/complex-upgrade.sol/ComplexUpgrade.json" + ) +} diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/circuits_capacity.rs b/core/lib/multivm/src/versions/vm_latest/tracers/circuits_capacity.rs new file mode 100644 index 000000000000..422294dd2065 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_latest/tracers/circuits_capacity.rs @@ -0,0 +1,67 @@ +use zkevm_test_harness_1_4_1::{geometry_config::get_geometry_config, toolset::GeometryConfig}; +use zksync_types::circuit::{CircuitCycleStatistic, CircuitStatistic}; + +// "Rich addressing" opcodes are opcodes that can write their return value/read the input onto the stack +// and so take 1-2 RAM permutations more than an average opcode. +// In the worst case, a rich addressing may take 3 ram permutations +// (1 for reading the opcode, 1 for writing input value, 1 for writing output value). +pub(crate) const RICH_ADDRESSING_OPCODE_RAM_CYCLES: u32 = 3; + +pub(crate) const AVERAGE_OPCODE_RAM_CYCLES: u32 = 1; + +pub(crate) const STORAGE_READ_RAM_CYCLES: u32 = 1; +pub(crate) const STORAGE_READ_LOG_DEMUXER_CYCLES: u32 = 1; +pub(crate) const STORAGE_READ_STORAGE_SORTER_CYCLES: u32 = 1; +pub(crate) const STORAGE_READ_STORAGE_APPLICATION_CYCLES: u32 = 1; + +pub(crate) const EVENT_RAM_CYCLES: u32 = 1; +pub(crate) const EVENT_LOG_DEMUXER_CYCLES: u32 = 2; +pub(crate) const EVENT_EVENTS_SORTER_CYCLES: u32 = 2; + +pub(crate) const STORAGE_WRITE_RAM_CYCLES: u32 = 1; +pub(crate) const STORAGE_WRITE_LOG_DEMUXER_CYCLES: u32 = 2; +pub(crate) const STORAGE_WRITE_STORAGE_SORTER_CYCLES: u32 = 2; +pub(crate) const STORAGE_WRITE_STORAGE_APPLICATION_CYCLES: u32 = 2; + +pub(crate) const FAR_CALL_RAM_CYCLES: u32 = 1; +pub(crate) const FAR_CALL_STORAGE_SORTER_CYCLES: u32 = 1; +pub(crate) const FAR_CALL_CODE_DECOMMITTER_SORTER_CYCLES: u32 = 1; + +// 5 RAM permutations, because: 1 to read opcode + 2 reads + 2 writes. +// 2 reads and 2 writes are needed because unaligned access is implemented with +// aligned queries. +pub(crate) const UMA_WRITE_RAM_CYCLES: u32 = 5; + +// 3 RAM permutations, because: 1 to read opcode + 2 reads. +// 2 reads are needed because unaligned access is implemented with aligned queries. +pub(crate) const UMA_READ_RAM_CYCLES: u32 = 3; + +pub(crate) const PRECOMPILE_RAM_CYCLES: u32 = 1; +pub(crate) const PRECOMPILE_LOG_DEMUXER_CYCLES: u32 = 1; + +const GEOMETRY_CONFIG: GeometryConfig = get_geometry_config(); + +pub(crate) fn circuit_statistic_from_cycles(cycles: CircuitCycleStatistic) -> CircuitStatistic { + CircuitStatistic { + main_vm: cycles.main_vm_cycles as f32 / GEOMETRY_CONFIG.cycles_per_vm_snapshot as f32, + ram_permutation: cycles.ram_permutation_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_ram_permutation as f32, + storage_application: cycles.storage_application_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_storage_application as f32, + storage_sorter: cycles.storage_sorter_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_storage_sorter as f32, + code_decommitter: cycles.code_decommitter_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_code_decommitter as f32, + code_decommitter_sorter: cycles.code_decommitter_sorter_cycles as f32 + / GEOMETRY_CONFIG.cycles_code_decommitter_sorter as f32, + log_demuxer: cycles.log_demuxer_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_log_demuxer as f32, + events_sorter: cycles.events_sorter_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_events_or_l1_messages_sorter as f32, + keccak256: cycles.keccak256_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_keccak256_circuit as f32, + ecrecover: cycles.ecrecover_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_ecrecover_circuit as f32, + sha256: cycles.sha256_cycles as f32 / GEOMETRY_CONFIG.cycles_per_sha256_circuit as f32, + } +} diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/circuits_tracer.rs b/core/lib/multivm/src/versions/vm_latest/tracers/circuits_tracer.rs new file mode 100644 index 000000000000..3c4214f1409a --- /dev/null +++ b/core/lib/multivm/src/versions/vm_latest/tracers/circuits_tracer.rs @@ -0,0 +1,233 @@ +use std::marker::PhantomData; + +use zk_evm_1_4_1::{ + tracing::{BeforeExecutionData, VmLocalStateData}, + zk_evm_abstractions::precompiles::PrecompileAddress, + zkevm_opcode_defs::{LogOpcode, Opcode, UMAOpcode}, +}; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_types::circuit::CircuitCycleStatistic; + +use super::circuits_capacity::*; +use crate::{ + interface::{dyn_tracers::vm_1_4_1::DynTracer, tracer::TracerExecutionStatus}, + vm_latest::{ + bootloader_state::BootloaderState, + old_vm::{history_recorder::HistoryMode, memory::SimpleMemory}, + tracers::traits::VmTracer, + types::internals::ZkSyncVmState, + }, +}; + +/// Tracer responsible for collecting information about refunds. +#[derive(Debug)] +pub(crate) struct CircuitsTracer { + pub(crate) statistics: CircuitCycleStatistic, + last_decommitment_history_entry_checked: Option, + last_written_keys_history_entry_checked: Option, + last_read_keys_history_entry_checked: Option, + last_precompile_inner_entry_checked: Option, + _phantom_data: PhantomData<(S, H)>, +} + +impl DynTracer> for CircuitsTracer { + fn before_execution( + &mut self, + _state: VmLocalStateData<'_>, + data: BeforeExecutionData, + _memory: &SimpleMemory, + _storage: StoragePtr, + ) { + self.statistics.main_vm_cycles += 1; + + match data.opcode.variant.opcode { + Opcode::Nop(_) + | Opcode::Add(_) + | Opcode::Sub(_) + | Opcode::Mul(_) + | Opcode::Div(_) + | Opcode::Jump(_) + | Opcode::Binop(_) + | Opcode::Shift(_) + | Opcode::Ptr(_) => { + self.statistics.ram_permutation_cycles += RICH_ADDRESSING_OPCODE_RAM_CYCLES; + } + Opcode::Context(_) | Opcode::Ret(_) | Opcode::NearCall(_) => { + self.statistics.ram_permutation_cycles += AVERAGE_OPCODE_RAM_CYCLES; + } + Opcode::Log(LogOpcode::StorageRead) => { + self.statistics.ram_permutation_cycles += STORAGE_READ_RAM_CYCLES; + self.statistics.log_demuxer_cycles += STORAGE_READ_LOG_DEMUXER_CYCLES; + self.statistics.storage_sorter_cycles += STORAGE_READ_STORAGE_SORTER_CYCLES; + } + Opcode::Log(LogOpcode::StorageWrite) => { + self.statistics.ram_permutation_cycles += STORAGE_WRITE_RAM_CYCLES; + self.statistics.log_demuxer_cycles += STORAGE_WRITE_LOG_DEMUXER_CYCLES; + self.statistics.storage_sorter_cycles += STORAGE_WRITE_STORAGE_SORTER_CYCLES; + } + Opcode::Log(LogOpcode::ToL1Message) | Opcode::Log(LogOpcode::Event) => { + self.statistics.ram_permutation_cycles += EVENT_RAM_CYCLES; + self.statistics.log_demuxer_cycles += EVENT_LOG_DEMUXER_CYCLES; + self.statistics.events_sorter_cycles += EVENT_EVENTS_SORTER_CYCLES; + } + Opcode::Log(LogOpcode::PrecompileCall) => { + self.statistics.ram_permutation_cycles += PRECOMPILE_RAM_CYCLES; + self.statistics.log_demuxer_cycles += PRECOMPILE_LOG_DEMUXER_CYCLES; + } + Opcode::FarCall(_) => { + self.statistics.ram_permutation_cycles += FAR_CALL_RAM_CYCLES; + self.statistics.code_decommitter_sorter_cycles += + FAR_CALL_CODE_DECOMMITTER_SORTER_CYCLES; + self.statistics.storage_sorter_cycles += FAR_CALL_STORAGE_SORTER_CYCLES; + } + Opcode::UMA(UMAOpcode::AuxHeapWrite | UMAOpcode::HeapWrite) => { + self.statistics.ram_permutation_cycles += UMA_WRITE_RAM_CYCLES; + } + Opcode::UMA( + UMAOpcode::AuxHeapRead | UMAOpcode::HeapRead | UMAOpcode::FatPointerRead, + ) => { + self.statistics.ram_permutation_cycles += UMA_READ_RAM_CYCLES; + } + Opcode::Invalid(_) => unreachable!(), // invalid opcodes are never executed + }; + } +} + +impl VmTracer for CircuitsTracer { + fn initialize_tracer(&mut self, state: &mut ZkSyncVmState) { + self.last_decommitment_history_entry_checked = Some( + state + .decommittment_processor + .decommitted_code_hashes + .history() + .len(), + ); + + self.last_written_keys_history_entry_checked = + Some(state.storage.written_keys.history().len()); + + self.last_read_keys_history_entry_checked = Some(state.storage.read_keys.history().len()); + + self.last_precompile_inner_entry_checked = Some( + state + .precompiles_processor + .precompile_cycles_history + .inner() + .len(), + ); + } + + fn finish_cycle( + &mut self, + state: &mut ZkSyncVmState, + _bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + self.trace_decommitments(state); + self.trace_storage_writes(state); + self.trace_storage_reads(state); + self.trace_precompile_calls(state); + + TracerExecutionStatus::Continue + } +} + +impl CircuitsTracer { + pub(crate) fn new() -> Self { + Self { + statistics: CircuitCycleStatistic::new(), + last_decommitment_history_entry_checked: None, + last_written_keys_history_entry_checked: None, + last_read_keys_history_entry_checked: None, + last_precompile_inner_entry_checked: None, + _phantom_data: Default::default(), + } + } + + fn trace_decommitments(&mut self, state: &ZkSyncVmState) { + let last_decommitment_history_entry_checked = self + .last_decommitment_history_entry_checked + .expect("Value must be set during init"); + let history = state + .decommittment_processor + .decommitted_code_hashes + .history(); + for (_, history_event) in &history[last_decommitment_history_entry_checked..] { + // We assume that only insertions may happen during a single VM inspection. + assert!(history_event.value.is_none()); + let bytecode_len = state + .decommittment_processor + .known_bytecodes + .inner() + .get(&history_event.key) + .expect("Bytecode must be known at this point") + .len(); + + // Each cycle of `CodeDecommitter` processes 2 words. + // If the number of words in bytecode is odd, then number of cycles must be rounded up. + let decommitter_cycles_used = (bytecode_len + 1) / 2; + self.statistics.code_decommitter_cycles += decommitter_cycles_used as u32; + } + self.last_decommitment_history_entry_checked = Some(history.len()); + } + + fn trace_storage_writes(&mut self, state: &ZkSyncVmState) { + let last_writes_history_entry_checked = self + .last_written_keys_history_entry_checked + .expect("Value must be set during init"); + let history = state.storage.written_keys.history(); + for (_, history_event) in &history[last_writes_history_entry_checked..] { + // We assume that only insertions may happen during a single VM inspection. + assert!(history_event.value.is_none()); + + self.statistics.storage_application_cycles += STORAGE_WRITE_STORAGE_APPLICATION_CYCLES; + } + self.last_written_keys_history_entry_checked = Some(history.len()); + } + + fn trace_storage_reads(&mut self, state: &ZkSyncVmState) { + let last_reads_history_entry_checked = self + .last_read_keys_history_entry_checked + .expect("Value must be set during init"); + let history = state.storage.read_keys.history(); + for (_, history_event) in &history[last_reads_history_entry_checked..] { + // We assume that only insertions may happen during a single VM inspection. + assert!(history_event.value.is_none()); + + // If the slot is already written to, then we've already taken 2 cycles into account. + if !state + .storage + .written_keys + .inner() + .contains_key(&history_event.key) + { + self.statistics.storage_application_cycles += + STORAGE_READ_STORAGE_APPLICATION_CYCLES; + } + } + self.last_read_keys_history_entry_checked = Some(history.len()); + } + + fn trace_precompile_calls(&mut self, state: &ZkSyncVmState) { + let last_precompile_inner_entry_checked = self + .last_precompile_inner_entry_checked + .expect("Value must be set during init"); + let inner = state + .precompiles_processor + .precompile_cycles_history + .inner(); + for (precompile, cycles) in &inner[last_precompile_inner_entry_checked..] { + match precompile { + PrecompileAddress::Ecrecover => { + self.statistics.ecrecover_cycles += *cycles as u32; + } + PrecompileAddress::SHA256 => { + self.statistics.sha256_cycles += *cycles as u32; + } + PrecompileAddress::Keccak256 => { + self.statistics.keccak256_cycles += *cycles as u32; + } + }; + } + self.last_precompile_inner_entry_checked = Some(inner.len()); + } +} diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/default_tracers.rs b/core/lib/multivm/src/versions/vm_latest/tracers/default_tracers.rs index 0e18d989af62..0c61bae00a5d 100644 --- a/core/lib/multivm/src/versions/vm_latest/tracers/default_tracers.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/default_tracers.rs @@ -3,7 +3,8 @@ use std::{ marker::PhantomData, }; -use zk_evm_1_4_0::{ +use zk_evm_1_4_1::{ + aux_structures::Timestamp, tracing::{ AfterDecodingData, AfterExecutionData, BeforeExecutionData, Tracer, VmLocalStateData, }, @@ -12,13 +13,13 @@ use zk_evm_1_4_0::{ zkevm_opcode_defs::{decoding::EncodingModeProduction, Opcode, RetOpcode}, }; use zksync_state::{StoragePtr, WriteStorage}; -use zksync_types::Timestamp; use super::PubdataTracer; use crate::{ + glue::GlueInto, interface::{ tracer::{TracerExecutionStopReason, VmExecutionStopReason}, - traits::tracers::dyn_tracers::vm_1_4_0::DynTracer, + traits::tracers::dyn_tracers::vm_1_4_1::DynTracer, types::tracer::TracerExecutionStatus, Halt, VmExecutionMode, }, @@ -32,7 +33,7 @@ use crate::{ computational_gas_price, gas_spent_on_bytecodes_and_long_messages_this_opcode, print_debug_if_needed, VmHook, }, - RefundsTracer, ResultTracer, + CircuitsTracer, RefundsTracer, ResultTracer, }, types::internals::ZkSyncVmState, VmTracer, @@ -54,7 +55,7 @@ pub(crate) struct DefaultExecutionTracer { pub(crate) result_tracer: ResultTracer, // This tracer is designed specifically for calculating refunds. Its separation from the custom tracer // ensures static dispatch, enhancing performance by avoiding dynamic dispatch overhead. - // Additionally, being an internal tracer, it saves the results directly to VmResultAndLogs. + // Additionally, being an internal tracer, it saves the results directly to `VmResultAndLogs`. pub(crate) refund_tracer: Option>, // The pubdata tracer is responsible for inserting the pubdata packing information into the bootloader // memory at the end of the batch. Its separation from the custom tracer @@ -62,6 +63,11 @@ pub(crate) struct DefaultExecutionTracer { pub(crate) pubdata_tracer: Option>, pub(crate) dispatcher: TracerDispatcher, ret_from_the_bootloader: Option, + // This tracer tracks what opcodes were executed and calculates how much circuits will be generated. + // It only takes into account circuits that are generated for actual execution. It doesn't + // take into account e.g circuits produced by the initial bootloader memory commitment. + pub(crate) circuits_tracer: CircuitsTracer, + storage: StoragePtr, _phantom: PhantomData, } @@ -88,6 +94,7 @@ impl DefaultExecutionTracer { dispatcher, pubdata_tracer, ret_from_the_bootloader: None, + circuits_tracer: CircuitsTracer::new(), storage, _phantom: PhantomData, } @@ -115,9 +122,11 @@ impl DefaultExecutionTracer { let l2_block = bootloader_state.insert_fictive_l2_block(); let mut memory = vec![]; apply_l2_block(&mut memory, l2_block, txs_index); - state - .memory - .populate_page(BOOTLOADER_HEAP_PAGE as usize, memory, current_timestamp); + state.memory.populate_page( + BOOTLOADER_HEAP_PAGE as usize, + memory, + current_timestamp.glue_into(), + ); self.final_batch_info_requested = false; } @@ -161,14 +170,15 @@ impl Debug for DefaultExecutionTracer { /// The macro passes the function call to all tracers. macro_rules! dispatch_tracers { ($self:ident.$function:ident($( $params:expr ),*)) => { - $self.result_tracer.$function($( $params ),*); - $self.dispatcher.$function($( $params ),*); + $self.result_tracer.$function($( $params ),*); + $self.dispatcher.$function($( $params ),*); if let Some(tracer) = &mut $self.refund_tracer { tracer.$function($( $params ),*); } if let Some(tracer) = &mut $self.pubdata_tracer { tracer.$function($( $params ),*); } + $self.circuits_tracer.$function($( $params ),*); }; } @@ -231,7 +241,7 @@ impl Tracer for DefaultExecutionTracer { memory: &Self::SupportedMemory, ) { if let VmExecutionMode::Bootloader = self.execution_mode { - let (next_opcode, _, _) = zk_evm_1_4_0::vm_state::read_and_decode( + let (next_opcode, _, _) = zk_evm_1_4_1::vm_state::read_and_decode( state.vm_local_state, memory, &mut DummyTracer, @@ -277,6 +287,12 @@ impl DefaultExecutionTracer { .finish_cycle(state, bootloader_state) .stricter(&result); } + + result = self + .circuits_tracer + .finish_cycle(state, bootloader_state) + .stricter(&result); + result.stricter(&self.should_stop_execution()) } @@ -291,7 +307,7 @@ impl DefaultExecutionTracer { } fn current_frame_is_bootloader(local_state: &VmLocalState) -> bool { - // The current frame is bootloader if the callstack depth is 1. + // The current frame is bootloader if the call stack depth is 1. // Some of the near calls inside the bootloader can be out of gas, which is totally normal behavior // and it shouldn't result in `is_bootloader_out_of_gas` becoming true. local_state.callstack.inner.len() == 1 diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/dispatcher.rs b/core/lib/multivm/src/versions/vm_latest/tracers/dispatcher.rs index 5ee5c8ab0c19..b6c779303a76 100644 --- a/core/lib/multivm/src/versions/vm_latest/tracers/dispatcher.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/dispatcher.rs @@ -1,11 +1,11 @@ -use zk_evm_1_4_0::tracing::{ +use zk_evm_1_4_1::tracing::{ AfterDecodingData, AfterExecutionData, BeforeExecutionData, VmLocalStateData, }; use zksync_state::{StoragePtr, WriteStorage}; use crate::{ interface::{ - dyn_tracers::vm_1_4_0::DynTracer, + dyn_tracers::vm_1_4_1::DynTracer, tracer::{TracerExecutionStatus, VmExecutionStopReason}, }, vm_latest::{ diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/mod.rs b/core/lib/multivm/src/versions/vm_latest/tracers/mod.rs index 33d043de6eb1..fe916e19e8ca 100644 --- a/core/lib/multivm/src/versions/vm_latest/tracers/mod.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/mod.rs @@ -1,13 +1,16 @@ +pub(crate) use circuits_tracer::CircuitsTracer; pub(crate) use default_tracers::DefaultExecutionTracer; pub(crate) use pubdata_tracer::PubdataTracer; pub(crate) use refunds::RefundsTracer; pub(crate) use result_tracer::ResultTracer; +pub(crate) mod circuits_tracer; pub(crate) mod default_tracers; pub(crate) mod pubdata_tracer; pub(crate) mod refunds; pub(crate) mod result_tracer; +pub(crate) mod circuits_capacity; pub mod dispatcher; pub(crate) mod traits; pub(crate) mod utils; diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/pubdata_tracer.rs b/core/lib/multivm/src/versions/vm_latest/tracers/pubdata_tracer.rs index 5773e3797e2b..2ff8c3896086 100644 --- a/core/lib/multivm/src/versions/vm_latest/tracers/pubdata_tracer.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/pubdata_tracer.rs @@ -1,9 +1,10 @@ use std::marker::PhantomData; -use zk_evm_1_4_0::{ +use zk_evm_1_4_1::{ aux_structures::Timestamp, tracing::{BeforeExecutionData, VmLocalStateData}, }; +use zkevm_test_harness_1_4_1::witness::sort_storage_access::sort_storage_access_queries; use zksync_state::{StoragePtr, WriteStorage}; use zksync_types::{ event::{ @@ -11,14 +12,13 @@ use zksync_types::{ extract_l2tol1logs_from_l1_messenger, extract_long_l2_to_l1_messages, L1MessengerL2ToL1Log, }, writes::StateDiffRecord, - zkevm_test_harness::witness::sort_storage_access::sort_storage_access_queries, AccountTreeId, StorageKey, L1_MESSENGER_ADDRESS, }; use zksync_utils::{h256_to_u256, u256_to_bytes_be, u256_to_h256}; use crate::{ interface::{ - dyn_tracers::vm_1_4_0::DynTracer, + dyn_tracers::vm_1_4_1::DynTracer, tracer::{TracerExecutionStatus, TracerExecutionStopReason}, types::inputs::L1BatchEnv, VmExecutionMode, @@ -40,6 +40,9 @@ pub(crate) struct PubdataTracer { l1_batch_env: L1BatchEnv, pubdata_info_requested: bool, execution_mode: VmExecutionMode, + // For testing purposes it might be helpful to supply an exact set of state diffs to be provided + // to the L1Messenger. + enforced_state_diffs: Option>, _phantom_data: PhantomData, } @@ -49,14 +52,30 @@ impl PubdataTracer { l1_batch_env, pubdata_info_requested: false, execution_mode, + enforced_state_diffs: None, + _phantom_data: Default::default(), + } + } + + // Creates the pubdata tracer with constant state diffs. + // To be used in tests only. + #[cfg(test)] + pub(crate) fn new_with_forced_state_diffs( + l1_batch_env: L1BatchEnv, + execution_mode: VmExecutionMode, + forced_state_diffs: Vec, + ) -> Self { + Self { + l1_batch_env, + pubdata_info_requested: false, + execution_mode, + enforced_state_diffs: Some(forced_state_diffs), _phantom_data: Default::default(), } } -} -impl PubdataTracer { // Packs part of L1 Messenger total pubdata that corresponds to - // L2toL1Logs sent in the block + // `L2toL1Logs` sent in the block fn get_total_user_logs( &self, state: &ZkSyncVmState, @@ -117,7 +136,14 @@ impl PubdataTracer { // Packs part of L1Messenger total pubdata that corresponds to // State diffs needed to be published on L1 - fn get_state_diffs(storage: &StorageOracle) -> Vec { + fn get_state_diffs( + &self, + storage: &StorageOracle, + ) -> Vec { + if let Some(enforced_state_diffs) = &self.enforced_state_diffs { + return enforced_state_diffs.clone(); + } + sort_storage_access_queries( storage .storage_log_queries_after_timestamp(Timestamp(0)) @@ -153,7 +179,7 @@ impl PubdataTracer { user_logs: self.get_total_user_logs(state), l2_to_l1_messages: self.get_total_l1_messenger_messages(state), published_bytecodes: self.get_total_published_bytecodes(state), - state_diffs: Self::get_state_diffs(&state.storage), + state_diffs: self.get_state_diffs(&state.storage), } } } diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/refunds.rs b/core/lib/multivm/src/versions/vm_latest/tracers/refunds.rs index e852fba1dac8..24003d6e81b2 100644 --- a/core/lib/multivm/src/versions/vm_latest/tracers/refunds.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/refunds.rs @@ -1,32 +1,30 @@ use std::marker::PhantomData; use vise::{Buckets, EncodeLabelSet, EncodeLabelValue, Family, Histogram, Metrics}; -use zk_evm_1_4_0::{ +use zk_evm_1_4_1::{ aux_structures::Timestamp, tracing::{BeforeExecutionData, VmLocalStateData}, vm_state::VmLocalState, + zkevm_opcode_defs::system_params::L1_MESSAGE_PUBDATA_BYTES, }; use zksync_state::{StoragePtr, WriteStorage}; use zksync_system_constants::{PUBLISH_BYTECODE_OVERHEAD, SYSTEM_CONTEXT_ADDRESS}; use zksync_types::{ event::{extract_long_l2_to_l1_messages, extract_published_bytecodes}, l2_to_l1_log::L2ToL1Log, - L1BatchNumber, U256, + L1BatchNumber, H256, U256, }; use zksync_utils::{bytecode::bytecode_len_in_bytes, ceil_div_u256, u256_to_h256}; use crate::{ interface::{ - traits::tracers::dyn_tracers::vm_1_4_0::DynTracer, types::tracer::TracerExecutionStatus, + traits::tracers::dyn_tracers::vm_1_4_1::DynTracer, types::tracer::TracerExecutionStatus, L1BatchEnv, Refunds, }, vm_latest::{ bootloader_state::BootloaderState, constants::{BOOTLOADER_HEAP_PAGE, OPERATOR_REFUNDS_OFFSET, TX_GAS_LIMIT_OFFSET}, - old_vm::{ - events::merge_events, history_recorder::HistoryMode, memory::SimpleMemory, - utils::eth_price_per_pubdata_byte, - }, + old_vm::{events::merge_events, history_recorder::HistoryMode, memory::SimpleMemory}, tracers::{ traits::VmTracer, utils::{ @@ -34,6 +32,7 @@ use crate::{ }, }, types::internals::ZkSyncVmState, + utils::fee::get_batch_base_fee, }, }; @@ -101,6 +100,7 @@ impl RefundsTracer { tx_gas_limit: u32, current_ergs_per_pubdata_byte: u32, pubdata_published: u32, + tx_hash: H256, ) -> u32 { let total_gas_spent = tx_gas_limit - bootloader_refund; @@ -116,13 +116,13 @@ impl RefundsTracer { }); // For now, bootloader charges only for base fee. - let effective_gas_price = self.l1_batch.base_fee(); + let effective_gas_price = get_batch_base_fee(&self.l1_batch); let bootloader_eth_price_per_pubdata_byte = U256::from(effective_gas_price) * U256::from(current_ergs_per_pubdata_byte); let fair_eth_price_per_pubdata_byte = - U256::from(eth_price_per_pubdata_byte(self.l1_batch.l1_gas_price)); + U256::from(self.l1_batch.fee_input.fair_pubdata_price()); // For now, L1 originated transactions are allowed to pay less than fair fee per pubdata, // so we should take it into account. @@ -132,7 +132,7 @@ impl RefundsTracer { ); let fair_fee_eth = U256::from(gas_spent_on_computation) - * U256::from(self.l1_batch.fair_l2_gas_price) + * U256::from(self.l1_batch.fee_input.fair_l2_gas_price()) + U256::from(pubdata_published) * eth_price_per_pubdata_byte_for_calculation; let pre_paid_eth = U256::from(tx_gas_limit) * U256::from(effective_gas_price); let refund_eth = pre_paid_eth.checked_sub(fair_fee_eth).unwrap_or_else(|| { @@ -144,6 +144,15 @@ impl RefundsTracer { U256::zero() }); + tracing::trace!( + "Fee benchmark for transaction with hash {}", + hex::encode(tx_hash.as_bytes()) + ); + tracing::trace!("Gas Limit: {}", tx_gas_limit); + tracing::trace!("Gas spent on computation: {}", gas_spent_on_computation); + tracing::trace!("Gas spent on pubdata: {}", gas_spent_on_pubdata); + tracing::trace!("Pubdata published: {}", pubdata_published); + ceil_div_u256(refund_eth, effective_gas_price.into()).as_u32() } @@ -214,8 +223,8 @@ impl VmTracer for RefundsTracer { #[vise::register] static METRICS: vise::Global = vise::Global::new(); - // This means that the bootloader has informed the system (usually via VMHooks) - that some gas - // should be refunded back (see askOperatorForRefund in bootloader.yul for details). + // This means that the bootloader has informed the system (usually via `VMHooks`) - that some gas + // should be refunded back (see `askOperatorForRefund` in `bootloader.yul` for details). if let Some(bootloader_refund) = self.requested_refund() { assert!( self.operator_refund.is_none(), @@ -249,12 +258,14 @@ impl VmTracer for RefundsTracer { self.pubdata_published = pubdata_published; let current_ergs_per_pubdata_byte = state.local_state.current_ergs_per_pubdata_byte; + let tx_body_refund = self.tx_body_refund( bootloader_refund, gas_spent_on_pubdata, tx_gas_limit, current_ergs_per_pubdata_byte, pubdata_published, + bootloader_state.last_l2_block().txs.last().unwrap().hash, ); if tx_body_refund < bootloader_refund { @@ -332,7 +343,7 @@ pub(crate) fn pubdata_published( }) .filter(|log| log.sender != SYSTEM_CONTEXT_ADDRESS) .count() as u32) - * zk_evm_1_4_0::zkevm_opcode_defs::system_params::L1_MESSAGE_PUBDATA_BYTES; + * L1_MESSAGE_PUBDATA_BYTES; let l2_l1_long_messages_bytes: u32 = extract_long_l2_to_l1_messages(&events) .iter() .map(|event| event.len() as u32) diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/result_tracer.rs b/core/lib/multivm/src/versions/vm_latest/tracers/result_tracer.rs index b3412587725c..71a7dcb3738f 100644 --- a/core/lib/multivm/src/versions/vm_latest/tracers/result_tracer.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/result_tracer.rs @@ -1,6 +1,6 @@ use std::marker::PhantomData; -use zk_evm_1_4_0::{ +use zk_evm_1_4_1::{ tracing::{AfterDecodingData, BeforeExecutionData, VmLocalStateData}, vm_state::{ErrorFlags, VmLocalState}, zkevm_opcode_defs::FatPointer, @@ -10,7 +10,7 @@ use zksync_types::U256; use crate::{ interface::{ - tracer::VmExecutionStopReason, traits::tracers::dyn_tracers::vm_1_4_0::DynTracer, + tracer::VmExecutionStopReason, traits::tracers::dyn_tracers::vm_1_4_1::DynTracer, types::tracer::TracerExecutionStopReason, ExecutionResult, Halt, TxRevertReason, VmExecutionMode, VmRevertReason, }, @@ -54,7 +54,7 @@ impl ResultTracer { } fn current_frame_is_bootloader(local_state: &VmLocalState) -> bool { - // The current frame is bootloader if the callstack depth is 1. + // The current frame is bootloader if the call stack depth is 1. // Some of the near calls inside the bootloader can be out of gas, which is totally normal behavior // and it shouldn't result in `is_bootloader_out_of_gas` becoming true. local_state.callstack.inner.len() == 1 @@ -150,7 +150,7 @@ impl ResultTracer { }); } VmExecutionResult::Revert(output) => { - // Unlike VmHook::ExecutionResult, vm has completely finished and returned not only the revert reason, + // Unlike `VmHook::ExecutionResult`, vm has completely finished and returned not only the revert reason, // but with bytecode, which represents the type of error from the bootloader side let revert_reason = TxRevertReason::parse_error(&output); diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/traits.rs b/core/lib/multivm/src/versions/vm_latest/tracers/traits.rs index 68307b3f2867..49cdc0b2839c 100644 --- a/core/lib/multivm/src/versions/vm_latest/tracers/traits.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/traits.rs @@ -2,7 +2,7 @@ use zksync_state::WriteStorage; use crate::{ interface::{ - dyn_tracers::vm_1_4_0::DynTracer, + dyn_tracers::vm_1_4_1::DynTracer, tracer::{TracerExecutionStatus, VmExecutionStopReason}, }, vm_latest::{ diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/utils.rs b/core/lib/multivm/src/versions/vm_latest/tracers/utils.rs index 93710586fdac..78129790c44e 100644 --- a/core/lib/multivm/src/versions/vm_latest/tracers/utils.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/utils.rs @@ -1,4 +1,4 @@ -use zk_evm_1_4_0::{ +use zk_evm_1_4_1::{ aux_structures::MemoryPage, tracing::{BeforeExecutionData, VmLocalStateData}, zkevm_opcode_defs::{ @@ -57,7 +57,7 @@ impl VmHook { let value = data.src1_value.value; - // Only UMA opcodes in the bootloader serve for vm hooks + // Only `UMA` opcodes in the bootloader serve for vm hooks if !matches!(opcode_variant.opcode, Opcode::UMA(UMAOpcode::HeapWrite)) || heap_page != BOOTLOADER_HEAP_PAGE || fat_ptr.offset != VM_HOOK_POSITION * 32 diff --git a/core/lib/multivm/src/versions/vm_latest/types/internals/pubdata.rs b/core/lib/multivm/src/versions/vm_latest/types/internals/pubdata.rs index aa9e8a7eda70..38489a6c8e92 100644 --- a/core/lib/multivm/src/versions/vm_latest/types/internals/pubdata.rs +++ b/core/lib/multivm/src/versions/vm_latest/types/internals/pubdata.rs @@ -24,14 +24,14 @@ impl PubdataInput { } = self; // Encoding user L2->L1 logs. - // Format: [(numberOfL2ToL1Logs as u32) || l2tol1logs[1] || ... || l2tol1logs[n]] + // Format: `[(numberOfL2ToL1Logs as u32) || l2tol1logs[1] || ... || l2tol1logs[n]]` l1_messenger_pubdata.extend((user_logs.len() as u32).to_be_bytes()); for l2tol1log in user_logs { l1_messenger_pubdata.extend(l2tol1log.packed_encoding()); } // Encoding L2->L1 messages - // Format: [(numberOfMessages as u32) || (messages[1].len() as u32) || messages[1] || ... || (messages[n].len() as u32) || messages[n]] + // Format: `[(numberOfMessages as u32) || (messages[1].len() as u32) || messages[1] || ... || (messages[n].len() as u32) || messages[n]]` l1_messenger_pubdata.extend((l2_to_l1_messages.len() as u32).to_be_bytes()); for message in l2_to_l1_messages { l1_messenger_pubdata.extend((message.len() as u32).to_be_bytes()); @@ -39,7 +39,7 @@ impl PubdataInput { } // Encoding bytecodes - // Format: [(numberOfBytecodes as u32) || (bytecodes[1].len() as u32) || bytecodes[1] || ... || (bytecodes[n].len() as u32) || bytecodes[n]] + // Format: `[(numberOfBytecodes as u32) || (bytecodes[1].len() as u32) || bytecodes[1] || ... || (bytecodes[n].len() as u32) || bytecodes[n]]` l1_messenger_pubdata.extend((published_bytecodes.len() as u32).to_be_bytes()); for bytecode in published_bytecodes { l1_messenger_pubdata.extend((bytecode.len() as u32).to_be_bytes()); @@ -47,7 +47,7 @@ impl PubdataInput { } // Encoding state diffs - // Format: [size of compressed state diffs u32 || compressed state diffs || (# state diffs: intial + repeated) as u32 || sorted state diffs by ] + // Format: `[size of compressed state diffs u32 || compressed state diffs || (# state diffs: intial + repeated) as u32 || sorted state diffs by ]` let state_diffs_compressed = compress_state_diffs(state_diffs.clone()); l1_messenger_pubdata.extend(state_diffs_compressed); diff --git a/core/lib/multivm/src/versions/vm_latest/types/internals/snapshot.rs b/core/lib/multivm/src/versions/vm_latest/types/internals/snapshot.rs index 2a9368c37a39..0633cf61cda1 100644 --- a/core/lib/multivm/src/versions/vm_latest/types/internals/snapshot.rs +++ b/core/lib/multivm/src/versions/vm_latest/types/internals/snapshot.rs @@ -1,4 +1,4 @@ -use zk_evm_1_4_0::vm_state::VmLocalState; +use zk_evm_1_4_1::vm_state::VmLocalState; use crate::vm_latest::bootloader_state::BootloaderStateSnapshot; diff --git a/core/lib/multivm/src/versions/vm_latest/types/internals/transaction_data.rs b/core/lib/multivm/src/versions/vm_latest/types/internals/transaction_data.rs index f5b97ca9793e..2445e1bdb726 100644 --- a/core/lib/multivm/src/versions/vm_latest/types/internals/transaction_data.rs +++ b/core/lib/multivm/src/versions/vm_latest/types/internals/transaction_data.rs @@ -11,7 +11,10 @@ use zksync_types::{ }; use zksync_utils::{address_to_h256, bytecode::hash_bytecode, bytes_to_be_words, h256_to_u256}; -use crate::vm_latest::utils::overhead::{get_amortized_overhead, OverheadCoefficients}; +use crate::vm_latest::{ + constants::{L1_TX_TYPE, MAX_GAS_PER_PUBDATA_BYTE, PRIORITY_TX_MAX_GAS_LIMIT}, + utils::overhead::derive_overhead, +}; /// This structure represents the data that is used by /// the Bootloader to describe the transaction. @@ -59,12 +62,22 @@ impl From for TransactionData { U256::zero() }; + // Ethereum transactions do not sign gas per pubdata limit, and so for them we need to use + // some default value. We use the maximum possible value that is allowed by the bootloader + // (i.e. we can not use u64::MAX, because the bootloader requires gas per pubdata for such + // transactions to be higher than `MAX_GAS_PER_PUBDATA_BYTE`). + let gas_per_pubdata_limit = if common_data.transaction_type.is_ethereum_type() { + MAX_GAS_PER_PUBDATA_BYTE.into() + } else { + common_data.fee.gas_per_pubdata_limit + }; + TransactionData { tx_type: (common_data.transaction_type as u32) as u8, from: common_data.initiator_address, to: execute_tx.execute.contract_address, gas_limit: common_data.fee.gas_limit, - pubdata_price_limit: common_data.fee.gas_per_pubdata_limit, + pubdata_price_limit: gas_per_pubdata_limit, max_fee_per_gas: common_data.fee.max_fee_per_gas, max_priority_fee_per_gas: common_data.fee.max_priority_fee_per_gas, paymaster: common_data.paymaster_params.paymaster, @@ -189,21 +202,7 @@ impl TransactionData { bytes_to_be_words(bytes) } - pub(crate) fn effective_gas_price_per_pubdata(&self, block_gas_price_per_pubdata: u32) -> u32 { - // It is enforced by the protocol that the L1 transactions always pay the exact amount of gas per pubdata - // as was supplied in the transaction. - if is_l1_tx_type(self.tx_type) { - self.pubdata_price_limit.as_u32() - } else { - block_gas_price_per_pubdata - } - } - - pub(crate) fn overhead_gas(&self, block_gas_price_per_pubdata: u32) -> u32 { - let total_gas_limit = self.gas_limit.as_u32(); - let gas_price_per_pubdata = - self.effective_gas_price_per_pubdata(block_gas_price_per_pubdata); - + pub(crate) fn overhead_gas(&self) -> u32 { let encoded_len = encoding_len( self.data.len() as u64, self.signature.len() as u64, @@ -212,16 +211,16 @@ impl TransactionData { self.reserved_dynamic.len() as u64, ); - let coefficients = OverheadCoefficients::from_tx_type(self.tx_type); - get_amortized_overhead( - total_gas_limit, - gas_price_per_pubdata, - encoded_len, - coefficients, - ) + derive_overhead(encoded_len) } - pub(crate) fn trusted_ergs_limit(&self, _block_gas_price_per_pubdata: u64) -> U256 { + pub(crate) fn trusted_ergs_limit(&self) -> U256 { + if self.tx_type == L1_TX_TYPE { + // In case we get a users' transactions with unexpected gas limit, we do not let it have more than + // a certain limit + return U256::from(PRIORITY_TX_MAX_GAS_LIMIT).min(self.gas_limit); + } + // TODO (EVM-66): correctly calculate the trusted gas limit for a transaction self.gas_limit } @@ -234,7 +233,7 @@ impl TransactionData { let l2_tx: L2Tx = self.clone().try_into().unwrap(); let transaction_request: TransactionRequest = l2_tx.into(); - // It is assumed that the TransactionData always has all the necessary components to recover the hash. + // It is assumed that the `TransactionData` always has all the necessary components to recover the hash. transaction_request .get_tx_hash(chain_id) .expect("Could not recover L2 transaction hash") diff --git a/core/lib/multivm/src/versions/vm_latest/types/internals/vm_state.rs b/core/lib/multivm/src/versions/vm_latest/types/internals/vm_state.rs index da9c81321440..54aa44874e88 100644 --- a/core/lib/multivm/src/versions/vm_latest/types/internals/vm_state.rs +++ b/core/lib/multivm/src/versions/vm_latest/types/internals/vm_state.rs @@ -1,4 +1,4 @@ -use zk_evm_1_4_0::{ +use zk_evm_1_4_1::{ aux_structures::{MemoryPage, Timestamp}, block_properties::BlockProperties, vm_state::{CallStackEntry, PrimitiveValue, VmState}, @@ -9,12 +9,10 @@ use zk_evm_1_4_0::{ STARTING_BASE_PAGE, STARTING_TIMESTAMP, }, }; +use zkevm_test_harness_1_3_3::INITIAL_MONOTONIC_CYCLE_COUNTER; use zksync_state::{StoragePtr, WriteStorage}; use zksync_system_constants::BOOTLOADER_ADDRESS; -use zksync_types::{ - block::MiniblockHasher, zkevm_test_harness::INITIAL_MONOTONIC_CYCLE_COUNTER, Address, - MiniblockNumber, -}; +use zksync_types::{block::MiniblockHasher, Address, MiniblockNumber}; use zksync_utils::h256_to_u256; use crate::{ @@ -40,7 +38,7 @@ pub type ZkSyncVmState = VmState< StorageOracle, SimpleMemory, InMemoryEventSink, - PrecompilesProcessorWithHistory, + PrecompilesProcessorWithHistory, DecommitterOracle, DummyTracer, >; @@ -84,7 +82,7 @@ pub(crate) fn new_vm_state( let storage_oracle: StorageOracle = StorageOracle::new(storage.clone()); let mut memory = SimpleMemory::default(); let event_sink = InMemoryEventSink::default(); - let precompiles_processor = PrecompilesProcessorWithHistory::::default(); + let precompiles_processor = PrecompilesProcessorWithHistory::::default(); let mut decommittment_processor: DecommitterOracle = DecommitterOracle::new(storage); diff --git a/core/lib/multivm/src/versions/vm_latest/types/l1_batch.rs b/core/lib/multivm/src/versions/vm_latest/types/l1_batch.rs index 6f16e95f8d77..b3bf15cb1be5 100644 --- a/core/lib/multivm/src/versions/vm_latest/types/l1_batch.rs +++ b/core/lib/multivm/src/versions/vm_latest/types/l1_batch.rs @@ -1,13 +1,13 @@ use zksync_types::U256; use zksync_utils::{address_to_u256, h256_to_u256}; -use crate::interface::L1BatchEnv; +use crate::{interface::L1BatchEnv, vm_latest::utils::fee::get_batch_base_fee}; const OPERATOR_ADDRESS_SLOT: usize = 0; const PREV_BLOCK_HASH_SLOT: usize = 1; const NEW_BLOCK_TIMESTAMP_SLOT: usize = 2; const NEW_BLOCK_NUMBER_SLOT: usize = 3; -const L1_GAS_PRICE_SLOT: usize = 4; +const FAIR_PUBDATA_PRICE_SLOT: usize = 4; const FAIR_L2_GAS_PRICE_SLOT: usize = 5; const EXPECTED_BASE_FEE_SLOT: usize = 6; const SHOULD_SET_NEW_BLOCK_SLOT: usize = 7; @@ -27,12 +27,18 @@ pub(crate) fn bootloader_initial_memory(l1_batch: &L1BatchEnv) -> Vec<(usize, U2 (PREV_BLOCK_HASH_SLOT, prev_block_hash), (NEW_BLOCK_TIMESTAMP_SLOT, U256::from(l1_batch.timestamp)), (NEW_BLOCK_NUMBER_SLOT, U256::from(l1_batch.number.0)), - (L1_GAS_PRICE_SLOT, U256::from(l1_batch.l1_gas_price)), + ( + FAIR_PUBDATA_PRICE_SLOT, + U256::from(l1_batch.fee_input.fair_pubdata_price()), + ), ( FAIR_L2_GAS_PRICE_SLOT, - U256::from(l1_batch.fair_l2_gas_price), + U256::from(l1_batch.fee_input.fair_l2_gas_price()), + ), + ( + EXPECTED_BASE_FEE_SLOT, + U256::from(get_batch_base_fee(l1_batch)), ), - (EXPECTED_BASE_FEE_SLOT, U256::from(l1_batch.base_fee())), (SHOULD_SET_NEW_BLOCK_SLOT, should_set_new_block), ] } diff --git a/core/lib/multivm/src/versions/vm_latest/utils/fee.rs b/core/lib/multivm/src/versions/vm_latest/utils/fee.rs index 23b744a348f7..ea4de7204434 100644 --- a/core/lib/multivm/src/versions/vm_latest/utils/fee.rs +++ b/core/lib/multivm/src/versions/vm_latest/utils/fee.rs @@ -1,29 +1,70 @@ //! Utility functions for vm -use zksync_system_constants::MAX_GAS_PER_PUBDATA_BYTE; +use zksync_types::{ + fee_model::{BatchFeeInput, PubdataIndependentBatchFeeModelInput}, + U256, +}; use zksync_utils::ceil_div; -use crate::vm_latest::old_vm::utils::eth_price_per_pubdata_byte; - -/// Calculates the amount of gas required to publish one byte of pubdata -pub fn base_fee_to_gas_per_pubdata(l1_gas_price: u64, base_fee: u64) -> u64 { - let eth_price_per_pubdata_byte = eth_price_per_pubdata_byte(l1_gas_price); - - ceil_div(eth_price_per_pubdata_byte, base_fee) -} +use crate::vm_latest::{constants::MAX_GAS_PER_PUBDATA_BYTE, L1BatchEnv}; /// Calculates the base fee and gas per pubdata for the given L1 gas price. -pub fn derive_base_fee_and_gas_per_pubdata(l1_gas_price: u64, fair_gas_price: u64) -> (u64, u64) { - let eth_price_per_pubdata_byte = eth_price_per_pubdata_byte(l1_gas_price); +pub(crate) fn derive_base_fee_and_gas_per_pubdata( + fee_input: PubdataIndependentBatchFeeModelInput, +) -> (u64, u64) { + let PubdataIndependentBatchFeeModelInput { + fair_l2_gas_price, + fair_pubdata_price, + .. + } = fee_input; - // The baseFee is set in such a way that it is always possible for a transaction to + // The `baseFee` is set in such a way that it is always possible for a transaction to // publish enough public data while compensating us for it. let base_fee = std::cmp::max( - fair_gas_price, - ceil_div(eth_price_per_pubdata_byte, MAX_GAS_PER_PUBDATA_BYTE), + fair_l2_gas_price, + ceil_div(fair_pubdata_price, MAX_GAS_PER_PUBDATA_BYTE), ); - ( - base_fee, - base_fee_to_gas_per_pubdata(l1_gas_price, base_fee), - ) + let gas_per_pubdata = ceil_div(fair_pubdata_price, base_fee); + + (base_fee, gas_per_pubdata) +} + +pub(crate) fn get_batch_base_fee(l1_batch_env: &L1BatchEnv) -> u64 { + if let Some(base_fee) = l1_batch_env.enforced_base_fee { + return base_fee; + } + let (base_fee, _) = + derive_base_fee_and_gas_per_pubdata(l1_batch_env.fee_input.into_pubdata_independent()); + base_fee +} + +/// Changes the fee model output so that the expected gas per pubdata is smaller than or the `tx_gas_per_pubdata_limit`. +/// This function expects that the currently expected gas per pubdata is greater than the `tx_gas_per_pubdata_limit`. +pub(crate) fn adjust_pubdata_price_for_tx( + mut batch_fee_input: BatchFeeInput, + tx_gas_per_pubdata_limit: U256, +) -> BatchFeeInput { + match &mut batch_fee_input { + BatchFeeInput::L1Pegged(fee_input) => { + // `gasPerPubdata = ceil(17 * l1gasprice / fair_l2_gas_price)` + // `gasPerPubdata <= 17 * l1gasprice / fair_l2_gas_price + 1` + // `fair_l2_gas_price(gasPerPubdata - 1) / 17 <= l1gasprice` + let new_l1_gas_price = U256::from(fee_input.fair_l2_gas_price) + * (tx_gas_per_pubdata_limit - U256::from(1u32)) + / U256::from(17); + + fee_input.l1_gas_price = new_l1_gas_price.as_u64(); + } + BatchFeeInput::PubdataIndependent(fee_input) => { + // `gasPerPubdata = ceil(fair_pubdata_price / fair_l2_gas_price)` + // `gasPerPubdata <= fair_pubdata_price / fair_l2_gas_price + 1` + // `fair_l2_gas_price(gasPerPubdata - 1) <= fair_pubdata_price` + let new_fair_pubdata_price = U256::from(fee_input.fair_l2_gas_price) + * (tx_gas_per_pubdata_limit - U256::from(1u32)); + + fee_input.fair_pubdata_price = new_fair_pubdata_price.as_u64(); + } + } + + batch_fee_input } diff --git a/core/lib/multivm/src/versions/vm_latest/utils/l2_blocks.rs b/core/lib/multivm/src/versions/vm_latest/utils/l2_blocks.rs index 5dd26c4c0277..e5832f7f5879 100644 --- a/core/lib/multivm/src/versions/vm_latest/utils/l2_blocks.rs +++ b/core/lib/multivm/src/versions/vm_latest/utils/l2_blocks.rs @@ -68,7 +68,7 @@ pub fn load_last_l2_block(storage: StoragePtr) -> Option u32 { - // Even if the gas limit is greater than the MAX_TX_ERGS_LIMIT, we assume that everything beyond MAX_TX_ERGS_LIMIT - // will be spent entirely on publishing bytecodes and so we derive the overhead solely based on the capped value - let gas_limit = std::cmp::min(MAX_TX_ERGS_LIMIT, gas_limit); - - // Using large U256 type to avoid overflow - let max_block_overhead = U256::from(block_overhead_gas(gas_price_per_pubdata)); - let gas_limit = U256::from(gas_limit); - let encoded_len = U256::from(encoded_len); - - // The MAX_TX_ERGS_LIMIT is formed in a way that may fulfills a single-instance circuits - // if used in full. That is, within MAX_TX_ERGS_LIMIT it is possible to fully saturate all the single-instance - // circuits. - let overhead_for_single_instance_circuits = - ceil_div_u256(gas_limit * max_block_overhead, MAX_TX_ERGS_LIMIT.into()); - - // The overhead for occupying the bootloader memory - let overhead_for_length = ceil_div_u256( - encoded_len * max_block_overhead, - BOOTLOADER_TX_ENCODING_SPACE.into(), - ); - - // The overhead for occupying a single tx slot - let tx_slot_overhead = ceil_div_u256(max_block_overhead, MAX_TXS_IN_BLOCK.into()); - - // We use "ceil" here for formal reasons to allow easier approach for calculating the overhead in O(1) - // let max_pubdata_in_tx = ceil_div_u256(gas_limit, gas_price_per_pubdata); - - // The maximal potential overhead from pubdata - // TODO (EVM-67): possibly use overhead for pubdata - // let pubdata_overhead = ceil_div_u256( - // max_pubdata_in_tx * max_block_overhead, - // MAX_PUBDATA_PER_BLOCK.into(), - // ); - - vec![ - (coefficients.ergs_limit_overhead_coeficient - * overhead_for_single_instance_circuits.as_u32() as f64) - .floor() as u32, - (coefficients.bootloader_memory_overhead_coeficient * overhead_for_length.as_u32() as f64) - .floor() as u32, - (coefficients.slot_overhead_coeficient * tx_slot_overhead.as_u32() as f64) as u32, - ] - .into_iter() - .max() - .unwrap() -} - -/// Contains the coefficients with which the overhead for transactions will be calculated. -/// All of the coefficients should be <= 1. There are here to provide a certain "discount" for normal transactions -/// at the risk of malicious transactions that may close the block prematurely. -/// IMPORTANT: to perform correct computations, `MAX_TX_ERGS_LIMIT / coefficients.ergs_limit_overhead_coeficient` MUST -/// result in an integer number -#[derive(Debug, Clone, Copy)] -pub struct OverheadCoefficients { - slot_overhead_coeficient: f64, - bootloader_memory_overhead_coeficient: f64, - ergs_limit_overhead_coeficient: f64, -} - -impl OverheadCoefficients { - // This method ensures that the parameters keep the required invariants - fn new_checked( - slot_overhead_coeficient: f64, - bootloader_memory_overhead_coeficient: f64, - ergs_limit_overhead_coeficient: f64, - ) -> Self { - assert!( - (MAX_TX_ERGS_LIMIT as f64 / ergs_limit_overhead_coeficient).round() - == MAX_TX_ERGS_LIMIT as f64 / ergs_limit_overhead_coeficient, - "MAX_TX_ERGS_LIMIT / ergs_limit_overhead_coeficient must be an integer" - ); - - Self { - slot_overhead_coeficient, - bootloader_memory_overhead_coeficient, - ergs_limit_overhead_coeficient, - } - } - - // L1->L2 do not receive any discounts - fn new_l1() -> Self { - OverheadCoefficients::new_checked(1.0, 1.0, 1.0) - } - - fn new_l2() -> Self { - OverheadCoefficients::new_checked( - 1.0, 1.0, - // For L2 transactions we allow a certain default discount with regard to the number of ergs. - // Multiinstance circuits can in theory be spawned infinite times, while projected future limitations - // on gas per pubdata allow for roughly 800kk gas per L1 batch, so the rough trust "discount" on the proof's part - // to be paid by the users is 0.1. - 0.1, - ) - } - - /// Return the coefficients for the given transaction type - pub fn from_tx_type(tx_type: u8) -> Self { - if is_l1_tx_type(tx_type) { - Self::new_l1() - } else { - Self::new_l2() - } - } -} - -/// This method returns the overhead for processing the block -pub(crate) fn get_amortized_overhead( - total_gas_limit: u32, - gas_per_pubdata_byte_limit: u32, - encoded_len: usize, - coefficients: OverheadCoefficients, -) -> u32 { - // Using large U256 type to prevent overflows. - let overhead_for_block_gas = U256::from(block_overhead_gas(gas_per_pubdata_byte_limit)); - let total_gas_limit = U256::from(total_gas_limit); - let encoded_len = U256::from(encoded_len); - - // Derivation of overhead consists of 4 parts: - // 1. The overhead for taking up a transaction's slot. (O1): O1 = 1 / MAX_TXS_IN_BLOCK - // 2. The overhead for taking up the bootloader's memory (O2): O2 = encoded_len / BOOTLOADER_TX_ENCODING_SPACE - // 3. The overhead for possible usage of pubdata. (O3): O3 = max_pubdata_in_tx / MAX_PUBDATA_PER_BLOCK - // 4. The overhead for possible usage of all the single-instance circuits. (O4): O4 = gas_limit / MAX_TX_ERGS_LIMIT - // - // The maximum of these is taken to derive the part of the block's overhead to be paid by the users: - // - // max_overhead = max(O1, O2, O3, O4) - // overhead_gas = ceil(max_overhead * overhead_for_block_gas). Thus, overhead_gas is a function of - // tx_gas_limit, gas_per_pubdata_byte_limit and encoded_len. - // - // While it is possible to derive the overhead with binary search in O(log n), it is too expensive to be done - // on L1, so here is a reference implementation of finding the overhead for transaction in O(1): - // - // Given total_gas_limit = tx_gas_limit + overhead_gas, we need to find overhead_gas and tx_gas_limit, such that: - // 1. overhead_gas is maximal possible (the operator is paid fairly) - // 2. overhead_gas(tx_gas_limit, gas_per_pubdata_byte_limit, encoded_len) >= overhead_gas (the user does not overpay) - // The third part boils to the following 4 inequalities (at least one of these must hold): - // ceil(O1 * overhead_for_block_gas) >= overhead_gas - // ceil(O2 * overhead_for_block_gas) >= overhead_gas - // ceil(O3 * overhead_for_block_gas) >= overhead_gas - // ceil(O4 * overhead_for_block_gas) >= overhead_gas - // - // Now, we need to solve each of these separately: - - // 1. The overhead for occupying a single tx slot is a constant: - let tx_slot_overhead = { - let tx_slot_overhead = - ceil_div_u256(overhead_for_block_gas, MAX_TXS_IN_BLOCK.into()).as_u32(); - (coefficients.slot_overhead_coeficient * tx_slot_overhead as f64).floor() as u32 - }; - - // 2. The overhead for occupying the bootloader memory can be derived from encoded_len - let overhead_for_length = { - let overhead_for_length = ceil_div_u256( - encoded_len * overhead_for_block_gas, - BOOTLOADER_TX_ENCODING_SPACE.into(), - ) - .as_u32(); - - (coefficients.bootloader_memory_overhead_coeficient * overhead_for_length as f64).floor() - as u32 - }; - - // TODO (EVM-67): possibly include the overhead for pubdata. The formula below has not been properly maintained, - // since the pubdat is not published. If decided to use the pubdata overhead, it needs to be updated. - // 3. ceil(O3 * overhead_for_block_gas) >= overhead_gas - // O3 = max_pubdata_in_tx / MAX_PUBDATA_PER_BLOCK = ceil(gas_limit / gas_per_pubdata_byte_limit) / MAX_PUBDATA_PER_BLOCK - // >= (gas_limit / (gas_per_pubdata_byte_limit * MAX_PUBDATA_PER_BLOCK). Throwing off the `ceil`, while may provide marginally lower - // overhead to the operator, provides substantially easier formula to work with. - // - // For better clarity, let's denote gas_limit = GL, MAX_PUBDATA_PER_BLOCK = MP, gas_per_pubdata_byte_limit = EP, overhead_for_block_gas = OB, total_gas_limit = TL, overhead_gas = OE - // ceil(OB * (TL - OE) / (EP * MP)) >= OE - // - // OB * (TL - OE) / (MP * EP) > OE - 1 - // OB * (TL - OE) > (OE - 1) * EP * MP - // OB * TL + EP * MP > OE * EP * MP + OE * OB - // (OB * TL + EP * MP) / (EP * MP + OB) > OE - // OE = floor((OB * TL + EP * MP) / (EP * MP + OB)) with possible -1 if the division is without remainder - // let overhead_for_pubdata = { - // let numerator: U256 = overhead_for_block_gas * total_gas_limit - // + gas_per_pubdata_byte_limit * U256::from(MAX_PUBDATA_PER_BLOCK); - // let denominator = - // gas_per_pubdata_byte_limit * U256::from(MAX_PUBDATA_PER_BLOCK) + overhead_for_block_gas; - - // // Corner case: if `total_gas_limit` = `gas_per_pubdata_byte_limit` = 0 - // // then the numerator will be 0 and subtracting 1 will cause a panic, so we just return a zero. - // if numerator.is_zero() { - // 0.into() - // } else { - // (numerator - 1) / denominator - // } - // }; - - // 4. K * ceil(O4 * overhead_for_block_gas) >= overhead_gas, where K is the discount - // O4 = gas_limit / MAX_TX_ERGS_LIMIT. Using the notation from the previous equation: - // ceil(OB * GL / MAX_TX_ERGS_LIMIT) >= (OE / K) - // ceil(OB * (TL - OE) / MAX_TX_ERGS_LIMIT) >= (OE/K) - // OB * (TL - OE) / MAX_TX_ERGS_LIMIT > (OE/K) - 1 - // OB * (TL - OE) > (OE/K) * MAX_TX_ERGS_LIMIT - MAX_TX_ERGS_LIMIT - // OB * TL + MAX_TX_ERGS_LIMIT > OE * ( MAX_TX_ERGS_LIMIT/K + OB) - // OE = floor(OB * TL + MAX_TX_ERGS_LIMIT / (MAX_TX_ERGS_LIMIT/K + OB)), with possible -1 if the division is without remainder - let overhead_for_gas = { - let numerator = overhead_for_block_gas * total_gas_limit + U256::from(MAX_TX_ERGS_LIMIT); - let denominator: U256 = U256::from( - (MAX_TX_ERGS_LIMIT as f64 / coefficients.ergs_limit_overhead_coeficient) as u64, - ) + overhead_for_block_gas; - - let overhead_for_gas = (numerator - 1) / denominator; - - overhead_for_gas.as_u32() - }; - - let overhead = vec![tx_slot_overhead, overhead_for_length, overhead_for_gas] - .into_iter() - .max() - // For the sake of consistency making sure that total_gas_limit >= max_overhead - .map(|max_overhead| std::cmp::min(max_overhead, total_gas_limit.as_u32())) - .unwrap(); - - let limit_after_deducting_overhead = total_gas_limit - overhead; - - // During double checking of the overhead, the bootloader will assume that the - // body of the transaction does not have any more than MAX_L2_TX_GAS_LIMIT ergs available to it. - if limit_after_deducting_overhead.as_u64() > MAX_L2_TX_GAS_LIMIT { - // We derive the same overhead that would exist for the MAX_L2_TX_GAS_LIMIT ergs - derive_overhead( - MAX_L2_TX_GAS_LIMIT as u32, - gas_per_pubdata_byte_limit, - encoded_len.as_usize(), - coefficients, - ) - } else { - overhead - } -} - -pub(crate) fn block_overhead_gas(gas_per_pubdata_byte: u32) -> u32 { - BLOCK_OVERHEAD_GAS + BLOCK_OVERHEAD_PUBDATA * gas_per_pubdata_byte -} - -#[cfg(test)] -mod tests { - - use super::*; - - // This method returns the maximum block overhead that can be charged from the user based on the binary search approach - pub(crate) fn get_maximal_allowed_overhead_bin_search( - total_gas_limit: u32, - gas_per_pubdata_byte_limit: u32, - encoded_len: usize, - coefficients: OverheadCoefficients, - ) -> u32 { - let mut left_bound = if MAX_TX_ERGS_LIMIT < total_gas_limit { - total_gas_limit - MAX_TX_ERGS_LIMIT - } else { - 0u32 - }; - // Safe cast: the gas_limit for a transaction can not be larger than 2^32 - let mut right_bound = total_gas_limit; - - // The closure returns whether a certain overhead would be accepted by the bootloader. - // It is accepted if the derived overhead (i.e. the actual overhead that the user has to pay) - // is >= than the overhead proposed by the operator. - let is_overhead_accepted = |suggested_overhead: u32| { - let derived_overhead = derive_overhead( - total_gas_limit - suggested_overhead, - gas_per_pubdata_byte_limit, - encoded_len, - coefficients, - ); - - derived_overhead >= suggested_overhead - }; - - // In order to find the maximal allowed overhead we are doing binary search - while left_bound + 1 < right_bound { - let mid = (left_bound + right_bound) / 2; - - if is_overhead_accepted(mid) { - left_bound = mid; - } else { - right_bound = mid; - } - } - - if is_overhead_accepted(right_bound) { - right_bound - } else { - left_bound - } - } - - #[test] - fn test_correctness_for_efficient_overhead() { - let test_params = |total_gas_limit: u32, - gas_per_pubdata: u32, - encoded_len: usize, - coefficients: OverheadCoefficients| { - let result_by_efficient_search = - get_amortized_overhead(total_gas_limit, gas_per_pubdata, encoded_len, coefficients); - - let result_by_binary_search = get_maximal_allowed_overhead_bin_search( - total_gas_limit, - gas_per_pubdata, - encoded_len, - coefficients, - ); - - assert_eq!(result_by_efficient_search, result_by_binary_search); - }; - - // Some arbitrary test - test_params(60_000_000, 800, 2900, OverheadCoefficients::new_l2()); - - // Very small parameters - test_params(0, 1, 12, OverheadCoefficients::new_l2()); - - // Relatively big parameters - let max_tx_overhead = derive_overhead( - MAX_TX_ERGS_LIMIT, - 5000, - 10000, - OverheadCoefficients::new_l2(), - ); - test_params( - MAX_TX_ERGS_LIMIT + max_tx_overhead, - 5000, - 10000, - OverheadCoefficients::new_l2(), - ); - - test_params(115432560, 800, 2900, OverheadCoefficients::new_l1()); - } +/// In the past, the overhead for transaction depended also on the effective gas per pubdata limit for the transaction. +/// Currently, the approach is more similar to EVM, where only the calldata length and the transaction overhead are taken +/// into account by a constant formula. +pub(crate) fn derive_overhead(encoded_len: usize) -> u32 { + TX_SLOT_OVERHEAD_GAS.max(TX_MEMORY_OVERHEAD_GAS * (encoded_len as u32)) } diff --git a/core/lib/multivm/src/versions/vm_latest/vm.rs b/core/lib/multivm/src/versions/vm_latest/vm.rs index 73d551942bff..4fa8c58a0e13 100644 --- a/core/lib/multivm/src/versions/vm_latest/vm.rs +++ b/core/lib/multivm/src/versions/vm_latest/vm.rs @@ -1,3 +1,4 @@ +use zkevm_test_harness_1_4_1::witness::sort_storage_access::sort_storage_access_queries; use zksync_state::{StoragePtr, WriteStorage}; use zksync_types::{ event::extract_l2tol1logs_from_l1_messenger, @@ -6,7 +7,9 @@ use zksync_types::{ }; use zksync_utils::bytecode::CompressedBytecodeInfo; +use super::constants::BOOTLOADER_BATCH_TIP_OVERHEAD; use crate::{ + glue::GlueInto, interface::{ BootloaderMemory, BytecodeCompressionError, CurrentExecutionState, FinishedL1Batch, L1BatchEnv, L2BlockEnv, SystemEnv, VmExecutionMode, VmExecutionResultAndLogs, VmInterface, @@ -27,7 +30,7 @@ use crate::{ pub struct Vm { pub(crate) bootloader_state: BootloaderState, // Current state and oracles of virtual machine - pub(crate) state: ZkSyncVmState, + pub(crate) state: ZkSyncVmState, pub(crate) storage: StoragePtr, pub(crate) system_env: SystemEnv, pub(crate) batch_env: L1BatchEnv, @@ -37,7 +40,7 @@ pub struct Vm { } impl VmInterface for Vm { - type TracerDispatcher = TracerDispatcher; + type TracerDispatcher = TracerDispatcher; fn new(batch_env: L1BatchEnv, system_env: SystemEnv, storage: StoragePtr) -> Self { let (state, bootloader_state) = new_vm_state(storage.clone(), &system_env, &batch_env); @@ -63,7 +66,7 @@ impl VmInterface for Vm { tracer: Self::TracerDispatcher, execution_mode: VmExecutionMode, ) -> VmExecutionResultAndLogs { - self.inspect_inner(tracer, execution_mode) + self.inspect_inner(tracer, execution_mode, None) } /// Get current state of bootloader memory. @@ -93,7 +96,7 @@ impl VmInterface for Vm { let user_l2_to_l1_logs = extract_l2tol1logs_from_l1_messenger(&events); let system_logs = l1_messages .into_iter() - .map(|log| SystemL2ToL1Log(log.into())) + .map(|log| SystemL2ToL1Log(log.glue_into())) .collect(); let total_log_queries = self.state.event_sink.get_log_queries() + self @@ -103,9 +106,21 @@ impl VmInterface for Vm { .len() + self.state.storage.get_final_log_queries().len(); + let storage_log_queries = self.state.storage.get_final_log_queries(); + + let deduped_storage_log_queries = + sort_storage_access_queries(storage_log_queries.iter().map(|log| &log.log_query)).1; + CurrentExecutionState { events, - storage_log_queries: self.state.storage.get_final_log_queries(), + storage_log_queries: storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), + deduplicated_storage_log_queries: deduped_storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), used_contract_hashes: self.get_used_contracts(), user_l2_to_l1_logs: user_l2_to_l1_logs .into_iter() @@ -114,7 +129,10 @@ impl VmInterface for Vm { system_logs, total_log_queries, cycles_used: self.state.local_state.monotonic_cycle_counter, - deduplicated_events_logs, + deduplicated_events_logs: deduplicated_events_logs + .into_iter() + .map(GlueInto::glue_into) + .collect(), storage_refunds: self.state.storage.returned_refunds.inner().clone(), } } @@ -127,13 +145,19 @@ impl VmInterface for Vm { tracer: Self::TracerDispatcher, tx: Transaction, with_compression: bool, - ) -> Result { + ) -> ( + Result<(), BytecodeCompressionError>, + VmExecutionResultAndLogs, + ) { self.push_transaction_with_compression(tx, with_compression); - let result = self.inspect_inner(tracer, VmExecutionMode::OneTx); + let result = self.inspect_inner(tracer, VmExecutionMode::OneTx, None); if self.has_unpublished_bytecodes() { - Err(BytecodeCompressionError::BytecodeCompressionFailed) + ( + Err(BytecodeCompressionError::BytecodeCompressionFailed), + result, + ) } else { - Ok(result) + (Ok(()), result) } } @@ -141,6 +165,10 @@ impl VmInterface for Vm { self.record_vm_memory_metrics_inner() } + fn has_enough_gas_for_batch_tip(&self) -> bool { + self.state.local_state.callstack.current.ergs_remaining >= BOOTLOADER_BATCH_TIP_OVERHEAD + } + fn finish_batch(&mut self) -> FinishedL1Batch { let result = self.execute(VmExecutionMode::Batch); let execution_state = self.get_current_execution_state(); diff --git a/core/lib/multivm/src/versions/vm_m5/errors/tx_revert_reason.rs b/core/lib/multivm/src/versions/vm_m5/errors/tx_revert_reason.rs index 9259dd87a376..439524108a95 100644 --- a/core/lib/multivm/src/versions/vm_m5/errors/tx_revert_reason.rs +++ b/core/lib/multivm/src/versions/vm_m5/errors/tx_revert_reason.rs @@ -7,11 +7,11 @@ use super::{BootloaderErrorCode, VmRevertReason}; // Reasons why the transaction executed inside the bootloader could fail. #[derive(Debug, Clone, PartialEq)] pub enum TxRevertReason { - // Can only be returned in EthCall execution mode (=ExecuteOnly) + // Can only be returned in EthCall execution mode `(=ExecuteOnly)` EthCall(VmRevertReason), // Returned when the execution of an L2 transaction has failed TxReverted(VmRevertReason), - // Can only be returned in VerifyAndExecute + // Can only be returned in `VerifyAndExecute` ValidationFailed(VmRevertReason), PaymasterValidationFailed(VmRevertReason), PrePaymasterPreparationFailed(VmRevertReason), @@ -20,7 +20,7 @@ pub enum TxRevertReason { FailedToChargeFee(VmRevertReason), // Emitted when trying to call a transaction from an account that has not // been deployed as an account (i.e. the `from` is just a contract). - // Can only be returned in VerifyAndExecute + // Can only be returned in `VerifyAndExecute` FromIsNotAnAccount, // Currently cannot be returned. Should be removed when refactoring errors. InnerTxError, @@ -98,7 +98,7 @@ impl TxRevertReason { BootloaderErrorCode::UnacceptablePubdataPrice => { Self::UnexpectedVMBehavior("UnacceptablePubdataPrice".to_owned()) } - // This is different from AccountTxValidationFailed error in a way that it means that + // This is different from `AccountTxValidationFailed` error in a way that it means that // the error was not produced by the account itself, but for some other unknown reason (most likely not enough gas) BootloaderErrorCode::TxValidationError => Self::ValidationFailed(revert_reason), // Note, that `InnerTxError` is derived only after the actual tx execution, so diff --git a/core/lib/multivm/src/versions/vm_m5/history_recorder.rs b/core/lib/multivm/src/versions/vm_m5/history_recorder.rs index 7a158b4dea79..f744be32d0bf 100644 --- a/core/lib/multivm/src/versions/vm_m5/history_recorder.rs +++ b/core/lib/multivm/src/versions/vm_m5/history_recorder.rs @@ -19,13 +19,13 @@ pub type MemoryWithHistory = HistoryRecorder; pub type FrameManagerWithHistory = HistoryRecorder>; pub type IntFrameManagerWithHistory = FrameManagerWithHistory>; -// Within the same cycle, timestamps in range timestamp..timestamp+TIME_DELTA_PER_CYCLE-1 -// can be used. This can sometimes vioalate monotonicity of the timestamp within the +// Within the same cycle, timestamps in range `timestamp..timestamp+TIME_DELTA_PER_CYCLE-1` +// can be used. This can sometimes violate monotonicity of the timestamp within the // same cycle, so it should be normalized. fn normalize_timestamp(timestamp: Timestamp) -> Timestamp { let timestamp = timestamp.0; - // Making sure it is divisible by TIME_DELTA_PER_CYCLE + // Making sure it is divisible by `TIME_DELTA_PER_CYCLE` Timestamp(timestamp - timestamp % zkevm_opcode_defs::TIME_DELTA_PER_CYCLE) } diff --git a/core/lib/multivm/src/versions/vm_m5/memory.rs b/core/lib/multivm/src/versions/vm_m5/memory.rs index dc58450263e4..34c083b21f79 100644 --- a/core/lib/multivm/src/versions/vm_m5/memory.rs +++ b/core/lib/multivm/src/versions/vm_m5/memory.rs @@ -34,7 +34,7 @@ impl OracleWithHistory for SimpleMemory { impl SimpleMemory { pub fn populate(&mut self, elements: Vec<(u32, Vec)>, timestamp: Timestamp) { for (page, values) in elements.into_iter() { - // Resizing the pages array to fit the page. + // Re-sizing the pages array to fit the page. let len = values.len(); assert!(len <= MEMORY_CELLS_OTHER_PAGES); @@ -261,7 +261,7 @@ impl Memory for SimpleMemory { let returndata_page = returndata_fat_pointer.memory_page; for page in current_observable_pages { - // If the page's number is greater than or equal to the base_page, + // If the page's number is greater than or equal to the `base_page`, // it means that it was created by the internal calls of this contract. // We need to add this check as the calldata pointer is also part of the // observable pages. @@ -276,7 +276,7 @@ impl Memory for SimpleMemory { } } -// It is expected that there is some intersection between [word_number*32..word_number*32+31] and [start, end] +// It is expected that there is some intersection between `[word_number*32..word_number*32+31]` and `[start, end]` fn extract_needed_bytes_from_word( word_value: Vec, word_number: usize, @@ -284,7 +284,7 @@ fn extract_needed_bytes_from_word( end: usize, ) -> Vec { let word_start = word_number * 32; - let word_end = word_start + 31; // Note, that at word_start + 32 a new word already starts + let word_end = word_start + 31; // Note, that at `word_start + 32` a new word already starts let intersection_left = std::cmp::max(word_start, start); let intersection_right = std::cmp::min(word_end, end); diff --git a/core/lib/multivm/src/versions/vm_m5/mod.rs b/core/lib/multivm/src/versions/vm_m5/mod.rs index fc549761e033..946b2e4bf56c 100644 --- a/core/lib/multivm/src/versions/vm_m5/mod.rs +++ b/core/lib/multivm/src/versions/vm_m5/mod.rs @@ -23,8 +23,6 @@ mod pubdata_utils; mod refunds; pub mod storage; pub mod test_utils; -#[cfg(test)] -mod tests; pub mod transaction_data; pub mod utils; mod vm; diff --git a/core/lib/multivm/src/versions/vm_m5/oracles/mod.rs b/core/lib/multivm/src/versions/vm_m5/oracles/mod.rs index 6b821c68e9d2..c43c9987de5d 100644 --- a/core/lib/multivm/src/versions/vm_m5/oracles/mod.rs +++ b/core/lib/multivm/src/versions/vm_m5/oracles/mod.rs @@ -1,9 +1,9 @@ use zk_evm_1_3_1::aux_structures::Timestamp; // All the changes to the events in the DB will be applied after the tx is executed, -// so fow now it is fine. +// so for now it is fine. pub use zk_evm_1_3_1::reference_impls::event_sink::InMemoryEventSink as EventSinkOracle; // We will discard RAM as soon as the execution of a tx ends, so -// it is ok for now to use SimpleMemory +// it is ok for now to use `SimpleMemory` pub use zk_evm_1_3_1::reference_impls::memory::SimpleMemory as RamOracle; pub use zk_evm_1_3_1::testing::simple_tracer::NoopTracer; diff --git a/core/lib/multivm/src/versions/vm_m5/oracles/storage.rs b/core/lib/multivm/src/versions/vm_m5/oracles/storage.rs index c81b90f9c9cf..02cf5e9cdbc0 100644 --- a/core/lib/multivm/src/versions/vm_m5/oracles/storage.rs +++ b/core/lib/multivm/src/versions/vm_m5/oracles/storage.rs @@ -7,21 +7,19 @@ use zk_evm_1_3_1::{ zkevm_opcode_defs::system_params::INITIAL_STORAGE_WRITE_PUBDATA_BYTES, }; use zksync_types::{ - utils::storage_key_for_eth_balance, AccountTreeId, Address, StorageKey, StorageLogQuery, - StorageLogQueryType, BOOTLOADER_ADDRESS, U256, + utils::storage_key_for_eth_balance, AccountTreeId, Address, StorageKey, StorageLogQueryType, + BOOTLOADER_ADDRESS, U256, }; use zksync_utils::u256_to_h256; use super::OracleWithHistory; -use crate::{ - glue::GlueInto, - vm_m5::{ - history_recorder::{ - AppDataFrameManagerWithHistory, HashMapHistoryEvent, HistoryRecorder, StorageWrapper, - }, - storage::{Storage, StoragePtr}, - vm_instance::MultiVMSubversion, +use crate::vm_m5::{ + history_recorder::{ + AppDataFrameManagerWithHistory, HashMapHistoryEvent, HistoryRecorder, StorageWrapper, }, + storage::{Storage, StoragePtr}, + utils::StorageLogQuery, + vm_instance::MultiVMSubversion, }; // While the storage does not support different shards, it was decided to write the @@ -95,7 +93,7 @@ impl StorageOracle { self.frames_stack.push_forward( StorageLogQuery { - log_query: query.glue_into(), + log_query: query, log_type: StorageLogQueryType::Read, }, query.timestamp, @@ -119,7 +117,7 @@ impl StorageOracle { query.read_value = current_value; let mut storage_log_query = StorageLogQuery { - log_query: query.glue_into(), + log_query: query, log_type: log_query_type, }; self.frames_stack @@ -183,6 +181,7 @@ impl VmStorageOracle for StorageOracle { _monotonic_cycle_counter: u32, query: LogQuery, ) -> LogQuery { + // ``` // tracing::trace!( // "execute partial query cyc {:?} addr {:?} key {:?}, rw {:?}, wr {:?}, tx {:?}", // _monotonic_cycle_counter, @@ -192,6 +191,7 @@ impl VmStorageOracle for StorageOracle { // query.written_value, // query.tx_number_in_block // ); + // ``` assert!(!query.rollback); if query.rw_flag { // The number of bytes that have been compensated by the user to perform this write @@ -260,7 +260,7 @@ impl VmStorageOracle for StorageOracle { } }; - let LogQuery { written_value, .. } = query.log_query.glue_into(); + let LogQuery { written_value, .. } = query.log_query; let key = triplet_to_storage_key( query.log_query.shard_id, query.log_query.address, @@ -274,7 +274,7 @@ impl VmStorageOracle for StorageOracle { ); // Additional validation that the current value was correct - // Unwrap is safe because the return value from write_inner is the previous value in this leaf. + // Unwrap is safe because the return value from `write_inner` is the previous value in this leaf. // It is impossible to set leaf value to `None` assert_eq!(current_value, written_value); } diff --git a/core/lib/multivm/src/versions/vm_m5/oracles/tracer.rs b/core/lib/multivm/src/versions/vm_m5/oracles/tracer.rs index ac370f832e4c..481e8a7e02e6 100644 --- a/core/lib/multivm/src/versions/vm_m5/oracles/tracer.rs +++ b/core/lib/multivm/src/versions/vm_m5/oracles/tracer.rs @@ -178,7 +178,7 @@ fn touches_allowed_context(address: Address, key: U256) -> bool { return false; } - // Only chain_id is allowed to be touched. + // Only `chain_id` is allowed to be touched. key == U256::from(0u32) } @@ -303,7 +303,7 @@ impl ValidationTracer { return true; } - // The pair of MSG_VALUE_SIMULATOR_ADDRESS & L2_ETH_TOKEN_ADDRESS simulates the behavior of transferring ETH + // The pair of `MSG_VALUE_SIMULATOR_ADDRESS` & `L2_ETH_TOKEN_ADDRESS` simulates the behavior of transferring ETH // that is safe for the DDoS protection rules. if valid_eth_token_call(address, msg_sender) { return true; @@ -347,20 +347,20 @@ impl ValidationTracer { let (potential_address_bytes, potential_position_bytes) = calldata.split_at(32); let potential_address = be_bytes_to_safe_address(potential_address_bytes); - // If the validation_address is equal to the potential_address, - // then it is a request that could be used for mapping of kind mapping(address => ...). + // If the `validation_address` is equal to the `potential_address`, + // then it is a request that could be used for mapping of kind `mapping(address => ...)`. // - // If the potential_position_bytes were already allowed before, then this keccak might be used - // for ERC-20 allowance or any other of mapping(address => mapping(...)) + // If the `potential_position_bytes` were already allowed before, then this keccak might be used + // for ERC-20 allowance or any other of `mapping(address => mapping(...))` if potential_address == Some(validated_address) || self .auxilary_allowed_slots .contains(&H256::from_slice(potential_position_bytes)) { - // This is request that could be used for mapping of kind mapping(address => ...) + // This is request that could be used for mapping of kind `mapping(address => ...)` // We could theoretically wait for the slot number to be returned by the - // keccak256 precompile itself, but this would complicate the code even further + // `keccak256` precompile itself, but this would complicate the code even further // so let's calculate it here. let slot = keccak256(calldata); @@ -719,7 +719,7 @@ impl PubdataSpentTracer for BootloaderTracer {} impl BootloaderTracer { fn current_frame_is_bootloader(local_state: &VmLocalState) -> bool { - // The current frame is bootloader if the callstack depth is 1. + // The current frame is bootloader if the call stack depth is 1. // Some of the near calls inside the bootloader can be out of gas, which is totally normal behavior // and it shouldn't result in `is_bootloader_out_of_gas` becoming true. local_state.callstack.inner.len() == 1 @@ -762,7 +762,7 @@ impl VmHook { let value = data.src1_value.value; - // Only UMA opcodes in the bootloader serve for vm hooks + // Only `UMA` opcodes in the bootloader serve for vm hooks if !matches!(opcode_variant.opcode, Opcode::UMA(UMAOpcode::HeapWrite)) || heap_page != BOOTLOADER_HEAP_PAGE || fat_ptr.offset != VM_HOOK_POSITION * 32 diff --git a/core/lib/multivm/src/versions/vm_m5/pubdata_utils.rs b/core/lib/multivm/src/versions/vm_m5/pubdata_utils.rs index 63e45edcbb85..1f8f9922c144 100644 --- a/core/lib/multivm/src/versions/vm_m5/pubdata_utils.rs +++ b/core/lib/multivm/src/versions/vm_m5/pubdata_utils.rs @@ -1,9 +1,10 @@ use std::collections::HashMap; -use zk_evm_1_3_1::aux_structures::Timestamp; +use itertools::Itertools; +use zk_evm_1_3_1::aux_structures::{LogQuery, Timestamp}; +use zkevm_test_harness_1_3_3::witness::sort_storage_access::sort_storage_access_queries; use zksync_types::{ event::{extract_long_l2_to_l1_messages, extract_published_bytecodes}, - zkevm_test_harness::witness::sort_storage_access::sort_storage_access_queries, StorageKey, PUBLISH_BYTECODE_OVERHEAD, SYSTEM_CONTEXT_ADDRESS, }; use zksync_utils::bytecode::bytecode_len_in_bytes; @@ -85,14 +86,27 @@ impl VmInstance { .forward, from_timestamp, ); - let (_, deduplicated_logs) = - sort_storage_access_queries(storage_logs.iter().map(|log| &log.log_query)); + + // To allow calling the `vm-1.3.3`s. method, the `v1.3.1`'s `LogQuery` has to be converted + // to the `vm-1.3.3`'s `LogQuery`. Then, we need to convert it back. + let deduplicated_logs: Vec = sort_storage_access_queries( + &storage_logs + .iter() + .map(|log| { + GlueInto::::glue_into(log.log_query) + }) + .collect_vec(), + ) + .1 + .into_iter() + .map(GlueInto::::glue_into) + .collect(); deduplicated_logs .into_iter() .filter_map(|log| { if log.rw_flag { - let key = storage_key_of_log(&log.glue_into()); + let key = storage_key_of_log(&log); let pre_paid = pre_paid_before_tx(&key); let to_pay_by_user = self.state.storage.base_price_for_write(&log.glue_into()); diff --git a/core/lib/multivm/src/versions/vm_m5/refunds.rs b/core/lib/multivm/src/versions/vm_m5/refunds.rs index 8e084fd9ee32..fd4e2788f035 100644 --- a/core/lib/multivm/src/versions/vm_m5/refunds.rs +++ b/core/lib/multivm/src/versions/vm_m5/refunds.rs @@ -75,7 +75,7 @@ impl VmInstance { ) -> u32 { // TODO (SMA-1715): Make users pay for the block overhead 0 - + // ``` // let pubdata_published = self.pubdata_published(from_timestamp); // // let total_gas_spent = gas_remaining_before - self.gas_remaining(); @@ -120,6 +120,7 @@ impl VmInstance { // ); // 0 // } + // ``` } // TODO (SMA-1715): Make users pay for the block overhead @@ -133,39 +134,39 @@ impl VmInstance { _l2_l1_logs: usize, ) -> u32 { 0 - + // ``` // let overhead_for_block_gas = U256::from(crate::transaction_data::block_overhead_gas( // gas_per_pubdata_byte_limit, // )); - + // // let encoded_len = U256::from(encoded_len); // let pubdata_published = U256::from(pubdata_published); // let gas_spent_on_computation = U256::from(gas_spent_on_computation); // let number_of_decommitment_requests = U256::from(number_of_decommitment_requests); // let l2_l1_logs = U256::from(l2_l1_logs); - + // // let tx_slot_overhead = ceil_div_u256(overhead_for_block_gas, MAX_TXS_IN_BLOCK.into()); - + // // let overhead_for_length = ceil_div_u256( // encoded_len * overhead_for_block_gas, // BOOTLOADER_TX_ENCODING_SPACE.into(), // ); - + // // let actual_overhead_for_pubdata = ceil_div_u256( // pubdata_published * overhead_for_block_gas, // MAX_PUBDATA_PER_BLOCK.into(), // ); - + // // let actual_gas_limit_overhead = ceil_div_u256( // gas_spent_on_computation * overhead_for_block_gas, // MAX_BLOCK_MULTIINSTANCE_GAS_LIMIT.into(), // ); - + // // let code_decommitter_sorter_circuit_overhead = ceil_div_u256( // number_of_decommitment_requests * overhead_for_block_gas, // GEOMETRY_CONFIG.limit_for_code_decommitter_sorter.into(), // ); - + // // let l1_l2_logs_overhead = ceil_div_u256( // l2_l1_logs * overhead_for_block_gas, // std::cmp::min( @@ -174,7 +175,7 @@ impl VmInstance { // ) // .into(), // ); - + // // let overhead = vec![ // tx_slot_overhead, // overhead_for_length, @@ -186,8 +187,9 @@ impl VmInstance { // .into_iter() // .max() // .unwrap(); - + // // overhead.as_u32() + // ``` } pub(crate) fn get_tx_gas_limit(&self, tx_index: usize) -> u32 { diff --git a/core/lib/multivm/src/versions/vm_m5/test_utils.rs b/core/lib/multivm/src/versions/vm_m5/test_utils.rs index 6920e77b8a8c..c052353ecb55 100644 --- a/core/lib/multivm/src/versions/vm_m5/test_utils.rs +++ b/core/lib/multivm/src/versions/vm_m5/test_utils.rs @@ -21,13 +21,13 @@ use zksync_types::{ fee::Fee, l2::L2Tx, web3::signing::keccak256, - Execute, L2ChainId, Nonce, StorageKey, StorageLogQuery, StorageValue, - CONTRACT_DEPLOYER_ADDRESS, H256, U256, + Execute, L2ChainId, Nonce, StorageKey, StorageValue, CONTRACT_DEPLOYER_ADDRESS, H256, U256, }; use zksync_utils::{ address_to_h256, bytecode::hash_bytecode, h256_to_account_address, u256_to_h256, }; +use super::utils::StorageLogQuery; use crate::vm_m5::{ event_sink::InMemoryEventSink, history_recorder::{FrameManager, HistoryRecorder}, diff --git a/core/lib/multivm/src/versions/vm_m5/tests/bootloader.rs b/core/lib/multivm/src/versions/vm_m5/tests/bootloader.rs deleted file mode 100644 index 1034e8595936..000000000000 --- a/core/lib/multivm/src/versions/vm_m5/tests/bootloader.rs +++ /dev/null @@ -1,1655 +0,0 @@ -// //! -// //! Tests for the bootloader -// //! The description for each of the tests can be found in the corresponding `.yul` file. -// //! -// #![cfg_attr(test, allow(unused_imports))] - -// use crate::errors::{VmRevertReason, VmRevertReasonParsingResult}; -// use crate::memory::SimpleMemory; -// use crate::oracles::tracer::{ -// read_pointer, ExecutionEndTracer, PendingRefundTracer, PubdataSpentTracer, -// TransactionResultTracer, VmHook, -// }; -// use crate::storage::{Storage, StoragePtr}; -// use crate::test_utils::{ -// get_create_execute, get_create_zksync_address, get_deploy_tx, get_error_tx, -// mock_loadnext_test_call, VmInstanceInnerState, -// }; -// use crate::utils::{ -// create_test_block_params, insert_system_contracts, read_bootloader_test_code, -// BASE_SYSTEM_CONTRACTS, BLOCK_GAS_LIMIT, -// }; -// use crate::vm::{ -// get_vm_hook_params, tx_has_failed, VmBlockResult, VmExecutionStopReason, ZkSyncVmState, -// MAX_MEM_SIZE_BYTES, -// }; -// use crate::vm_with_bootloader::{ -// bytecode_to_factory_dep, get_bootloader_memory, get_bootloader_memory_for_encoded_tx, -// init_vm_inner, push_raw_transaction_to_bootloader_memory, -// push_transaction_to_bootloader_memory, BlockContext, DerivedBlockContext, BOOTLOADER_HEAP_PAGE, -// BOOTLOADER_TX_DESCRIPTION_OFFSET, TX_DESCRIPTION_OFFSET, TX_GAS_LIMIT_OFFSET, -// }; -// use crate::vm_with_bootloader::{BlockContextMode, BootloaderJobType, TxExecutionMode}; -// use crate::{test_utils, VmInstance}; -// use crate::{TxRevertReason, VmExecutionResult}; -// use itertools::Itertools; -// use std::cell::RefCell; -// use std::convert::TryFrom; -// use std::ops::{Add, DivAssign}; -// use std::rc::Rc; -// use tempfile::TempDir; -// use zk_evm_1_3_1::abstractions::{ -// AfterDecodingData, AfterExecutionData, BeforeExecutionData, Tracer, VmLocalStateData, -// MAX_HEAP_PAGE_SIZE_IN_WORDS, MAX_MEMORY_BYTES, -// }; -// use zk_evm_1_3_1::aux_structures::Timestamp; -// use zk_evm_1_3_1::block_properties::BlockProperties; -// use zk_evm_1_3_1::sha3::digest::typenum::U830; -// use zk_evm_1_3_1::witness_trace::VmWitnessTracer; -// use zk_evm_1_3_1::zkevm_opcode_defs::decoding::VmEncodingMode; -// use zk_evm_1_3_1::zkevm_opcode_defs::FatPointer; -// use zksync_types::block::DeployedContract; -// use zksync_types::ethabi::encode; -// use zksync_types::l1::L1Tx; -// use zksync_types::tx::tx_execution_info::{TxExecutionStatus, VmExecutionLogs}; -// use zksync_utils::test_utils::LoadnextContractExecutionParams; -// use zksync_utils::{ -// address_to_h256, bytecode::hash_bytecode, bytes_to_be_words, bytes_to_le_words, h256_to_u256, -// u256_to_h256, -// }; -// use zksync_utils::{h256_to_account_address, u256_to_account_address}; - -// use crate::{transaction_data::TransactionData, OracleTools}; -// use std::time; -// use zksync_contracts::{ -// default_erc20_bytecode, get_loadnext_contract, known_codes_contract, load_contract, -// load_sys_contract, read_bootloader_code, read_bytecode, read_zbin_bytecode, -// BaseSystemContracts, SystemContractCode, PLAYGROUND_BLOCK_BOOTLOADER_CODE, -// }; -// use zksync_crypto::rand::random; -// use zksync_state::secondary_storage::SecondaryStateStorage; -// use zksync_state::storage_view::StorageView; -// use zksync_storage::db::Database; -// use zksync_storage::RocksDB; -// use zksync_types::system_contracts::{DEPLOYMENT_NONCE_INCREMENT, TX_NONCE_INCREMENT}; -// use zksync_types::utils::{ -// deployed_address_create, storage_key_for_eth_balance, storage_key_for_standard_token_balance, -// }; -// use zksync_types::{ -// ethabi::Token, AccountTreeId, Address, Execute, ExecuteTransactionCommon, L1BatchNumber, -// L2ChainId, PackedEthSignature, StorageKey, StorageLogQueryType, Transaction, H256, -// KNOWN_CODES_STORAGE_ADDRESS, U256, -// }; -// use zksync_types::{fee::Fee, l2::L2Tx, l2_to_l1_log::L2ToL1Log, tx::ExecutionMetrics}; -// use zksync_types::{ -// get_code_key, get_is_account_key, get_known_code_key, get_nonce_key, L1TxCommonData, Nonce, -// PriorityOpId, SerialId, StorageLog, ZkSyncReadStorage, BOOTLOADER_ADDRESS, -// CONTRACT_DEPLOYER_ADDRESS, H160, L2_ETH_TOKEN_ADDRESS, MAX_GAS_PER_PUBDATA_BYTE, -// MAX_TXS_IN_BLOCK, SYSTEM_CONTEXT_ADDRESS, SYSTEM_CONTEXT_GAS_PRICE_POSITION, -// SYSTEM_CONTEXT_MINIMAL_BASE_FEE, SYSTEM_CONTEXT_TX_ORIGIN_POSITION, -// }; - -// use once_cell::sync::Lazy; -// use zksync_system_constants::ZKPORTER_IS_AVAILABLE; - -// fn run_vm_with_custom_factory_deps<'a>( -// oracle_tools: &'a mut OracleTools<'a, false>, -// block_context: BlockContext, -// block_properties: &'a BlockProperties, -// encoded_tx: Vec, -// predefined_overhead: u32, -// expected_error: Option, -// ) { -// let mut base_system_contracts = BASE_SYSTEM_CONTRACTS.clone(); -// base_system_contracts.bootloader = PLAYGROUND_BLOCK_BOOTLOADER_CODE.clone(); -// let mut vm = init_vm_inner( -// oracle_tools, -// BlockContextMode::OverrideCurrent(block_context.into()), -// block_properties, -// BLOCK_GAS_LIMIT, -// &base_system_contracts, -// TxExecutionMode::VerifyExecute, -// ); - -// vm.bootloader_state.add_tx_data(encoded_tx.len()); -// vm.state.memory.populate_page( -// BOOTLOADER_HEAP_PAGE as usize, -// get_bootloader_memory_for_encoded_tx( -// encoded_tx, -// 0, -// TxExecutionMode::VerifyExecute, -// 0, -// 0, -// predefined_overhead, -// ), -// Timestamp(0), -// ); - -// let result = vm.execute_next_tx().err(); - -// assert_eq!(expected_error, result); -// } - -// fn get_balance(token_id: AccountTreeId, account: &Address, main_storage: StoragePtr<'_>) -> U256 { -// let key = storage_key_for_standard_token_balance(token_id, account); -// h256_to_u256(main_storage.borrow_mut().get_value(&key)) -// } - -// #[test] -// fn test_dummy_bootloader() { -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); -// let mut storage_accessor = StorageView::new(&raw_storage); -// let storage_ptr: &mut dyn Storage = &mut storage_accessor; - -// let mut oracle_tools = OracleTools::new(storage_ptr); -// let (block_context, block_properties) = create_test_block_params(); -// let mut base_system_contracts = BASE_SYSTEM_CONTRACTS.clone(); -// let bootloader_code = read_bootloader_test_code("dummy"); -// let bootloader_hash = hash_bytecode(&bootloader_code); - -// base_system_contracts.bootloader = SystemContractCode { -// code: bytes_to_be_words(bootloader_code), -// hash: bootloader_hash, -// }; - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context.into(), Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &base_system_contracts, -// TxExecutionMode::VerifyExecute, -// ); - -// let VmBlockResult { -// full_result: res, .. -// } = vm.execute_till_block_end(BootloaderJobType::BlockPostprocessing); - -// // Dummy bootloader should not panic -// assert!(res.revert_reason.is_none()); - -// let correct_first_cell = U256::from_str_radix("123123123", 16).unwrap(); - -// verify_required_memory( -// &vm.state, -// vec![(correct_first_cell, BOOTLOADER_HEAP_PAGE, 0)], -// ); -// } - -// #[test] -// fn test_bootloader_out_of_gas() { -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); -// let mut storage_accessor = StorageView::new(&raw_storage); -// let storage_ptr: &mut dyn Storage = &mut storage_accessor; - -// let mut oracle_tools = OracleTools::new(storage_ptr); -// let (block_context, block_properties) = create_test_block_params(); - -// let mut base_system_contracts = BASE_SYSTEM_CONTRACTS.clone(); - -// let bootloader_code = read_bootloader_test_code("dummy"); -// let bootloader_hash = hash_bytecode(&bootloader_code); - -// base_system_contracts.bootloader = SystemContractCode { -// code: bytes_to_be_words(bootloader_code), -// hash: bootloader_hash, -// }; - -// // init vm with only 100 ergs -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context.into(), Default::default()), -// &block_properties, -// 10, -// &base_system_contracts, -// TxExecutionMode::VerifyExecute, -// ); - -// let res = vm.execute_block_tip(); - -// assert_eq!(res.revert_reason, Some(TxRevertReason::BootloaderOutOfGas)); -// } - -// fn verify_required_storage(state: &ZkSyncVmState<'_>, required_values: Vec<(H256, StorageKey)>) { -// for (required_value, key) in required_values { -// let current_value = state.storage.storage.read_from_storage(&key); - -// assert_eq!( -// u256_to_h256(current_value), -// required_value, -// "Invalid value at key {key:?}" -// ); -// } -// } - -// fn verify_required_memory(state: &ZkSyncVmState<'_>, required_values: Vec<(U256, u32, u32)>) { -// for (required_value, memory_page, cell) in required_values { -// let current_value = state -// .memory -// .dump_page_content_as_u256_words(memory_page, cell..cell + 1)[0]; -// assert_eq!(current_value, required_value); -// } -// } - -// #[test] -// fn test_default_aa_interaction() { -// // In this test, we aim to test whether a simple account interaction (without any fee logic) -// // will work. The account will try to deploy a simple contract from integration tests. - -// let (block_context, block_properties) = create_test_block_params(); -// let block_context: DerivedBlockContext = block_context.into(); - -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); -// let storage_ptr: &mut dyn Storage = &mut StorageView::new(&raw_storage); - -// let operator_address = block_context.context.operator_address; -// let base_fee = block_context.base_fee; -// // We deploy here counter contract, because its logic is trivial -// let contract_code = read_test_contract(); -// let contract_code_hash = hash_bytecode(&contract_code); -// let tx: Transaction = get_deploy_tx( -// H256::random(), -// Nonce(0), -// &contract_code, -// vec![], -// &[], -// Fee { -// gas_limit: U256::from(10000000u32), -// max_fee_per_gas: U256::from(base_fee), -// max_priority_fee_per_gas: U256::from(0), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); -// let tx_data: TransactionData = tx.clone().into(); - -// let maximal_fee = tx_data.gas_limit * tx_data.max_fee_per_gas; -// let sender_address = tx_data.from(); -// // set balance - -// let key = storage_key_for_eth_balance(&sender_address); -// storage_ptr.set_value(&key, u256_to_h256(U256([0, 0, 1, 0]))); - -// let mut oracle_tools = OracleTools::new(storage_ptr); - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context, Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute); - -// let tx_execution_result = vm -// .execute_next_tx() -// .expect("Bootloader failed while processing transaction"); - -// assert_eq!( -// tx_execution_result.status, -// TxExecutionStatus::Success, -// "Transaction wasn't successful" -// ); - -// let VmBlockResult { -// full_result: res, .. -// } = vm.execute_till_block_end(BootloaderJobType::TransactionExecution); -// // Should not panic -// assert!( -// res.revert_reason.is_none(), -// "Bootloader was not expected to revert: {:?}", -// res.revert_reason -// ); - -// // Both deployment and ordinary nonce should be incremented by one. -// let account_nonce_key = get_nonce_key(&sender_address); -// let expected_nonce = TX_NONCE_INCREMENT + DEPLOYMENT_NONCE_INCREMENT; - -// // The code hash of the deployed contract should be marked as republished. -// let known_codes_key = get_known_code_key(&contract_code_hash); - -// // The contract should be deployed successfully. -// let deployed_address = deployed_address_create(sender_address, U256::zero()); -// let account_code_key = get_code_key(&deployed_address); - -// let expected_slots = vec![ -// (u256_to_h256(expected_nonce), account_nonce_key), -// (u256_to_h256(U256::from(1u32)), known_codes_key), -// (contract_code_hash, account_code_key), -// ]; - -// verify_required_storage(&vm.state, expected_slots); - -// assert!(!tx_has_failed(&vm.state, 0)); - -// let expected_fee = -// maximal_fee - U256::from(tx_execution_result.gas_refunded) * U256::from(base_fee); -// let operator_balance = get_balance( -// AccountTreeId::new(L2_ETH_TOKEN_ADDRESS), -// &operator_address, -// vm.state.storage.storage.get_ptr(), -// ); - -// assert!( -// operator_balance == expected_fee, -// "Operator did not receive his fee" -// ); -// } - -// fn execute_vm_with_predetermined_refund(txs: Vec, refunds: Vec) -> VmBlockResult { -// let (block_context, block_properties) = create_test_block_params(); -// let block_context: DerivedBlockContext = block_context.into(); - -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); -// let storage_ptr: &mut dyn Storage = &mut StorageView::new(&raw_storage); - -// // set balance -// for tx in txs.iter() { -// let sender_address = tx.initiator_account(); -// let key = storage_key_for_eth_balance(&sender_address); -// storage_ptr.set_value(&key, u256_to_h256(U256([0, 0, 1, 0]))); -// } - -// let mut oracle_tools = OracleTools::new(storage_ptr); - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context, Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); - -// let codes_for_decommiter = txs -// .iter() -// .flat_map(|tx| { -// tx.execute -// .factory_deps -// .clone() -// .unwrap_or_default() -// .iter() -// .map(|dep| bytecode_to_factory_dep(dep.clone())) -// .collect::)>>() -// }) -// .collect(); - -// vm.state.decommittment_processor.populate( -// codes_for_decommiter, -// Timestamp(vm.state.local_state.timestamp), -// ); - -// let memory_with_suggested_refund = get_bootloader_memory( -// txs.into_iter().map(Into::into).collect(), -// refunds, -// TxExecutionMode::VerifyExecute, -// BlockContextMode::NewBlock(block_context, Default::default()), -// ); - -// vm.state.memory.populate_page( -// BOOTLOADER_HEAP_PAGE as usize, -// memory_with_suggested_refund, -// Timestamp(0), -// ); - -// vm.execute_till_block_end(BootloaderJobType::TransactionExecution) -// } - -// #[test] -// fn test_predetermined_refunded_gas() { -// // In this test, we compare the execution of the bootloader with the predefined -// // refunded gas and without them - -// let (block_context, block_properties) = create_test_block_params(); -// let block_context: DerivedBlockContext = block_context.into(); - -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); -// let storage_ptr: &mut dyn Storage = &mut StorageView::new(&raw_storage); - -// let base_fee = block_context.base_fee; -// // We deploy here counter contract, because its logic is trivial -// let contract_code = read_test_contract(); -// let tx: Transaction = get_deploy_tx( -// H256::random(), -// Nonce(0), -// &contract_code, -// vec![], -// &[], -// Fee { -// gas_limit: U256::from(10000000u32), -// max_fee_per_gas: U256::from(base_fee), -// max_priority_fee_per_gas: U256::from(0), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); - -// let sender_address = tx.initiator_account(); - -// // set balance -// let key = storage_key_for_eth_balance(&sender_address); -// storage_ptr.set_value(&key, u256_to_h256(U256([0, 0, 1, 0]))); - -// let mut oracle_tools = OracleTools::new(storage_ptr); - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context, Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); - -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute); - -// let tx_execution_result = vm -// .execute_next_tx() -// .expect("Bootloader failed while processing transaction"); - -// assert_eq!( -// tx_execution_result.status, -// TxExecutionStatus::Success, -// "Transaction wasn't successful" -// ); - -// // If the refund provided by the operator or the final refund are the 0 -// // there is no impact of the operator's refund at all and so this test does not -// // make much sense. -// assert!( -// tx_execution_result.operator_suggested_refund > 0, -// "The operator's refund is 0" -// ); -// assert!( -// tx_execution_result.gas_refunded > 0, -// "The final refund is 0" -// ); - -// let mut result = vm.execute_till_block_end(BootloaderJobType::TransactionExecution); -// assert!( -// result.full_result.revert_reason.is_none(), -// "Bootloader was not expected to revert: {:?}", -// result.full_result.revert_reason -// ); - -// let mut result_with_predetermined_refund = execute_vm_with_predetermined_refund( -// vec![tx], -// vec![tx_execution_result.operator_suggested_refund], -// ); -// // We need to sort these lists as those are flattened from HashMaps -// result.full_result.used_contract_hashes.sort(); -// result_with_predetermined_refund -// .full_result -// .used_contract_hashes -// .sort(); - -// assert_eq!( -// result.full_result.events, -// result_with_predetermined_refund.full_result.events -// ); -// assert_eq!( -// result.full_result.l2_to_l1_logs, -// result_with_predetermined_refund.full_result.l2_to_l1_logs -// ); -// assert_eq!( -// result.full_result.storage_log_queries, -// result_with_predetermined_refund -// .full_result -// .storage_log_queries -// ); -// assert_eq!( -// result.full_result.used_contract_hashes, -// result_with_predetermined_refund -// .full_result -// .used_contract_hashes -// ); -// } - -// #[derive(Debug, Clone)] -// enum TransactionRollbackTestInfo { -// Rejected(Transaction, TxRevertReason), -// Processed(Transaction, bool, TxExecutionStatus), -// } - -// impl TransactionRollbackTestInfo { -// fn new_rejected(transaction: Transaction, revert_reason: TxRevertReason) -> Self { -// Self::Rejected(transaction, revert_reason) -// } - -// fn new_processed( -// transaction: Transaction, -// should_be_rollbacked: bool, -// expected_status: TxExecutionStatus, -// ) -> Self { -// Self::Processed(transaction, should_be_rollbacked, expected_status) -// } - -// fn get_transaction(&self) -> &Transaction { -// match self { -// TransactionRollbackTestInfo::Rejected(tx, _) => tx, -// TransactionRollbackTestInfo::Processed(tx, _, _) => tx, -// } -// } - -// fn rejection_reason(&self) -> Option { -// match self { -// TransactionRollbackTestInfo::Rejected(_, revert_reason) => Some(revert_reason.clone()), -// TransactionRollbackTestInfo::Processed(_, _, _) => None, -// } -// } - -// fn should_rollback(&self) -> bool { -// match self { -// TransactionRollbackTestInfo::Rejected(_, _) => true, -// TransactionRollbackTestInfo::Processed(_, x, _) => *x, -// } -// } - -// fn expected_status(&self) -> TxExecutionStatus { -// match self { -// TransactionRollbackTestInfo::Rejected(_, _) => { -// panic!("There is no execution status for rejected transaction") -// } -// TransactionRollbackTestInfo::Processed(_, _, status) => *status, -// } -// } -// } - -// // Accepts the address of the sender as well as the list of pairs of its transactions -// // and whether these transactions should succeed. -// fn execute_vm_with_possible_rollbacks( -// sender_address: Address, -// transactions: Vec, -// block_context: DerivedBlockContext, -// block_properties: BlockProperties, -// ) -> VmExecutionResult { -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); -// let storage_ptr: &mut dyn Storage = &mut StorageView::new(&raw_storage); - -// // Setting infinite balance for the sender. -// let key = storage_key_for_eth_balance(&sender_address); -// storage_ptr.set_value(&key, u256_to_h256(U256([0, 0, 1, 0]))); - -// let mut oracle_tools = OracleTools::new(storage_ptr); - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context, Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); - -// for test_info in transactions { -// vm.save_current_vm_as_snapshot(); -// let vm_state_before_tx = vm.dump_inner_state(); -// push_transaction_to_bootloader_memory( -// &mut vm, -// test_info.get_transaction(), -// TxExecutionMode::VerifyExecute, -// ); - -// match vm.execute_next_tx() { -// Err(reason) => { -// assert_eq!(test_info.rejection_reason(), Some(reason)); -// } -// Ok(res) => { -// assert_eq!(test_info.rejection_reason(), None); -// assert_eq!( -// res.status, -// test_info.expected_status(), -// "Transaction status is not correct" -// ); -// } -// }; - -// if test_info.should_rollback() { -// // Some error has occurred, we should reject the transaction -// vm.rollback_to_latest_snapshot(); - -// // vm_state_before_tx. -// let state_after_rollback = vm.dump_inner_state(); -// assert_eq!( -// vm_state_before_tx, state_after_rollback, -// "Did not rollback VM state correctly" -// ); -// } -// } - -// let VmBlockResult { -// full_result: mut result, -// .. -// } = vm.execute_till_block_end(BootloaderJobType::BlockPostprocessing); -// // Used contract hashes are retrieved in unordered manner. -// // However it must be sorted for the comparisons in tests to work -// result.used_contract_hashes.sort(); - -// result -// } - -// // Sets the signature for an L2 transaction and returns the same transaction -// // but this different signature. -// fn change_signature(mut tx: Transaction, signature: Vec) -> Transaction { -// tx.common_data = match tx.common_data { -// ExecuteTransactionCommon::L2(mut data) => { -// data.signature = signature; -// ExecuteTransactionCommon::L2(data) -// } -// _ => unreachable!(), -// }; - -// tx -// } - -// #[test] -// fn test_vm_rollbacks() { -// let (block_context, block_properties): (DerivedBlockContext, BlockProperties) = { -// let (block_context, block_properties) = create_test_block_params(); -// (block_context.into(), block_properties) -// }; - -// let base_fee = U256::from(block_context.base_fee); - -// let sender_private_key = H256::random(); -// let contract_code = read_test_contract(); - -// let tx_nonce_0: Transaction = get_deploy_tx( -// sender_private_key, -// Nonce(0), -// &contract_code, -// vec![], -// &[], -// Fee { -// gas_limit: U256::from(10000000u32), -// max_fee_per_gas: base_fee, -// max_priority_fee_per_gas: U256::zero(), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); -// let tx_nonce_1: Transaction = get_deploy_tx( -// sender_private_key, -// Nonce(1), -// &contract_code, -// vec![], -// &[], -// Fee { -// gas_limit: U256::from(10000000u32), -// max_fee_per_gas: base_fee, -// max_priority_fee_per_gas: U256::zero(), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); -// let tx_nonce_2: Transaction = get_deploy_tx( -// sender_private_key, -// Nonce(2), -// &contract_code, -// vec![], -// &[], -// Fee { -// gas_limit: U256::from(10000000u32), -// max_fee_per_gas: base_fee, -// max_priority_fee_per_gas: U256::zero(), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); - -// let wrong_signature_length_tx = change_signature(tx_nonce_0.clone(), vec![1u8; 32]); -// let wrong_v_tx = change_signature(tx_nonce_0.clone(), vec![1u8; 65]); -// let wrong_signature_tx = change_signature(tx_nonce_0.clone(), vec![27u8; 65]); - -// let sender_address = tx_nonce_0.initiator_account(); - -// let result_without_rollbacks = execute_vm_with_possible_rollbacks( -// sender_address, -// vec![ -// // The nonces are ordered correctly, all the transactions should succeed. -// TransactionRollbackTestInfo::new_processed( -// tx_nonce_0.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// TransactionRollbackTestInfo::new_processed( -// tx_nonce_1.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// TransactionRollbackTestInfo::new_processed( -// tx_nonce_2.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// ], -// block_context, -// block_properties, -// ); - -// let incorrect_nonce = TxRevertReason::ValidationFailed(VmRevertReason::General { -// msg: "Incorrect nonce".to_string(), -// }); -// let reusing_nonce_twice = TxRevertReason::ValidationFailed(VmRevertReason::General { -// msg: "Reusing the same nonce twice".to_string(), -// }); -// let signature_length_is_incorrect = TxRevertReason::ValidationFailed(VmRevertReason::General { -// msg: "Signature length is incorrect".to_string(), -// }); -// let v_is_incorrect = TxRevertReason::ValidationFailed(VmRevertReason::General { -// msg: "v is neither 27 nor 28".to_string(), -// }); -// let signature_is_incorrect = TxRevertReason::ValidationFailed(VmRevertReason::General { -// msg: "Account validation returned invalid magic value. Most often this means that the signature is incorrect".to_string(), -// }); - -// let result_with_rollbacks = execute_vm_with_possible_rollbacks( -// sender_address, -// vec![ -// TransactionRollbackTestInfo::new_rejected( -// wrong_signature_length_tx, -// signature_length_is_incorrect, -// ), -// TransactionRollbackTestInfo::new_rejected(wrong_v_tx, v_is_incorrect), -// TransactionRollbackTestInfo::new_rejected(wrong_signature_tx, signature_is_incorrect), -// // The correct nonce is 0, this tx will fail -// TransactionRollbackTestInfo::new_rejected(tx_nonce_2.clone(), incorrect_nonce.clone()), -// // This tx will succeed -// TransactionRollbackTestInfo::new_processed( -// tx_nonce_0.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// // The correct nonce is 1, this tx will fail -// TransactionRollbackTestInfo::new_rejected( -// tx_nonce_0.clone(), -// reusing_nonce_twice.clone(), -// ), -// // The correct nonce is 1, this tx will fail -// TransactionRollbackTestInfo::new_rejected(tx_nonce_2.clone(), incorrect_nonce), -// // This tx will succeed -// TransactionRollbackTestInfo::new_processed( -// tx_nonce_1, -// false, -// TxExecutionStatus::Success, -// ), -// // The correct nonce is 2, this tx will fail -// TransactionRollbackTestInfo::new_rejected(tx_nonce_0, reusing_nonce_twice.clone()), -// // This tx will succeed -// TransactionRollbackTestInfo::new_processed( -// tx_nonce_2.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// // This tx will fail -// TransactionRollbackTestInfo::new_rejected(tx_nonce_2, reusing_nonce_twice.clone()), -// ], -// block_context, -// block_properties, -// ); - -// assert_eq!(result_without_rollbacks, result_with_rollbacks); - -// let loadnext_contract = get_loadnext_contract(); - -// let loadnext_constructor_data = encode(&[Token::Uint(U256::from(100))]); -// let loadnext_deploy_tx: Transaction = get_deploy_tx( -// sender_private_key, -// Nonce(0), -// &loadnext_contract.bytecode, -// loadnext_contract.factory_deps, -// &loadnext_constructor_data, -// Fee { -// gas_limit: U256::from(60000000u32), -// max_fee_per_gas: base_fee, -// max_priority_fee_per_gas: U256::zero(), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); -// let loadnext_contract_address = -// get_create_zksync_address(loadnext_deploy_tx.initiator_account(), Nonce(0)); -// let deploy_loadnext_tx_info = TransactionRollbackTestInfo::new_processed( -// loadnext_deploy_tx, -// false, -// TxExecutionStatus::Success, -// ); - -// let get_load_next_tx = |params: LoadnextContractExecutionParams, nonce: Nonce| { -// // Here we test loadnext with various kinds of operations -// let tx: Transaction = mock_loadnext_test_call( -// sender_private_key, -// nonce, -// loadnext_contract_address, -// Fee { -// gas_limit: U256::from(80000000u32), -// max_fee_per_gas: base_fee, -// max_priority_fee_per_gas: U256::zero(), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// params, -// ) -// .into(); - -// tx -// }; - -// let loadnext_tx_0 = get_load_next_tx( -// LoadnextContractExecutionParams { -// reads: 100, -// writes: 100, -// events: 100, -// hashes: 500, -// recursive_calls: 10, -// deploys: 60, -// }, -// Nonce(1), -// ); -// let loadnext_tx_1 = get_load_next_tx( -// LoadnextContractExecutionParams { -// reads: 100, -// writes: 100, -// events: 100, -// hashes: 500, -// recursive_calls: 10, -// deploys: 60, -// }, -// Nonce(2), -// ); - -// let result_without_rollbacks = execute_vm_with_possible_rollbacks( -// sender_address, -// vec![ -// deploy_loadnext_tx_info.clone(), -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_0.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_1.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// ], -// block_context, -// block_properties, -// ); - -// let result_with_rollbacks = execute_vm_with_possible_rollbacks( -// sender_address, -// vec![ -// deploy_loadnext_tx_info, -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_0.clone(), -// true, -// TxExecutionStatus::Success, -// ), -// // After the previous tx has been rolled back, this one should succeed -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_0.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// // The nonce has been bumped up, this transaction should now fail -// TransactionRollbackTestInfo::new_rejected(loadnext_tx_0, reusing_nonce_twice.clone()), -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_1.clone(), -// true, -// TxExecutionStatus::Success, -// ), -// // After the previous tx has been rolled back, this one should succeed -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_1.clone(), -// true, -// TxExecutionStatus::Success, -// ), -// // After the previous tx has been rolled back, this one should succeed -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_1.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// // The nonce has been bumped up, this transaction should now fail -// TransactionRollbackTestInfo::new_rejected(loadnext_tx_1, reusing_nonce_twice), -// ], -// block_context, -// block_properties, -// ); - -// assert_eq!(result_without_rollbacks, result_with_rollbacks); -// } - -// // Inserts the contracts into the test environment, bypassing the -// // deployer system contract. Besides the reference to storage -// // it accepts a `contracts` tuple of information about the contract -// // and whether or not it is an account. -// fn insert_contracts( -// raw_storage: &mut SecondaryStateStorage, -// contracts: Vec<(DeployedContract, bool)>, -// ) { -// let logs: Vec = contracts -// .iter() -// .flat_map(|(contract, is_account)| { -// let mut new_logs = vec![]; - -// let deployer_code_key = get_code_key(contract.account_id.address()); -// new_logs.push(StorageLog::new_write_log( -// deployer_code_key, -// hash_bytecode(&contract.bytecode), -// )); - -// if *is_account { -// let is_account_key = get_is_account_key(contract.account_id.address()); -// new_logs.push(StorageLog::new_write_log( -// is_account_key, -// u256_to_h256(1u32.into()), -// )); -// } - -// new_logs -// }) -// .collect(); -// raw_storage.process_transaction_logs(&logs); - -// for (contract, _) in contracts { -// raw_storage.store_contract(*contract.account_id.address(), contract.bytecode.clone()); -// raw_storage.store_factory_dep(hash_bytecode(&contract.bytecode), contract.bytecode); -// } -// raw_storage.save(L1BatchNumber(0)); -// } - -// enum NonceHolderTestMode { -// SetValueUnderNonce, -// IncreaseMinNonceBy5, -// IncreaseMinNonceTooMuch, -// LeaveNonceUnused, -// IncreaseMinNonceBy1, -// SwitchToArbitraryOrdering, -// } - -// impl From for u8 { -// fn from(mode: NonceHolderTestMode) -> u8 { -// match mode { -// NonceHolderTestMode::SetValueUnderNonce => 0, -// NonceHolderTestMode::IncreaseMinNonceBy5 => 1, -// NonceHolderTestMode::IncreaseMinNonceTooMuch => 2, -// NonceHolderTestMode::LeaveNonceUnused => 3, -// NonceHolderTestMode::IncreaseMinNonceBy1 => 4, -// NonceHolderTestMode::SwitchToArbitraryOrdering => 5, -// } -// } -// } - -// fn get_nonce_holder_test_tx( -// nonce: U256, -// account_address: Address, -// test_mode: NonceHolderTestMode, -// block_context: &DerivedBlockContext, -// ) -> TransactionData { -// TransactionData { -// tx_type: 113, -// from: account_address, -// to: account_address, -// gas_limit: U256::from(10000000u32), -// pubdata_price_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// max_fee_per_gas: U256::from(block_context.base_fee), -// max_priority_fee_per_gas: U256::zero(), -// nonce, -// // The reserved fields that are unique for different types of transactions. -// // E.g. nonce is currently used in all transaction, but it should not be mandatory -// // in the long run. -// reserved: [U256::zero(); 4], -// data: vec![12], -// signature: vec![test_mode.into()], - -// ..Default::default() -// } -// } - -// fn run_vm_with_raw_tx<'a>( -// oracle_tools: &'a mut OracleTools<'a, false>, -// block_context: DerivedBlockContext, -// block_properties: &'a BlockProperties, -// tx: TransactionData, -// ) -> (VmExecutionResult, bool) { -// let mut base_system_contracts = BASE_SYSTEM_CONTRACTS.clone(); -// base_system_contracts.bootloader = PLAYGROUND_BLOCK_BOOTLOADER_CODE.clone(); -// let mut vm = init_vm_inner( -// oracle_tools, -// BlockContextMode::OverrideCurrent(block_context), -// block_properties, -// BLOCK_GAS_LIMIT, -// &base_system_contracts, -// TxExecutionMode::VerifyExecute, -// ); - -// let overhead = tx.overhead_gas(); -// push_raw_transaction_to_bootloader_memory( -// &mut vm, -// tx, -// TxExecutionMode::VerifyExecute, -// overhead, -// ); -// let VmBlockResult { -// full_result: result, -// .. -// } = vm.execute_till_block_end(BootloaderJobType::TransactionExecution); - -// (result, tx_has_failed(&vm.state, 0)) -// } - -// #[test] -// fn test_nonce_holder() { -// let (block_context, block_properties): (DerivedBlockContext, BlockProperties) = { -// let (block_context, block_properties) = create_test_block_params(); -// (block_context.into(), block_properties) -// }; - -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); - -// let account_address = H160::random(); -// let account = DeployedContract { -// account_id: AccountTreeId::new(account_address), -// bytecode: read_nonce_holder_tester(), -// }; - -// insert_contracts(&mut raw_storage, vec![(account, true)]); - -// let storage_ptr: &mut dyn Storage = &mut StorageView::new(&raw_storage); - -// // We deploy here counter contract, because its logic is trivial - -// let key = storage_key_for_eth_balance(&account_address); -// storage_ptr.set_value(&key, u256_to_h256(U256([0, 0, 1, 0]))); - -// let mut run_nonce_test = |nonce: U256, -// test_mode: NonceHolderTestMode, -// error_message: Option, -// comment: &'static str| { -// let tx = get_nonce_holder_test_tx(nonce, account_address, test_mode, &block_context); - -// let mut oracle_tools = OracleTools::new(storage_ptr); -// let (result, tx_has_failed) = -// run_vm_with_raw_tx(&mut oracle_tools, block_context, &block_properties, tx); -// if let Some(msg) = error_message { -// let expected_error = TxRevertReason::ValidationFailed(VmRevertReason::General { msg }); -// assert_eq!( -// result -// .revert_reason -// .expect("No revert reason") -// .revert_reason, -// expected_error, -// "{}", -// comment -// ); -// } else { -// assert!(!tx_has_failed, "{}", comment); -// } -// }; - -// // Test 1: trying to set value under non sequential nonce value. -// run_nonce_test( -// 1u32.into(), -// NonceHolderTestMode::SetValueUnderNonce, -// Some("Previous nonce has not been used".to_string()), -// "Allowed to set value under non sequential value", -// ); - -// // Test 2: increase min nonce by 1 with sequential nonce ordering: -// run_nonce_test( -// 0u32.into(), -// NonceHolderTestMode::IncreaseMinNonceBy1, -// None, -// "Failed to increment nonce by 1 for sequential account", -// ); - -// // Test 3: correctly set value under nonce with sequential nonce ordering: -// run_nonce_test( -// 1u32.into(), -// NonceHolderTestMode::SetValueUnderNonce, -// None, -// "Failed to set value under nonce sequential value", -// ); - -// // Test 5: migrate to the arbitrary nonce ordering: -// run_nonce_test( -// 2u32.into(), -// NonceHolderTestMode::SwitchToArbitraryOrdering, -// None, -// "Failed to switch to arbitrary ordering", -// ); - -// // Test 6: increase min nonce by 5 -// run_nonce_test( -// 6u32.into(), -// NonceHolderTestMode::IncreaseMinNonceBy5, -// None, -// "Failed to increase min nonce by 5", -// ); - -// // Test 7: since the nonces in range [6,10] are no longer allowed, the -// // tx with nonce 10 should not be allowed -// run_nonce_test( -// 10u32.into(), -// NonceHolderTestMode::IncreaseMinNonceBy5, -// Some("Reusing the same nonce twice".to_string()), -// "Allowed to reuse nonce below the minimal one", -// ); - -// // Test 8: we should be able to use nonce 13 -// run_nonce_test( -// 13u32.into(), -// NonceHolderTestMode::SetValueUnderNonce, -// None, -// "Did not allow to use unused nonce 10", -// ); - -// // Test 9: we should not be able to reuse nonce 13 -// run_nonce_test( -// 13u32.into(), -// NonceHolderTestMode::IncreaseMinNonceBy5, -// Some("Reusing the same nonce twice".to_string()), -// "Allowed to reuse the same nonce twice", -// ); - -// // Test 10: we should be able to simply use nonce 14, while bumping the minimal nonce by 5 -// run_nonce_test( -// 14u32.into(), -// NonceHolderTestMode::IncreaseMinNonceBy5, -// None, -// "Did not allow to use a bumped nonce", -// ); - -// // Test 6: Do not allow bumping nonce by too much -// run_nonce_test( -// 16u32.into(), -// NonceHolderTestMode::IncreaseMinNonceTooMuch, -// Some("The value for incrementing the nonce is too high".to_string()), -// "Allowed for incrementing min nonce too much", -// ); - -// // Test 7: Do not allow not setting a nonce as used -// run_nonce_test( -// 16u32.into(), -// NonceHolderTestMode::LeaveNonceUnused, -// Some("The nonce was not set as used".to_string()), -// "Allowed to leave nonce as unused", -// ); -// } - -// #[test] -// fn test_l1_tx_execution() { -// // In this test, we try to execute a contract deployment from L1 -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); -// let mut storage_accessor = StorageView::new(&raw_storage); -// let storage_ptr: &mut dyn Storage = &mut storage_accessor; - -// let mut oracle_tools = OracleTools::new(storage_ptr); -// let (block_context, block_properties) = create_test_block_params(); - -// // Here instead of marking code hash via the bootloader means, we will -// // using L1->L2 communication, the same it would likely be done during the priority mode. -// let contract_code = read_test_contract(); -// let contract_code_hash = hash_bytecode(&contract_code); -// let l1_deploy_tx = get_l1_deploy_tx(&contract_code, &[]); -// let l1_deploy_tx_data: TransactionData = l1_deploy_tx.clone().into(); - -// let required_l2_to_l1_logs = vec![ -// L2ToL1Log { -// shard_id: 0, -// is_service: false, -// tx_number_in_block: 0, -// sender: SYSTEM_CONTEXT_ADDRESS, -// key: u256_to_h256(U256::from(block_context.block_timestamp)), -// value: Default::default(), -// }, -// L2ToL1Log { -// shard_id: 0, -// is_service: true, -// tx_number_in_block: 0, -// sender: BOOTLOADER_ADDRESS, -// key: l1_deploy_tx_data.canonical_l1_tx_hash(), -// value: u256_to_h256(U256::from(1u32)), -// }, -// ]; - -// let sender_address = l1_deploy_tx_data.from(); - -// oracle_tools.decommittment_processor.populate( -// vec![( -// h256_to_u256(contract_code_hash), -// bytes_to_be_words(contract_code), -// )], -// Timestamp(0), -// ); - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context.into(), Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); -// push_transaction_to_bootloader_memory(&mut vm, &l1_deploy_tx, TxExecutionMode::VerifyExecute); - -// let res = vm.execute_next_tx().unwrap(); - -// // The code hash of the deployed contract should be marked as republished. -// let known_codes_key = get_known_code_key(&contract_code_hash); - -// // The contract should be deployed successfully. -// let deployed_address = deployed_address_create(sender_address, U256::zero()); -// let account_code_key = get_code_key(&deployed_address); - -// let expected_slots = vec![ -// (u256_to_h256(U256::from(1u32)), known_codes_key), -// (contract_code_hash, account_code_key), -// ]; -// assert!(!tx_has_failed(&vm.state, 0)); - -// verify_required_storage(&vm.state, expected_slots); - -// assert_eq!(res.result.logs.l2_to_l1_logs, required_l2_to_l1_logs); - -// let tx = get_l1_execute_test_contract_tx(deployed_address, true); -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute); -// let res = ExecutionMetrics::new(&vm.execute_next_tx().unwrap().result.logs, 0, 0, 0, 0); -// assert_eq!(res.initial_storage_writes, 0); - -// let tx = get_l1_execute_test_contract_tx(deployed_address, false); -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute); -// let res = ExecutionMetrics::new(&vm.execute_next_tx().unwrap().result.logs, 0, 0, 0, 0); -// assert_eq!(res.initial_storage_writes, 2); - -// let repeated_writes = res.repeated_storage_writes; - -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute); -// let res = ExecutionMetrics::new(&vm.execute_next_tx().unwrap().result.logs, 0, 0, 0, 0); -// assert_eq!(res.initial_storage_writes, 1); -// // We do the same storage write, so it will be deduplicated -// assert_eq!(res.repeated_storage_writes, repeated_writes); - -// let mut tx = get_l1_execute_test_contract_tx(deployed_address, false); -// tx.execute.value = U256::from(1); -// match &mut tx.common_data { -// ExecuteTransactionCommon::L1(l1_data) => { -// l1_data.to_mint = U256::from(4); -// } -// _ => unreachable!(), -// } -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute); -// let execution_result = vm.execute_next_tx().unwrap(); -// // The method is not payable, so the transaction with non-zero value should fail -// assert_eq!( -// execution_result.status, -// TxExecutionStatus::Failure, -// "The transaction should fail" -// ); - -// let res = ExecutionMetrics::new(&execution_result.result.logs, 0, 0, 0, 0); - -// // There are 2 initial writes here: -// // - totalSupply of ETH token -// // - balance of the refund recipient -// assert_eq!(res.initial_storage_writes, 2); -// } - -// #[test] -// fn test_invalid_bytecode() { -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); -// let (block_context, block_properties) = create_test_block_params(); - -// let test_vm_with_custom_bytecode_hash = -// |bytecode_hash: H256, expected_revert_reason: Option| { -// let mut storage_accessor = StorageView::new(&raw_storage); -// let storage_ptr: &mut dyn Storage = &mut storage_accessor; -// let mut oracle_tools = OracleTools::new(storage_ptr); - -// let (encoded_tx, predefined_overhead) = -// get_l1_tx_with_custom_bytecode_hash(h256_to_u256(bytecode_hash)); - -// run_vm_with_custom_factory_deps( -// &mut oracle_tools, -// block_context, -// &block_properties, -// encoded_tx, -// predefined_overhead, -// expected_revert_reason, -// ); -// }; - -// let failed_to_mark_factory_deps = |msg: &str| { -// TxRevertReason::FailedToMarkFactoryDependencies(VmRevertReason::General { -// msg: msg.to_string(), -// }) -// }; - -// // Here we provide the correctly-formatted bytecode hash of -// // odd length, so it should work. -// test_vm_with_custom_bytecode_hash( -// H256([ -// 1, 0, 0, 1, 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, -// ]), -// None, -// ); - -// // Here we provide correctly formatted bytecode of even length, so -// // it should fail. -// test_vm_with_custom_bytecode_hash( -// H256([ -// 1, 0, 2, 2, 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, -// ]), -// Some(failed_to_mark_factory_deps( -// "Code length in words must be odd", -// )), -// ); - -// // Here we provide incorrectly formatted bytecode of odd length, so -// // it should fail. -// test_vm_with_custom_bytecode_hash( -// H256([ -// 1, 1, 0, 1, 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, -// ]), -// Some(failed_to_mark_factory_deps( -// "Incorrectly formatted bytecodeHash", -// )), -// ); - -// // Here we provide incorrectly formatted bytecode of odd length, so -// // it should fail. -// test_vm_with_custom_bytecode_hash( -// H256([ -// 2, 0, 0, 1, 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, -// ]), -// Some(failed_to_mark_factory_deps( -// "Incorrectly formatted bytecodeHash", -// )), -// ); -// } - -// #[test] -// fn test_tracing_of_execution_errors() { -// // In this test, we are checking that the execution errors are transmitted correctly from the bootloader. -// let (block_context, block_properties) = create_test_block_params(); -// let block_context: DerivedBlockContext = block_context.into(); - -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); - -// let contract_address = Address::random(); -// let error_contract = DeployedContract { -// account_id: AccountTreeId::new(contract_address), -// bytecode: read_error_contract(), -// }; - -// let tx = get_error_tx( -// H256::random(), -// Nonce(0), -// contract_address, -// Fee { -// gas_limit: U256::from(1000000u32), -// max_fee_per_gas: U256::from(10000000000u64), -// max_priority_fee_per_gas: U256::zero(), -// gas_per_pubdata_limit: U256::from(50000u32), -// }, -// ); - -// insert_contracts(&mut raw_storage, vec![(error_contract, false)]); - -// let storage_ptr: &mut dyn Storage = &mut StorageView::new(&raw_storage); - -// let key = storage_key_for_eth_balance(&tx.common_data.initiator_address); -// storage_ptr.set_value(&key, u256_to_h256(U256([0, 0, 1, 0]))); - -// let mut oracle_tools = OracleTools::new(storage_ptr); - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context, Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); -// push_transaction_to_bootloader_memory(&mut vm, &tx.into(), TxExecutionMode::VerifyExecute); - -// let mut tracer = TransactionResultTracer::default(); -// assert_eq!( -// vm.execute_with_custom_tracer(&mut tracer), -// VmExecutionStopReason::VmFinished, -// "Tracer should never request stop" -// ); - -// match tracer.revert_reason { -// Some(revert_reason) => { -// let revert_reason = VmRevertReason::try_from(&revert_reason as &[u8]).unwrap(); -// assert_eq!( -// revert_reason, -// VmRevertReason::General { -// msg: "short".to_string() -// } -// ) -// } -// _ => panic!( -// "Tracer captured incorrect result {:#?}", -// tracer.revert_reason -// ), -// } -// } - -// /// Checks that `TX_GAS_LIMIT_OFFSET` constant is correct. -// #[test] -// fn test_tx_gas_limit_offset() { -// let gas_limit = U256::from(999999); - -// let (block_context, block_properties) = create_test_block_params(); -// let block_context: DerivedBlockContext = block_context.into(); - -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let raw_storage = SecondaryStateStorage::new(db); -// let storage_ptr: &mut dyn Storage = &mut StorageView::new(&raw_storage); - -// let contract_code = read_test_contract(); -// let tx: Transaction = get_deploy_tx( -// H256::random(), -// Nonce(0), -// &contract_code, -// Default::default(), -// Default::default(), -// Fee { -// gas_limit, -// ..Default::default() -// }, -// ) -// .into(); - -// let mut oracle_tools = OracleTools::new(storage_ptr); - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context, Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute); - -// let gas_limit_from_memory = vm -// .state -// .memory -// .read_slot( -// BOOTLOADER_HEAP_PAGE as usize, -// TX_DESCRIPTION_OFFSET + TX_GAS_LIMIT_OFFSET, -// ) -// .value; -// assert_eq!(gas_limit_from_memory, gas_limit); -// } - -// #[test] -// fn test_is_write_initial_behaviour() { -// // In this test, we check result of `is_write_initial` at different stages. - -// let (block_context, block_properties) = create_test_block_params(); -// let block_context: DerivedBlockContext = block_context.into(); - -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); -// let storage_ptr: &mut dyn Storage = &mut StorageView::new(&raw_storage); - -// let base_fee = block_context.base_fee; -// let account_pk = H256::random(); -// let contract_code = read_test_contract(); -// let tx: Transaction = get_deploy_tx( -// account_pk, -// Nonce(0), -// &contract_code, -// vec![], -// &[], -// Fee { -// gas_limit: U256::from(10000000u32), -// max_fee_per_gas: U256::from(base_fee), -// max_priority_fee_per_gas: U256::from(0), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); - -// let sender_address = tx.initiator_account(); -// let nonce_key = get_nonce_key(&sender_address); - -// // Check that the next write to the nonce key will be initial. -// assert!(storage_ptr.is_write_initial(&nonce_key)); - -// // Set balance to be able to pay fee for txs. -// let balance_key = storage_key_for_eth_balance(&sender_address); -// storage_ptr.set_value(&balance_key, u256_to_h256(U256([0, 0, 1, 0]))); - -// let mut oracle_tools = OracleTools::new(storage_ptr); - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context, Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); - -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute); - -// vm.execute_next_tx() -// .expect("Bootloader failed while processing the first transaction"); -// // Check that `is_write_initial` still returns true for the nonce key. -// assert!(storage_ptr.is_write_initial(&nonce_key)); -// } - -// pub fn get_l1_tx_with_custom_bytecode_hash(bytecode_hash: U256) -> (Vec, u32) { -// let tx: TransactionData = get_l1_execute_test_contract_tx(Default::default(), false).into(); -// let predefined_overhead = tx.overhead_gas_with_custom_factory_deps(vec![bytecode_hash]); -// let tx_bytes = tx.abi_encode_with_custom_factory_deps(vec![bytecode_hash]); - -// (bytes_to_be_words(tx_bytes), predefined_overhead) -// } - -// const L1_TEST_GAS_PER_PUBDATA_BYTE: u32 = 800; - -// pub fn get_l1_execute_test_contract_tx(deployed_address: Address, with_panic: bool) -> Transaction { -// let execute = execute_test_contract(deployed_address, with_panic); -// Transaction { -// common_data: ExecuteTransactionCommon::L1(L1TxCommonData { -// sender: H160::random(), -// gas_limit: U256::from(1000000u32), -// gas_per_pubdata_limit: L1_TEST_GAS_PER_PUBDATA_BYTE.into(), -// ..Default::default() -// }), -// execute, -// received_timestamp_ms: 0, -// } -// } - -// pub fn get_l1_deploy_tx(code: &[u8], calldata: &[u8]) -> Transaction { -// let execute = get_create_execute(code, calldata); - -// Transaction { -// common_data: ExecuteTransactionCommon::L1(L1TxCommonData { -// sender: H160::random(), -// gas_limit: U256::from(2000000u32), -// gas_per_pubdata_limit: L1_TEST_GAS_PER_PUBDATA_BYTE.into(), -// ..Default::default() -// }), -// execute, -// received_timestamp_ms: 0, -// } -// } - -// fn read_test_contract() -> Vec { -// read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/counter/counter.sol/Counter.json") -// } - -// fn read_nonce_holder_tester() -> Vec { -// read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/custom-account/nonce-holder-test.sol/NonceHolderTest.json") -// } - -// fn read_error_contract() -> Vec { -// read_bytecode( -// "etc/contracts-test-data/artifacts-zk/contracts/error/error.sol/SimpleRequire.json", -// ) -// } - -// fn execute_test_contract(address: Address, with_panic: bool) -> Execute { -// let test_contract = load_contract( -// "etc/contracts-test-data/artifacts-zk/contracts/counter/counter.sol/Counter.json", -// ); - -// let function = test_contract.function("incrementWithRevert").unwrap(); - -// let calldata = function -// .encode_input(&[Token::Uint(U256::from(1u8)), Token::Bool(with_panic)]) -// .expect("failed to encode parameters"); -// Execute { -// contract_address: address, -// calldata, -// value: U256::zero(), -// factory_deps: None, -// } -// } diff --git a/core/lib/multivm/src/versions/vm_m5/tests/mod.rs b/core/lib/multivm/src/versions/vm_m5/tests/mod.rs deleted file mode 100644 index 3900135abeaa..000000000000 --- a/core/lib/multivm/src/versions/vm_m5/tests/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod bootloader; diff --git a/core/lib/multivm/src/versions/vm_m5/transaction_data.rs b/core/lib/multivm/src/versions/vm_m5/transaction_data.rs index f150db2ebaa9..c3fba68bc8d2 100644 --- a/core/lib/multivm/src/versions/vm_m5/transaction_data.rs +++ b/core/lib/multivm/src/versions/vm_m5/transaction_data.rs @@ -3,14 +3,15 @@ use zksync_types::{ ethabi::{encode, Address, Token}, fee::encoding_len, l2::TransactionType, - ExecuteTransactionCommon, Transaction, MAX_TXS_IN_BLOCK, U256, + ExecuteTransactionCommon, Transaction, U256, }; use zksync_utils::{ address_to_h256, bytecode::hash_bytecode, bytes_to_be_words, ceil_div_u256, h256_to_u256, }; +use super::vm_with_bootloader::MAX_GAS_PER_PUBDATA_BYTE; use crate::vm_m5::vm_with_bootloader::{ - BLOCK_OVERHEAD_GAS, BLOCK_OVERHEAD_PUBDATA, BOOTLOADER_TX_ENCODING_SPACE, + BLOCK_OVERHEAD_GAS, BLOCK_OVERHEAD_PUBDATA, BOOTLOADER_TX_ENCODING_SPACE, MAX_TXS_IN_BLOCK, }; const L1_TX_TYPE: u8 = 255; @@ -59,12 +60,22 @@ impl From for TransactionData { U256::zero() }; + // Ethereum transactions do not sign gas per pubdata limit, and so for them we need to use + // some default value. We use the maximum possible value that is allowed by the bootloader + // (i.e. we can not use u64::MAX, because the bootloader requires gas per pubdata for such + // transactions to be higher than `MAX_GAS_PER_PUBDATA_BYTE`). + let gas_per_pubdata_limit = if common_data.transaction_type.is_ethereum_type() { + MAX_GAS_PER_PUBDATA_BYTE.into() + } else { + common_data.fee.gas_per_pubdata_limit + }; + TransactionData { tx_type: (common_data.transaction_type as u32) as u8, from: execute_tx.initiator_account(), to: execute_tx.execute.contract_address, gas_limit: common_data.fee.gas_limit, - pubdata_price_limit: common_data.fee.gas_per_pubdata_limit, + pubdata_price_limit: gas_per_pubdata_limit, max_fee_per_gas: common_data.fee.max_fee_per_gas, max_priority_fee_per_gas: common_data.fee.max_priority_fee_per_gas, paymaster: common_data.paymaster_params.paymaster, @@ -184,7 +195,7 @@ impl TransactionData { get_maximal_allowed_overhead(total_gas_limit, gas_per_pubdata_byte_limit, encoded_len) } - + // ``` // #[cfg(test)] // pub(crate) fn overhead_gas_with_custom_factory_deps( // &self, @@ -201,22 +212,27 @@ impl TransactionData { // ); // get_maximal_allowed_overhead(total_gas_limit, gas_per_pubdata_byte_limit, encoded_len) // } - + // // #[cfg(test)] // pub(crate) fn canonical_l1_tx_hash(&self) -> zksync_types::H256 { // use zksync_types::web3::signing::keccak256; - + // // if self.tx_type != L1_TX_TYPE { // panic!("Trying to get L1 tx hash for non-L1 tx"); // } - + // // let encoded_bytes = self.clone().abi_encode(); - + // // zksync_types::H256(keccak256(&encoded_bytes)) // } + // ``` } -pub fn derive_overhead(gas_limit: u32, gas_price_per_pubdata: u32, encoded_len: usize) -> u32 { +pub(crate) fn derive_overhead( + gas_limit: u32, + gas_price_per_pubdata: u32, + encoded_len: usize, +) -> u32 { assert!( gas_limit <= MAX_TX_ERGS_LIMIT, "gas limit is larger than the maximal one" @@ -228,8 +244,8 @@ pub fn derive_overhead(gas_limit: u32, gas_price_per_pubdata: u32, encoded_len: let gas_price_per_pubdata = U256::from(gas_price_per_pubdata); let encoded_len = U256::from(encoded_len); - // The MAX_TX_ERGS_LIMIT is formed in a way that may fulfills a single-instance circuits - // if used in full. That is, within MAX_TX_ERGS_LIMIT it is possible to fully saturate all the single-instance + // The `MAX_TX_ERGS_LIMIT` is formed in a way that may fulfills a single-instance circuits + // if used in full. That is, within `MAX_TX_ERGS_LIMIT` it is possible to fully saturate all the single-instance // circuits. let overhead_for_single_instance_circuits = ceil_div_u256(gas_limit * max_block_overhead, MAX_TX_ERGS_LIMIT.into()); @@ -243,7 +259,7 @@ pub fn derive_overhead(gas_limit: u32, gas_price_per_pubdata: u32, encoded_len: // The overhead for occupying a single tx slot let tx_slot_overhead = ceil_div_u256(max_block_overhead, MAX_TXS_IN_BLOCK.into()); - // We use "ceil" here for formal reasons to allow easier approach for calculating the overhead in O(1) + // We use `ceil` here for formal reasons to allow easier approach for calculating the overhead in O(1) let max_pubdata_in_tx = ceil_div_u256(gas_limit, gas_price_per_pubdata); // The maximal potential overhead from pubdata @@ -277,53 +293,55 @@ pub fn get_maximal_allowed_overhead( let encoded_len = U256::from(encoded_len); // Derivation of overhead consists of 4 parts: - // 1. The overhead for taking up a transaction's slot. (O1): O1 = 1 / MAX_TXS_IN_BLOCK - // 2. The overhead for taking up the bootloader's memory (O2): O2 = encoded_len / BOOTLOADER_TX_ENCODING_SPACE - // 3. The overhead for possible usage of pubdata. (O3): O3 = max_pubdata_in_tx / MAX_PUBDATA_PER_BLOCK - // 4. The overhead for possible usage of all the single-instance circuits. (O4): O4 = gas_limit / MAX_TX_ERGS_LIMIT + // 1. The overhead for taking up a transaction's slot. `(O1): O1 = 1 / MAX_TXS_IN_BLOCK` + // 2. The overhead for taking up the bootloader's memory `(O2): O2 = encoded_len / BOOTLOADER_TX_ENCODING_SPACE` + // 3. The overhead for possible usage of pubdata. `(O3): O3 = max_pubdata_in_tx / MAX_PUBDATA_PER_BLOCK` + // 4. The overhead for possible usage of all the single-instance circuits. `(O4): O4 = gas_limit / MAX_TX_ERGS_LIMIT` // // The maximum of these is taken to derive the part of the block's overhead to be paid by the users: // - // max_overhead = max(O1, O2, O3, O4) - // overhead_gas = ceil(max_overhead * overhead_for_block_gas). Thus, overhead_gas is a function of - // tx_gas_limit, gas_per_pubdata_byte_limit and encoded_len. + // `max_overhead = max(O1, O2, O3, O4)` + // `overhead_gas = ceil(max_overhead * overhead_for_block_gas)`. Thus, `overhead_gas` is a function of + // `tx_gas_limit`, `gas_per_pubdata_byte_limit` and `encoded_len`. // - // While it is possible to derive the overhead with binary search in O(log n), it is too expensive to be done + // While it is possible to derive the overhead with binary search in `O(log n)`, it is too expensive to be done // on L1, so here is a reference implementation of finding the overhead for transaction in O(1): // - // Given total_gas_limit = tx_gas_limit + overhead_gas, we need to find overhead_gas and tx_gas_limit, such that: - // 1. overhead_gas is maximal possible (the operator is paid fairly) - // 2. overhead_gas(tx_gas_limit, gas_per_pubdata_byte_limit, encoded_len) >= overhead_gas (the user does not overpay) + // Given `total_gas_limit = tx_gas_limit + overhead_gas`, we need to find `overhead_gas` and `tx_gas_limit`, such that: + // 1. `overhead_gas` is maximal possible (the operator is paid fairly) + // 2. `overhead_gas(tx_gas_limit, gas_per_pubdata_byte_limit, encoded_len) >= overhead_gas` (the user does not overpay) // The third part boils to the following 4 inequalities (at least one of these must hold): - // ceil(O1 * overhead_for_block_gas) >= overhead_gas - // ceil(O2 * overhead_for_block_gas) >= overhead_gas - // ceil(O3 * overhead_for_block_gas) >= overhead_gas - // ceil(O4 * overhead_for_block_gas) >= overhead_gas + // `ceil(O1 * overhead_for_block_gas) >= overhead_gas` + // `ceil(O2 * overhead_for_block_gas) >= overhead_gas` + // `ceil(O3 * overhead_for_block_gas) >= overhead_gas` + // `ceil(O4 * overhead_for_block_gas) >= overhead_gas` // // Now, we need to solve each of these separately: // 1. The overhead for occupying a single tx slot is a constant: let tx_slot_overhead = ceil_div_u256(overhead_for_block_gas, MAX_TXS_IN_BLOCK.into()); - // 2. The overhead for occupying the bootloader memory can be derived from encoded_len + // 2. The overhead for occupying the bootloader memory can be derived from `encoded_len` let overhead_for_length = ceil_div_u256( encoded_len * overhead_for_block_gas, BOOTLOADER_TX_ENCODING_SPACE.into(), ); - + // ``` // 3. ceil(O3 * overhead_for_block_gas) >= overhead_gas // O3 = max_pubdata_in_tx / MAX_PUBDATA_PER_BLOCK = ceil(gas_limit / gas_per_pubdata_byte_limit) / MAX_PUBDATA_PER_BLOCK - // >= (gas_limit / (gas_per_pubdata_byte_limit * MAX_PUBDATA_PER_BLOCK). Throwing off the `ceil`, while may provide marginally lower - // overhead to the operator, provides substantially easier formula to work with. + // >= (gas_limit / (gas_per_pubdata_byte_limit * MAX_PUBDATA_PER_BLOCK). + // ``` + //Throwing off the `ceil`, while may provide marginally lower + //overhead to the operator, provides substantially easier formula to work with. // - // For better clarity, let's denote gas_limit = GL, MAX_PUBDATA_PER_BLOCK = MP, gas_per_pubdata_byte_limit = EP, overhead_for_block_gas = OB, total_gas_limit = TL, overhead_gas = OE - // ceil(OB * (TL - OE) / (EP * MP)) >= OE + // For better clarity, let's denote `gas_limit = GL, MAX_PUBDATA_PER_BLOCK = MP, gas_per_pubdata_byte_limit = EP, overhead_for_block_gas = OB, total_gas_limit = TL, overhead_gas = OE` + // `ceil(OB * (TL - OE) / (EP * MP)) >= OE` // - // OB * (TL - OE) / (MP * EP) > OE - 1 - // OB * (TL - OE) > (OE - 1) * EP * MP - // OB * TL + EP * MP > OE * EP * MP + OE * OB - // (OB * TL + EP * MP) / (EP * MP + OB) > OE - // OE = floor((OB * TL + EP * MP) / (EP * MP + OB)) with possible -1 if the division is without remainder + // `OB * (TL - OE) / (MP * EP) > OE - 1` + // `OB * (TL - OE) > (OE - 1) * EP * MP` + // `OB * TL + EP * MP > OE * EP * MP + OE * OB` + // `(OB * TL + EP * MP) / (EP * MP + OB) > OE` + // `OE = floor((OB * TL + EP * MP) / (EP * MP + OB))` with possible -1 if the division is without remainder let overhead_for_pubdata = { let numerator: U256 = overhead_for_block_gas * total_gas_limit + gas_per_pubdata_byte_limit * U256::from(MAX_PUBDATA_PER_BLOCK); @@ -338,7 +356,7 @@ pub fn get_maximal_allowed_overhead( (numerator - 1) / denominator } }; - + // ``` // 4. ceil(O4 * overhead_for_block_gas) >= overhead_gas // O4 = gas_limit / MAX_TX_ERGS_LIMIT. Using the notation from the previous equation: // ceil(OB * GL / MAX_TX_ERGS_LIMIT) >= OE @@ -347,6 +365,7 @@ pub fn get_maximal_allowed_overhead( // OB * (TL - OE) > OE * MAX_TX_ERGS_LIMIT - MAX_TX_ERGS_LIMIT // OB * TL + MAX_TX_ERGS_LIMIT > OE * ( MAX_TX_ERGS_LIMIT + OB) // OE = floor(OB * TL + MAX_TX_ERGS_LIMIT / (MAX_TX_ERGS_LIMIT + OB)), with possible -1 if the division is without remainder + // ``` let overhead_for_gas = { let numerator = overhead_for_block_gas * total_gas_limit + U256::from(MAX_TX_ERGS_LIMIT); let denominator: U256 = U256::from(MAX_TX_ERGS_LIMIT) + overhead_for_block_gas; @@ -391,7 +410,7 @@ mod tests { } else { 0u32 }; - // Safe cast: the gas_limit for a transaction can not be larger than 2^32 + // Safe cast: the gas_limit for a transaction can not be larger than `2^32` let mut right_bound = total_gas_limit; // The closure returns whether a certain overhead would be accepted by the bootloader. diff --git a/core/lib/multivm/src/versions/vm_m5/utils.rs b/core/lib/multivm/src/versions/vm_m5/utils.rs index 511cf6202a76..2e401b9de8b2 100644 --- a/core/lib/multivm/src/versions/vm_m5/utils.rs +++ b/core/lib/multivm/src/versions/vm_m5/utils.rs @@ -7,7 +7,7 @@ use zk_evm_1_3_1::{ }; use zksync_contracts::{read_zbin_bytecode, BaseSystemContracts}; use zksync_system_constants::ZKPORTER_IS_AVAILABLE; -use zksync_types::{Address, StorageLogQuery, H160, MAX_L2_TX_GAS_LIMIT, U256}; +use zksync_types::{Address, StorageLogQueryType, H160, MAX_L2_TX_GAS_LIMIT, U256}; use zksync_utils::h256_to_u256; use crate::{ @@ -224,7 +224,7 @@ pub fn collect_log_queries_after_timestamp( /// Receives sorted slice of timestamps. /// Returns count of timestamps that are greater than or equal to `from_timestamp`. -/// Works in O(log(sorted_timestamps.len())). +/// Works in `O(log(sorted_timestamps.len()))`. pub fn precompile_calls_count_after_timestamp( sorted_timestamps: &[Timestamp], from_timestamp: Timestamp, @@ -255,7 +255,14 @@ pub fn create_test_block_params() -> (BlockContext, BlockProperties) { pub fn read_bootloader_test_code(test: &str) -> Vec { read_zbin_bytecode(format!( - "contracts/system-contracts/bootloader/tests/artifacts/{}.yul/{}.yul.zbin", - test, test + "contracts/system-contracts/bootloader/tests/artifacts/{}.yul.zbin", + test )) } + +/// Log query, which handle initial and repeated writes to the storage +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct StorageLogQuery { + pub log_query: LogQuery, + pub log_type: StorageLogQueryType, +} diff --git a/core/lib/multivm/src/versions/vm_m5/vm.rs b/core/lib/multivm/src/versions/vm_m5/vm.rs index 67c4f126309d..472f06882487 100644 --- a/core/lib/multivm/src/versions/vm_m5/vm.rs +++ b/core/lib/multivm/src/versions/vm_m5/vm.rs @@ -1,3 +1,6 @@ +use itertools::Itertools; +use zk_evm_1_3_1::aux_structures::LogQuery; +use zkevm_test_harness_1_3_3::witness::sort_storage_access::sort_storage_access_queries; use zksync_state::StoragePtr; use zksync_types::{ l2_to_l1_log::{L2ToL1Log, UserL2ToL1Log}, @@ -153,15 +156,39 @@ impl VmInterface for Vm { .cloned() .collect(); + let storage_log_queries = self.vm.get_final_log_queries(); + + // To allow calling the `vm-1.3.3`s. method, the `v1.3.1`'s `LogQuery` has to be converted + // to the `vm-1.3.3`'s `LogQuery`. Then, we need to convert it back. + let deduplicated_logs: Vec = sort_storage_access_queries( + &storage_log_queries + .iter() + .map(|log| { + GlueInto::::glue_into(log.log_query) + }) + .collect_vec(), + ) + .1 + .into_iter() + .map(GlueInto::::glue_into) + .collect(); + CurrentExecutionState { events, - storage_log_queries: self.vm.get_final_log_queries(), + storage_log_queries: storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), + deduplicated_storage_log_queries: deduplicated_logs + .into_iter() + .map(GlueInto::glue_into) + .collect(), used_contract_hashes, system_logs: vec![], user_l2_to_l1_logs: l2_to_l1_logs, total_log_queries, cycles_used: self.vm.state.local_state.monotonic_cycle_counter, - // It's not applicable for vm5 + // It's not applicable for `vm5` deduplicated_events_logs: vec![], storage_refunds: vec![], } @@ -172,13 +199,16 @@ impl VmInterface for Vm { _tracer: Self::TracerDispatcher, tx: Transaction, _with_compression: bool, - ) -> Result { + ) -> ( + Result<(), BytecodeCompressionError>, + VmExecutionResultAndLogs, + ) { crate::vm_m5::vm_with_bootloader::push_transaction_to_bootloader_memory( &mut self.vm, &tx, self.system_env.execution_mode.glue_into(), ); - Ok(self.execute(VmExecutionMode::OneTx)) + (Ok(()), self.execute(VmExecutionMode::OneTx)) } fn record_vm_memory_metrics(&self) -> VmMemoryMetrics { @@ -194,6 +224,12 @@ impl VmInterface for Vm { } } + fn has_enough_gas_for_batch_tip(&self) -> bool { + // For this version this overhead has not been calculated and it has not been used with those versions. + // We return some value just in case for backwards compatibility + true + } + fn finish_batch(&mut self) -> FinishedL1Batch { self.vm .execute_till_block_end( diff --git a/core/lib/multivm/src/versions/vm_m5/vm_instance.rs b/core/lib/multivm/src/versions/vm_m5/vm_instance.rs index 99a96ded4d47..ed7d8078e19b 100644 --- a/core/lib/multivm/src/versions/vm_m5/vm_instance.rs +++ b/core/lib/multivm/src/versions/vm_m5/vm_instance.rs @@ -9,12 +9,11 @@ use zk_evm_1_3_1::{ definitions::RET_IMPLICIT_RETURNDATA_PARAMS_REGISTER, }, }; -use zksync_system_constants::MAX_TXS_IN_BLOCK; use zksync_types::{ l2_to_l1_log::{L2ToL1Log, UserL2ToL1Log}, tx::tx_execution_info::TxExecutionStatus, vm_trace::VmExecutionTrace, - L1BatchNumber, StorageLogQuery, VmEvent, U256, + L1BatchNumber, VmEvent, U256, }; use crate::{ @@ -41,6 +40,7 @@ use crate::{ utils::{ collect_log_queries_after_timestamp, collect_storage_log_queries_after_timestamp, dump_memory_page_using_primitive_value, precompile_calls_count_after_timestamp, + StorageLogQuery, }, vm_with_bootloader::{ BootloaderJobType, DerivedBlockContext, TxExecutionMode, BOOTLOADER_HEAP_PAGE, @@ -176,6 +176,7 @@ pub enum VmExecutionStopReason { TracerRequestedStop, } +use super::vm_with_bootloader::MAX_TXS_IN_BLOCK; use crate::vm_m5::utils::VmExecutionResult as NewVmExecutionResult; fn vm_may_have_ended_inner( @@ -205,7 +206,7 @@ fn vm_may_have_ended_inner( } (false, _) => None, (true, l) if l == outer_eh_location => { - // check r1,r2,r3 + // check `r1,r2,r3` if vm.local_state.flags.overflow_or_less_than_flag { Some(NewVmExecutionResult::Panic) } else { @@ -233,7 +234,7 @@ fn vm_may_have_ended(vm: &VmInstance, gas_before: u32) -> Option< NewVmExecutionResult::Ok(data) => { Some(VmExecutionResult { // The correct `events` value for this field should be set separately - // later on based on the information inside the event_sink oracle. + // later on based on the information inside the `event_sink` oracle. events: vec![], storage_log_queries: vm.get_final_log_queries(), used_contract_hashes: vm.get_used_contracts(), @@ -380,8 +381,8 @@ impl VmInstance { pub fn save_current_vm_as_snapshot(&mut self) { self.snapshots.push(VmSnapshot { // Vm local state contains O(1) various parameters (registers/etc). - // The only "expensive" copying here is copying of the callstack. - // It will take O(callstack_depth) to copy it. + // The only "expensive" copying here is copying of the call stack. + // It will take `O(callstack_depth)` to copy it. // So it is generally recommended to get snapshots of the bootloader frame, // where the depth is 1. local_state: self.state.local_state.clone(), @@ -468,10 +469,7 @@ impl VmInstance { .collect(); ( events, - l1_messages - .into_iter() - .map(|log| L2ToL1Log::from(GlueInto::::glue_into(log))) - .collect(), + l1_messages.into_iter().map(GlueInto::glue_into).collect(), ) } @@ -507,7 +505,7 @@ impl VmInstance { from_timestamp, ); VmExecutionLogs { - storage_logs, + storage_logs: storage_logs.into_iter().map(GlueInto::glue_into).collect(), events, user_l2_to_l1_logs: l2_to_l1_logs.into_iter().map(UserL2ToL1Log).collect(), system_l2_to_l1_logs: vec![], @@ -626,8 +624,8 @@ impl VmInstance { } // Err when transaction is rejected. - // Ok(status: TxExecutionStatus::Success) when the transaction succeeded - // Ok(status: TxExecutionStatus::Failure) when the transaction failed. + // `Ok(status: TxExecutionStatus::Success)` when the transaction succeeded + // `Ok(status: TxExecutionStatus::Failure)` when the transaction failed. // Note that failed transactions are considered properly processed and are included in blocks pub fn execute_next_tx(&mut self) -> Result { let tx_index = self.bootloader_state.next_unexecuted_tx() as u32; @@ -672,7 +670,7 @@ impl VmInstance { revert_reason: None, // getting contracts used during this transaction // at least for now the number returned here is always <= to the number - // of the code hashes actually used by the transaction, since it might've + // of the code hashes actually used by the transaction, since it might have // reused bytecode hashes from some of the previous ones. contracts_used: self .state @@ -752,12 +750,8 @@ impl VmInstance { e.into_vm_event(L1BatchNumber(self.block_context.context.block_number)) }) .collect(); - full_result.l2_to_l1_logs = l1_messages - .into_iter() - .map(|log| { - L2ToL1Log::from(GlueInto::::glue_into(log)) - }) - .collect(); + full_result.l2_to_l1_logs = + l1_messages.into_iter().map(GlueInto::glue_into).collect(); VmBlockResult { full_result, block_tip_result, diff --git a/core/lib/multivm/src/versions/vm_m5/vm_with_bootloader.rs b/core/lib/multivm/src/versions/vm_m5/vm_with_bootloader.rs index f9ba88fea143..f51c5842d988 100644 --- a/core/lib/multivm/src/versions/vm_m5/vm_with_bootloader.rs +++ b/core/lib/multivm/src/versions/vm_m5/vm_with_bootloader.rs @@ -10,30 +10,34 @@ use zk_evm_1_3_1::{ BOOTLOADER_CALLDATA_PAGE, STARTING_BASE_PAGE, STARTING_TIMESTAMP, }, }; +use zkevm_test_harness_1_3_3::INITIAL_MONOTONIC_CYCLE_COUNTER; use zksync_contracts::BaseSystemContracts; -use zksync_system_constants::MAX_TXS_IN_BLOCK; +use zksync_system_constants::MAX_L2_TX_GAS_LIMIT; use zksync_types::{ - zkevm_test_harness::INITIAL_MONOTONIC_CYCLE_COUNTER, Address, Transaction, BOOTLOADER_ADDRESS, - L1_GAS_PER_PUBDATA_BYTE, MAX_GAS_PER_PUBDATA_BYTE, MAX_NEW_FACTORY_DEPS, U256, + fee_model::L1PeggedBatchFeeModelInput, Address, Transaction, BOOTLOADER_ADDRESS, + L1_GAS_PER_PUBDATA_BYTE, MAX_NEW_FACTORY_DEPS, U256, }; use zksync_utils::{ address_to_u256, bytecode::hash_bytecode, bytes_to_be_words, h256_to_u256, misc::ceil_div, }; -use crate::vm_m5::{ - bootloader_state::BootloaderState, - oracles::OracleWithHistory, - storage::Storage, - transaction_data::TransactionData, - utils::{ - code_page_candidate_from_base, heap_page_from_base, BLOCK_GAS_LIMIT, INITIAL_BASE_PAGE, +use crate::{ + vm_latest::L1BatchEnv, + vm_m5::{ + bootloader_state::BootloaderState, + oracles::OracleWithHistory, + storage::Storage, + transaction_data::TransactionData, + utils::{ + code_page_candidate_from_base, heap_page_from_base, BLOCK_GAS_LIMIT, INITIAL_BASE_PAGE, + }, + vm_instance::{MultiVMSubversion, VmInstance, ZkSyncVmState}, + OracleTools, }, - vm_instance::{MultiVMSubversion, VmInstance, ZkSyncVmState}, - OracleTools, }; -// TODO (SMA-1703): move these to config and make them programmatically generatable. -// fill these values in the similar fasion as other overhead-related constants +// TODO (SMA-1703): move these to config and make them programmatically generable. +// fill these values in the similar fashion as other overhead-related constants pub const BLOCK_OVERHEAD_GAS: u32 = 1200000; pub const BLOCK_OVERHEAD_L1_GAS: u32 = 1000000; pub const BLOCK_OVERHEAD_PUBDATA: u32 = BLOCK_OVERHEAD_L1_GAS / L1_GAS_PER_PUBDATA_BYTE; @@ -67,37 +71,76 @@ pub(crate) fn eth_price_per_pubdata_byte(l1_gas_price: u64) -> u64 { l1_gas_price * (L1_GAS_PER_PUBDATA_BYTE as u64) } -pub fn base_fee_to_gas_per_pubdata(l1_gas_price: u64, base_fee: u64) -> u64 { +pub(crate) fn base_fee_to_gas_per_pubdata(l1_gas_price: u64, base_fee: u64) -> u64 { let eth_price_per_pubdata_byte = eth_price_per_pubdata_byte(l1_gas_price); ceil_div(eth_price_per_pubdata_byte, base_fee) } -pub fn derive_base_fee_and_gas_per_pubdata(l1_gas_price: u64, fair_gas_price: u64) -> (u64, u64) { +pub(crate) fn derive_base_fee_and_gas_per_pubdata( + fee_input: L1PeggedBatchFeeModelInput, +) -> (u64, u64) { + let L1PeggedBatchFeeModelInput { + l1_gas_price, + fair_l2_gas_price, + } = fee_input; + let eth_price_per_pubdata_byte = eth_price_per_pubdata_byte(l1_gas_price); - // The baseFee is set in such a way that it is always possible to a transaciton to + // The `baseFee` is set in such a way that it is always possible to a transaction to // publish enough public data while compensating us for it. let base_fee = std::cmp::max( - fair_gas_price, + fair_l2_gas_price, ceil_div(eth_price_per_pubdata_byte, MAX_GAS_PER_PUBDATA_BYTE), ); ( base_fee, - base_fee_to_gas_per_pubdata(l1_gas_price, base_fee), + base_fee_to_gas_per_pubdata(fee_input.l1_gas_price, base_fee), ) } +pub(crate) fn get_batch_base_fee(l1_batch_env: &L1BatchEnv) -> u64 { + if let Some(base_fee) = l1_batch_env.enforced_base_fee { + return base_fee; + } + let (base_fee, _) = + derive_base_fee_and_gas_per_pubdata(l1_batch_env.fee_input.into_l1_pegged()); + base_fee +} + impl From for DerivedBlockContext { fn from(context: BlockContext) -> Self { - let base_fee = - derive_base_fee_and_gas_per_pubdata(context.l1_gas_price, context.fair_l2_gas_price).0; + let base_fee = derive_base_fee_and_gas_per_pubdata(L1PeggedBatchFeeModelInput { + l1_gas_price: context.l1_gas_price, + fair_l2_gas_price: context.fair_l2_gas_price, + }) + .0; DerivedBlockContext { context, base_fee } } } +/// The size of the bootloader memory in bytes which is used by the protocol. +/// While the maximal possible size is a lot higher, we restrict ourselves to a certain limit to reduce +/// the requirements on RAM. +pub(crate) const USED_BOOTLOADER_MEMORY_BYTES: usize = 1 << 24; +pub(crate) const USED_BOOTLOADER_MEMORY_WORDS: usize = USED_BOOTLOADER_MEMORY_BYTES / 32; + +// This the number of pubdata such that it should be always possible to publish +// from a single transaction. Note, that these pubdata bytes include only bytes that are +// to be published inside the body of transaction (i.e. excluding of factory deps). +pub(crate) const GUARANTEED_PUBDATA_PER_L1_BATCH: u64 = 4000; + +// The users should always be able to provide `MAX_GAS_PER_PUBDATA_BYTE` gas per pubdata in their +// transactions so that they are able to send at least `GUARANTEED_PUBDATA_PER_L1_BATCH` bytes per +// transaction. +pub(crate) const MAX_GAS_PER_PUBDATA_BYTE: u64 = + MAX_L2_TX_GAS_LIMIT / GUARANTEED_PUBDATA_PER_L1_BATCH; + +// The maximal number of transactions in a single batch +pub(crate) const MAX_TXS_IN_BLOCK: usize = 1024; + // The first 32 slots are reserved for debugging purposes pub const DEBUG_SLOTS_OFFSET: usize = 8; pub const DEBUG_FIRST_SLOTS: usize = 32; @@ -132,7 +175,7 @@ pub const TX_OVERHEAD_SLOTS: usize = MAX_TXS_IN_BLOCK; pub const BOOTLOADER_TX_DESCRIPTION_OFFSET: usize = TX_OVERHEAD_OFFSET + TX_OVERHEAD_SLOTS; // The size of the bootloader memory dedicated to the encodings of transactions -pub const BOOTLOADER_TX_ENCODING_SPACE: u32 = +pub(crate) const BOOTLOADER_TX_ENCODING_SPACE: u32 = (MAX_HEAP_PAGE_SIZE_IN_WORDS - TX_DESCRIPTION_OFFSET - MAX_TXS_IN_BLOCK) as u32; // Size of the bootloader tx description in words @@ -216,12 +259,12 @@ pub fn init_vm_with_gas_limit( } #[derive(Debug, Clone, Copy)] -// The block.number/block.timestamp data are stored in the CONTEXT_SYSTEM_CONTRACT. +// The `block.number` / `block.timestamp` data are stored in the `CONTEXT_SYSTEM_CONTRACT`. // The bootloader can support execution in two modes: -// - "NewBlock" when the new block is created. It is enforced that the block.number is incremented by 1 +// - `NewBlock` when the new block is created. It is enforced that the block.number is incremented by 1 // and the timestamp is non-decreasing. Also, the L2->L1 message used to verify the correctness of the previous root hash is sent. // This is the mode that should be used in the state keeper. -// - "OverrideCurrent" when we need to provide custom block.number and block.timestamp. ONLY to be used in testing/ethCalls. +// - `OverrideCurrent` when we need to provide custom `block.number` and `block.timestamp`. ONLY to be used in testing / `ethCalls`. pub enum BlockContextMode { NewBlock(DerivedBlockContext, U256), OverrideCurrent(DerivedBlockContext), diff --git a/core/lib/multivm/src/versions/vm_m6/errors/tx_revert_reason.rs b/core/lib/multivm/src/versions/vm_m6/errors/tx_revert_reason.rs index 4775d8339f79..3ddaa0684614 100644 --- a/core/lib/multivm/src/versions/vm_m6/errors/tx_revert_reason.rs +++ b/core/lib/multivm/src/versions/vm_m6/errors/tx_revert_reason.rs @@ -7,11 +7,11 @@ use super::{BootloaderErrorCode, VmRevertReason}; // Reasons why the transaction executed inside the bootloader could fail. #[derive(Debug, Clone, PartialEq)] pub enum TxRevertReason { - // Can only be returned in EthCall execution mode (=ExecuteOnly) + // Can only be returned in EthCall execution mode `(=ExecuteOnly)` EthCall(VmRevertReason), // Returned when the execution of an L2 transaction has failed TxReverted(VmRevertReason), - // Can only be returned in VerifyAndExecute + // Can only be returned in `VerifyAndExecute` ValidationFailed(VmRevertReason), PaymasterValidationFailed(VmRevertReason), PrePaymasterPreparationFailed(VmRevertReason), @@ -20,7 +20,7 @@ pub enum TxRevertReason { FailedToChargeFee(VmRevertReason), // Emitted when trying to call a transaction from an account that has not // been deployed as an account (i.e. the `from` is just a contract). - // Can only be returned in VerifyAndExecute + // Can only be returned in `VerifyAndExecute` FromIsNotAnAccount, // Currently cannot be returned. Should be removed when refactoring errors. InnerTxError, @@ -101,7 +101,7 @@ impl TxRevertReason { BootloaderErrorCode::UnacceptablePubdataPrice => { Self::UnexpectedVMBehavior("UnacceptablePubdataPrice".to_owned()) } - // This is different from AccountTxValidationFailed error in a way that it means that + // This is different from `AccountTxValidationFailed` error in a way that it means that // the error was not produced by the account itself, but for some other unknown reason (most likely not enough gas) BootloaderErrorCode::TxValidationError => Self::ValidationFailed(revert_reason), // Note, that `InnerTxError` is derived only after the actual tx execution, so diff --git a/core/lib/multivm/src/versions/vm_m6/errors/vm_revert_reason.rs b/core/lib/multivm/src/versions/vm_m6/errors/vm_revert_reason.rs index fb2341c0b2eb..0e5bf9fd8346 100644 --- a/core/lib/multivm/src/versions/vm_m6/errors/vm_revert_reason.rs +++ b/core/lib/multivm/src/versions/vm_m6/errors/vm_revert_reason.rs @@ -73,7 +73,7 @@ impl VmRevertReason { pub fn to_user_friendly_string(&self) -> String { match self { - // In case of `Unknown` reason we suppress it to prevent verbose Error function_selector = 0x{} + // In case of `Unknown` reason we suppress it to prevent verbose `Error function_selector = 0x{}` // message shown to user. VmRevertReason::Unknown { .. } => "".to_owned(), _ => self.to_string(), diff --git a/core/lib/multivm/src/versions/vm_m6/history_recorder.rs b/core/lib/multivm/src/versions/vm_m6/history_recorder.rs index 7ec8b2fde3bf..63dc9be4933a 100644 --- a/core/lib/multivm/src/versions/vm_m6/history_recorder.rs +++ b/core/lib/multivm/src/versions/vm_m6/history_recorder.rs @@ -18,13 +18,13 @@ pub type MemoryWithHistory = HistoryRecorder; pub type IntFrameManagerWithHistory = HistoryRecorder, H>; // Within the same cycle, timestamps in range timestamp..timestamp+TIME_DELTA_PER_CYCLE-1 -// can be used. This can sometimes vioalate monotonicity of the timestamp within the +// can be used. This can sometimes violate monotonicity of the timestamp within the // same cycle, so it should be normalized. #[inline] fn normalize_timestamp(timestamp: Timestamp) -> Timestamp { let timestamp = timestamp.0; - // Making sure it is divisible by TIME_DELTA_PER_CYCLE + // Making sure it is divisible by `TIME_DELTA_PER_CYCLE` Timestamp(timestamp - timestamp % zkevm_opcode_defs::TIME_DELTA_PER_CYCLE) } diff --git a/core/lib/multivm/src/versions/vm_m6/memory.rs b/core/lib/multivm/src/versions/vm_m6/memory.rs index 5a5042e5657f..6ad92c3a1e08 100644 --- a/core/lib/multivm/src/versions/vm_m6/memory.rs +++ b/core/lib/multivm/src/versions/vm_m6/memory.rs @@ -31,7 +31,7 @@ impl OracleWithHistory for SimpleMemory { impl SimpleMemory { pub fn populate(&mut self, elements: Vec<(u32, Vec)>, timestamp: Timestamp) { for (page, values) in elements.into_iter() { - // Resizing the pages array to fit the page. + // Re-sizing the pages array to fit the page. let len = values.len(); assert!(len <= MEMORY_CELLS_OTHER_PAGES); @@ -281,7 +281,7 @@ impl Memory for SimpleMemory { let returndata_page = returndata_fat_pointer.memory_page; for &page in current_observable_pages { - // If the page's number is greater than or equal to the base_page, + // If the page's number is greater than or equal to the `base_page`, // it means that it was created by the internal calls of this contract. // We need to add this check as the calldata pointer is also part of the // observable pages. @@ -298,7 +298,7 @@ impl Memory for SimpleMemory { } } -// It is expected that there is some intersection between [word_number*32..word_number*32+31] and [start, end] +// It is expected that there is some intersection between `[word_number*32..word_number*32+31]` and `[start, end]` fn extract_needed_bytes_from_word( word_value: Vec, word_number: usize, @@ -306,7 +306,7 @@ fn extract_needed_bytes_from_word( end: usize, ) -> Vec { let word_start = word_number * 32; - let word_end = word_start + 31; // Note, that at word_start + 32 a new word already starts + let word_end = word_start + 31; // Note, that at `word_start + 32` a new word already starts let intersection_left = std::cmp::max(word_start, start); let intersection_right = std::cmp::min(word_end, end); diff --git a/core/lib/multivm/src/versions/vm_m6/mod.rs b/core/lib/multivm/src/versions/vm_m6/mod.rs index 88367cf38578..3aeff47dbdcd 100644 --- a/core/lib/multivm/src/versions/vm_m6/mod.rs +++ b/core/lib/multivm/src/versions/vm_m6/mod.rs @@ -17,8 +17,6 @@ pub mod utils; pub mod vm_instance; pub mod vm_with_bootloader; -#[cfg(test)] -mod tests; mod vm; pub use errors::TxRevertReason; diff --git a/core/lib/multivm/src/versions/vm_m6/oracles/decommitter.rs b/core/lib/multivm/src/versions/vm_m6/oracles/decommitter.rs index a1c2a97edf9f..fe59580e2ce9 100644 --- a/core/lib/multivm/src/versions/vm_m6/oracles/decommitter.rs +++ b/core/lib/multivm/src/versions/vm_m6/oracles/decommitter.rs @@ -15,7 +15,7 @@ use crate::vm_m6::{ storage::{Storage, StoragePtr}, }; -/// The main job of the DecommiterOracle is to implement the DecommittmentProcessor trait - that is +/// The main job of the DecommiterOracle is to implement the DecommitmentProcessor trait - that is /// used by the VM to 'load' bytecodes into memory. #[derive(Debug)] pub struct DecommitterOracle { diff --git a/core/lib/multivm/src/versions/vm_m6/oracles/mod.rs b/core/lib/multivm/src/versions/vm_m6/oracles/mod.rs index 2b7aa3a49f7d..450ed4cf1e0c 100644 --- a/core/lib/multivm/src/versions/vm_m6/oracles/mod.rs +++ b/core/lib/multivm/src/versions/vm_m6/oracles/mod.rs @@ -1,9 +1,9 @@ use zk_evm_1_3_1::aux_structures::Timestamp; // All the changes to the events in the DB will be applied after the tx is executed, -// so fow now it is fine. +// so for now it is fine. pub use zk_evm_1_3_1::reference_impls::event_sink::InMemoryEventSink as EventSinkOracle; // We will discard RAM as soon as the execution of a tx ends, so -// it is ok for now to use SimpleMemory +// it is ok for now to use `SimpleMemory` pub use zk_evm_1_3_1::reference_impls::memory::SimpleMemory as RamOracle; pub use zk_evm_1_3_1::testing::simple_tracer::NoopTracer; diff --git a/core/lib/multivm/src/versions/vm_m6/oracles/storage.rs b/core/lib/multivm/src/versions/vm_m6/oracles/storage.rs index 7ceab94bd472..a354ef627e3a 100644 --- a/core/lib/multivm/src/versions/vm_m6/oracles/storage.rs +++ b/core/lib/multivm/src/versions/vm_m6/oracles/storage.rs @@ -6,21 +6,19 @@ use zk_evm_1_3_1::{ zkevm_opcode_defs::system_params::INITIAL_STORAGE_WRITE_PUBDATA_BYTES, }; use zksync_types::{ - utils::storage_key_for_eth_balance, AccountTreeId, Address, StorageKey, StorageLogQuery, - StorageLogQueryType, BOOTLOADER_ADDRESS, U256, + utils::storage_key_for_eth_balance, AccountTreeId, Address, StorageKey, StorageLogQueryType, + BOOTLOADER_ADDRESS, U256, }; use zksync_utils::u256_to_h256; use super::OracleWithHistory; -use crate::{ - glue::GlueInto, - vm_m6::{ - history_recorder::{ - AppDataFrameManagerWithHistory, HashMapHistoryEvent, HistoryEnabled, HistoryMode, - HistoryRecorder, StorageWrapper, WithHistory, - }, - storage::{Storage, StoragePtr}, +use crate::vm_m6::{ + history_recorder::{ + AppDataFrameManagerWithHistory, HashMapHistoryEvent, HistoryEnabled, HistoryMode, + HistoryRecorder, StorageWrapper, WithHistory, }, + storage::{Storage, StoragePtr}, + utils::StorageLogQuery, }; // While the storage does not support different shards, it was decided to write the @@ -85,7 +83,7 @@ impl StorageOracle { self.frames_stack.push_forward( StorageLogQuery { - log_query: query.glue_into(), + log_query: query, log_type: StorageLogQueryType::Read, }, query.timestamp, @@ -109,7 +107,7 @@ impl StorageOracle { query.read_value = current_value; let mut storage_log_query = StorageLogQuery { - log_query: query.glue_into(), + log_query: query, log_type: log_query_type, }; self.frames_stack @@ -190,6 +188,7 @@ impl VmStorageOracle for StorageOracle { _monotonic_cycle_counter: u32, query: LogQuery, ) -> LogQuery { + // ``` // tracing::trace!( // "execute partial query cyc {:?} addr {:?} key {:?}, rw {:?}, wr {:?}, tx {:?}", // _monotonic_cycle_counter, @@ -199,6 +198,7 @@ impl VmStorageOracle for StorageOracle { // query.written_value, // query.tx_number_in_block // ); + // ``` assert!(!query.rollback); if query.rw_flag { // The number of bytes that have been compensated by the user to perform this write @@ -264,7 +264,7 @@ impl VmStorageOracle for StorageOracle { } }; - let LogQuery { written_value, .. } = query.log_query.glue_into(); + let LogQuery { written_value, .. } = query.log_query; let key = triplet_to_storage_key( query.log_query.shard_id, query.log_query.address, @@ -278,7 +278,7 @@ impl VmStorageOracle for StorageOracle { ); // Additional validation that the current value was correct - // Unwrap is safe because the return value from write_inner is the previous value in this leaf. + // Unwrap is safe because the return value from `write_inner` is the previous value in this leaf. // It is impossible to set leaf value to `None` assert_eq!(current_value, written_value); } @@ -292,8 +292,8 @@ impl VmStorageOracle for StorageOracle { /// Returns the number of bytes needed to publish a slot. // Since we need to publish the state diffs onchain, for each of the updated storage slot -// we basically need to publish the following pair: (). -// While new_value is always 32 bytes long, for key we use the following optimization: +// we basically need to publish the following pair: `()`. +// While `new_value` is always 32 bytes long, for key we use the following optimization: // - The first time we publish it, we use 32 bytes. // Then, we remember a 8-byte id for this slot and assign it to it. We call this initial write. // - The second time we publish it, we will use this 8-byte instead of the 32 bytes of the entire key. diff --git a/core/lib/multivm/src/versions/vm_m6/oracles/tracer/bootloader.rs b/core/lib/multivm/src/versions/vm_m6/oracles/tracer/bootloader.rs index 5509cef90832..f2780c6ae80f 100644 --- a/core/lib/multivm/src/versions/vm_m6/oracles/tracer/bootloader.rs +++ b/core/lib/multivm/src/versions/vm_m6/oracles/tracer/bootloader.rs @@ -100,7 +100,7 @@ impl PubdataSpentTracer for BootloaderTracer { impl BootloaderTracer { fn current_frame_is_bootloader(local_state: &VmLocalState) -> bool { - // The current frame is bootloader if the callstack depth is 1. + // The current frame is bootloader if the call stack depth is 1. // Some of the near calls inside the bootloader can be out of gas, which is totally normal behavior // and it shouldn't result in `is_bootloader_out_of_gas` becoming true. local_state.callstack.inner.len() == 1 diff --git a/core/lib/multivm/src/versions/vm_m6/oracles/tracer/call.rs b/core/lib/multivm/src/versions/vm_m6/oracles/tracer/call.rs index 1166e7a8cdb6..19cbf13b2756 100644 --- a/core/lib/multivm/src/versions/vm_m6/oracles/tracer/call.rs +++ b/core/lib/multivm/src/versions/vm_m6/oracles/tracer/call.rs @@ -189,7 +189,7 @@ impl CallTracer { let fat_data_pointer = state.vm_local_state.registers[RET_IMPLICIT_RETURNDATA_PARAMS_REGISTER as usize]; - // if fat_data_pointer is not a pointer then there is no output + // if `fat_data_pointer` is not a pointer then there is no output let output = if fat_data_pointer.is_pointer { let fat_data_pointer = FatPointer::from_u256(fat_data_pointer.value); if !fat_data_pointer.is_trivial() { @@ -256,8 +256,8 @@ impl CallTracer { // Filter all near calls from the call stack // Important that the very first call is near call - // And this NearCall includes several Normal or Mimic calls - // So we return all childrens of this NearCall + // And this `NearCall` includes several Normal or Mimic calls + // So we return all children of this `NearCall` pub fn extract_calls(&mut self) -> Vec { if let Some(current_call) = self.stack.pop() { filter_near_call(current_call) @@ -268,7 +268,7 @@ impl CallTracer { } // Filter all near calls from the call stack -// Normally wr are not interested in NearCall, because it's just a wrapper for internal calls +// Normally we are not interested in `NearCall`, because it's just a wrapper for internal calls fn filter_near_call(mut call: Call) -> Vec { let mut calls = vec![]; let original_calls = std::mem::take(&mut call.calls); diff --git a/core/lib/multivm/src/versions/vm_m6/oracles/tracer/one_tx.rs b/core/lib/multivm/src/versions/vm_m6/oracles/tracer/one_tx.rs index 346daba21317..53e5e4ee2f6a 100644 --- a/core/lib/multivm/src/versions/vm_m6/oracles/tracer/one_tx.rs +++ b/core/lib/multivm/src/versions/vm_m6/oracles/tracer/one_tx.rs @@ -19,7 +19,7 @@ use crate::vm_m6::{ }; /// Allows any opcodes, but tells the VM to end the execution once the tx is over. -// Internally depeds on Bootloader's VMHooks to get the notification once the transaction is finished. +// Internally depends on Bootloader's `VMHooks` to get the notification once the transaction is finished. #[derive(Debug)] pub struct OneTxTracer { tx_has_been_processed: bool, diff --git a/core/lib/multivm/src/versions/vm_m6/oracles/tracer/utils.rs b/core/lib/multivm/src/versions/vm_m6/oracles/tracer/utils.rs index d29476ea4ccc..2df22aa2d3f8 100644 --- a/core/lib/multivm/src/versions/vm_m6/oracles/tracer/utils.rs +++ b/core/lib/multivm/src/versions/vm_m6/oracles/tracer/utils.rs @@ -48,7 +48,7 @@ impl VmHook { let value = data.src1_value.value; - // Only UMA opcodes in the bootloader serve for vm hooks + // Only `UMA` opcodes in the bootloader serve for vm hooks if !matches!(opcode_variant.opcode, Opcode::UMA(UMAOpcode::HeapWrite)) || heap_page != BOOTLOADER_HEAP_PAGE || fat_ptr.offset != VM_HOOK_POSITION * 32 diff --git a/core/lib/multivm/src/versions/vm_m6/oracles/tracer/validation.rs b/core/lib/multivm/src/versions/vm_m6/oracles/tracer/validation.rs index e75a9f34a4ba..704a967548be 100644 --- a/core/lib/multivm/src/versions/vm_m6/oracles/tracer/validation.rs +++ b/core/lib/multivm/src/versions/vm_m6/oracles/tracer/validation.rs @@ -100,7 +100,7 @@ fn touches_allowed_context(address: Address, key: U256) -> bool { return false; } - // Only chain_id is allowed to be touched. + // Only `chain_id` is allowed to be touched. key == U256::from(0u32) } @@ -235,7 +235,7 @@ impl ValidationTracer { return true; } - // The pair of MSG_VALUE_SIMULATOR_ADDRESS & L2_ETH_TOKEN_ADDRESS simulates the behavior of transferring ETH + // The pair of `MSG_VALUE_SIMULATOR_ADDRESS` & `L2_ETH_TOKEN_ADDRESS` simulates the behavior of transferring ETH // that is safe for the DDoS protection rules. if valid_eth_token_call(address, msg_sender) { return true; @@ -279,20 +279,20 @@ impl ValidationTracer { let (potential_address_bytes, potential_position_bytes) = calldata.split_at(32); let potential_address = be_bytes_to_safe_address(potential_address_bytes); - // If the validation_address is equal to the potential_address, - // then it is a request that could be used for mapping of kind mapping(address => ...). + // If the `validation_address` is equal to the `potential_address`, + // then it is a request that could be used for mapping of kind `mapping(address => ...)`. // - // If the potential_position_bytes were already allowed before, then this keccak might be used - // for ERC-20 allowance or any other of mapping(address => mapping(...)) + // If the `potential_position_bytes` were already allowed before, then this keccak might be used + // for ERC-20 allowance or any other of `mapping(address => mapping(...))` if potential_address == Some(validated_address) || self .auxilary_allowed_slots .contains(&H256::from_slice(potential_position_bytes)) { - // This is request that could be used for mapping of kind mapping(address => ...) + // This is request that could be used for mapping of kind `mapping(address => ...)` // We could theoretically wait for the slot number to be returned by the - // keccak256 precompile itself, but this would complicate the code even further + // `keccak256` precompile itself, but this would complicate the code even further // so let's calculate it here. let slot = keccak256(calldata); diff --git a/core/lib/multivm/src/versions/vm_m6/pubdata_utils.rs b/core/lib/multivm/src/versions/vm_m6/pubdata_utils.rs index 33307507f7ec..b9b89a38f043 100644 --- a/core/lib/multivm/src/versions/vm_m6/pubdata_utils.rs +++ b/core/lib/multivm/src/versions/vm_m6/pubdata_utils.rs @@ -1,9 +1,10 @@ use std::collections::HashMap; -use zk_evm_1_3_1::aux_structures::Timestamp; +use itertools::Itertools; +use zk_evm_1_3_1::aux_structures::{LogQuery, Timestamp}; +use zkevm_test_harness_1_3_3::witness::sort_storage_access::sort_storage_access_queries; use zksync_types::{ event::{extract_long_l2_to_l1_messages, extract_published_bytecodes}, - zkevm_test_harness::witness::sort_storage_access::sort_storage_access_queries, StorageKey, PUBLISH_BYTECODE_OVERHEAD, SYSTEM_CONTEXT_ADDRESS, }; use zksync_utils::bytecode::bytecode_len_in_bytes; @@ -79,8 +80,21 @@ impl VmInstance { self.state.storage.frames_stack.forward().current_frame(), from_timestamp, ); - let (_, deduplicated_logs) = - sort_storage_access_queries(storage_logs.iter().map(|log| &log.log_query)); + + // To allow calling the `vm-1.3.3`s. method, the `v1.3.1`'s `LogQuery` has to be converted + // to the `vm-1.3.3`'s `LogQuery`. Then, we need to convert it back. + let deduplicated_logs: Vec = sort_storage_access_queries( + &storage_logs + .iter() + .map(|log| { + GlueInto::::glue_into(log.log_query) + }) + .collect_vec(), + ) + .1 + .into_iter() + .map(GlueInto::::glue_into) + .collect(); deduplicated_logs .into_iter() diff --git a/core/lib/multivm/src/versions/vm_m6/refunds.rs b/core/lib/multivm/src/versions/vm_m6/refunds.rs index 4b4229b306b9..406bf380a0b2 100644 --- a/core/lib/multivm/src/versions/vm_m6/refunds.rs +++ b/core/lib/multivm/src/versions/vm_m6/refunds.rs @@ -76,7 +76,7 @@ impl VmInstance { ) -> u32 { // TODO (SMA-1715): Make users pay for the block overhead 0 - + // ``` // let pubdata_published = self.pubdata_published(from_timestamp); // // let total_gas_spent = gas_remaining_before - self.gas_remaining(); @@ -121,6 +121,7 @@ impl VmInstance { // ); // 0 // } + // ``` } // TODO (SMA-1715): Make users pay for the block overhead @@ -134,39 +135,39 @@ impl VmInstance { _l2_l1_logs: usize, ) -> u32 { 0 - + // ``` // let overhead_for_block_gas = U256::from(crate::transaction_data::block_overhead_gas( // gas_per_pubdata_byte_limit, // )); - + // // let encoded_len = U256::from(encoded_len); // let pubdata_published = U256::from(pubdata_published); // let gas_spent_on_computation = U256::from(gas_spent_on_computation); // let number_of_decommitment_requests = U256::from(number_of_decommitment_requests); // let l2_l1_logs = U256::from(l2_l1_logs); - + // // let tx_slot_overhead = ceil_div_u256(overhead_for_block_gas, MAX_TXS_IN_BLOCK.into()); - + // // let overhead_for_length = ceil_div_u256( // encoded_len * overhead_for_block_gas, // BOOTLOADER_TX_ENCODING_SPACE.into(), // ); - + // // let actual_overhead_for_pubdata = ceil_div_u256( // pubdata_published * overhead_for_block_gas, // MAX_PUBDATA_PER_BLOCK.into(), // ); - + // // let actual_gas_limit_overhead = ceil_div_u256( // gas_spent_on_computation * overhead_for_block_gas, // MAX_BLOCK_MULTIINSTANCE_GAS_LIMIT.into(), // ); - + // // let code_decommitter_sorter_circuit_overhead = ceil_div_u256( // number_of_decommitment_requests * overhead_for_block_gas, // GEOMETRY_CONFIG.limit_for_code_decommitter_sorter.into(), // ); - + // // let l1_l2_logs_overhead = ceil_div_u256( // l2_l1_logs * overhead_for_block_gas, // std::cmp::min( @@ -175,7 +176,7 @@ impl VmInstance { // ) // .into(), // ); - + // // let overhead = vec![ // tx_slot_overhead, // overhead_for_length, @@ -187,8 +188,9 @@ impl VmInstance { // .into_iter() // .max() // .unwrap(); - + // // overhead.as_u32() + // ``` } /// Returns the given transactions' gas limit - by reading it directly from the VM memory. diff --git a/core/lib/multivm/src/versions/vm_m6/test_utils.rs b/core/lib/multivm/src/versions/vm_m6/test_utils.rs index 55e5add11648..528731ee888d 100644 --- a/core/lib/multivm/src/versions/vm_m6/test_utils.rs +++ b/core/lib/multivm/src/versions/vm_m6/test_utils.rs @@ -19,13 +19,13 @@ use zksync_types::{ fee::Fee, l2::L2Tx, web3::signing::keccak256, - Execute, L2ChainId, Nonce, StorageKey, StorageLogQuery, StorageValue, - CONTRACT_DEPLOYER_ADDRESS, H256, U256, + Execute, L2ChainId, Nonce, StorageKey, StorageValue, CONTRACT_DEPLOYER_ADDRESS, H256, U256, }; use zksync_utils::{ address_to_h256, bytecode::hash_bytecode, h256_to_account_address, u256_to_h256, }; +use super::utils::StorageLogQuery; use crate::vm_m6::{ event_sink::InMemoryEventSink, history_recorder::{ diff --git a/core/lib/multivm/src/versions/vm_m6/tests/bootloader.rs b/core/lib/multivm/src/versions/vm_m6/tests/bootloader.rs deleted file mode 100644 index be840e16a142..000000000000 --- a/core/lib/multivm/src/versions/vm_m6/tests/bootloader.rs +++ /dev/null @@ -1,2174 +0,0 @@ -// //! -// //! Tests for the bootloader -// //! The description for each of the tests can be found in the corresponding `.yul` file. -// //! -// use itertools::Itertools; -// use std::{ -// collections::{HashMap, HashSet}, -// convert::TryFrom, -// }; -// use tempfile::TempDir; - -// use crate::{ -// errors::VmRevertReason, -// history_recorder::HistoryMode, -// oracles::tracer::{StorageInvocationTracer, TransactionResultTracer}, -// storage::{Storage, StoragePtr}, -// test_utils::{ -// get_create_execute, get_create_zksync_address, get_deploy_tx, get_error_tx, -// mock_loadnext_test_call, -// }, -// transaction_data::TransactionData, -// utils::{ -// create_test_block_params, insert_system_contracts, read_bootloader_test_code, -// BASE_SYSTEM_CONTRACTS, BLOCK_GAS_LIMIT, -// }, -// vm::{tx_has_failed, VmExecutionStopReason, ZkSyncVmState}, -// vm_with_bootloader::{ -// bytecode_to_factory_dep, get_bootloader_memory, get_bootloader_memory_for_encoded_tx, -// push_raw_transaction_to_bootloader_memory, BlockContext, BlockContextMode, -// BootloaderJobType, TxExecutionMode, -// }, -// vm_with_bootloader::{ -// init_vm_inner, push_transaction_to_bootloader_memory, DerivedBlockContext, -// BOOTLOADER_HEAP_PAGE, TX_DESCRIPTION_OFFSET, TX_GAS_LIMIT_OFFSET, -// }, -// HistoryEnabled, OracleTools, TxRevertReason, VmBlockResult, VmExecutionResult, VmInstance, -// }; - -// use zk_evm_1_3_1::{ -// aux_structures::Timestamp, block_properties::BlockProperties, zkevm_opcode_defs::FarCallOpcode, -// }; - -// use zksync_types::{ -// block::DeployedContract, -// ethabi::encode, -// get_is_account_key, -// storage_writes_deduplicator::StorageWritesDeduplicator, -// system_contracts::{DEPLOYMENT_NONCE_INCREMENT, TX_NONCE_INCREMENT}, -// tx::tx_execution_info::TxExecutionStatus, -// utils::{ -// deployed_address_create, storage_key_for_eth_balance, -// storage_key_for_standard_token_balance, -// }, -// vm_trace::{Call, CallType}, -// Execute, L1BatchNumber, L1TxCommonData, StorageKey, StorageLog, L1_MESSENGER_ADDRESS, -// {ethabi::Token, AccountTreeId, Address, ExecuteTransactionCommon, Transaction, H256, U256}, -// {fee::Fee, l2_to_l1_log::L2ToL1Log}, -// { -// get_code_key, get_known_code_key, get_nonce_key, Nonce, BOOTLOADER_ADDRESS, H160, -// L2_ETH_TOKEN_ADDRESS, MAX_GAS_PER_PUBDATA_BYTE, SYSTEM_CONTEXT_ADDRESS, -// }, -// }; - -// use zksync_utils::{ -// bytecode::CompressedBytecodeInfo, -// test_utils::LoadnextContractExecutionParams, -// {bytecode::hash_bytecode, bytes_to_be_words, h256_to_u256, u256_to_h256}, -// }; - -// use zksync_contracts::{ -// get_loadnext_contract, load_contract, read_bytecode, SystemContractCode, -// PLAYGROUND_BLOCK_BOOTLOADER_CODE, -// }; - -// use zksync_state::{secondary_storage::SecondaryStateStorage, storage_view::StorageView}; -// use zksync_storage::{db::Database, RocksDB}; - -// fn run_vm_with_custom_factory_deps<'a, H: HistoryMode>( -// oracle_tools: &'a mut OracleTools<'a, false, H>, -// block_context: BlockContext, -// block_properties: &'a BlockProperties, -// encoded_tx: Vec, -// predefined_overhead: u32, -// expected_error: Option, -// ) { -// let mut base_system_contracts = BASE_SYSTEM_CONTRACTS.clone(); -// base_system_contracts.bootloader = PLAYGROUND_BLOCK_BOOTLOADER_CODE.clone(); -// let mut vm = init_vm_inner( -// oracle_tools, -// BlockContextMode::OverrideCurrent(block_context.into()), -// block_properties, -// BLOCK_GAS_LIMIT, -// &base_system_contracts, -// TxExecutionMode::VerifyExecute, -// ); - -// vm.bootloader_state.add_tx_data(encoded_tx.len()); -// vm.state.memory.populate_page( -// BOOTLOADER_HEAP_PAGE as usize, -// get_bootloader_memory_for_encoded_tx( -// encoded_tx, -// 0, -// TxExecutionMode::VerifyExecute, -// 0, -// 0, -// predefined_overhead, -// u32::MAX, -// 0, -// vec![], -// ), -// Timestamp(0), -// ); - -// let result = vm.execute_next_tx(u32::MAX, false).err(); - -// assert_eq!(expected_error, result); -// } - -// fn get_balance(token_id: AccountTreeId, account: &Address, main_storage: StoragePtr<'_>) -> U256 { -// let key = storage_key_for_standard_token_balance(token_id, account); -// h256_to_u256(main_storage.borrow_mut().get_value(&key)) -// } - -// #[test] -// fn test_dummy_bootloader() { -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); -// let mut storage_accessor = StorageView::new(&raw_storage); -// let storage_ptr: &mut dyn Storage = &mut storage_accessor; - -// let mut oracle_tools = OracleTools::new(storage_ptr, HistoryEnabled); -// let (block_context, block_properties) = create_test_block_params(); -// let mut base_system_contracts = BASE_SYSTEM_CONTRACTS.clone(); -// let bootloader_code = read_bootloader_test_code("dummy"); -// let bootloader_hash = hash_bytecode(&bootloader_code); - -// base_system_contracts.bootloader = SystemContractCode { -// code: bytes_to_be_words(bootloader_code), -// hash: bootloader_hash, -// }; - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context.into(), Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &base_system_contracts, -// TxExecutionMode::VerifyExecute, -// ); - -// let VmBlockResult { -// full_result: res, .. -// } = vm.execute_till_block_end(BootloaderJobType::BlockPostprocessing); - -// // Dummy bootloader should not panic -// assert!(res.revert_reason.is_none()); - -// let correct_first_cell = U256::from_str_radix("123123123", 16).unwrap(); - -// verify_required_memory( -// &vm.state, -// vec![(correct_first_cell, BOOTLOADER_HEAP_PAGE, 0)], -// ); -// } - -// #[test] -// fn test_bootloader_out_of_gas() { -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); -// let mut storage_accessor = StorageView::new(&raw_storage); -// let storage_ptr: &mut dyn Storage = &mut storage_accessor; - -// let mut oracle_tools = OracleTools::new(storage_ptr, HistoryEnabled); -// let (block_context, block_properties) = create_test_block_params(); - -// let mut base_system_contracts = BASE_SYSTEM_CONTRACTS.clone(); - -// let bootloader_code = read_bootloader_test_code("dummy"); -// let bootloader_hash = hash_bytecode(&bootloader_code); - -// base_system_contracts.bootloader = SystemContractCode { -// code: bytes_to_be_words(bootloader_code), -// hash: bootloader_hash, -// }; - -// // init vm with only 10 ergs -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context.into(), Default::default()), -// &block_properties, -// 10, -// &base_system_contracts, -// TxExecutionMode::VerifyExecute, -// ); - -// let res = vm.execute_block_tip(); - -// assert_eq!(res.revert_reason, Some(TxRevertReason::BootloaderOutOfGas)); -// } - -// fn verify_required_storage( -// state: &ZkSyncVmState<'_, H>, -// required_values: Vec<(H256, StorageKey)>, -// ) { -// for (required_value, key) in required_values { -// let current_value = state.storage.storage.read_from_storage(&key); - -// assert_eq!( -// u256_to_h256(current_value), -// required_value, -// "Invalid value at key {key:?}" -// ); -// } -// } - -// fn verify_required_memory( -// state: &ZkSyncVmState<'_, H>, -// required_values: Vec<(U256, u32, u32)>, -// ) { -// for (required_value, memory_page, cell) in required_values { -// let current_value = state -// .memory -// .read_slot(memory_page as usize, cell as usize) -// .value; -// assert_eq!(current_value, required_value); -// } -// } - -// #[test] -// fn test_default_aa_interaction() { -// // In this test, we aim to test whether a simple account interaction (without any fee logic) -// // will work. The account will try to deploy a simple contract from integration tests. - -// let (block_context, block_properties) = create_test_block_params(); -// let block_context: DerivedBlockContext = block_context.into(); - -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); -// let storage_ptr: &mut dyn Storage = &mut StorageView::new(&raw_storage); - -// let operator_address = block_context.context.operator_address; -// let base_fee = block_context.base_fee; -// // We deploy here counter contract, because its logic is trivial -// let contract_code = read_test_contract(); -// let contract_code_hash = hash_bytecode(&contract_code); -// let tx: Transaction = get_deploy_tx( -// H256::random(), -// Nonce(0), -// &contract_code, -// vec![], -// &[], -// Fee { -// gas_limit: U256::from(20000000u32), -// max_fee_per_gas: U256::from(base_fee), -// max_priority_fee_per_gas: U256::from(0), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); -// let tx_data: TransactionData = tx.clone().into(); - -// let maximal_fee = tx_data.gas_limit * tx_data.max_fee_per_gas; -// let sender_address = tx_data.from(); -// // set balance - -// let key = storage_key_for_eth_balance(&sender_address); -// storage_ptr.set_value(&key, u256_to_h256(U256([0, 0, 1, 0]))); - -// let mut oracle_tools = OracleTools::new(storage_ptr, HistoryEnabled); - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context, Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); - -// let tx_execution_result = vm -// .execute_next_tx(u32::MAX, false) -// .expect("Bootloader failed while processing transaction"); - -// assert_eq!( -// tx_execution_result.status, -// TxExecutionStatus::Success, -// "Transaction wasn't successful" -// ); - -// let VmBlockResult { -// full_result: res, .. -// } = vm.execute_till_block_end(BootloaderJobType::TransactionExecution); -// // Should not panic -// assert!( -// res.revert_reason.is_none(), -// "Bootloader was not expected to revert: {:?}", -// res.revert_reason -// ); - -// // Both deployment and ordinary nonce should be incremented by one. -// let account_nonce_key = get_nonce_key(&sender_address); -// let expected_nonce = TX_NONCE_INCREMENT + DEPLOYMENT_NONCE_INCREMENT; - -// // The code hash of the deployed contract should be marked as republished. -// let known_codes_key = get_known_code_key(&contract_code_hash); - -// // The contract should be deployed successfully. -// let deployed_address = deployed_address_create(sender_address, U256::zero()); -// let account_code_key = get_code_key(&deployed_address); - -// let expected_slots = vec![ -// (u256_to_h256(expected_nonce), account_nonce_key), -// (u256_to_h256(U256::from(1u32)), known_codes_key), -// (contract_code_hash, account_code_key), -// ]; - -// verify_required_storage(&vm.state, expected_slots); - -// assert!(!tx_has_failed(&vm.state, 0)); - -// let expected_fee = -// maximal_fee - U256::from(tx_execution_result.gas_refunded) * U256::from(base_fee); -// let operator_balance = get_balance( -// AccountTreeId::new(L2_ETH_TOKEN_ADDRESS), -// &operator_address, -// vm.state.storage.storage.get_ptr(), -// ); - -// assert!( -// operator_balance == expected_fee, -// "Operator did not receive his fee" -// ); -// } - -// fn execute_vm_with_predetermined_refund( -// txs: Vec, -// refunds: Vec, -// compressed_bytecodes: Vec>, -// ) -> VmBlockResult { -// let (block_context, block_properties) = create_test_block_params(); -// let block_context: DerivedBlockContext = block_context.into(); - -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); -// let storage_ptr: &mut dyn Storage = &mut StorageView::new(&raw_storage); - -// // set balance -// for tx in txs.iter() { -// let sender_address = tx.initiator_account(); -// let key = storage_key_for_eth_balance(&sender_address); -// storage_ptr.set_value(&key, u256_to_h256(U256([0, 0, 1, 0]))); -// } - -// let mut oracle_tools = OracleTools::new(storage_ptr, HistoryEnabled); - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context, Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); - -// let codes_for_decommiter = txs -// .iter() -// .flat_map(|tx| { -// tx.execute -// .factory_deps -// .clone() -// .unwrap_or_default() -// .iter() -// .map(|dep| bytecode_to_factory_dep(dep.clone())) -// .collect::)>>() -// }) -// .collect(); - -// vm.state.decommittment_processor.populate( -// codes_for_decommiter, -// Timestamp(vm.state.local_state.timestamp), -// ); - -// let memory_with_suggested_refund = get_bootloader_memory( -// txs.into_iter().map(Into::into).collect(), -// refunds, -// compressed_bytecodes, -// TxExecutionMode::VerifyExecute, -// BlockContextMode::NewBlock(block_context, Default::default()), -// ); - -// vm.state.memory.populate_page( -// BOOTLOADER_HEAP_PAGE as usize, -// memory_with_suggested_refund, -// Timestamp(0), -// ); - -// vm.execute_till_block_end(BootloaderJobType::TransactionExecution) -// } - -// #[test] -// fn test_predetermined_refunded_gas() { -// // In this test, we compare the execution of the bootloader with the predefined -// // refunded gas and without them - -// let (block_context, block_properties) = create_test_block_params(); -// let block_context: DerivedBlockContext = block_context.into(); - -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); -// let storage_ptr: &mut dyn Storage = &mut StorageView::new(&raw_storage); - -// let base_fee = block_context.base_fee; - -// // We deploy here counter contract, because its logic is trivial -// let contract_code = read_test_contract(); -// let published_bytecode = CompressedBytecodeInfo::from_original(contract_code.clone()).unwrap(); -// let tx: Transaction = get_deploy_tx( -// H256::random(), -// Nonce(0), -// &contract_code, -// vec![], -// &[], -// Fee { -// gas_limit: U256::from(20000000u32), -// max_fee_per_gas: U256::from(base_fee), -// max_priority_fee_per_gas: U256::from(0), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); - -// let sender_address = tx.initiator_account(); - -// // set balance -// let key = storage_key_for_eth_balance(&sender_address); -// storage_ptr.set_value(&key, u256_to_h256(U256([0, 0, 1, 0]))); - -// let mut oracle_tools = OracleTools::new(storage_ptr, HistoryEnabled); - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context, Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); - -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); - -// let tx_execution_result = vm -// .execute_next_tx(u32::MAX, false) -// .expect("Bootloader failed while processing transaction"); - -// assert_eq!( -// tx_execution_result.status, -// TxExecutionStatus::Success, -// "Transaction wasn't successful" -// ); - -// // If the refund provided by the operator or the final refund are the 0 -// // there is no impact of the operator's refund at all and so this test does not -// // make much sense. -// assert!( -// tx_execution_result.operator_suggested_refund > 0, -// "The operator's refund is 0" -// ); -// assert!( -// tx_execution_result.gas_refunded > 0, -// "The final refund is 0" -// ); - -// let mut result = vm.execute_till_block_end(BootloaderJobType::TransactionExecution); -// assert!( -// result.full_result.revert_reason.is_none(), -// "Bootloader was not expected to revert: {:?}", -// result.full_result.revert_reason -// ); - -// let mut result_with_predetermined_refund = execute_vm_with_predetermined_refund( -// vec![tx], -// vec![tx_execution_result.operator_suggested_refund], -// vec![vec![published_bytecode]], -// ); -// // We need to sort these lists as those are flattened from HashMaps -// result.full_result.used_contract_hashes.sort(); -// result_with_predetermined_refund -// .full_result -// .used_contract_hashes -// .sort(); - -// assert_eq!( -// result.full_result.events, -// result_with_predetermined_refund.full_result.events -// ); -// assert_eq!( -// result.full_result.l2_to_l1_logs, -// result_with_predetermined_refund.full_result.l2_to_l1_logs -// ); -// assert_eq!( -// result.full_result.storage_log_queries, -// result_with_predetermined_refund -// .full_result -// .storage_log_queries -// ); -// assert_eq!( -// result.full_result.used_contract_hashes, -// result_with_predetermined_refund -// .full_result -// .used_contract_hashes -// ); -// } - -// #[derive(Debug, Clone)] -// enum TransactionRollbackTestInfo { -// Rejected(Transaction, TxRevertReason), -// Processed(Transaction, bool, TxExecutionStatus), -// } - -// impl TransactionRollbackTestInfo { -// fn new_rejected(transaction: Transaction, revert_reason: TxRevertReason) -> Self { -// Self::Rejected(transaction, revert_reason) -// } - -// fn new_processed( -// transaction: Transaction, -// should_be_rollbacked: bool, -// expected_status: TxExecutionStatus, -// ) -> Self { -// Self::Processed(transaction, should_be_rollbacked, expected_status) -// } - -// fn get_transaction(&self) -> &Transaction { -// match self { -// TransactionRollbackTestInfo::Rejected(tx, _) => tx, -// TransactionRollbackTestInfo::Processed(tx, _, _) => tx, -// } -// } - -// fn rejection_reason(&self) -> Option { -// match self { -// TransactionRollbackTestInfo::Rejected(_, revert_reason) => Some(revert_reason.clone()), -// TransactionRollbackTestInfo::Processed(_, _, _) => None, -// } -// } - -// fn should_rollback(&self) -> bool { -// match self { -// TransactionRollbackTestInfo::Rejected(_, _) => true, -// TransactionRollbackTestInfo::Processed(_, x, _) => *x, -// } -// } - -// fn expected_status(&self) -> TxExecutionStatus { -// match self { -// TransactionRollbackTestInfo::Rejected(_, _) => { -// panic!("There is no execution status for rejected transaction") -// } -// TransactionRollbackTestInfo::Processed(_, _, status) => *status, -// } -// } -// } - -// // Accepts the address of the sender as well as the list of pairs of its transactions -// // and whether these transactions should succeed. -// fn execute_vm_with_possible_rollbacks( -// sender_address: Address, -// transactions: Vec, -// block_context: DerivedBlockContext, -// block_properties: BlockProperties, -// ) -> VmExecutionResult { -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); -// let storage_ptr: &mut dyn Storage = &mut StorageView::new(&raw_storage); - -// // Setting infinite balance for the sender. -// let key = storage_key_for_eth_balance(&sender_address); -// storage_ptr.set_value(&key, u256_to_h256(U256([0, 0, 1, 0]))); - -// let mut oracle_tools = OracleTools::new(storage_ptr, HistoryEnabled); - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context, Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); - -// for test_info in transactions { -// vm.save_current_vm_as_snapshot(); -// let vm_state_before_tx = vm.dump_inner_state(); -// push_transaction_to_bootloader_memory( -// &mut vm, -// test_info.get_transaction(), -// TxExecutionMode::VerifyExecute, -// None, -// ); - -// match vm.execute_next_tx(u32::MAX, false) { -// Err(reason) => { -// assert_eq!(test_info.rejection_reason(), Some(reason)); -// } -// Ok(res) => { -// assert_eq!(test_info.rejection_reason(), None); -// assert_eq!( -// res.status, -// test_info.expected_status(), -// "Transaction status is not correct" -// ); -// } -// }; - -// if test_info.should_rollback() { -// // Some error has occurred, we should reject the transaction -// vm.rollback_to_latest_snapshot(); - -// // vm_state_before_tx. -// let state_after_rollback = vm.dump_inner_state(); -// assert_eq!( -// vm_state_before_tx, state_after_rollback, -// "Did not rollback VM state correctly" -// ); -// } -// } - -// let VmBlockResult { -// full_result: mut result, -// .. -// } = vm.execute_till_block_end(BootloaderJobType::BlockPostprocessing); -// // Used contract hashes are retrieved in unordered manner. -// // However it must be sorted for the comparisons in tests to work -// result.used_contract_hashes.sort(); - -// result -// } - -// // Sets the signature for an L2 transaction and returns the same transaction -// // but this different signature. -// fn change_signature(mut tx: Transaction, signature: Vec) -> Transaction { -// tx.common_data = match tx.common_data { -// ExecuteTransactionCommon::L2(mut data) => { -// data.signature = signature; -// ExecuteTransactionCommon::L2(data) -// } -// _ => unreachable!(), -// }; - -// tx -// } - -// #[test] -// fn test_vm_rollbacks() { -// let (block_context, block_properties): (DerivedBlockContext, BlockProperties) = { -// let (block_context, block_properties) = create_test_block_params(); -// (block_context.into(), block_properties) -// }; - -// let base_fee = U256::from(block_context.base_fee); - -// let sender_private_key = H256::random(); -// let contract_code = read_test_contract(); - -// let tx_nonce_0: Transaction = get_deploy_tx( -// sender_private_key, -// Nonce(0), -// &contract_code, -// vec![], -// &[], -// Fee { -// gas_limit: U256::from(12000000u32), -// max_fee_per_gas: base_fee, -// max_priority_fee_per_gas: U256::zero(), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); -// let tx_nonce_1: Transaction = get_deploy_tx( -// sender_private_key, -// Nonce(1), -// &contract_code, -// vec![], -// &[], -// Fee { -// gas_limit: U256::from(12000000u32), -// max_fee_per_gas: base_fee, -// max_priority_fee_per_gas: U256::zero(), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); -// let tx_nonce_2: Transaction = get_deploy_tx( -// sender_private_key, -// Nonce(2), -// &contract_code, -// vec![], -// &[], -// Fee { -// gas_limit: U256::from(12000000u32), -// max_fee_per_gas: base_fee, -// max_priority_fee_per_gas: U256::zero(), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); - -// let wrong_signature_length_tx = change_signature(tx_nonce_0.clone(), vec![1u8; 32]); -// let wrong_v_tx = change_signature(tx_nonce_0.clone(), vec![1u8; 65]); -// let wrong_signature_tx = change_signature(tx_nonce_0.clone(), vec![27u8; 65]); - -// let sender_address = tx_nonce_0.initiator_account(); - -// let result_without_rollbacks = execute_vm_with_possible_rollbacks( -// sender_address, -// vec![ -// // The nonces are ordered correctly, all the transactions should succeed. -// TransactionRollbackTestInfo::new_processed( -// tx_nonce_0.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// TransactionRollbackTestInfo::new_processed( -// tx_nonce_1.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// TransactionRollbackTestInfo::new_processed( -// tx_nonce_2.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// ], -// block_context, -// block_properties, -// ); - -// let incorrect_nonce = TxRevertReason::ValidationFailed(VmRevertReason::General { -// msg: "Incorrect nonce".to_string(), -// data: vec![ -// 8, 195, 121, 160, 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, 32, 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, 15, 73, 110, 99, 111, 114, 114, 101, 99, 116, 32, 110, -// 111, 110, 99, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -// ], -// }); -// let reusing_nonce_twice = TxRevertReason::ValidationFailed(VmRevertReason::General { -// msg: "Reusing the same nonce twice".to_string(), -// data: vec![ -// 8, 195, 121, 160, 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, 32, 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, 28, 82, 101, 117, 115, 105, 110, 103, 32, 116, 104, -// 101, 32, 115, 97, 109, 101, 32, 110, 111, 110, 99, 101, 32, 116, 119, 105, 99, 101, 0, -// 0, 0, 0, -// ], -// }); -// let signature_length_is_incorrect = TxRevertReason::ValidationFailed(VmRevertReason::General { -// msg: "Signature length is incorrect".to_string(), -// data: vec![ -// 8, 195, 121, 160, 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, 32, 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, 29, 83, 105, 103, 110, 97, 116, 117, 114, 101, 32, -// 108, 101, 110, 103, 116, 104, 32, 105, 115, 32, 105, 110, 99, 111, 114, 114, 101, 99, -// 116, 0, 0, 0, -// ], -// }); -// let v_is_incorrect = TxRevertReason::ValidationFailed(VmRevertReason::General { -// msg: "v is neither 27 nor 28".to_string(), -// data: vec![ -// 8, 195, 121, 160, 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, 32, 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, 22, 118, 32, 105, 115, 32, 110, 101, 105, 116, 104, -// 101, 114, 32, 50, 55, 32, 110, 111, 114, 32, 50, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -// ], -// }); -// let signature_is_incorrect = TxRevertReason::ValidationFailed(VmRevertReason::General { -// msg: "Account validation returned invalid magic value. Most often this means that the signature is incorrect".to_string(), -// data: vec![], -// }); - -// let result_with_rollbacks = execute_vm_with_possible_rollbacks( -// sender_address, -// vec![ -// TransactionRollbackTestInfo::new_rejected( -// wrong_signature_length_tx, -// signature_length_is_incorrect, -// ), -// TransactionRollbackTestInfo::new_rejected(wrong_v_tx, v_is_incorrect), -// TransactionRollbackTestInfo::new_rejected(wrong_signature_tx, signature_is_incorrect), -// // The correct nonce is 0, this tx will fail -// TransactionRollbackTestInfo::new_rejected(tx_nonce_2.clone(), incorrect_nonce.clone()), -// // This tx will succeed -// TransactionRollbackTestInfo::new_processed( -// tx_nonce_0.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// // The correct nonce is 1, this tx will fail -// TransactionRollbackTestInfo::new_rejected( -// tx_nonce_0.clone(), -// reusing_nonce_twice.clone(), -// ), -// // The correct nonce is 1, this tx will fail -// TransactionRollbackTestInfo::new_rejected(tx_nonce_2.clone(), incorrect_nonce), -// // This tx will succeed -// TransactionRollbackTestInfo::new_processed( -// tx_nonce_1, -// false, -// TxExecutionStatus::Success, -// ), -// // The correct nonce is 2, this tx will fail -// TransactionRollbackTestInfo::new_rejected(tx_nonce_0, reusing_nonce_twice.clone()), -// // This tx will succeed -// TransactionRollbackTestInfo::new_processed( -// tx_nonce_2.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// // This tx will fail -// TransactionRollbackTestInfo::new_rejected(tx_nonce_2, reusing_nonce_twice.clone()), -// ], -// block_context, -// block_properties, -// ); - -// assert_eq!(result_without_rollbacks, result_with_rollbacks); - -// let loadnext_contract = get_loadnext_contract(); - -// let loadnext_constructor_data = encode(&[Token::Uint(U256::from(100))]); -// let loadnext_deploy_tx: Transaction = get_deploy_tx( -// sender_private_key, -// Nonce(0), -// &loadnext_contract.bytecode, -// loadnext_contract.factory_deps, -// &loadnext_constructor_data, -// Fee { -// gas_limit: U256::from(70000000u32), -// max_fee_per_gas: base_fee, -// max_priority_fee_per_gas: U256::zero(), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); -// let loadnext_contract_address = -// get_create_zksync_address(loadnext_deploy_tx.initiator_account(), Nonce(0)); -// let deploy_loadnext_tx_info = TransactionRollbackTestInfo::new_processed( -// loadnext_deploy_tx, -// false, -// TxExecutionStatus::Success, -// ); - -// let get_load_next_tx = |params: LoadnextContractExecutionParams, nonce: Nonce| { -// // Here we test loadnext with various kinds of operations -// let tx: Transaction = mock_loadnext_test_call( -// sender_private_key, -// nonce, -// loadnext_contract_address, -// Fee { -// gas_limit: U256::from(100000000u32), -// max_fee_per_gas: base_fee, -// max_priority_fee_per_gas: U256::zero(), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// params, -// ) -// .into(); - -// tx -// }; - -// let loadnext_tx_0 = get_load_next_tx( -// LoadnextContractExecutionParams { -// reads: 100, -// writes: 100, -// events: 100, -// hashes: 500, -// recursive_calls: 10, -// deploys: 60, -// }, -// Nonce(1), -// ); -// let loadnext_tx_1 = get_load_next_tx( -// LoadnextContractExecutionParams { -// reads: 100, -// writes: 100, -// events: 100, -// hashes: 500, -// recursive_calls: 10, -// deploys: 60, -// }, -// Nonce(2), -// ); - -// let result_without_rollbacks = execute_vm_with_possible_rollbacks( -// sender_address, -// vec![ -// deploy_loadnext_tx_info.clone(), -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_0.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_1.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// ], -// block_context, -// block_properties, -// ); - -// let result_with_rollbacks = execute_vm_with_possible_rollbacks( -// sender_address, -// vec![ -// deploy_loadnext_tx_info, -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_0.clone(), -// true, -// TxExecutionStatus::Success, -// ), -// // After the previous tx has been rolled back, this one should succeed -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_0.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// // The nonce has been bumped up, this transaction should now fail -// TransactionRollbackTestInfo::new_rejected(loadnext_tx_0, reusing_nonce_twice.clone()), -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_1.clone(), -// true, -// TxExecutionStatus::Success, -// ), -// // After the previous tx has been rolled back, this one should succeed -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_1.clone(), -// true, -// TxExecutionStatus::Success, -// ), -// // After the previous tx has been rolled back, this one should succeed -// TransactionRollbackTestInfo::new_processed( -// loadnext_tx_1.clone(), -// false, -// TxExecutionStatus::Success, -// ), -// // The nonce has been bumped up, this transaction should now fail -// TransactionRollbackTestInfo::new_rejected(loadnext_tx_1, reusing_nonce_twice), -// ], -// block_context, -// block_properties, -// ); - -// assert_eq!(result_without_rollbacks, result_with_rollbacks); -// } - -// // Inserts the contracts into the test environment, bypassing the -// // deployer system contract. Besides the reference to storage -// // it accepts a `contracts` tuple of information about the contract -// // and whether or not it is an account. -// fn insert_contracts( -// raw_storage: &mut SecondaryStateStorage, -// contracts: Vec<(DeployedContract, bool)>, -// ) { -// let logs: Vec = contracts -// .iter() -// .flat_map(|(contract, is_account)| { -// let mut new_logs = vec![]; - -// let deployer_code_key = get_code_key(contract.account_id.address()); -// new_logs.push(StorageLog::new_write_log( -// deployer_code_key, -// hash_bytecode(&contract.bytecode), -// )); - -// if *is_account { -// let is_account_key = get_is_account_key(contract.account_id.address()); -// new_logs.push(StorageLog::new_write_log( -// is_account_key, -// u256_to_h256(1u32.into()), -// )); -// } - -// new_logs -// }) -// .collect(); -// raw_storage.process_transaction_logs(&logs); - -// for (contract, _) in contracts { -// raw_storage.store_factory_dep(hash_bytecode(&contract.bytecode), contract.bytecode); -// } -// raw_storage.save(L1BatchNumber(0)); -// } - -// enum NonceHolderTestMode { -// SetValueUnderNonce, -// IncreaseMinNonceBy5, -// IncreaseMinNonceTooMuch, -// LeaveNonceUnused, -// IncreaseMinNonceBy1, -// SwitchToArbitraryOrdering, -// } - -// impl From for u8 { -// fn from(mode: NonceHolderTestMode) -> u8 { -// match mode { -// NonceHolderTestMode::SetValueUnderNonce => 0, -// NonceHolderTestMode::IncreaseMinNonceBy5 => 1, -// NonceHolderTestMode::IncreaseMinNonceTooMuch => 2, -// NonceHolderTestMode::LeaveNonceUnused => 3, -// NonceHolderTestMode::IncreaseMinNonceBy1 => 4, -// NonceHolderTestMode::SwitchToArbitraryOrdering => 5, -// } -// } -// } - -// fn get_nonce_holder_test_tx( -// nonce: U256, -// account_address: Address, -// test_mode: NonceHolderTestMode, -// block_context: &DerivedBlockContext, -// ) -> TransactionData { -// TransactionData { -// tx_type: 113, -// from: account_address, -// to: account_address, -// gas_limit: U256::from(10000000u32), -// pubdata_price_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// max_fee_per_gas: U256::from(block_context.base_fee), -// max_priority_fee_per_gas: U256::zero(), -// nonce, -// // The reserved fields that are unique for different types of transactions. -// // E.g. nonce is currently used in all transaction, but it should not be mandatory -// // in the long run. -// reserved: [U256::zero(); 4], -// data: vec![12], -// signature: vec![test_mode.into()], - -// ..Default::default() -// } -// } - -// fn run_vm_with_raw_tx<'a, H: HistoryMode>( -// oracle_tools: &'a mut OracleTools<'a, false, H>, -// block_context: DerivedBlockContext, -// block_properties: &'a BlockProperties, -// tx: TransactionData, -// ) -> (VmExecutionResult, bool) { -// let mut base_system_contracts = BASE_SYSTEM_CONTRACTS.clone(); -// base_system_contracts.bootloader = PLAYGROUND_BLOCK_BOOTLOADER_CODE.clone(); -// let mut vm = init_vm_inner( -// oracle_tools, -// BlockContextMode::OverrideCurrent(block_context), -// block_properties, -// BLOCK_GAS_LIMIT, -// &base_system_contracts, -// TxExecutionMode::VerifyExecute, -// ); - -// let block_gas_price_per_pubdata = block_context.context.block_gas_price_per_pubdata(); - -// let overhead = tx.overhead_gas(block_gas_price_per_pubdata as u32); -// push_raw_transaction_to_bootloader_memory( -// &mut vm, -// tx, -// TxExecutionMode::VerifyExecute, -// overhead, -// None, -// ); -// let VmBlockResult { -// full_result: result, -// .. -// } = vm.execute_till_block_end(BootloaderJobType::TransactionExecution); - -// (result, tx_has_failed(&vm.state, 0)) -// } - -// #[test] -// fn test_nonce_holder() { -// let (block_context, block_properties): (DerivedBlockContext, BlockProperties) = { -// let (block_context, block_properties) = create_test_block_params(); -// (block_context.into(), block_properties) -// }; - -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); - -// let account_address = H160::random(); -// let account = DeployedContract { -// account_id: AccountTreeId::new(account_address), -// bytecode: read_nonce_holder_tester(), -// }; - -// insert_contracts(&mut raw_storage, vec![(account, true)]); - -// let storage_ptr: &mut dyn Storage = &mut StorageView::new(&raw_storage); - -// // We deploy here counter contract, because its logic is trivial - -// let key = storage_key_for_eth_balance(&account_address); -// storage_ptr.set_value(&key, u256_to_h256(U256([0, 0, 1, 0]))); - -// let mut run_nonce_test = |nonce: U256, -// test_mode: NonceHolderTestMode, -// error_message: Option, -// comment: &'static str| { -// let tx = get_nonce_holder_test_tx(nonce, account_address, test_mode, &block_context); - -// let mut oracle_tools = OracleTools::new(storage_ptr, HistoryEnabled); -// let (result, tx_has_failed) = -// run_vm_with_raw_tx(&mut oracle_tools, block_context, &block_properties, tx); -// if let Some(msg) = error_message { -// let expected_error = -// TxRevertReason::ValidationFailed(VmRevertReason::General { msg, data: vec![] }); -// assert_eq!( -// result -// .revert_reason -// .expect("No revert reason") -// .revert_reason -// .to_string(), -// expected_error.to_string(), -// "{}", -// comment -// ); -// } else { -// assert!(!tx_has_failed, "{}", comment); -// } -// }; - -// // Test 1: trying to set value under non sequential nonce value. -// run_nonce_test( -// 1u32.into(), -// NonceHolderTestMode::SetValueUnderNonce, -// Some("Previous nonce has not been used".to_string()), -// "Allowed to set value under non sequential value", -// ); - -// // Test 2: increase min nonce by 1 with sequential nonce ordering: -// run_nonce_test( -// 0u32.into(), -// NonceHolderTestMode::IncreaseMinNonceBy1, -// None, -// "Failed to increment nonce by 1 for sequential account", -// ); - -// // Test 3: correctly set value under nonce with sequential nonce ordering: -// run_nonce_test( -// 1u32.into(), -// NonceHolderTestMode::SetValueUnderNonce, -// None, -// "Failed to set value under nonce sequential value", -// ); - -// // Test 5: migrate to the arbitrary nonce ordering: -// run_nonce_test( -// 2u32.into(), -// NonceHolderTestMode::SwitchToArbitraryOrdering, -// None, -// "Failed to switch to arbitrary ordering", -// ); - -// // Test 6: increase min nonce by 5 -// run_nonce_test( -// 6u32.into(), -// NonceHolderTestMode::IncreaseMinNonceBy5, -// None, -// "Failed to increase min nonce by 5", -// ); - -// // Test 7: since the nonces in range [6,10] are no longer allowed, the -// // tx with nonce 10 should not be allowed -// run_nonce_test( -// 10u32.into(), -// NonceHolderTestMode::IncreaseMinNonceBy5, -// Some("Reusing the same nonce twice".to_string()), -// "Allowed to reuse nonce below the minimal one", -// ); - -// // Test 8: we should be able to use nonce 13 -// run_nonce_test( -// 13u32.into(), -// NonceHolderTestMode::SetValueUnderNonce, -// None, -// "Did not allow to use unused nonce 10", -// ); - -// // Test 9: we should not be able to reuse nonce 13 -// run_nonce_test( -// 13u32.into(), -// NonceHolderTestMode::IncreaseMinNonceBy5, -// Some("Reusing the same nonce twice".to_string()), -// "Allowed to reuse the same nonce twice", -// ); - -// // Test 10: we should be able to simply use nonce 14, while bumping the minimal nonce by 5 -// run_nonce_test( -// 14u32.into(), -// NonceHolderTestMode::IncreaseMinNonceBy5, -// None, -// "Did not allow to use a bumped nonce", -// ); - -// // Test 6: Do not allow bumping nonce by too much -// run_nonce_test( -// 16u32.into(), -// NonceHolderTestMode::IncreaseMinNonceTooMuch, -// Some("The value for incrementing the nonce is too high".to_string()), -// "Allowed for incrementing min nonce too much", -// ); - -// // Test 7: Do not allow not setting a nonce as used -// run_nonce_test( -// 16u32.into(), -// NonceHolderTestMode::LeaveNonceUnused, -// Some("The nonce was not set as used".to_string()), -// "Allowed to leave nonce as unused", -// ); -// } - -// #[test] -// fn test_l1_tx_execution() { -// // In this test, we try to execute a contract deployment from L1 -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); -// let mut storage_accessor = StorageView::new(&raw_storage); -// let storage_ptr: &mut dyn Storage = &mut storage_accessor; - -// let mut oracle_tools = OracleTools::new(storage_ptr, HistoryEnabled); -// let (block_context, block_properties) = create_test_block_params(); - -// // Here instead of marking code hash via the bootloader means, we will -// // using L1->L2 communication, the same it would likely be done during the priority mode. -// let contract_code = read_test_contract(); -// let contract_code_hash = hash_bytecode(&contract_code); -// let l1_deploy_tx = get_l1_deploy_tx(&contract_code, &[]); -// let l1_deploy_tx_data: TransactionData = l1_deploy_tx.clone().into(); - -// let required_l2_to_l1_logs = vec![ -// L2ToL1Log { -// shard_id: 0, -// is_service: false, -// tx_number_in_block: 0, -// sender: SYSTEM_CONTEXT_ADDRESS, -// key: u256_to_h256(U256::from(block_context.block_timestamp)), -// value: Default::default(), -// }, -// L2ToL1Log { -// shard_id: 0, -// is_service: true, -// tx_number_in_block: 0, -// sender: BOOTLOADER_ADDRESS, -// key: l1_deploy_tx_data.canonical_l1_tx_hash(), -// value: u256_to_h256(U256::from(1u32)), -// }, -// ]; - -// let sender_address = l1_deploy_tx_data.from(); - -// oracle_tools.decommittment_processor.populate( -// vec![( -// h256_to_u256(contract_code_hash), -// bytes_to_be_words(contract_code), -// )], -// Timestamp(0), -// ); - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context.into(), Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); -// push_transaction_to_bootloader_memory( -// &mut vm, -// &l1_deploy_tx, -// TxExecutionMode::VerifyExecute, -// None, -// ); - -// let res = vm.execute_next_tx(u32::MAX, false).unwrap(); - -// // The code hash of the deployed contract should be marked as republished. -// let known_codes_key = get_known_code_key(&contract_code_hash); - -// // The contract should be deployed successfully. -// let deployed_address = deployed_address_create(sender_address, U256::zero()); -// let account_code_key = get_code_key(&deployed_address); - -// let expected_slots = vec![ -// (u256_to_h256(U256::from(1u32)), known_codes_key), -// (contract_code_hash, account_code_key), -// ]; -// assert!(!tx_has_failed(&vm.state, 0)); - -// verify_required_storage(&vm.state, expected_slots); - -// assert_eq!(res.result.logs.l2_to_l1_logs, required_l2_to_l1_logs); - -// let tx = get_l1_execute_test_contract_tx(deployed_address, true); -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); - -// let res = StorageWritesDeduplicator::apply_on_empty_state( -// &vm.execute_next_tx(u32::MAX, false) -// .unwrap() -// .result -// .logs -// .storage_logs, -// ); -// assert_eq!(res.initial_storage_writes, 0); - -// let tx = get_l1_execute_test_contract_tx(deployed_address, false); -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); -// let res = StorageWritesDeduplicator::apply_on_empty_state( -// &vm.execute_next_tx(u32::MAX, false) -// .unwrap() -// .result -// .logs -// .storage_logs, -// ); -// assert_eq!(res.initial_storage_writes, 2); - -// let repeated_writes = res.repeated_storage_writes; - -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); -// let res = StorageWritesDeduplicator::apply_on_empty_state( -// &vm.execute_next_tx(u32::MAX, false) -// .unwrap() -// .result -// .logs -// .storage_logs, -// ); -// assert_eq!(res.initial_storage_writes, 1); -// // We do the same storage write, so it will be deduplicated -// assert_eq!(res.repeated_storage_writes, repeated_writes); - -// let mut tx = get_l1_execute_test_contract_tx(deployed_address, false); -// tx.execute.value = U256::from(1); -// match &mut tx.common_data { -// ExecuteTransactionCommon::L1(l1_data) => { -// l1_data.to_mint = U256::from(4); -// } -// _ => unreachable!(), -// } -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); -// let execution_result = vm.execute_next_tx(u32::MAX, false).unwrap(); -// // The method is not payable, so the transaction with non-zero value should fail -// assert_eq!( -// execution_result.status, -// TxExecutionStatus::Failure, -// "The transaction should fail" -// ); - -// let res = -// StorageWritesDeduplicator::apply_on_empty_state(&execution_result.result.logs.storage_logs); - -// // There are 2 initial writes here: -// // - totalSupply of ETH token -// // - balance of the refund recipient -// assert_eq!(res.initial_storage_writes, 2); -// } - -// #[test] -// fn test_invalid_bytecode() { -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); -// let (block_context, block_properties) = create_test_block_params(); -// let block_gas_per_pubdata = block_context.block_gas_price_per_pubdata(); - -// let test_vm_with_custom_bytecode_hash = -// |bytecode_hash: H256, expected_revert_reason: Option| { -// let mut storage_accessor = StorageView::new(&raw_storage); -// let storage_ptr: &mut dyn Storage = &mut storage_accessor; -// let mut oracle_tools = OracleTools::new(storage_ptr, HistoryEnabled); - -// let (encoded_tx, predefined_overhead) = get_l1_tx_with_custom_bytecode_hash( -// h256_to_u256(bytecode_hash), -// block_gas_per_pubdata as u32, -// ); - -// run_vm_with_custom_factory_deps( -// &mut oracle_tools, -// block_context, -// &block_properties, -// encoded_tx, -// predefined_overhead, -// expected_revert_reason, -// ); -// }; - -// let failed_to_mark_factory_deps = |msg: &str, data: Vec| { -// TxRevertReason::FailedToMarkFactoryDependencies(VmRevertReason::General { -// msg: msg.to_string(), -// data, -// }) -// }; - -// // Here we provide the correctly-formatted bytecode hash of -// // odd length, so it should work. -// test_vm_with_custom_bytecode_hash( -// H256([ -// 1, 0, 0, 1, 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, -// ]), -// None, -// ); - -// // Here we provide correctly formatted bytecode of even length, so -// // it should fail. -// test_vm_with_custom_bytecode_hash( -// H256([ -// 1, 0, 2, 2, 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, -// ]), -// Some(failed_to_mark_factory_deps( -// "Code length in words must be odd", -// vec![ -// 8, 195, 121, 160, 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, 32, 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, 32, 67, 111, 100, 101, 32, 108, 101, 110, -// 103, 116, 104, 32, 105, 110, 32, 119, 111, 114, 100, 115, 32, 109, 117, 115, 116, -// 32, 98, 101, 32, 111, 100, 100, -// ], -// )), -// ); - -// // Here we provide incorrectly formatted bytecode of odd length, so -// // it should fail. -// test_vm_with_custom_bytecode_hash( -// H256([ -// 1, 1, 0, 1, 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, -// ]), -// Some(failed_to_mark_factory_deps( -// "Incorrectly formatted bytecodeHash", -// vec![ -// 8, 195, 121, 160, 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, 32, 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, 34, 73, 110, 99, 111, 114, 114, 101, 99, -// 116, 108, 121, 32, 102, 111, 114, 109, 97, 116, 116, 101, 100, 32, 98, 121, 116, -// 101, 99, 111, 100, 101, 72, 97, 115, 104, 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, -// ], -// )), -// ); - -// // Here we provide incorrectly formatted bytecode of odd length, so -// // it should fail. -// test_vm_with_custom_bytecode_hash( -// H256([ -// 2, 0, 0, 1, 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, -// ]), -// Some(failed_to_mark_factory_deps( -// "Incorrectly formatted bytecodeHash", -// vec![ -// 8, 195, 121, 160, 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, 32, 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, 34, 73, 110, 99, 111, 114, 114, 101, 99, -// 116, 108, 121, 32, 102, 111, 114, 109, 97, 116, 116, 101, 100, 32, 98, 121, 116, -// 101, 99, 111, 100, 101, 72, 97, 115, 104, 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, -// ], -// )), -// ); -// } - -// #[test] -// fn test_tracing_of_execution_errors() { -// // In this test, we are checking that the execution errors are transmitted correctly from the bootloader. -// let (block_context, block_properties) = create_test_block_params(); -// let block_context: DerivedBlockContext = block_context.into(); - -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); -// let private_key = H256::random(); - -// let contract_address = Address::random(); -// let error_contract = DeployedContract { -// account_id: AccountTreeId::new(contract_address), -// bytecode: read_error_contract(), -// }; - -// let tx = get_error_tx( -// private_key, -// Nonce(0), -// contract_address, -// Fee { -// gas_limit: U256::from(1000000u32), -// max_fee_per_gas: U256::from(10000000000u64), -// max_priority_fee_per_gas: U256::zero(), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ); - -// insert_contracts(&mut raw_storage, vec![(error_contract, false)]); - -// let storage_ptr: &mut dyn Storage = &mut StorageView::new(&raw_storage); - -// let key = storage_key_for_eth_balance(&tx.common_data.initiator_address); -// storage_ptr.set_value(&key, u256_to_h256(U256([0, 0, 1, 0]))); - -// let mut oracle_tools = OracleTools::new(storage_ptr, HistoryEnabled); - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context, Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); -// push_transaction_to_bootloader_memory( -// &mut vm, -// &tx.into(), -// TxExecutionMode::VerifyExecute, -// None, -// ); - -// let mut tracer = TransactionResultTracer::new(usize::MAX, false); -// assert_eq!( -// vm.execute_with_custom_tracer(&mut tracer), -// VmExecutionStopReason::VmFinished, -// "Tracer should never request stop" -// ); - -// match tracer.revert_reason { -// Some(revert_reason) => { -// let revert_reason = VmRevertReason::try_from(&revert_reason as &[u8]).unwrap(); -// assert_eq!( -// revert_reason, -// VmRevertReason::General { -// msg: "short".to_string(), -// data: vec![ -// 8, 195, 121, 160, 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, 32, 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, 5, 115, 104, 111, -// 114, 116, 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 -// ], -// } -// ) -// } -// _ => panic!( -// "Tracer captured incorrect result {:#?}", -// tracer.revert_reason -// ), -// } -// let mut oracle_tools = OracleTools::new(storage_ptr, HistoryEnabled); - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context, Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); -// let tx = get_error_tx( -// private_key, -// Nonce(1), -// contract_address, -// Fee { -// gas_limit: U256::from(1000000u32), -// max_fee_per_gas: U256::from(10000000000u64), -// max_priority_fee_per_gas: U256::zero(), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ); -// push_transaction_to_bootloader_memory( -// &mut vm, -// &tx.into(), -// TxExecutionMode::VerifyExecute, -// None, -// ); - -// let mut tracer = TransactionResultTracer::new(10, false); -// assert_eq!( -// vm.execute_with_custom_tracer(&mut tracer), -// VmExecutionStopReason::TracerRequestedStop, -// ); -// assert!(tracer.is_limit_reached()); -// } - -// /// Checks that `TX_GAS_LIMIT_OFFSET` constant is correct. -// #[test] -// fn test_tx_gas_limit_offset() { -// let gas_limit = U256::from(999999); - -// let (block_context, block_properties) = create_test_block_params(); -// let block_context: DerivedBlockContext = block_context.into(); - -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let raw_storage = SecondaryStateStorage::new(db); -// let storage_ptr: &mut dyn Storage = &mut StorageView::new(&raw_storage); - -// let contract_code = read_test_contract(); -// let tx: Transaction = get_deploy_tx( -// H256::random(), -// Nonce(0), -// &contract_code, -// Default::default(), -// Default::default(), -// Fee { -// gas_limit, -// ..Default::default() -// }, -// ) -// .into(); - -// let mut oracle_tools = OracleTools::new(storage_ptr, HistoryEnabled); - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context, Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); - -// let gas_limit_from_memory = vm -// .state -// .memory -// .read_slot( -// BOOTLOADER_HEAP_PAGE as usize, -// TX_DESCRIPTION_OFFSET + TX_GAS_LIMIT_OFFSET, -// ) -// .value; -// assert_eq!(gas_limit_from_memory, gas_limit); -// } - -// #[test] -// fn test_is_write_initial_behaviour() { -// // In this test, we check result of `is_write_initial` at different stages. - -// let (block_context, block_properties) = create_test_block_params(); -// let block_context: DerivedBlockContext = block_context.into(); - -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); -// let storage_ptr: &mut dyn Storage = &mut StorageView::new(&raw_storage); - -// let base_fee = block_context.base_fee; -// let account_pk = H256::random(); -// let contract_code = read_test_contract(); -// let tx: Transaction = get_deploy_tx( -// account_pk, -// Nonce(0), -// &contract_code, -// vec![], -// &[], -// Fee { -// gas_limit: U256::from(20000000u32), -// max_fee_per_gas: U256::from(base_fee), -// max_priority_fee_per_gas: U256::from(0), -// gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), -// }, -// ) -// .into(); - -// let sender_address = tx.initiator_account(); -// let nonce_key = get_nonce_key(&sender_address); - -// // Check that the next write to the nonce key will be initial. -// assert!(storage_ptr.is_write_initial(&nonce_key)); - -// // Set balance to be able to pay fee for txs. -// let balance_key = storage_key_for_eth_balance(&sender_address); -// storage_ptr.set_value(&balance_key, u256_to_h256(U256([0, 0, 1, 0]))); - -// let mut oracle_tools = OracleTools::new(storage_ptr, HistoryEnabled); - -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context, Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); - -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); - -// vm.execute_next_tx(u32::MAX, false) -// .expect("Bootloader failed while processing the first transaction"); -// // Check that `is_write_initial` still returns true for the nonce key. -// assert!(storage_ptr.is_write_initial(&nonce_key)); -// } - -// pub fn get_l1_tx_with_custom_bytecode_hash( -// bytecode_hash: U256, -// block_gas_per_pubdata: u32, -// ) -> (Vec, u32) { -// let tx: TransactionData = get_l1_execute_test_contract_tx(Default::default(), false).into(); -// let predefined_overhead = -// tx.overhead_gas_with_custom_factory_deps(vec![bytecode_hash], block_gas_per_pubdata); -// let tx_bytes = tx.abi_encode_with_custom_factory_deps(vec![bytecode_hash]); - -// (bytes_to_be_words(tx_bytes), predefined_overhead) -// } - -// const L1_TEST_GAS_PER_PUBDATA_BYTE: u32 = 800; - -// pub fn get_l1_execute_test_contract_tx(deployed_address: Address, with_panic: bool) -> Transaction { -// let sender = H160::random(); -// get_l1_execute_test_contract_tx_with_sender( -// sender, -// deployed_address, -// with_panic, -// U256::zero(), -// false, -// ) -// } - -// pub fn get_l1_tx_with_large_output(sender: Address, deployed_address: Address) -> Transaction { -// let test_contract = load_contract( -// "etc/contracts-test-data/artifacts-zk/contracts/long-return-data/long-return-data.sol/LongReturnData.json", -// ); - -// let function = test_contract.function("longReturnData").unwrap(); - -// let calldata = function -// .encode_input(&[]) -// .expect("failed to encode parameters"); - -// Transaction { -// common_data: ExecuteTransactionCommon::L1(L1TxCommonData { -// sender, -// gas_limit: U256::from(100000000u32), -// gas_per_pubdata_limit: L1_TEST_GAS_PER_PUBDATA_BYTE.into(), -// ..Default::default() -// }), -// execute: Execute { -// contract_address: deployed_address, -// calldata, -// value: U256::zero(), -// factory_deps: None, -// }, -// received_timestamp_ms: 0, -// } -// } - -// pub fn get_l1_execute_test_contract_tx_with_sender( -// sender: Address, -// deployed_address: Address, -// with_panic: bool, -// value: U256, -// payable: bool, -// ) -> Transaction { -// let execute = execute_test_contract(deployed_address, with_panic, value, payable); - -// Transaction { -// common_data: ExecuteTransactionCommon::L1(L1TxCommonData { -// sender, -// gas_limit: U256::from(200_000_000u32), -// gas_per_pubdata_limit: L1_TEST_GAS_PER_PUBDATA_BYTE.into(), -// to_mint: value, -// ..Default::default() -// }), -// execute, -// received_timestamp_ms: 0, -// } -// } - -// pub fn get_l1_deploy_tx(code: &[u8], calldata: &[u8]) -> Transaction { -// let execute = get_create_execute(code, calldata); - -// Transaction { -// common_data: ExecuteTransactionCommon::L1(L1TxCommonData { -// sender: H160::random(), -// gas_limit: U256::from(2000000u32), -// gas_per_pubdata_limit: L1_TEST_GAS_PER_PUBDATA_BYTE.into(), -// ..Default::default() -// }), -// execute, -// received_timestamp_ms: 0, -// } -// } - -// fn read_test_contract() -> Vec { -// read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/counter/counter.sol/Counter.json") -// } - -// fn read_long_return_data_contract() -> Vec { -// read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/long-return-data/long-return-data.sol/LongReturnData.json") -// } - -// fn read_nonce_holder_tester() -> Vec { -// read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/custom-account/nonce-holder-test.sol/NonceHolderTest.json") -// } - -// fn read_error_contract() -> Vec { -// read_bytecode( -// "etc/contracts-test-data/artifacts-zk/contracts/error/error.sol/SimpleRequire.json", -// ) -// } - -// fn execute_test_contract( -// address: Address, -// with_panic: bool, -// value: U256, -// payable: bool, -// ) -> Execute { -// let test_contract = load_contract( -// "etc/contracts-test-data/artifacts-zk/contracts/counter/counter.sol/Counter.json", -// ); - -// let function = if payable { -// test_contract -// .function("incrementWithRevertPayable") -// .unwrap() -// } else { -// test_contract.function("incrementWithRevert").unwrap() -// }; - -// let calldata = function -// .encode_input(&[Token::Uint(U256::from(1u8)), Token::Bool(with_panic)]) -// .expect("failed to encode parameters"); - -// Execute { -// contract_address: address, -// calldata, -// value, -// factory_deps: None, -// } -// } - -// #[test] -// fn test_call_tracer() { -// let sender = H160::random(); -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); - -// let (block_context, block_properties) = create_test_block_params(); - -// let contract_code = read_test_contract(); -// let contract_code_hash = hash_bytecode(&contract_code); -// let l1_deploy_tx = get_l1_deploy_tx(&contract_code, &[]); -// let l1_deploy_tx_data: TransactionData = l1_deploy_tx.clone().into(); - -// let sender_address_counter = l1_deploy_tx_data.from(); -// let mut storage_accessor = StorageView::new(&raw_storage); -// let storage_ptr: &mut dyn Storage = &mut storage_accessor; - -// let key = storage_key_for_eth_balance(&sender_address_counter); -// storage_ptr.set_value(&key, u256_to_h256(U256([0, 0, 1, 0]))); - -// let mut oracle_tools = OracleTools::new(storage_ptr, HistoryEnabled); -// oracle_tools.decommittment_processor.populate( -// vec![( -// h256_to_u256(contract_code_hash), -// bytes_to_be_words(contract_code), -// )], -// Timestamp(0), -// ); - -// let contract_code = read_long_return_data_contract(); -// let contract_code_hash = hash_bytecode(&contract_code); -// let l1_deploy_long_return_data_tx = get_l1_deploy_tx(&contract_code, &[]); -// oracle_tools.decommittment_processor.populate( -// vec![( -// h256_to_u256(contract_code_hash), -// bytes_to_be_words(contract_code), -// )], -// Timestamp(0), -// ); - -// let tx_data: TransactionData = l1_deploy_long_return_data_tx.clone().into(); -// let sender_long_return_address = tx_data.from(); -// // The contract should be deployed successfully. -// let deployed_address_long_return_data = -// deployed_address_create(sender_long_return_address, U256::zero()); -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context.into(), Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); - -// push_transaction_to_bootloader_memory( -// &mut vm, -// &l1_deploy_tx, -// TxExecutionMode::VerifyExecute, -// None, -// ); - -// // The contract should be deployed successfully. -// let deployed_address = deployed_address_create(sender_address_counter, U256::zero()); -// let res = vm.execute_next_tx(u32::MAX, true).unwrap(); -// let calls = res.call_traces; -// let mut create_call = None; -// // The first MIMIC call is call to value simulator. All calls goes through it. -// // The second MIMIC call is call to Deployer contract. -// // And only third level call is construct call to the newly deployed contract And we call it create_call. -// for call in &calls { -// if let CallType::Call(FarCallOpcode::Mimic) = call.r#type { -// for call in &call.calls { -// if let CallType::Call(FarCallOpcode::Mimic) = call.r#type { -// for call in &call.calls { -// if let CallType::Create = call.r#type { -// create_call = Some(call.clone()); -// } -// } -// } -// } -// } -// } -// let expected = Call { -// r#type: CallType::Create, -// to: deployed_address, -// from: sender_address_counter, -// parent_gas: 0, -// gas_used: 0, -// gas: 0, -// value: U256::zero(), -// input: vec![], -// output: vec![ -// 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, 32, 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, -// ], -// error: None, -// revert_reason: None, -// calls: vec![], -// }; -// assert_eq!(create_call.unwrap(), expected); - -// push_transaction_to_bootloader_memory( -// &mut vm, -// &l1_deploy_long_return_data_tx, -// TxExecutionMode::VerifyExecute, -// None, -// ); - -// vm.execute_next_tx(u32::MAX, false).unwrap(); - -// let tx = get_l1_execute_test_contract_tx_with_sender( -// sender, -// deployed_address, -// false, -// U256::from(1u8), -// true, -// ); - -// let tx_data: TransactionData = tx.clone().into(); -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); - -// let res = vm.execute_next_tx(u32::MAX, true).unwrap(); -// let calls = res.call_traces; - -// // We don't want to compare gas used, because it's not fully deterministic. -// let expected = Call { -// r#type: CallType::Call(FarCallOpcode::Mimic), -// to: deployed_address, -// from: tx_data.from(), -// parent_gas: 0, -// gas_used: 0, -// gas: 0, -// value: U256::from(1), -// input: tx_data.data, -// output: vec![ -// 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, 1, -// ], -// error: None, -// revert_reason: None, -// calls: vec![], -// }; - -// // First loop filter out the bootloaders calls and -// // the second loop filters out the calls msg value simulator calls -// for call in calls { -// if let CallType::Call(FarCallOpcode::Mimic) = call.r#type { -// for call in call.calls { -// if let CallType::Call(FarCallOpcode::Mimic) = call.r#type { -// assert_eq!(expected, call); -// } -// } -// } -// } - -// let tx = get_l1_execute_test_contract_tx_with_sender( -// sender, -// deployed_address, -// true, -// U256::from(1u8), -// true, -// ); - -// let tx_data: TransactionData = tx.clone().into(); -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); - -// let res = vm.execute_next_tx(u32::MAX, true).unwrap(); -// let calls = res.call_traces; - -// let expected = Call { -// r#type: CallType::Call(FarCallOpcode::Mimic), -// to: deployed_address, -// from: tx_data.from(), -// parent_gas: 257030, -// gas_used: 348, -// gas: 253008, -// value: U256::from(1u8), -// input: tx_data.data, -// output: vec![], -// error: None, -// revert_reason: Some("This method always reverts".to_string()), -// calls: vec![], -// }; - -// for call in calls { -// if let CallType::Call(FarCallOpcode::Mimic) = call.r#type { -// for call in call.calls { -// if let CallType::Call(FarCallOpcode::Mimic) = call.r#type { -// assert_eq!(expected, call); -// } -// } -// } -// } - -// let tx = get_l1_tx_with_large_output(sender, deployed_address_long_return_data); - -// let tx_data: TransactionData = tx.clone().into(); -// push_transaction_to_bootloader_memory(&mut vm, &tx, TxExecutionMode::VerifyExecute, None); - -// assert_ne!(deployed_address_long_return_data, deployed_address); -// let res = vm.execute_next_tx(u32::MAX, true).unwrap(); -// let calls = res.call_traces; -// for call in calls { -// if let CallType::Call(FarCallOpcode::Mimic) = call.r#type { -// for call in call.calls { -// if let CallType::Call(FarCallOpcode::Mimic) = call.r#type { -// assert_eq!(call.input, tx_data.data); -// assert_eq!( -// call.revert_reason, -// Some("Unknown revert reason".to_string()) -// ); -// } -// } -// } -// } -// } - -// #[test] -// fn test_get_used_contracts() { -// // get block context -// let (block_context, block_properties) = create_test_block_params(); -// let block_context: DerivedBlockContext = block_context.into(); - -// // insert system contracts to avoid vm errors during initialization -// let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); -// let db = RocksDB::new(Database::StateKeeper, temp_dir.as_ref(), false); -// let mut raw_storage = SecondaryStateStorage::new(db); -// insert_system_contracts(&mut raw_storage); - -// // get oracle tools -// let storage_ptr: &mut dyn Storage = &mut StorageView::new(&raw_storage); -// let mut oracle_tools = OracleTools::new(storage_ptr, HistoryEnabled); - -// // init vm -// let mut vm = init_vm_inner( -// &mut oracle_tools, -// BlockContextMode::NewBlock(block_context, Default::default()), -// &block_properties, -// BLOCK_GAS_LIMIT, -// &BASE_SYSTEM_CONTRACTS, -// TxExecutionMode::VerifyExecute, -// ); - -// assert!(known_bytecodes_without_aa_code(&vm).is_empty()); - -// // create and push and execute some not-empty factory deps transaction with success status -// // to check that get_used_contracts() updates -// let contract_code = read_test_contract(); -// let contract_code_hash = hash_bytecode(&contract_code); -// let tx1 = get_l1_deploy_tx(&contract_code, &[]); - -// push_transaction_to_bootloader_memory(&mut vm, &tx1, TxExecutionMode::VerifyExecute, None); - -// let res1 = vm.execute_next_tx(u32::MAX, true).unwrap(); -// assert_eq!(res1.status, TxExecutionStatus::Success); -// assert!(vm -// .get_used_contracts() -// .contains(&h256_to_u256(contract_code_hash))); - -// assert_eq!( -// vm.get_used_contracts() -// .into_iter() -// .collect::>(), -// known_bytecodes_without_aa_code(&vm) -// .keys() -// .cloned() -// .collect::>() -// ); - -// // create push and execute some non-empty factory deps transaction that fails -// // (known_bytecodes will be updated but we expect get_used_contracts() to not be updated) - -// let mut tx2 = tx1; -// tx2.execute.contract_address = L1_MESSENGER_ADDRESS; - -// let calldata = vec![1, 2, 3]; -// let big_calldata: Vec = calldata -// .iter() -// .cycle() -// .take(calldata.len() * 1024) -// .cloned() -// .collect(); - -// tx2.execute.calldata = big_calldata; -// tx2.execute.factory_deps = Some(vec![vec![1; 32]]); - -// push_transaction_to_bootloader_memory(&mut vm, &tx2, TxExecutionMode::VerifyExecute, None); - -// let res2 = vm.execute_next_tx(u32::MAX, false).unwrap(); - -// assert_eq!(res2.status, TxExecutionStatus::Failure); - -// for factory_dep in tx2.execute.factory_deps.unwrap() { -// let hash = hash_bytecode(&factory_dep); -// let hash_to_u256 = h256_to_u256(hash); -// assert!(known_bytecodes_without_aa_code(&vm) -// .keys() -// .contains(&hash_to_u256)); -// assert!(!vm.get_used_contracts().contains(&hash_to_u256)); -// } -// } - -// fn known_bytecodes_without_aa_code(vm: &VmInstance) -> HashMap> { -// let mut known_bytecodes_without_aa_code = vm -// .state -// .decommittment_processor -// .known_bytecodes -// .inner() -// .clone(); - -// known_bytecodes_without_aa_code -// .remove(&h256_to_u256(BASE_SYSTEM_CONTRACTS.default_aa.hash)) -// .unwrap(); - -// known_bytecodes_without_aa_code -// } diff --git a/core/lib/multivm/src/versions/vm_m6/tests/mod.rs b/core/lib/multivm/src/versions/vm_m6/tests/mod.rs deleted file mode 100644 index 3900135abeaa..000000000000 --- a/core/lib/multivm/src/versions/vm_m6/tests/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod bootloader; diff --git a/core/lib/multivm/src/versions/vm_m6/transaction_data.rs b/core/lib/multivm/src/versions/vm_m6/transaction_data.rs index 136a6d7647ac..5934199a96fe 100644 --- a/core/lib/multivm/src/versions/vm_m6/transaction_data.rs +++ b/core/lib/multivm/src/versions/vm_m6/transaction_data.rs @@ -4,12 +4,13 @@ use zksync_types::{ fee::encoding_len, l1::is_l1_tx_type, l2::TransactionType, - ExecuteTransactionCommon, Transaction, MAX_L2_TX_GAS_LIMIT, MAX_TXS_IN_BLOCK, U256, + ExecuteTransactionCommon, Transaction, MAX_L2_TX_GAS_LIMIT, U256, }; use zksync_utils::{ address_to_h256, bytecode::hash_bytecode, bytes_to_be_words, ceil_div_u256, h256_to_u256, }; +use super::vm_with_bootloader::{MAX_GAS_PER_PUBDATA_BYTE, MAX_TXS_IN_BLOCK}; use crate::vm_m6::vm_with_bootloader::{ BLOCK_OVERHEAD_GAS, BLOCK_OVERHEAD_PUBDATA, BOOTLOADER_TX_ENCODING_SPACE, }; @@ -60,12 +61,22 @@ impl From for TransactionData { U256::zero() }; + // Ethereum transactions do not sign gas per pubdata limit, and so for them we need to use + // some default value. We use the maximum possible value that is allowed by the bootloader + // (i.e. we can not use u64::MAX, because the bootloader requires gas per pubdata for such + // transactions to be higher than `MAX_GAS_PER_PUBDATA_BYTE`). + let gas_per_pubdata_limit = if common_data.transaction_type.is_ethereum_type() { + MAX_GAS_PER_PUBDATA_BYTE.into() + } else { + common_data.fee.gas_per_pubdata_limit + }; + TransactionData { tx_type: (common_data.transaction_type as u32) as u8, from: execute_tx.initiator_account(), to: execute_tx.execute.contract_address, gas_limit: common_data.fee.gas_limit, - pubdata_price_limit: common_data.fee.gas_per_pubdata_limit, + pubdata_price_limit: gas_per_pubdata_limit, max_fee_per_gas: common_data.fee.max_fee_per_gas, max_priority_fee_per_gas: common_data.fee.max_priority_fee_per_gas, paymaster: common_data.paymaster_params.paymaster, @@ -231,13 +242,13 @@ impl TransactionData { } } -pub fn derive_overhead( +pub(crate) fn derive_overhead( gas_limit: u32, gas_price_per_pubdata: u32, encoded_len: usize, coefficients: OverheadCoefficients, ) -> u32 { - // Even if the gas limit is greater than the MAX_TX_ERGS_LIMIT, we assume that everything beyond MAX_TX_ERGS_LIMIT + // Even if the gas limit is greater than the `MAX_TX_ERGS_LIMIT`, we assume that everything beyond `MAX_TX_ERGS_LIMIT` // will be spent entirely on publishing bytecodes and so we derive the overhead solely based on the capped value let gas_limit = std::cmp::min(MAX_TX_ERGS_LIMIT, gas_limit); @@ -246,8 +257,8 @@ pub fn derive_overhead( let gas_limit = U256::from(gas_limit); let encoded_len = U256::from(encoded_len); - // The MAX_TX_ERGS_LIMIT is formed in a way that may fulfills a single-instance circuits - // if used in full. That is, within MAX_TX_ERGS_LIMIT it is possible to fully saturate all the single-instance + // The `MAX_TX_ERGS_LIMIT` is formed in a way that may fulfills a single-instance circuits + // if used in full. That is, within `MAX_TX_ERGS_LIMIT` it is possible to fully saturate all the single-instance // circuits. let overhead_for_single_instance_circuits = ceil_div_u256(gas_limit * max_block_overhead, MAX_TX_ERGS_LIMIT.into()); @@ -261,16 +272,17 @@ pub fn derive_overhead( // The overhead for occupying a single tx slot let tx_slot_overhead = ceil_div_u256(max_block_overhead, MAX_TXS_IN_BLOCK.into()); - // We use "ceil" here for formal reasons to allow easier approach for calculating the overhead in O(1) - // let max_pubdata_in_tx = ceil_div_u256(gas_limit, gas_price_per_pubdata); + // We use `ceil` here for formal reasons to allow easier approach for calculating the overhead in O(1) + // `let max_pubdata_in_tx = ceil_div_u256(gas_limit, gas_price_per_pubdata);` // The maximal potential overhead from pubdata // TODO (EVM-67): possibly use overhead for pubdata + // ``` // let pubdata_overhead = ceil_div_u256( // max_pubdata_in_tx * max_block_overhead, // MAX_PUBDATA_PER_BLOCK.into(), // ); - + // ``` vec![ (coefficients.ergs_limit_overhead_coeficient * overhead_for_single_instance_circuits.as_u32() as f64) @@ -287,7 +299,7 @@ pub fn derive_overhead( /// Contains the coefficients with which the overhead for transactions will be calculated. /// All of the coefficients should be <= 1. There are here to provide a certain "discount" for normal transactions /// at the risk of malicious transactions that may close the block prematurely. -/// IMPORTANT: to perform correct computations, `MAX_TX_ERGS_LIMIT / coefficients.ergs_limit_overhead_coeficient` MUST +/// IMPORTANT: to perform correct computations, `MAX_TX_ERGS_LIMIT / coefficients.ergs_limit_overhead_coefficient` MUST /// result in an integer number #[derive(Debug, Clone, Copy)] pub struct OverheadCoefficients { @@ -325,8 +337,8 @@ impl OverheadCoefficients { OverheadCoefficients::new_checked( 1.0, 1.0, // For L2 transactions we allow a certain default discount with regard to the number of ergs. - // Multiinstance circuits can in theory be spawned infinite times, while projected future limitations - // on gas per pubdata allow for roughly 800kk gas per L1 batch, so the rough trust "discount" on the proof's part + // Multi-instance circuits can in theory be spawned infinite times, while projected future limitations + // on gas per pubdata allow for roughly 800k gas per L1 batch, so the rough trust "discount" on the proof's part // to be paid by the users is 0.1. 0.1, ) @@ -354,28 +366,28 @@ pub fn get_amortized_overhead( let encoded_len = U256::from(encoded_len); // Derivation of overhead consists of 4 parts: - // 1. The overhead for taking up a transaction's slot. (O1): O1 = 1 / MAX_TXS_IN_BLOCK - // 2. The overhead for taking up the bootloader's memory (O2): O2 = encoded_len / BOOTLOADER_TX_ENCODING_SPACE - // 3. The overhead for possible usage of pubdata. (O3): O3 = max_pubdata_in_tx / MAX_PUBDATA_PER_BLOCK - // 4. The overhead for possible usage of all the single-instance circuits. (O4): O4 = gas_limit / MAX_TX_ERGS_LIMIT + // 1. The overhead for taking up a transaction's slot. `(O1): O1 = 1 / MAX_TXS_IN_BLOCK` + // 2. The overhead for taking up the bootloader's memory `(O2): O2 = encoded_len / BOOTLOADER_TX_ENCODING_SPACE` + // 3. The overhead for possible usage of pubdata. `(O3): O3 = max_pubdata_in_tx / MAX_PUBDATA_PER_BLOCK` + // 4. The overhead for possible usage of all the single-instance circuits. `(O4): O4 = gas_limit / MAX_TX_ERGS_LIMIT` // // The maximum of these is taken to derive the part of the block's overhead to be paid by the users: // - // max_overhead = max(O1, O2, O3, O4) - // overhead_gas = ceil(max_overhead * overhead_for_block_gas). Thus, overhead_gas is a function of - // tx_gas_limit, gas_per_pubdata_byte_limit and encoded_len. + // `max_overhead = max(O1, O2, O3, O4)` + // `overhead_gas = ceil(max_overhead * overhead_for_block_gas)`. Thus, `overhead_gas` is a function of + // `tx_gas_limit`, `gas_per_pubdata_byte_limit` and `encoded_len`. // - // While it is possible to derive the overhead with binary search in O(log n), it is too expensive to be done + // While it is possible to derive the overhead with binary search in `O(log n)`, it is too expensive to be done // on L1, so here is a reference implementation of finding the overhead for transaction in O(1): // - // Given total_gas_limit = tx_gas_limit + overhead_gas, we need to find overhead_gas and tx_gas_limit, such that: - // 1. overhead_gas is maximal possible (the operator is paid fairly) - // 2. overhead_gas(tx_gas_limit, gas_per_pubdata_byte_limit, encoded_len) >= overhead_gas (the user does not overpay) + // Given `total_gas_limit = tx_gas_limit + overhead_gas`, we need to find `overhead_gas` and `tx_gas_limit`, such that: + // 1. `overhead_gas` is maximal possible (the operator is paid fairly) + // 2. `overhead_gas(tx_gas_limit, gas_per_pubdata_byte_limit, encoded_len) >= overhead_gas` (the user does not overpay) // The third part boils to the following 4 inequalities (at least one of these must hold): - // ceil(O1 * overhead_for_block_gas) >= overhead_gas - // ceil(O2 * overhead_for_block_gas) >= overhead_gas - // ceil(O3 * overhead_for_block_gas) >= overhead_gas - // ceil(O4 * overhead_for_block_gas) >= overhead_gas + // `ceil(O1 * overhead_for_block_gas) >= overhead_gas` + // `ceil(O2 * overhead_for_block_gas) >= overhead_gas` + // `ceil(O3 * overhead_for_block_gas) >= overhead_gas` + // `ceil(O4 * overhead_for_block_gas) >= overhead_gas` // // Now, we need to solve each of these separately: @@ -386,7 +398,7 @@ pub fn get_amortized_overhead( (coefficients.slot_overhead_coeficient * tx_slot_overhead as f64).floor() as u32 }; - // 2. The overhead for occupying the bootloader memory can be derived from encoded_len + // 2. The overhead for occupying the bootloader memory can be derived from `encoded_len` let overhead_for_length = { let overhead_for_length = ceil_div_u256( encoded_len * overhead_for_block_gas, @@ -399,15 +411,18 @@ pub fn get_amortized_overhead( }; // TODO (EVM-67): possibly include the overhead for pubdata. The formula below has not been properly maintained, - // since the pubdat is not published. If decided to use the pubdata overhead, it needs to be updated. + // since the pubdata is not published. If decided to use the pubdata overhead, it needs to be updated. + // ``` // 3. ceil(O3 * overhead_for_block_gas) >= overhead_gas // O3 = max_pubdata_in_tx / MAX_PUBDATA_PER_BLOCK = ceil(gas_limit / gas_per_pubdata_byte_limit) / MAX_PUBDATA_PER_BLOCK - // >= (gas_limit / (gas_per_pubdata_byte_limit * MAX_PUBDATA_PER_BLOCK). Throwing off the `ceil`, while may provide marginally lower + // >= (gas_limit / (gas_per_pubdata_byte_limit * MAX_PUBDATA_PER_BLOCK). + // ``` + // Throwing off the `ceil`, while may provide marginally lower // overhead to the operator, provides substantially easier formula to work with. // - // For better clarity, let's denote gas_limit = GL, MAX_PUBDATA_PER_BLOCK = MP, gas_per_pubdata_byte_limit = EP, overhead_for_block_gas = OB, total_gas_limit = TL, overhead_gas = OE - // ceil(OB * (TL - OE) / (EP * MP)) >= OE - // + // For better clarity, let's denote `gas_limit = GL, MAX_PUBDATA_PER_BLOCK = MP, gas_per_pubdata_byte_limit = EP, overhead_for_block_gas = OB, total_gas_limit = TL, overhead_gas = OE` + // `ceil(OB * (TL - OE) / (EP * MP)) >= OE` + // ``` // OB * (TL - OE) / (MP * EP) > OE - 1 // OB * (TL - OE) > (OE - 1) * EP * MP // OB * TL + EP * MP > OE * EP * MP + OE * OB @@ -418,7 +433,7 @@ pub fn get_amortized_overhead( // + gas_per_pubdata_byte_limit * U256::from(MAX_PUBDATA_PER_BLOCK); // let denominator = // gas_per_pubdata_byte_limit * U256::from(MAX_PUBDATA_PER_BLOCK) + overhead_for_block_gas; - + // // // Corner case: if `total_gas_limit` = `gas_per_pubdata_byte_limit` = 0 // // then the numerator will be 0 and subtracting 1 will cause a panic, so we just return a zero. // if numerator.is_zero() { @@ -427,7 +442,7 @@ pub fn get_amortized_overhead( // (numerator - 1) / denominator // } // }; - + // // 4. K * ceil(O4 * overhead_for_block_gas) >= overhead_gas, where K is the discount // O4 = gas_limit / MAX_TX_ERGS_LIMIT. Using the notation from the previous equation: // ceil(OB * GL / MAX_TX_ERGS_LIMIT) >= (OE / K) @@ -436,6 +451,7 @@ pub fn get_amortized_overhead( // OB * (TL - OE) > (OE/K) * MAX_TX_ERGS_LIMIT - MAX_TX_ERGS_LIMIT // OB * TL + MAX_TX_ERGS_LIMIT > OE * ( MAX_TX_ERGS_LIMIT/K + OB) // OE = floor(OB * TL + MAX_TX_ERGS_LIMIT / (MAX_TX_ERGS_LIMIT/K + OB)), with possible -1 if the division is without remainder + // ``` let overhead_for_gas = { let numerator = overhead_for_block_gas * total_gas_limit + U256::from(MAX_TX_ERGS_LIMIT); let denominator: U256 = U256::from( @@ -450,16 +466,16 @@ pub fn get_amortized_overhead( let overhead = vec![tx_slot_overhead, overhead_for_length, overhead_for_gas] .into_iter() .max() - // For the sake of consistency making sure that total_gas_limit >= max_overhead + // For the sake of consistency making sure that `total_gas_limit >= max_overhead` .map(|max_overhead| std::cmp::min(max_overhead, total_gas_limit.as_u32())) .unwrap(); let limit_after_deducting_overhead = total_gas_limit - overhead; // During double checking of the overhead, the bootloader will assume that the - // body of the transaction does not have any more than MAX_L2_TX_GAS_LIMIT ergs available to it. + // body of the transaction does not have any more than `MAX_L2_TX_GAS_LIMIT` ergs available to it. if limit_after_deducting_overhead.as_u64() > MAX_L2_TX_GAS_LIMIT { - // We derive the same overhead that would exist for the MAX_L2_TX_GAS_LIMIT ergs + // We derive the same overhead that would exist for the `MAX_L2_TX_GAS_LIMIT` ergs derive_overhead( MAX_L2_TX_GAS_LIMIT as u32, gas_per_pubdata_byte_limit, @@ -494,7 +510,7 @@ mod tests { } else { 0u32 }; - // Safe cast: the gas_limit for a transaction can not be larger than 2^32 + // Safe cast: the gas_limit for a transaction can not be larger than `2^32` let mut right_bound = total_gas_limit; // The closure returns whether a certain overhead would be accepted by the bootloader. diff --git a/core/lib/multivm/src/versions/vm_m6/utils.rs b/core/lib/multivm/src/versions/vm_m6/utils.rs index 476cf341cbab..59bf6bb1d29f 100644 --- a/core/lib/multivm/src/versions/vm_m6/utils.rs +++ b/core/lib/multivm/src/versions/vm_m6/utils.rs @@ -7,7 +7,7 @@ use zk_evm_1_3_1::{ }; use zksync_contracts::{read_zbin_bytecode, BaseSystemContracts}; use zksync_system_constants::ZKPORTER_IS_AVAILABLE; -use zksync_types::{Address, StorageLogQuery, H160, MAX_L2_TX_GAS_LIMIT, U256}; +use zksync_types::{Address, StorageLogQueryType, H160, MAX_L2_TX_GAS_LIMIT, U256}; use zksync_utils::h256_to_u256; use crate::{ @@ -227,7 +227,7 @@ pub fn collect_log_queries_after_timestamp( /// Receives sorted slice of timestamps. /// Returns count of timestamps that are greater than or equal to `from_timestamp`. -/// Works in O(log(sorted_timestamps.len())). +/// Works in `O(log(sorted_timestamps.len()))`. pub fn precompile_calls_count_after_timestamp( sorted_timestamps: &[Timestamp], from_timestamp: Timestamp, @@ -258,8 +258,8 @@ pub fn create_test_block_params() -> (BlockContext, BlockProperties) { pub fn read_bootloader_test_code(test: &str) -> Vec { read_zbin_bytecode(format!( - "contracts/system-contracts/bootloader/tests/artifacts/{}.yul/{}.yul.zbin", - test, test + "contracts/system-contracts/bootloader/tests/artifacts/{}.yul.zbin", + test )) } @@ -289,3 +289,10 @@ pub(crate) fn calculate_computational_gas_used< 0 }) } + +/// Log query, which handle initial and repeated writes to the storage +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct StorageLogQuery { + pub log_query: LogQuery, + pub log_type: StorageLogQueryType, +} diff --git a/core/lib/multivm/src/versions/vm_m6/vm.rs b/core/lib/multivm/src/versions/vm_m6/vm.rs index e82d51d2bf3b..698041d6cb23 100644 --- a/core/lib/multivm/src/versions/vm_m6/vm.rs +++ b/core/lib/multivm/src/versions/vm_m6/vm.rs @@ -1,5 +1,8 @@ use std::collections::HashSet; +use itertools::Itertools; +use zk_evm_1_3_1::aux_structures::LogQuery; +use zkevm_test_harness_1_3_3::witness::sort_storage_access::sort_storage_access_queries; use zksync_state::StoragePtr; use zksync_types::{ l2_to_l1_log::{L2ToL1Log, UserL2ToL1Log}, @@ -17,6 +20,7 @@ use crate::{ L1BatchEnv, L2BlockEnv, SystemEnv, TxExecutionMode, VmExecutionMode, VmExecutionResultAndLogs, VmInterface, VmInterfaceHistoryEnabled, VmMemoryMetrics, }, + tracers::old_tracers::TracerDispatcher, vm_m6::{events::merge_events, storage::Storage, vm_instance::MultiVMSubversion, VmInstance}, }; @@ -61,8 +65,7 @@ impl Vm { } impl VmInterface for Vm { - /// Tracers are not supported. So we use `()` as a placeholder - type TracerDispatcher = (); + type TracerDispatcher = TracerDispatcher; fn new(batch_env: L1BatchEnv, system_env: SystemEnv, storage: StoragePtr) -> Self { let vm_version: VmVersion = system_env.version.into(); @@ -85,26 +88,35 @@ impl VmInterface for Vm { fn inspect( &mut self, - _tracer: Self::TracerDispatcher, + tracer: Self::TracerDispatcher, execution_mode: VmExecutionMode, ) -> VmExecutionResultAndLogs { + if let Some(storage_invocations) = tracer.storage_invocations { + self.vm + .execution_mode + .set_invocation_limit(storage_invocations); + } + match execution_mode { - VmExecutionMode::OneTx => { - match self.system_env.execution_mode { - TxExecutionMode::VerifyExecute => { - // Even that call tracer is supported here, we don't use it now - self.vm.execute_next_tx( - self.system_env.default_validation_computational_gas_limit, - false, - ).glue_into() + VmExecutionMode::OneTx => match self.system_env.execution_mode { + TxExecutionMode::VerifyExecute => { + let enable_call_tracer = tracer.call_tracer.is_some(); + let result = self.vm.execute_next_tx( + self.system_env.default_validation_computational_gas_limit, + enable_call_tracer, + ); + if let (Ok(result), Some(call_tracer)) = (&result, &tracer.call_tracer) { + call_tracer.set(result.call_traces.clone()).unwrap(); } - TxExecutionMode::EstimateFee | TxExecutionMode::EthCall => self.vm - .execute_till_block_end( - crate::vm_m6::vm_with_bootloader::BootloaderJobType::TransactionExecution, - ) - .glue_into(), + result.glue_into() } - } + TxExecutionMode::EstimateFee | TxExecutionMode::EthCall => self + .vm + .execute_till_block_end( + crate::vm_m6::vm_with_bootloader::BootloaderJobType::TransactionExecution, + ) + .glue_into(), + }, VmExecutionMode::Batch => self.finish_batch().block_tip_execution_result, VmExecutionMode::Bootloader => self.vm.execute_block_tip().glue_into(), } @@ -160,14 +172,40 @@ impl VmInterface for Vm { .cloned() .collect(); + let storage_log_queries = self.vm.get_final_log_queries(); + + // To allow calling the `vm-1.3.3`s. method, the `v1.3.1`'s `LogQuery` has to be converted + // to the `vm-1.3.3`'s `LogQuery`. Then, we need to convert it back. + let deduplicated_logs: Vec = sort_storage_access_queries( + &storage_log_queries + .iter() + .map(|log| { + GlueInto::::glue_into(log.log_query) + }) + .collect_vec(), + ) + .1 + .into_iter() + .map(GlueInto::::glue_into) + .collect(); + CurrentExecutionState { events, - storage_log_queries: self.vm.get_final_log_queries(), + storage_log_queries: self + .vm + .get_final_log_queries() + .into_iter() + .map(GlueInto::glue_into) + .collect(), + deduplicated_storage_log_queries: deduplicated_logs + .into_iter() + .map(GlueInto::glue_into) + .collect(), used_contract_hashes, system_logs: vec![], total_log_queries, cycles_used: self.vm.state.local_state.monotonic_cycle_counter, - // It's not applicable for vm6 + // It's not applicable for `vm6` deduplicated_events_logs: vec![], storage_refunds: vec![], user_l2_to_l1_logs: l2_to_l1_logs, @@ -176,10 +214,19 @@ impl VmInterface for Vm { fn inspect_transaction_with_bytecode_compression( &mut self, - _tracer: Self::TracerDispatcher, + tracer: Self::TracerDispatcher, tx: Transaction, with_compression: bool, - ) -> Result { + ) -> ( + Result<(), BytecodeCompressionError>, + VmExecutionResultAndLogs, + ) { + if let Some(storage_invocations) = tracer.storage_invocations { + self.vm + .execution_mode + .set_invocation_limit(storage_invocations); + } + self.last_tx_compressed_bytecodes = vec![]; let bytecodes = if with_compression { let deps = tx.execute.factory_deps.as_deref().unwrap_or_default(); @@ -218,17 +265,35 @@ impl VmInterface for Vm { }; // Even that call tracer is supported here, we don't use it. - let result = self.vm.execute_next_tx( - self.system_env.default_validation_computational_gas_limit, - false, - ); + let result = match self.system_env.execution_mode { + TxExecutionMode::VerifyExecute => { + let enable_call_tracer = tracer.call_tracer.is_some(); + let result = self.vm.execute_next_tx( + self.system_env.default_validation_computational_gas_limit, + enable_call_tracer, + ); + if let (Ok(result), Some(call_tracer)) = (&result, &tracer.call_tracer) { + call_tracer.set(result.call_traces.clone()).unwrap(); + } + result.glue_into() + } + TxExecutionMode::EstimateFee | TxExecutionMode::EthCall => self + .vm + .execute_till_block_end( + crate::vm_m6::vm_with_bootloader::BootloaderJobType::TransactionExecution, + ) + .glue_into(), + }; if bytecodes .iter() .any(|info| !self.vm.is_bytecode_exists(info)) { - Err(crate::interface::BytecodeCompressionError::BytecodeCompressionFailed) + ( + Err(BytecodeCompressionError::BytecodeCompressionFailed), + result, + ) } else { - Ok(result.glue_into()) + (Ok(()), result) } } @@ -249,6 +314,12 @@ impl VmInterface for Vm { } } + fn has_enough_gas_for_batch_tip(&self) -> bool { + // For this version this overhead has not been calculated and it has not been used with those versions. + // We return some value just in case for backwards compatibility + true + } + fn finish_batch(&mut self) -> FinishedL1Batch { self.vm .execute_till_block_end( diff --git a/core/lib/multivm/src/versions/vm_m6/vm_instance.rs b/core/lib/multivm/src/versions/vm_m6/vm_instance.rs index 379476d7664c..68416970ee8e 100644 --- a/core/lib/multivm/src/versions/vm_m6/vm_instance.rs +++ b/core/lib/multivm/src/versions/vm_m6/vm_instance.rs @@ -9,12 +9,11 @@ use zk_evm_1_3_1::{ definitions::RET_IMPLICIT_RETURNDATA_PARAMS_REGISTER, }, }; -use zksync_system_constants::MAX_TXS_IN_BLOCK; use zksync_types::{ l2_to_l1_log::{L2ToL1Log, UserL2ToL1Log}, tx::tx_execution_info::TxExecutionStatus, vm_trace::{Call, VmExecutionTrace, VmTrace}, - L1BatchNumber, StorageLogQuery, VmEvent, H256, U256, + L1BatchNumber, VmEvent, H256, U256, }; use crate::{ @@ -42,7 +41,7 @@ use crate::{ utils::{ calculate_computational_gas_used, collect_log_queries_after_timestamp, collect_storage_log_queries_after_timestamp, dump_memory_page_using_primitive_value, - precompile_calls_count_after_timestamp, + precompile_calls_count_after_timestamp, StorageLogQuery, }, vm_with_bootloader::{ BootloaderJobType, DerivedBlockContext, TxExecutionMode, BOOTLOADER_HEAP_PAGE, @@ -180,6 +179,7 @@ pub enum VmExecutionStopReason { TracerRequestedStop, } +use super::vm_with_bootloader::MAX_TXS_IN_BLOCK; use crate::vm_m6::utils::VmExecutionResult as NewVmExecutionResult; fn vm_may_have_ended_inner( @@ -202,7 +202,7 @@ fn vm_may_have_ended_inner( } (false, _) => None, (true, l) if l == outer_eh_location => { - // check r1,r2,r3 + // check `r1,r2,r3` if vm.local_state.flags.overflow_or_less_than_flag { Some(NewVmExecutionResult::Panic) } else { @@ -235,7 +235,7 @@ fn vm_may_have_ended( NewVmExecutionResult::Ok(data) => { Some(VmExecutionResult { // The correct `events` value for this field should be set separately - // later on based on the information inside the event_sink oracle. + // later on based on the information inside the `event_sink` oracle. events: vec![], storage_log_queries: vm.get_final_log_queries(), used_contract_hashes: vm.get_used_contracts(), @@ -436,10 +436,7 @@ impl VmInstance { .collect(); ( events, - l1_messages - .into_iter() - .map(|log| L2ToL1Log::from(GlueInto::::glue_into(log))) - .collect(), + l1_messages.into_iter().map(GlueInto::glue_into).collect(), ) } @@ -463,7 +460,7 @@ impl VmInstance { from_timestamp, ); VmExecutionLogs { - storage_logs, + storage_logs: storage_logs.into_iter().map(GlueInto::glue_into).collect(), events, user_l2_to_l1_logs: l2_to_l1_logs.into_iter().map(UserL2ToL1Log).collect(), system_l2_to_l1_logs: vec![], @@ -508,8 +505,8 @@ impl VmInstance { ); } - // This means that the bootloader has informed the system (usually via VMHooks) - that some gas - // should be refunded back (see askOperatorForRefund in bootloader.yul for details). + // This means that the bootloader has informed the system (usually via `VMHooks`) - that some gas + // should be refunded back (see `askOperatorForRefund` in `bootloader.yul` for details). if let Some(bootloader_refund) = tracer.requested_refund() { assert!( operator_refund.is_none(), @@ -605,8 +602,8 @@ impl VmInstance { /// Panics if there are no new transactions in bootloader. /// Internally uses the OneTxTracer to stop the VM when the last opcode from the transaction is reached. // Err when transaction is rejected. - // Ok(status: TxExecutionStatus::Success) when the transaction succeeded - // Ok(status: TxExecutionStatus::Failure) when the transaction failed. + // `Ok(status: TxExecutionStatus::Success)` when the transaction succeeded + // `Ok(status: TxExecutionStatus::Failure)` when the transaction failed. // Note that failed transactions are considered properly processed and are included in blocks pub fn execute_next_tx( &mut self, @@ -666,7 +663,7 @@ impl VmInstance { revert_reason: None, // getting contracts used during this transaction // at least for now the number returned here is always <= to the number - // of the code hashes actually used by the transaction, since it might've + // of the code hashes actually used by the transaction, since it might have // reused bytecode hashes from some of the previous ones. contracts_used: self .state @@ -788,12 +785,8 @@ impl VmInstance { e.into_vm_event(L1BatchNumber(self.block_context.context.block_number)) }) .collect(); - full_result.l2_to_l1_logs = l1_messages - .into_iter() - .map(|log| { - L2ToL1Log::from(GlueInto::::glue_into(log)) - }) - .collect(); + full_result.l2_to_l1_logs = + l1_messages.into_iter().map(GlueInto::glue_into).collect(); full_result.computational_gas_used = block_tip_result.computational_gas_used; VmBlockResult { full_result, @@ -951,8 +944,8 @@ impl VmInstance { pub fn save_current_vm_as_snapshot(&mut self) { self.snapshots.push(VmSnapshot { // Vm local state contains O(1) various parameters (registers/etc). - // The only "expensive" copying here is copying of the callstack. - // It will take O(callstack_depth) to copy it. + // The only "expensive" copying here is copying of the call stack. + // It will take `O(callstack_depth)` to copy it. // So it is generally recommended to get snapshots of the bootloader frame, // where the depth is 1. local_state: self.state.local_state.clone(), diff --git a/core/lib/multivm/src/versions/vm_m6/vm_with_bootloader.rs b/core/lib/multivm/src/versions/vm_m6/vm_with_bootloader.rs index c7d4ee3d45e8..3601e480ee41 100644 --- a/core/lib/multivm/src/versions/vm_m6/vm_with_bootloader.rs +++ b/core/lib/multivm/src/versions/vm_m6/vm_with_bootloader.rs @@ -10,11 +10,12 @@ use zk_evm_1_3_1::{ BOOTLOADER_CALLDATA_PAGE, STARTING_BASE_PAGE, STARTING_TIMESTAMP, }, }; +use zkevm_test_harness_1_3_3::INITIAL_MONOTONIC_CYCLE_COUNTER; use zksync_contracts::BaseSystemContracts; -use zksync_system_constants::MAX_TXS_IN_BLOCK; +use zksync_system_constants::MAX_L2_TX_GAS_LIMIT; use zksync_types::{ - zkevm_test_harness::INITIAL_MONOTONIC_CYCLE_COUNTER, Address, Transaction, BOOTLOADER_ADDRESS, - L1_GAS_PER_PUBDATA_BYTE, MAX_GAS_PER_PUBDATA_BYTE, MAX_NEW_FACTORY_DEPS, U256, + fee_model::L1PeggedBatchFeeModelInput, Address, Transaction, BOOTLOADER_ADDRESS, + L1_GAS_PER_PUBDATA_BYTE, MAX_NEW_FACTORY_DEPS, U256, }; use zksync_utils::{ address_to_u256, @@ -23,20 +24,23 @@ use zksync_utils::{ misc::ceil_div, }; -use crate::vm_m6::{ - bootloader_state::BootloaderState, - history_recorder::HistoryMode, - storage::Storage, - transaction_data::{TransactionData, L1_TX_TYPE}, - utils::{ - code_page_candidate_from_base, heap_page_from_base, BLOCK_GAS_LIMIT, INITIAL_BASE_PAGE, +use crate::{ + vm_latest::L1BatchEnv, + vm_m6::{ + bootloader_state::BootloaderState, + history_recorder::HistoryMode, + storage::Storage, + transaction_data::{TransactionData, L1_TX_TYPE}, + utils::{ + code_page_candidate_from_base, heap_page_from_base, BLOCK_GAS_LIMIT, INITIAL_BASE_PAGE, + }, + vm_instance::{MultiVMSubversion, ZkSyncVmState}, + OracleTools, VmInstance, }, - vm_instance::{MultiVMSubversion, ZkSyncVmState}, - OracleTools, VmInstance, }; -// TODO (SMA-1703): move these to config and make them programmatically generatable. -// fill these values in the similar fasion as other overhead-related constants +// TODO (SMA-1703): move these to config and make them programmatically generable. +// fill these values in the similar fashion as other overhead-related constants pub const BLOCK_OVERHEAD_GAS: u32 = 1200000; pub const BLOCK_OVERHEAD_L1_GAS: u32 = 1000000; pub const BLOCK_OVERHEAD_PUBDATA: u32 = BLOCK_OVERHEAD_L1_GAS / L1_GAS_PER_PUBDATA_BYTE; @@ -58,7 +62,11 @@ pub struct BlockContext { impl BlockContext { pub fn block_gas_price_per_pubdata(&self) -> u64 { - derive_base_fee_and_gas_per_pubdata(self.l1_gas_price, self.fair_l2_gas_price).1 + derive_base_fee_and_gas_per_pubdata(L1PeggedBatchFeeModelInput { + l1_gas_price: self.l1_gas_price, + fair_l2_gas_price: self.fair_l2_gas_price, + }) + .1 } } @@ -76,37 +84,76 @@ pub(crate) fn eth_price_per_pubdata_byte(l1_gas_price: u64) -> u64 { l1_gas_price * (L1_GAS_PER_PUBDATA_BYTE as u64) } -pub fn base_fee_to_gas_per_pubdata(l1_gas_price: u64, base_fee: u64) -> u64 { +pub(crate) fn base_fee_to_gas_per_pubdata(l1_gas_price: u64, base_fee: u64) -> u64 { let eth_price_per_pubdata_byte = eth_price_per_pubdata_byte(l1_gas_price); ceil_div(eth_price_per_pubdata_byte, base_fee) } -pub fn derive_base_fee_and_gas_per_pubdata(l1_gas_price: u64, fair_gas_price: u64) -> (u64, u64) { +pub(crate) fn derive_base_fee_and_gas_per_pubdata( + fee_input: L1PeggedBatchFeeModelInput, +) -> (u64, u64) { + let L1PeggedBatchFeeModelInput { + l1_gas_price, + fair_l2_gas_price, + } = fee_input; + let eth_price_per_pubdata_byte = eth_price_per_pubdata_byte(l1_gas_price); - // The baseFee is set in such a way that it is always possible for a transaction to + // The `baseFee` is set in such a way that it is always possible for a transaction to // publish enough public data while compensating us for it. let base_fee = std::cmp::max( - fair_gas_price, + fair_l2_gas_price, ceil_div(eth_price_per_pubdata_byte, MAX_GAS_PER_PUBDATA_BYTE), ); ( base_fee, - base_fee_to_gas_per_pubdata(l1_gas_price, base_fee), + base_fee_to_gas_per_pubdata(fee_input.l1_gas_price, base_fee), ) } +pub(crate) fn get_batch_base_fee(l1_batch_env: &L1BatchEnv) -> u64 { + if let Some(base_fee) = l1_batch_env.enforced_base_fee { + return base_fee; + } + let (base_fee, _) = + derive_base_fee_and_gas_per_pubdata(l1_batch_env.fee_input.into_l1_pegged()); + base_fee +} + impl From for DerivedBlockContext { fn from(context: BlockContext) -> Self { - let base_fee = - derive_base_fee_and_gas_per_pubdata(context.l1_gas_price, context.fair_l2_gas_price).0; + let base_fee = derive_base_fee_and_gas_per_pubdata(L1PeggedBatchFeeModelInput { + l1_gas_price: context.l1_gas_price, + fair_l2_gas_price: context.fair_l2_gas_price, + }) + .0; DerivedBlockContext { context, base_fee } } } +/// The size of the bootloader memory in bytes which is used by the protocol. +/// While the maximal possible size is a lot higher, we restrict ourselves to a certain limit to reduce +/// the requirements on RAM. +pub(crate) const USED_BOOTLOADER_MEMORY_BYTES: usize = 1 << 24; +pub(crate) const USED_BOOTLOADER_MEMORY_WORDS: usize = USED_BOOTLOADER_MEMORY_BYTES / 32; + +// This the number of pubdata such that it should be always possible to publish +// from a single transaction. Note, that these pubdata bytes include only bytes that are +// to be published inside the body of transaction (i.e. excluding of factory deps). +pub(crate) const GUARANTEED_PUBDATA_PER_L1_BATCH: u64 = 4000; + +// The users should always be able to provide `MAX_GAS_PER_PUBDATA_BYTE` gas per pubdata in their +// transactions so that they are able to send at least `GUARANTEED_PUBDATA_PER_L1_BATCH` bytes per +// transaction. +pub(crate) const MAX_GAS_PER_PUBDATA_BYTE: u64 = + MAX_L2_TX_GAS_LIMIT / GUARANTEED_PUBDATA_PER_L1_BATCH; + +// The maximal number of transactions in a single batch +pub(crate) const MAX_TXS_IN_BLOCK: usize = 1024; + // The first 32 slots are reserved for debugging purposes pub const DEBUG_SLOTS_OFFSET: usize = 8; pub const DEBUG_FIRST_SLOTS: usize = 32; @@ -149,7 +196,7 @@ pub const BOOTLOADER_TX_DESCRIPTION_OFFSET: usize = COMPRESSED_BYTECODES_OFFSET + COMPRESSED_BYTECODES_SLOTS; // The size of the bootloader memory dedicated to the encodings of transactions -pub const BOOTLOADER_TX_ENCODING_SPACE: u32 = +pub(crate) const BOOTLOADER_TX_ENCODING_SPACE: u32 = (MAX_HEAP_PAGE_SIZE_IN_WORDS - TX_DESCRIPTION_OFFSET - MAX_TXS_IN_BLOCK) as u32; // Size of the bootloader tx description in words @@ -197,6 +244,18 @@ impl TxExecutionMode { } => *missed_storage_invocation_limit, } } + + pub fn set_invocation_limit(&mut self, limit: usize) { + match self { + Self::VerifyExecute => {} + TxExecutionMode::EstimateFee { + missed_storage_invocation_limit, + } => *missed_storage_invocation_limit = limit, + TxExecutionMode::EthCall { + missed_storage_invocation_limit, + } => *missed_storage_invocation_limit = limit, + } + } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -251,12 +310,12 @@ pub fn init_vm_with_gas_limit( } #[derive(Debug, Clone, Copy)] -// The block.number/block.timestamp data are stored in the CONTEXT_SYSTEM_CONTRACT. +// The `block.number` / `block.timestamp` data are stored in the `CONTEXT_SYSTEM_CONTRACT`. // The bootloader can support execution in two modes: -// - "NewBlock" when the new block is created. It is enforced that the block.number is incremented by 1 +// - `NewBlock` when the new block is created. It is enforced that the block.number is incremented by 1 // and the timestamp is non-decreasing. Also, the L2->L1 message used to verify the correctness of the previous root hash is sent. // This is the mode that should be used in the state keeper. -// - "OverrideCurrent" when we need to provide custom block.number and block.timestamp. ONLY to be used in testing/ethCalls. +// - `OverrideCurrent` when we need to provide custom `block.number` and `block.timestamp`. ONLY to be used in testing / `ethCalls`. pub enum BlockContextMode { NewBlock(DerivedBlockContext, U256), OverrideCurrent(DerivedBlockContext), diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/README.md b/core/lib/multivm/src/versions/vm_refunds_enhancement/README.md index d515df0dfc60..52dbeb5187bb 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/README.md +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/README.md @@ -40,5 +40,4 @@ The `VMInstance` in `vm.rs` allows for easy rollbacks. You can save the current This rollback affects all subcomponents, such as memory, storage, and events, and is mainly used if a transaction doesn't fit in a block. -[zk_evm_repo]: https://github.com/matter-labs/zk_evm 'internal zk EVM repo' [zk_evm_repo_ext]: https://github.com/matter-labs/era-zk_evm 'external zk EVM repo' diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/bootloader_state/l2_block.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/bootloader_state/l2_block.rs index 6cd1096b3bd3..03544d8b054b 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/bootloader_state/l2_block.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/bootloader_state/l2_block.rs @@ -19,7 +19,7 @@ pub(crate) struct BootloaderL2Block { pub(crate) timestamp: u64, pub(crate) txs_rolling_hash: H256, // The rolling hash of all the transactions in the miniblock pub(crate) prev_block_hash: H256, - // Number of the first l2 block tx in l1 batch + // Number of the first L2 block tx in L1 batch pub(crate) first_tx_index: usize, pub(crate) max_virtual_blocks_to_create: u32, pub(super) txs: Vec, diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/bootloader_state/utils.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/bootloader_state/utils.rs index 8adeb3e0b428..f47b95d6cbf7 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/bootloader_state/utils.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/bootloader_state/utils.rs @@ -92,8 +92,8 @@ pub(crate) fn apply_l2_block( bootloader_l2_block: &BootloaderL2Block, txs_index: usize, ) { - // Since L2 block infos start from the TX_OPERATOR_L2_BLOCK_INFO_OFFSET and each - // L2 block info takes TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO slots, the position where the L2 block info + // Since L2 block information start from the `TX_OPERATOR_L2_BLOCK_INFO_OFFSET` and each + // L2 block info takes `TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO` slots, the position where the L2 block info // for this transaction needs to be written is: let block_position = diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/constants.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/constants.rs index 82ab754e4036..3c5560e7ea8a 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/constants.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/constants.rs @@ -2,13 +2,30 @@ use zk_evm_1_3_3::aux_structures::MemoryPage; pub use zk_evm_1_3_3::zkevm_opcode_defs::system_params::{ ERGS_PER_CIRCUIT, INITIAL_STORAGE_WRITE_PUBDATA_BYTES, MAX_PUBDATA_PER_BLOCK, }; -use zksync_system_constants::{ - L1_GAS_PER_PUBDATA_BYTE, MAX_L2_TX_GAS_LIMIT, MAX_NEW_FACTORY_DEPS, MAX_TXS_IN_BLOCK, - USED_BOOTLOADER_MEMORY_WORDS, -}; +use zksync_system_constants::{L1_GAS_PER_PUBDATA_BYTE, MAX_L2_TX_GAS_LIMIT, MAX_NEW_FACTORY_DEPS}; use crate::vm_refunds_enhancement::old_vm::utils::heap_page_from_base; +/// The size of the bootloader memory in bytes which is used by the protocol. +/// While the maximal possible size is a lot higher, we restrict ourselves to a certain limit to reduce +/// the requirements on RAM. +pub(crate) const USED_BOOTLOADER_MEMORY_BYTES: usize = 1 << 24; +pub(crate) const USED_BOOTLOADER_MEMORY_WORDS: usize = USED_BOOTLOADER_MEMORY_BYTES / 32; + +// This the number of pubdata such that it should be always possible to publish +// from a single transaction. Note, that these pubdata bytes include only bytes that are +// to be published inside the body of transaction (i.e. excluding of factory deps). +pub(crate) const GUARANTEED_PUBDATA_PER_L1_BATCH: u64 = 4000; + +// The users should always be able to provide `MAX_GAS_PER_PUBDATA_BYTE` gas per pubdata in their +// transactions so that they are able to send at least `GUARANTEED_PUBDATA_PER_L1_BATCH` bytes per +// transaction. +pub(crate) const MAX_GAS_PER_PUBDATA_BYTE: u64 = + MAX_L2_TX_GAS_LIMIT / GUARANTEED_PUBDATA_PER_L1_BATCH; + +// The maximal number of transactions in a single batch +pub(crate) const MAX_TXS_IN_BLOCK: usize = 1024; + /// Max cycles for a single transaction. pub const MAX_CYCLES_FOR_TX: u32 = u32::MAX; @@ -52,7 +69,7 @@ pub(crate) const BOOTLOADER_TX_DESCRIPTION_OFFSET: usize = COMPRESSED_BYTECODES_OFFSET + COMPRESSED_BYTECODES_SLOTS; /// The size of the bootloader memory dedicated to the encodings of transactions -pub const BOOTLOADER_TX_ENCODING_SPACE: u32 = +pub(crate) const BOOTLOADER_TX_ENCODING_SPACE: u32 = (USED_BOOTLOADER_MEMORY_WORDS - TX_DESCRIPTION_OFFSET - MAX_TXS_IN_BLOCK) as u32; // Size of the bootloader tx description in words diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/logs.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/logs.rs index bded1c19041f..dee06ee6180a 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/logs.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/logs.rs @@ -6,6 +6,7 @@ use zksync_types::{ }; use crate::{ + glue::GlueInto, interface::types::outputs::VmExecutionLogs, vm_refunds_enhancement::{ old_vm::{events::merge_events, utils::precompile_calls_count_after_timestamp}, @@ -44,7 +45,7 @@ impl Vm { let total_log_queries_count = storage_logs_count + log_queries.len() + precompile_calls_count; VmExecutionLogs { - storage_logs, + storage_logs: storage_logs.into_iter().map(GlueInto::glue_into).collect(), events, user_l2_to_l1_logs: l2_to_l1_logs.into_iter().map(UserL2ToL1Log).collect(), system_l2_to_l1_logs: vec![], @@ -64,6 +65,9 @@ impl Vm { .into_iter() .map(|e| e.into_vm_event(self.batch_env.number)) .collect(); - (events, l1_messages.into_iter().map(Into::into).collect()) + ( + events, + l1_messages.into_iter().map(GlueInto::glue_into).collect(), + ) } } diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/snapshots.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/snapshots.rs index c34535726c04..56c219fffa4b 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/snapshots.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/snapshots.rs @@ -37,8 +37,8 @@ impl Vm { pub(crate) fn make_snapshot_inner(&mut self) { self.snapshots.push(VmSnapshot { // Vm local state contains O(1) various parameters (registers/etc). - // The only "expensive" copying here is copying of the callstack. - // It will take O(callstack_depth) to copy it. + // The only "expensive" copying here is copying of the call stack. + // It will take `O(callstack_depth)` to copy it. // So it is generally recommended to get snapshots of the bootloader frame, // where the depth is 1. local_state: self.state.local_state.clone(), diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/statistics.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/statistics.rs index 3e9de5de4ec0..49d4b02de8b2 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/statistics.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/statistics.rs @@ -40,6 +40,7 @@ impl Vm { computational_gas_used, total_log_queries: total_log_queries_count, pubdata_published, + circuit_statistic: Default::default(), } } diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/tx.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/tx.rs index a786e9b0ad7e..6dc4772d095a 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/tx.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/implementation/tx.rs @@ -7,6 +7,7 @@ use crate::{ constants::BOOTLOADER_HEAP_PAGE, implementation::bytecode::{bytecode_to_factory_dep, compress_bytecodes}, types::internals::TransactionData, + utils::fee::get_batch_gas_per_pubdata, vm::Vm, }, HistoryMode, @@ -38,8 +39,7 @@ impl Vm { .decommittment_processor .populate(codes_for_decommiter, timestamp); - let trusted_ergs_limit = - tx.trusted_ergs_limit(self.batch_env.block_gas_price_per_pubdata()); + let trusted_ergs_limit = tx.trusted_ergs_limit(get_batch_gas_per_pubdata(&self.batch_env)); let memory = self.bootloader_state.push_tx( tx, @@ -61,7 +61,7 @@ impl Vm { with_compression: bool, ) { let tx: TransactionData = tx.into(); - let block_gas_per_pubdata_byte = self.batch_env.block_gas_price_per_pubdata(); + let block_gas_per_pubdata_byte = get_batch_gas_per_pubdata(&self.batch_env); let overhead = tx.overhead_gas(block_gas_per_pubdata_byte as u32); self.push_raw_transaction(tx, overhead, 0, with_compression); } diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/old_vm/event_sink.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/old_vm/event_sink.rs index 43019cce1ce7..74dca71d10f6 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/old_vm/event_sink.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/old_vm/event_sink.rs @@ -50,7 +50,7 @@ impl InMemoryEventSink { pub fn log_queries_after_timestamp(&self, from_timestamp: Timestamp) -> &[Box] { let events = self.frames_stack.forward().current_frame(); - // Select all of the last elements where e.timestamp >= from_timestamp. + // Select all of the last elements where `e.timestamp >= from_timestamp`. // Note, that using binary search here is dangerous, because the logs are not sorted by timestamp. events .rsplit(|e| e.timestamp < from_timestamp) diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/old_vm/history_recorder.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/old_vm/history_recorder.rs index fc6179cb1481..e862f57898ae 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/old_vm/history_recorder.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/old_vm/history_recorder.rs @@ -12,14 +12,14 @@ use zksync_utils::{h256_to_u256, u256_to_h256}; pub(crate) type MemoryWithHistory = HistoryRecorder; pub(crate) type IntFrameManagerWithHistory = HistoryRecorder, H>; -// Within the same cycle, timestamps in range timestamp..timestamp+TIME_DELTA_PER_CYCLE-1 +// Within the same cycle, timestamps in range `timestamp..timestamp+TIME_DELTA_PER_CYCLE-1` // can be used. This can sometimes violate monotonicity of the timestamp within the // same cycle, so it should be normalized. #[inline] fn normalize_timestamp(timestamp: Timestamp) -> Timestamp { let timestamp = timestamp.0; - // Making sure it is divisible by TIME_DELTA_PER_CYCLE + // Making sure it is divisible by `TIME_DELTA_PER_CYCLE` Timestamp(timestamp - timestamp % zkevm_opcode_defs::TIME_DELTA_PER_CYCLE) } diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/old_vm/memory.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/old_vm/memory.rs index 8568d6c72157..9219126d76e8 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/old_vm/memory.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/old_vm/memory.rs @@ -282,7 +282,7 @@ impl Memory for SimpleMemory { let returndata_page = returndata_fat_pointer.memory_page; for &page in current_observable_pages { - // If the page's number is greater than or equal to the base_page, + // If the page's number is greater than or equal to the `base_page`, // it means that it was created by the internal calls of this contract. // We need to add this check as the calldata pointer is also part of the // observable pages. @@ -299,7 +299,7 @@ impl Memory for SimpleMemory { } } -// It is expected that there is some intersection between [word_number*32..word_number*32+31] and [start, end] +// It is expected that there is some intersection between `[word_number*32..word_number*32+31]` and `[start, end]` fn extract_needed_bytes_from_word( word_value: Vec, word_number: usize, @@ -307,7 +307,7 @@ fn extract_needed_bytes_from_word( end: usize, ) -> Vec { let word_start = word_number * 32; - let word_end = word_start + 31; // Note, that at word_start + 32 a new word already starts + let word_end = word_start + 31; // Note, that at `word_start + 32` a new word already starts let intersection_left = std::cmp::max(word_start, start); let intersection_right = std::cmp::min(word_end, end); diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/old_vm/oracles/decommitter.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/old_vm/oracles/decommitter.rs index 6705831dbade..9a7addc97e11 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/old_vm/oracles/decommitter.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/old_vm/oracles/decommitter.rs @@ -15,7 +15,7 @@ use crate::vm_refunds_enhancement::old_vm::history_recorder::{ HistoryEnabled, HistoryMode, HistoryRecorder, WithHistory, }; -/// The main job of the DecommiterOracle is to implement the DecommittmentProcessor trait - that is +/// The main job of the DecommiterOracle is to implement the DecommitmentProcessor trait - that is /// used by the VM to 'load' bytecodes into memory. #[derive(Debug)] pub struct DecommitterOracle { diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/old_vm/utils.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/old_vm/utils.rs index bc4b2c3eff15..c2478edf7a89 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/old_vm/utils.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/old_vm/utils.rs @@ -122,7 +122,7 @@ pub(crate) fn vm_may_have_ended_inner( } (false, _) => None, (true, l) if l == outer_eh_location => { - // check r1,r2,r3 + // check `r1,r2,r3` if vm.local_state.flags.overflow_or_less_than_flag { Some(VmExecutionResult::Panic) } else { diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/oracles/storage.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/oracles/storage.rs index b970a8a95f73..40b2d83030a2 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/oracles/storage.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/oracles/storage.rs @@ -7,17 +7,20 @@ use zk_evm_1_3_3::{ }; use zksync_state::{StoragePtr, WriteStorage}; use zksync_types::{ - utils::storage_key_for_eth_balance, AccountTreeId, Address, StorageKey, StorageLogQuery, - StorageLogQueryType, BOOTLOADER_ADDRESS, U256, + utils::storage_key_for_eth_balance, AccountTreeId, Address, StorageKey, StorageLogQueryType, + BOOTLOADER_ADDRESS, U256, }; use zksync_utils::u256_to_h256; -use crate::vm_refunds_enhancement::old_vm::{ - history_recorder::{ - AppDataFrameManagerWithHistory, HashMapHistoryEvent, HistoryEnabled, HistoryMode, - HistoryRecorder, StorageWrapper, VectorHistoryEvent, WithHistory, +use crate::vm_refunds_enhancement::{ + old_vm::{ + history_recorder::{ + AppDataFrameManagerWithHistory, HashMapHistoryEvent, HistoryEnabled, HistoryMode, + HistoryRecorder, StorageWrapper, VectorHistoryEvent, WithHistory, + }, + oracles::OracleWithHistory, }, - oracles::OracleWithHistory, + utils::logs::StorageLogQuery, }; // While the storage does not support different shards, it was decided to write the @@ -48,7 +51,7 @@ pub struct StorageOracle { pub(crate) paid_changes: HistoryRecorder, H>, // The map that contains all the first values read from storage for each slot. - // While formally it does not have to be rollbackable, we still do it to avoid memory bloat + // While formally it does not have to be capable of rolling back, we still do it to avoid memory bloat // for unused slots. pub(crate) initial_values: HistoryRecorder, H>, @@ -182,7 +185,7 @@ impl StorageOracle { let required_pubdata = self.base_price_for_write(&key, first_slot_value, current_slot_value); - // We assume that "prepaid_for_slot" represents both the number of pubdata published and the number of bytes paid by the previous transactions + // We assume that `prepaid_for_slot` represents both the number of pubdata published and the number of bytes paid by the previous transactions // as they should be identical. let prepaid_for_slot = self .pre_paid_changes @@ -252,7 +255,7 @@ impl StorageOracle { ) -> &[Box] { let logs = self.frames_stack.forward().current_frame(); - // Select all of the last elements where l.log_query.timestamp >= from_timestamp. + // Select all of the last elements where `l.log_query.timestamp >= from_timestamp`. // Note, that using binary search here is dangerous, because the logs are not sorted by timestamp. logs.rsplit(|l| l.log_query.timestamp < from_timestamp) .next() @@ -300,6 +303,7 @@ impl VmStorageOracle for StorageOracle { _monotonic_cycle_counter: u32, query: LogQuery, ) -> LogQuery { + // ``` // tracing::trace!( // "execute partial query cyc {:?} addr {:?} key {:?}, rw {:?}, wr {:?}, tx {:?}", // _monotonic_cycle_counter, @@ -309,6 +313,7 @@ impl VmStorageOracle for StorageOracle { // query.written_value, // query.tx_number_in_block // ); + // ``` assert!(!query.rollback); if query.rw_flag { // The number of bytes that have been compensated by the user to perform this write @@ -394,7 +399,7 @@ impl VmStorageOracle for StorageOracle { ); // Additional validation that the current value was correct - // Unwrap is safe because the return value from write_inner is the previous value in this leaf. + // Unwrap is safe because the return value from `write_inner` is the previous value in this leaf. // It is impossible to set leaf value to `None` assert_eq!(current_value, written_value); } @@ -408,8 +413,8 @@ impl VmStorageOracle for StorageOracle { /// Returns the number of bytes needed to publish a slot. // Since we need to publish the state diffs onchain, for each of the updated storage slot -// we basically need to publish the following pair: (). -// While new_value is always 32 bytes long, for key we use the following optimization: +// we basically need to publish the following pair: `()`. +// While `new_value` is always 32 bytes long, for key we use the following optimization: // - The first time we publish it, we use 32 bytes. // Then, we remember a 8-byte id for this slot and assign it to it. We call this initial write. // - The second time we publish it, we will use this 8-byte instead of the 32 bytes of the entire key. diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/tests/utils.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/tests/utils.rs index b88b4ced89dc..3a936f95681d 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/tests/utils.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/tests/utils.rs @@ -61,8 +61,8 @@ pub(crate) fn read_test_contract() -> Vec { pub(crate) fn get_bootloader(test: &str) -> SystemContractCode { let bootloader_code = read_zbin_bytecode(format!( - "contracts/system-contracts/bootloader/tests/artifacts/{}.yul/{}.yul.zbin", - test, test + "contracts/system-contracts/bootloader/tests/artifacts/{}.yul.zbin", + test )); let bootloader_hash = hash_bytecode(&bootloader_code); diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/tracers/default_tracers.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/tracers/default_tracers.rs index 8e9c0f11aba4..b5787a6ec47f 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/tracers/default_tracers.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/tracers/default_tracers.rs @@ -1,6 +1,7 @@ use std::fmt::{Debug, Formatter}; use zk_evm_1_3_3::{ + aux_structures::Timestamp, tracing::{ AfterDecodingData, AfterExecutionData, BeforeExecutionData, Tracer, VmLocalStateData, }, @@ -9,7 +10,6 @@ use zk_evm_1_3_3::{ zkevm_opcode_defs::{decoding::EncodingModeProduction, Opcode, RetOpcode}, }; use zksync_state::{StoragePtr, WriteStorage}; -use zksync_types::Timestamp; use crate::{ interface::{ @@ -49,7 +49,7 @@ pub(crate) struct DefaultExecutionTracer { pub(crate) result_tracer: ResultTracer, // This tracer is designed specifically for calculating refunds. Its separation from the custom tracer // ensures static dispatch, enhancing performance by avoiding dynamic dispatch overhead. - // Additionally, being an internal tracer, it saves the results directly to VmResultAndLogs. + // Additionally, being an internal tracer, it saves the results directly to `VmResultAndLogs`. pub(crate) refund_tracer: Option, pub(crate) dispatcher: TracerDispatcher, ret_from_the_bootloader: Option, @@ -291,7 +291,7 @@ impl VmTracer for DefaultExecutionTracer< } fn current_frame_is_bootloader(local_state: &VmLocalState) -> bool { - // The current frame is bootloader if the callstack depth is 1. + // The current frame is bootloader if the call stack depth is 1. // Some of the near calls inside the bootloader can be out of gas, which is totally normal behavior // and it shouldn't result in `is_bootloader_out_of_gas` becoming true. local_state.callstack.inner.len() == 1 diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/tracers/refunds.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/tracers/refunds.rs index f906cef6230b..20e799a3883d 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/tracers/refunds.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/tracers/refunds.rs @@ -31,6 +31,7 @@ use crate::{ }, }, types::internals::ZkSyncVmState, + utils::fee::get_batch_base_fee, }, }; @@ -111,13 +112,14 @@ impl RefundsTracer { }); // For now, bootloader charges only for base fee. - let effective_gas_price = self.l1_batch.base_fee(); + let effective_gas_price = get_batch_base_fee(&self.l1_batch); let bootloader_eth_price_per_pubdata_byte = U256::from(effective_gas_price) * U256::from(current_ergs_per_pubdata_byte); - let fair_eth_price_per_pubdata_byte = - U256::from(eth_price_per_pubdata_byte(self.l1_batch.l1_gas_price)); + let fair_eth_price_per_pubdata_byte = U256::from(eth_price_per_pubdata_byte( + self.l1_batch.fee_input.l1_gas_price(), + )); // For now, L1 originated transactions are allowed to pay less than fair fee per pubdata, // so we should take it into account. @@ -127,7 +129,7 @@ impl RefundsTracer { ); let fair_fee_eth = U256::from(gas_spent_on_computation) - * U256::from(self.l1_batch.fair_l2_gas_price) + * U256::from(self.l1_batch.fee_input.fair_l2_gas_price()) + U256::from(pubdata_published) * eth_price_per_pubdata_byte_for_calculation; let pre_paid_eth = U256::from(tx_gas_limit) * U256::from(effective_gas_price); let refund_eth = pre_paid_eth.checked_sub(fair_fee_eth).unwrap_or_else(|| { @@ -209,8 +211,8 @@ impl VmTracer for RefundsTracer { #[vise::register] static METRICS: vise::Global = vise::Global::new(); - // This means that the bootloader has informed the system (usually via VMHooks) - that some gas - // should be refunded back (see askOperatorForRefund in bootloader.yul for details). + // This means that the bootloader has informed the system (usually via `VMHooks`) - that some gas + // should be refunded back (see `askOperatorForRefund` in `bootloader.yul` for details). if let Some(bootloader_refund) = self.requested_refund() { assert!( self.operator_refund.is_none(), diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/tracers/result_tracer.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/tracers/result_tracer.rs index 1281b416bb47..22cf08c8ef93 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/tracers/result_tracer.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/tracers/result_tracer.rs @@ -52,7 +52,7 @@ impl ResultTracer { } fn current_frame_is_bootloader(local_state: &VmLocalState) -> bool { - // The current frame is bootloader if the callstack depth is 1. + // The current frame is bootloader if the call stack depth is 1. // Some of the near calls inside the bootloader can be out of gas, which is totally normal behavior // and it shouldn't result in `is_bootloader_out_of_gas` becoming true. local_state.callstack.inner.len() == 1 @@ -151,7 +151,7 @@ impl ResultTracer { }); } VmExecutionResult::Revert(output) => { - // Unlike VmHook::ExecutionResult, vm has completely finished and returned not only the revert reason, + // Unlike `VmHook::ExecutionResult`, vm has completely finished and returned not only the revert reason, // but with bytecode, which represents the type of error from the bootloader side let revert_reason = TxRevertReason::parse_error(&output); diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/tracers/utils.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/tracers/utils.rs index 8de2ad181f47..ccacea0cd7e4 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/tracers/utils.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/tracers/utils.rs @@ -55,7 +55,7 @@ impl VmHook { let value = data.src1_value.value; - // Only UMA opcodes in the bootloader serve for vm hooks + // Only `UMA` opcodes in the bootloader serve for vm hooks if !matches!(opcode_variant.opcode, Opcode::UMA(UMAOpcode::HeapWrite)) || heap_page != BOOTLOADER_HEAP_PAGE || fat_ptr.offset != VM_HOOK_POSITION * 32 diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/types/internals/transaction_data.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/types/internals/transaction_data.rs index 4b70a79fdd4c..1493cf7e59da 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/types/internals/transaction_data.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/types/internals/transaction_data.rs @@ -11,8 +11,9 @@ use zksync_types::{ }; use zksync_utils::{address_to_h256, bytecode::hash_bytecode, bytes_to_be_words, h256_to_u256}; -use crate::vm_refunds_enhancement::utils::overhead::{ - get_amortized_overhead, OverheadCoefficients, +use crate::vm_refunds_enhancement::{ + constants::MAX_GAS_PER_PUBDATA_BYTE, + utils::overhead::{get_amortized_overhead, OverheadCoefficients}, }; /// This structure represents the data that is used by @@ -61,12 +62,22 @@ impl From for TransactionData { U256::zero() }; + // Ethereum transactions do not sign gas per pubdata limit, and so for them we need to use + // some default value. We use the maximum possible value that is allowed by the bootloader + // (i.e. we can not use u64::MAX, because the bootloader requires gas per pubdata for such + // transactions to be higher than `MAX_GAS_PER_PUBDATA_BYTE`). + let gas_per_pubdata_limit = if common_data.transaction_type.is_ethereum_type() { + MAX_GAS_PER_PUBDATA_BYTE.into() + } else { + common_data.fee.gas_per_pubdata_limit + }; + TransactionData { tx_type: (common_data.transaction_type as u32) as u8, from: common_data.initiator_address, to: execute_tx.execute.contract_address, gas_limit: common_data.fee.gas_limit, - pubdata_price_limit: common_data.fee.gas_per_pubdata_limit, + pubdata_price_limit: gas_per_pubdata_limit, max_fee_per_gas: common_data.fee.max_fee_per_gas, max_priority_fee_per_gas: common_data.fee.max_priority_fee_per_gas, paymaster: common_data.paymaster_params.paymaster, @@ -236,7 +247,7 @@ impl TransactionData { let l2_tx: L2Tx = self.clone().try_into().unwrap(); let transaction_request: TransactionRequest = l2_tx.into(); - // It is assumed that the TransactionData always has all the necessary components to recover the hash. + // It is assumed that the `TransactionData` always has all the necessary components to recover the hash. transaction_request .get_tx_hash(chain_id) .expect("Could not recover L2 transaction hash") diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/types/internals/vm_state.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/types/internals/vm_state.rs index 48c1e1f082f2..756bd2e71094 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/types/internals/vm_state.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/types/internals/vm_state.rs @@ -9,12 +9,10 @@ use zk_evm_1_3_3::{ STARTING_BASE_PAGE, STARTING_TIMESTAMP, }, }; +use zkevm_test_harness_1_3_3::INITIAL_MONOTONIC_CYCLE_COUNTER; use zksync_state::{StoragePtr, WriteStorage}; use zksync_system_constants::BOOTLOADER_ADDRESS; -use zksync_types::{ - block::MiniblockHasher, zkevm_test_harness::INITIAL_MONOTONIC_CYCLE_COUNTER, Address, - MiniblockNumber, -}; +use zksync_types::{block::MiniblockHasher, Address, MiniblockNumber}; use zksync_utils::h256_to_u256; use crate::{ diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/types/l1_batch.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/types/l1_batch.rs index 6f16e95f8d77..b449165be348 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/types/l1_batch.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/types/l1_batch.rs @@ -1,7 +1,7 @@ use zksync_types::U256; use zksync_utils::{address_to_u256, h256_to_u256}; -use crate::interface::L1BatchEnv; +use crate::{interface::L1BatchEnv, vm_refunds_enhancement::utils::fee::get_batch_base_fee}; const OPERATOR_ADDRESS_SLOT: usize = 0; const PREV_BLOCK_HASH_SLOT: usize = 1; @@ -19,6 +19,8 @@ pub(crate) fn bootloader_initial_memory(l1_batch: &L1BatchEnv) -> Vec<(usize, U2 .map(|prev_block_hash| (h256_to_u256(prev_block_hash), U256::one())) .unwrap_or_default(); + let fee_input = l1_batch.fee_input.into_l1_pegged(); + vec![ ( OPERATOR_ADDRESS_SLOT, @@ -27,12 +29,15 @@ pub(crate) fn bootloader_initial_memory(l1_batch: &L1BatchEnv) -> Vec<(usize, U2 (PREV_BLOCK_HASH_SLOT, prev_block_hash), (NEW_BLOCK_TIMESTAMP_SLOT, U256::from(l1_batch.timestamp)), (NEW_BLOCK_NUMBER_SLOT, U256::from(l1_batch.number.0)), - (L1_GAS_PRICE_SLOT, U256::from(l1_batch.l1_gas_price)), + (L1_GAS_PRICE_SLOT, U256::from(fee_input.l1_gas_price)), ( FAIR_L2_GAS_PRICE_SLOT, - U256::from(l1_batch.fair_l2_gas_price), + U256::from(fee_input.fair_l2_gas_price), + ), + ( + EXPECTED_BASE_FEE_SLOT, + U256::from(get_batch_base_fee(l1_batch)), ), - (EXPECTED_BASE_FEE_SLOT, U256::from(l1_batch.base_fee())), (SHOULD_SET_NEW_BLOCK_SLOT, should_set_new_block), ] } diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/utils/fee.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/utils/fee.rs index cc6081d7a229..a2fccb596309 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/utils/fee.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/utils/fee.rs @@ -1,29 +1,53 @@ //! Utility functions for vm -use zksync_system_constants::MAX_GAS_PER_PUBDATA_BYTE; +use zksync_types::fee_model::L1PeggedBatchFeeModelInput; use zksync_utils::ceil_div; -use crate::vm_refunds_enhancement::old_vm::utils::eth_price_per_pubdata_byte; +use crate::{ + vm_latest::L1BatchEnv, + vm_refunds_enhancement::{ + constants::MAX_GAS_PER_PUBDATA_BYTE, old_vm::utils::eth_price_per_pubdata_byte, + }, +}; /// Calculates the amount of gas required to publish one byte of pubdata -pub fn base_fee_to_gas_per_pubdata(l1_gas_price: u64, base_fee: u64) -> u64 { +pub(crate) fn base_fee_to_gas_per_pubdata(l1_gas_price: u64, base_fee: u64) -> u64 { let eth_price_per_pubdata_byte = eth_price_per_pubdata_byte(l1_gas_price); ceil_div(eth_price_per_pubdata_byte, base_fee) } /// Calculates the base fee and gas per pubdata for the given L1 gas price. -pub fn derive_base_fee_and_gas_per_pubdata(l1_gas_price: u64, fair_gas_price: u64) -> (u64, u64) { +pub(crate) fn derive_base_fee_and_gas_per_pubdata( + fee_input: L1PeggedBatchFeeModelInput, +) -> (u64, u64) { + let L1PeggedBatchFeeModelInput { + l1_gas_price, + fair_l2_gas_price, + } = fee_input; let eth_price_per_pubdata_byte = eth_price_per_pubdata_byte(l1_gas_price); - // The baseFee is set in such a way that it is always possible for a transaction to + // The `baseFee` is set in such a way that it is always possible for a transaction to // publish enough public data while compensating us for it. let base_fee = std::cmp::max( - fair_gas_price, + fair_l2_gas_price, ceil_div(eth_price_per_pubdata_byte, MAX_GAS_PER_PUBDATA_BYTE), ); ( base_fee, - base_fee_to_gas_per_pubdata(l1_gas_price, base_fee), + base_fee_to_gas_per_pubdata(fee_input.l1_gas_price, base_fee), ) } + +pub(crate) fn get_batch_base_fee(l1_batch_env: &L1BatchEnv) -> u64 { + if let Some(base_fee) = l1_batch_env.enforced_base_fee { + return base_fee; + } + let (base_fee, _) = + derive_base_fee_and_gas_per_pubdata(l1_batch_env.fee_input.into_l1_pegged()); + base_fee +} + +pub(crate) fn get_batch_gas_per_pubdata(l1_batch_env: &L1BatchEnv) -> u64 { + derive_base_fee_and_gas_per_pubdata(l1_batch_env.fee_input.into_l1_pegged()).1 +} diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/utils/l2_blocks.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/utils/l2_blocks.rs index 5dd26c4c0277..e5832f7f5879 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/utils/l2_blocks.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/utils/l2_blocks.rs @@ -68,7 +68,7 @@ pub fn load_last_l2_block(storage: StoragePtr) -> Option u32 { - // Even if the gas limit is greater than the MAX_TX_ERGS_LIMIT, we assume that everything beyond MAX_TX_ERGS_LIMIT + // Even if the gas limit is greater than the `MAX_TX_ERGS_LIMIT`, we assume that everything beyond `MAX_TX_ERGS_LIMIT` // will be spent entirely on publishing bytecodes and so we derive the overhead solely based on the capped value let gas_limit = std::cmp::min(MAX_TX_ERGS_LIMIT, gas_limit); @@ -23,8 +23,8 @@ pub fn derive_overhead( let gas_limit = U256::from(gas_limit); let encoded_len = U256::from(encoded_len); - // The MAX_TX_ERGS_LIMIT is formed in a way that may fulfills a single-instance circuits - // if used in full. That is, within MAX_TX_ERGS_LIMIT it is possible to fully saturate all the single-instance + // The `MAX_TX_ERGS_LIMIT` is formed in a way that may fulfills a single-instance circuits + // if used in full. That is, within `MAX_TX_ERGS_LIMIT` it is possible to fully saturate all the single-instance // circuits. let overhead_for_single_instance_circuits = ceil_div_u256(gas_limit * max_block_overhead, MAX_TX_ERGS_LIMIT.into()); @@ -38,15 +38,17 @@ pub fn derive_overhead( // The overhead for occupying a single tx slot let tx_slot_overhead = ceil_div_u256(max_block_overhead, MAX_TXS_IN_BLOCK.into()); - // We use "ceil" here for formal reasons to allow easier approach for calculating the overhead in O(1) - // let max_pubdata_in_tx = ceil_div_u256(gas_limit, gas_price_per_pubdata); + // We use `ceil` here for formal reasons to allow easier approach for calculating the overhead in O(1) + // `let max_pubdata_in_tx = ceil_div_u256(gas_limit, gas_price_per_pubdata);` // The maximal potential overhead from pubdata // TODO (EVM-67): possibly use overhead for pubdata + // ``` // let pubdata_overhead = ceil_div_u256( // max_pubdata_in_tx * max_block_overhead, // MAX_PUBDATA_PER_BLOCK.into(), // ); + // ``` vec![ (coefficients.ergs_limit_overhead_coeficient @@ -102,8 +104,8 @@ impl OverheadCoefficients { OverheadCoefficients::new_checked( 1.0, 1.0, // For L2 transactions we allow a certain default discount with regard to the number of ergs. - // Multiinstance circuits can in theory be spawned infinite times, while projected future limitations - // on gas per pubdata allow for roughly 800kk gas per L1 batch, so the rough trust "discount" on the proof's part + // Multi-instance circuits can in theory be spawned infinite times, while projected future limitations + // on gas per pubdata allow for roughly 800k gas per L1 batch, so the rough trust "discount" on the proof's part // to be paid by the users is 0.1. 0.1, ) @@ -132,28 +134,28 @@ pub(crate) fn get_amortized_overhead( let encoded_len = U256::from(encoded_len); // Derivation of overhead consists of 4 parts: - // 1. The overhead for taking up a transaction's slot. (O1): O1 = 1 / MAX_TXS_IN_BLOCK - // 2. The overhead for taking up the bootloader's memory (O2): O2 = encoded_len / BOOTLOADER_TX_ENCODING_SPACE - // 3. The overhead for possible usage of pubdata. (O3): O3 = max_pubdata_in_tx / MAX_PUBDATA_PER_BLOCK - // 4. The overhead for possible usage of all the single-instance circuits. (O4): O4 = gas_limit / MAX_TX_ERGS_LIMIT + // 1. The overhead for taking up a transaction's slot. `(O1): O1 = 1 / MAX_TXS_IN_BLOCK` + // 2. The overhead for taking up the bootloader's memory `(O2): O2 = encoded_len / BOOTLOADER_TX_ENCODING_SPACE` + // 3. The overhead for possible usage of pubdata. `(O3): O3 = max_pubdata_in_tx / MAX_PUBDATA_PER_BLOCK` + // 4. The overhead for possible usage of all the single-instance circuits. `(O4): O4 = gas_limit / MAX_TX_ERGS_LIMIT` // // The maximum of these is taken to derive the part of the block's overhead to be paid by the users: // - // max_overhead = max(O1, O2, O3, O4) - // overhead_gas = ceil(max_overhead * overhead_for_block_gas). Thus, overhead_gas is a function of - // tx_gas_limit, gas_per_pubdata_byte_limit and encoded_len. + // `max_overhead = max(O1, O2, O3, O4)` + // `overhead_gas = ceil(max_overhead * overhead_for_block_gas)`. Thus, `overhead_gas` is a function of + // `tx_gas_limit`, `gas_per_pubdata_byte_limit` and `encoded_len`. // - // While it is possible to derive the overhead with binary search in O(log n), it is too expensive to be done + // While it is possible to derive the overhead with binary search in `O(log n)`, it is too expensive to be done // on L1, so here is a reference implementation of finding the overhead for transaction in O(1): // - // Given total_gas_limit = tx_gas_limit + overhead_gas, we need to find overhead_gas and tx_gas_limit, such that: - // 1. overhead_gas is maximal possible (the operator is paid fairly) - // 2. overhead_gas(tx_gas_limit, gas_per_pubdata_byte_limit, encoded_len) >= overhead_gas (the user does not overpay) + // Given `total_gas_limit = tx_gas_limit + overhead_gas`, we need to find `overhead_gas` and `tx_gas_limit`, such that: + // 1. `overhead_gas` is maximal possible (the operator is paid fairly) + // 2. `overhead_gas(tx_gas_limit, gas_per_pubdata_byte_limit, encoded_len) >= overhead_gas` (the user does not overpay) // The third part boils to the following 4 inequalities (at least one of these must hold): - // ceil(O1 * overhead_for_block_gas) >= overhead_gas - // ceil(O2 * overhead_for_block_gas) >= overhead_gas - // ceil(O3 * overhead_for_block_gas) >= overhead_gas - // ceil(O4 * overhead_for_block_gas) >= overhead_gas + // `ceil(O1 * overhead_for_block_gas) >= overhead_gas` + // `ceil(O2 * overhead_for_block_gas) >= overhead_gas` + // `ceil(O3 * overhead_for_block_gas) >= overhead_gas` + // `ceil(O4 * overhead_for_block_gas) >= overhead_gas` // // Now, we need to solve each of these separately: @@ -164,7 +166,7 @@ pub(crate) fn get_amortized_overhead( (coefficients.slot_overhead_coeficient * tx_slot_overhead as f64).floor() as u32 }; - // 2. The overhead for occupying the bootloader memory can be derived from encoded_len + // 2. The overhead for occupying the bootloader memory can be derived from `encoded_len` let overhead_for_length = { let overhead_for_length = ceil_div_u256( encoded_len * overhead_for_block_gas, @@ -177,15 +179,18 @@ pub(crate) fn get_amortized_overhead( }; // TODO (EVM-67): possibly include the overhead for pubdata. The formula below has not been properly maintained, - // since the pubdat is not published. If decided to use the pubdata overhead, it needs to be updated. - // 3. ceil(O3 * overhead_for_block_gas) >= overhead_gas - // O3 = max_pubdata_in_tx / MAX_PUBDATA_PER_BLOCK = ceil(gas_limit / gas_per_pubdata_byte_limit) / MAX_PUBDATA_PER_BLOCK - // >= (gas_limit / (gas_per_pubdata_byte_limit * MAX_PUBDATA_PER_BLOCK). Throwing off the `ceil`, while may provide marginally lower + // since the pubdata is not published. If decided to use the pubdata overhead, it needs to be updated. + // ``` + // 3. ceil(O3 * overhead_for_block_gas) >= overhead_gas` + // O3 = max_pubdata_in_tx / MAX_PUBDATA_PER_BLOCK = ceil(gas_limit / gas_per_pubdata_byte_limit) / MAX_PUBDATA_PER_BLOCK` + // >= (gas_limit / (gas_per_pubdata_byte_limit * MAX_PUBDATA_PER_BLOCK). + // ``` + // Throwing off the `ceil`, while may provide marginally lower // overhead to the operator, provides substantially easier formula to work with. // - // For better clarity, let's denote gas_limit = GL, MAX_PUBDATA_PER_BLOCK = MP, gas_per_pubdata_byte_limit = EP, overhead_for_block_gas = OB, total_gas_limit = TL, overhead_gas = OE - // ceil(OB * (TL - OE) / (EP * MP)) >= OE - // + // For better clarity, let's denote `gas_limit = GL, MAX_PUBDATA_PER_BLOCK = MP, gas_per_pubdata_byte_limit = EP, overhead_for_block_gas = OB, total_gas_limit = TL, overhead_gas = OE` + // `ceil(OB * (TL - OE) / (EP * MP)) >= OE` + // ``` // OB * (TL - OE) / (MP * EP) > OE - 1 // OB * (TL - OE) > (OE - 1) * EP * MP // OB * TL + EP * MP > OE * EP * MP + OE * OB @@ -196,7 +201,7 @@ pub(crate) fn get_amortized_overhead( // + gas_per_pubdata_byte_limit * U256::from(MAX_PUBDATA_PER_BLOCK); // let denominator = // gas_per_pubdata_byte_limit * U256::from(MAX_PUBDATA_PER_BLOCK) + overhead_for_block_gas; - + // // // Corner case: if `total_gas_limit` = `gas_per_pubdata_byte_limit` = 0 // // then the numerator will be 0 and subtracting 1 will cause a panic, so we just return a zero. // if numerator.is_zero() { @@ -205,7 +210,7 @@ pub(crate) fn get_amortized_overhead( // (numerator - 1) / denominator // } // }; - + // // 4. K * ceil(O4 * overhead_for_block_gas) >= overhead_gas, where K is the discount // O4 = gas_limit / MAX_TX_ERGS_LIMIT. Using the notation from the previous equation: // ceil(OB * GL / MAX_TX_ERGS_LIMIT) >= (OE / K) @@ -214,6 +219,7 @@ pub(crate) fn get_amortized_overhead( // OB * (TL - OE) > (OE/K) * MAX_TX_ERGS_LIMIT - MAX_TX_ERGS_LIMIT // OB * TL + MAX_TX_ERGS_LIMIT > OE * ( MAX_TX_ERGS_LIMIT/K + OB) // OE = floor(OB * TL + MAX_TX_ERGS_LIMIT / (MAX_TX_ERGS_LIMIT/K + OB)), with possible -1 if the division is without remainder + // ``` let overhead_for_gas = { let numerator = overhead_for_block_gas * total_gas_limit + U256::from(MAX_TX_ERGS_LIMIT); let denominator: U256 = U256::from( @@ -228,16 +234,16 @@ pub(crate) fn get_amortized_overhead( let overhead = vec![tx_slot_overhead, overhead_for_length, overhead_for_gas] .into_iter() .max() - // For the sake of consistency making sure that total_gas_limit >= max_overhead + // For the sake of consistency making sure that `total_gas_limit >= max_overhead` .map(|max_overhead| std::cmp::min(max_overhead, total_gas_limit.as_u32())) .unwrap(); let limit_after_deducting_overhead = total_gas_limit - overhead; // During double checking of the overhead, the bootloader will assume that the - // body of the transaction does not have any more than MAX_L2_TX_GAS_LIMIT ergs available to it. + // body of the transaction does not have any more than `MAX_L2_TX_GAS_LIMIT` ergs available to it. if limit_after_deducting_overhead.as_u64() > MAX_L2_TX_GAS_LIMIT { - // We derive the same overhead that would exist for the MAX_L2_TX_GAS_LIMIT ergs + // We derive the same overhead that would exist for the `MAX_L2_TX_GAS_LIMIT` ergs derive_overhead( MAX_L2_TX_GAS_LIMIT as u32, gas_per_pubdata_byte_limit, @@ -270,7 +276,7 @@ mod tests { } else { 0u32 }; - // Safe cast: the gas_limit for a transaction can not be larger than 2^32 + // Safe cast: the `gas_limit` for a transaction can not be larger than `2^32` let mut right_bound = total_gas_limit; // The closure returns whether a certain overhead would be accepted by the bootloader. diff --git a/core/lib/multivm/src/versions/vm_refunds_enhancement/vm.rs b/core/lib/multivm/src/versions/vm_refunds_enhancement/vm.rs index 678a467d4474..2e4df854e5a7 100644 --- a/core/lib/multivm/src/versions/vm_refunds_enhancement/vm.rs +++ b/core/lib/multivm/src/versions/vm_refunds_enhancement/vm.rs @@ -1,8 +1,10 @@ +use zkevm_test_harness_1_3_3::witness::sort_storage_access::sort_storage_access_queries; use zksync_state::{StoragePtr, WriteStorage}; use zksync_types::{l2_to_l1_log::UserL2ToL1Log, Transaction}; use zksync_utils::bytecode::CompressedBytecodeInfo; use crate::{ + glue::GlueInto, interface::{ BootloaderMemory, BytecodeCompressionError, CurrentExecutionState, L1BatchEnv, L2BlockEnv, SystemEnv, VmExecutionMode, VmExecutionResultAndLogs, VmInterface, @@ -89,7 +91,7 @@ impl VmInterface for Vm { let l2_to_l1_logs = l1_messages .into_iter() - .map(|log| UserL2ToL1Log(log.into())) + .map(|log| UserL2ToL1Log(log.glue_into())) .collect(); let total_log_queries = self.state.event_sink.get_log_queries() + self @@ -99,15 +101,30 @@ impl VmInterface for Vm { .len() + self.state.storage.get_final_log_queries().len(); + let storage_log_queries = self.state.storage.get_final_log_queries(); + + let deduped_storage_log_queries = + sort_storage_access_queries(storage_log_queries.iter().map(|log| &log.log_query)).1; + CurrentExecutionState { events, - storage_log_queries: self.state.storage.get_final_log_queries(), + storage_log_queries: storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), + deduplicated_storage_log_queries: deduped_storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), used_contract_hashes: self.get_used_contracts(), user_l2_to_l1_logs: l2_to_l1_logs, system_logs: vec![], total_log_queries, cycles_used: self.state.local_state.monotonic_cycle_counter, - deduplicated_events_logs, + deduplicated_events_logs: deduplicated_events_logs + .into_iter() + .map(GlueInto::glue_into) + .collect(), storage_refunds: self.state.storage.returned_refunds.inner().clone(), } } @@ -118,16 +135,28 @@ impl VmInterface for Vm { dispatcher: Self::TracerDispatcher, tx: Transaction, with_compression: bool, - ) -> Result { + ) -> ( + Result<(), BytecodeCompressionError>, + VmExecutionResultAndLogs, + ) { self.push_transaction_with_compression(tx, with_compression); let result = self.inspect(dispatcher, VmExecutionMode::OneTx); if self.has_unpublished_bytecodes() { - Err(BytecodeCompressionError::BytecodeCompressionFailed) + ( + Err(BytecodeCompressionError::BytecodeCompressionFailed), + result, + ) } else { - Ok(result) + (Ok(()), result) } } + fn has_enough_gas_for_batch_tip(&self) -> bool { + // For this version this overhead has not been calculated and it has not been used with those versions. + // We return some value just in case for backwards compatibility + true + } + fn record_vm_memory_metrics(&self) -> VmMemoryMetrics { self.record_vm_memory_metrics_inner() } diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/bootloader_state/l2_block.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/bootloader_state/l2_block.rs index 8ce851d6699c..48284bcc2ac8 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/bootloader_state/l2_block.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/bootloader_state/l2_block.rs @@ -19,7 +19,7 @@ pub(crate) struct BootloaderL2Block { pub(crate) timestamp: u64, pub(crate) txs_rolling_hash: H256, // The rolling hash of all the transactions in the miniblock pub(crate) prev_block_hash: H256, - // Number of the first l2 block tx in l1 batch + // Number of the first L2 block tx in L1 batch pub(crate) first_tx_index: usize, pub(crate) max_virtual_blocks_to_create: u32, pub(super) txs: Vec, diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/bootloader_state/utils.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/bootloader_state/utils.rs index a3986d6fe463..9a682da3a5ab 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/bootloader_state/utils.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/bootloader_state/utils.rs @@ -92,8 +92,8 @@ pub(crate) fn apply_l2_block( bootloader_l2_block: &BootloaderL2Block, txs_index: usize, ) { - // Since L2 block infos start from the TX_OPERATOR_L2_BLOCK_INFO_OFFSET and each - // L2 block info takes TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO slots, the position where the L2 block info + // Since L2 block information start from the `TX_OPERATOR_L2_BLOCK_INFO_OFFSET` and each + // L2 block info takes `TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO` slots, the position where the L2 block info // for this transaction needs to be written is: let block_position = diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/constants.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/constants.rs index c03260f1b6de..0e0eab85877b 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/constants.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/constants.rs @@ -2,13 +2,30 @@ use zk_evm_1_3_3::aux_structures::MemoryPage; pub use zk_evm_1_3_3::zkevm_opcode_defs::system_params::{ ERGS_PER_CIRCUIT, INITIAL_STORAGE_WRITE_PUBDATA_BYTES, MAX_PUBDATA_PER_BLOCK, }; -use zksync_system_constants::{ - L1_GAS_PER_PUBDATA_BYTE, MAX_L2_TX_GAS_LIMIT, MAX_NEW_FACTORY_DEPS, MAX_TXS_IN_BLOCK, - USED_BOOTLOADER_MEMORY_WORDS, -}; +use zksync_system_constants::{L1_GAS_PER_PUBDATA_BYTE, MAX_L2_TX_GAS_LIMIT, MAX_NEW_FACTORY_DEPS}; use crate::vm_virtual_blocks::old_vm::utils::heap_page_from_base; +/// The size of the bootloader memory in bytes which is used by the protocol. +/// While the maximal possible size is a lot higher, we restrict ourselves to a certain limit to reduce +/// the requirements on RAM. +pub(crate) const USED_BOOTLOADER_MEMORY_BYTES: usize = 1 << 24; +pub(crate) const USED_BOOTLOADER_MEMORY_WORDS: usize = USED_BOOTLOADER_MEMORY_BYTES / 32; + +// This the number of pubdata such that it should be always possible to publish +// from a single transaction. Note, that these pubdata bytes include only bytes that are +// to be published inside the body of transaction (i.e. excluding of factory deps). +pub(crate) const GUARANTEED_PUBDATA_PER_L1_BATCH: u64 = 4000; + +// The users should always be able to provide `MAX_GAS_PER_PUBDATA_BYTE` gas per pubdata in their +// transactions so that they are able to send at least `GUARANTEED_PUBDATA_PER_L1_BATCH` bytes per +// transaction. +pub(crate) const MAX_GAS_PER_PUBDATA_BYTE: u64 = + MAX_L2_TX_GAS_LIMIT / GUARANTEED_PUBDATA_PER_L1_BATCH; + +// The maximal number of transactions in a single batch +pub(crate) const MAX_TXS_IN_BLOCK: usize = 1024; + /// Max cycles for a single transaction. pub const MAX_CYCLES_FOR_TX: u32 = u32::MAX; @@ -52,7 +69,7 @@ pub(crate) const BOOTLOADER_TX_DESCRIPTION_OFFSET: usize = COMPRESSED_BYTECODES_OFFSET + COMPRESSED_BYTECODES_SLOTS; /// The size of the bootloader memory dedicated to the encodings of transactions -pub const BOOTLOADER_TX_ENCODING_SPACE: u32 = +pub(crate) const BOOTLOADER_TX_ENCODING_SPACE: u32 = (USED_BOOTLOADER_MEMORY_WORDS - TX_DESCRIPTION_OFFSET - MAX_TXS_IN_BLOCK) as u32; // Size of the bootloader tx description in words diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/logs.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/logs.rs index 0d407efd0411..6c2b801c1d0f 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/logs.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/logs.rs @@ -6,6 +6,7 @@ use zksync_types::{ }; use crate::{ + glue::GlueInto, interface::types::outputs::VmExecutionLogs, vm_virtual_blocks::{ old_vm::{events::merge_events, utils::precompile_calls_count_after_timestamp}, @@ -44,7 +45,7 @@ impl Vm { let total_log_queries_count = storage_logs_count + log_queries.len() + precompile_calls_count; VmExecutionLogs { - storage_logs, + storage_logs: storage_logs.into_iter().map(GlueInto::glue_into).collect(), events, user_l2_to_l1_logs: l2_to_l1_logs.into_iter().map(UserL2ToL1Log).collect(), system_l2_to_l1_logs: vec![], @@ -64,6 +65,9 @@ impl Vm { .into_iter() .map(|e| e.into_vm_event(self.batch_env.number)) .collect(); - (events, l1_messages.into_iter().map(Into::into).collect()) + ( + events, + l1_messages.into_iter().map(GlueInto::glue_into).collect(), + ) } } diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/snapshots.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/snapshots.rs index 569e11150390..2b653333a5c1 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/snapshots.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/snapshots.rs @@ -35,8 +35,8 @@ impl Vm { pub(crate) fn make_snapshot_inner(&mut self) { self.snapshots.push(VmSnapshot { // Vm local state contains O(1) various parameters (registers/etc). - // The only "expensive" copying here is copying of the callstack. - // It will take O(callstack_depth) to copy it. + // The only "expensive" copying here is copying of the call stack. + // It will take `O(callstack_depth)` to copy it. // So it is generally recommended to get snapshots of the bootloader frame, // where the depth is 1. local_state: self.state.local_state.clone(), diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/statistics.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/statistics.rs index 074e8dae56ed..06ef4f90340e 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/statistics.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/statistics.rs @@ -38,8 +38,9 @@ impl Vm { gas_used: gas_remaining_before - gas_remaining_after, computational_gas_used, total_log_queries: total_log_queries_count, - // This field will be populated by the RefundTracer + // This field will be populated by the `RefundTracer` pubdata_published: 0, + circuit_statistic: Default::default(), } } diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/tx.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/tx.rs index 72a7dbc65de0..0f4705a633f2 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/tx.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/implementation/tx.rs @@ -7,6 +7,7 @@ use crate::{ constants::BOOTLOADER_HEAP_PAGE, implementation::bytecode::{bytecode_to_factory_dep, compress_bytecodes}, types::internals::TransactionData, + utils::fee::get_batch_gas_per_pubdata, vm::Vm, }, HistoryMode, @@ -38,8 +39,7 @@ impl Vm { .decommittment_processor .populate(codes_for_decommiter, timestamp); - let trusted_ergs_limit = - tx.trusted_ergs_limit(self.batch_env.block_gas_price_per_pubdata()); + let trusted_ergs_limit = tx.trusted_ergs_limit(get_batch_gas_per_pubdata(&self.batch_env)); let memory = self.bootloader_state.push_tx( tx, @@ -61,7 +61,7 @@ impl Vm { with_compression: bool, ) { let tx: TransactionData = tx.into(); - let block_gas_per_pubdata_byte = self.batch_env.block_gas_price_per_pubdata(); + let block_gas_per_pubdata_byte = get_batch_gas_per_pubdata(&self.batch_env); let overhead = tx.overhead_gas(block_gas_per_pubdata_byte as u32); self.push_raw_transaction(tx, overhead, 0, with_compression); } diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/event_sink.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/event_sink.rs index 02938594b5cf..00a03ca0adb8 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/event_sink.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/event_sink.rs @@ -50,7 +50,7 @@ impl InMemoryEventSink { pub fn log_queries_after_timestamp(&self, from_timestamp: Timestamp) -> &[Box] { let events = self.frames_stack.forward().current_frame(); - // Select all of the last elements where e.timestamp >= from_timestamp. + // Select all of the last elements where `e.timestamp >= from_timestamp`. // Note, that using binary search here is dangerous, because the logs are not sorted by timestamp. events .rsplit(|e| e.timestamp < from_timestamp) diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/history_recorder.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/history_recorder.rs index 6154dc8e24d6..baed63c14b89 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/history_recorder.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/history_recorder.rs @@ -12,14 +12,14 @@ use zksync_utils::{h256_to_u256, u256_to_h256}; pub(crate) type MemoryWithHistory = HistoryRecorder; pub(crate) type IntFrameManagerWithHistory = HistoryRecorder, H>; -// Within the same cycle, timestamps in range timestamp..timestamp+TIME_DELTA_PER_CYCLE-1 +// Within the same cycle, timestamps in range `timestamp..timestamp+TIME_DELTA_PER_CYCLE-1` // can be used. This can sometimes violate monotonicity of the timestamp within the // same cycle, so it should be normalized. #[inline] fn normalize_timestamp(timestamp: Timestamp) -> Timestamp { let timestamp = timestamp.0; - // Making sure it is divisible by TIME_DELTA_PER_CYCLE + // Making sure it is divisible by `TIME_DELTA_PER_CYCLE` Timestamp(timestamp - timestamp % zkevm_opcode_defs::TIME_DELTA_PER_CYCLE) } diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/memory.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/memory.rs index c78f8a9e7798..a48620db11ce 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/memory.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/memory.rs @@ -282,7 +282,7 @@ impl Memory for SimpleMemory { let returndata_page = returndata_fat_pointer.memory_page; for &page in current_observable_pages { - // If the page's number is greater than or equal to the base_page, + // If the page's number is greater than or equal to the `base_page`, // it means that it was created by the internal calls of this contract. // We need to add this check as the calldata pointer is also part of the // observable pages. @@ -299,7 +299,7 @@ impl Memory for SimpleMemory { } } -// It is expected that there is some intersection between [word_number*32..word_number*32+31] and [start, end] +// It is expected that there is some intersection between `[word_number*32..word_number*32+31]` and `[start, end]` fn extract_needed_bytes_from_word( word_value: Vec, word_number: usize, @@ -307,7 +307,7 @@ fn extract_needed_bytes_from_word( end: usize, ) -> Vec { let word_start = word_number * 32; - let word_end = word_start + 31; // Note, that at word_start + 32 a new word already starts + let word_end = word_start + 31; // Note, that at `word_start + 32` a new word already starts let intersection_left = std::cmp::max(word_start, start); let intersection_right = std::cmp::min(word_end, end); diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/oracles/decommitter.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/oracles/decommitter.rs index 061912f83c92..f01394cebb52 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/oracles/decommitter.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/oracles/decommitter.rs @@ -15,7 +15,7 @@ use crate::vm_virtual_blocks::old_vm::history_recorder::{ HistoryEnabled, HistoryMode, HistoryRecorder, WithHistory, }; -/// The main job of the DecommiterOracle is to implement the DecommittmentProcessor trait - that is +/// The main job of the DecommiterOracle is to implement the DecommitmentProcessor trait - that is /// used by the VM to 'load' bytecodes into memory. #[derive(Debug)] pub struct DecommitterOracle { diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/oracles/storage.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/oracles/storage.rs index 91c293f4ac80..b099930cbed4 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/oracles/storage.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/oracles/storage.rs @@ -7,15 +7,18 @@ use zk_evm_1_3_3::{ }; use zksync_state::{StoragePtr, WriteStorage}; use zksync_types::{ - utils::storage_key_for_eth_balance, AccountTreeId, Address, StorageKey, StorageLogQuery, - StorageLogQueryType, BOOTLOADER_ADDRESS, U256, + utils::storage_key_for_eth_balance, AccountTreeId, Address, StorageKey, StorageLogQueryType, + BOOTLOADER_ADDRESS, U256, }; use zksync_utils::u256_to_h256; use super::OracleWithHistory; -use crate::vm_virtual_blocks::old_vm::history_recorder::{ - AppDataFrameManagerWithHistory, HashMapHistoryEvent, HistoryEnabled, HistoryMode, - HistoryRecorder, StorageWrapper, WithHistory, +use crate::vm_virtual_blocks::{ + old_vm::history_recorder::{ + AppDataFrameManagerWithHistory, HashMapHistoryEvent, HistoryEnabled, HistoryMode, + HistoryRecorder, StorageWrapper, WithHistory, + }, + utils::logs::StorageLogQuery, }; // While the storage does not support different shards, it was decided to write the @@ -167,7 +170,7 @@ impl StorageOracle { ) -> &[Box] { let logs = self.frames_stack.forward().current_frame(); - // Select all of the last elements where l.log_query.timestamp >= from_timestamp. + // Select all of the last elements where `l.log_query.timestamp >= from_timestamp`. // Note, that using binary search here is dangerous, because the logs are not sorted by timestamp. logs.rsplit(|l| l.log_query.timestamp < from_timestamp) .next() @@ -208,13 +211,14 @@ impl StorageOracle { } impl VmStorageOracle for StorageOracle { - // Perform a storage read/write access by taking an partially filled query + // Perform a storage read / write access by taking an partially filled query // and returning filled query and cold/warm marker for pricing purposes fn execute_partial_query( &mut self, _monotonic_cycle_counter: u32, query: LogQuery, ) -> LogQuery { + // ``` // tracing::trace!( // "execute partial query cyc {:?} addr {:?} key {:?}, rw {:?}, wr {:?}, tx {:?}", // _monotonic_cycle_counter, @@ -224,6 +228,7 @@ impl VmStorageOracle for StorageOracle { // query.written_value, // query.tx_number_in_block // ); + // ``` assert!(!query.rollback); if query.rw_flag { // The number of bytes that have been compensated by the user to perform this write @@ -303,7 +308,7 @@ impl VmStorageOracle for StorageOracle { ); // Additional validation that the current value was correct - // Unwrap is safe because the return value from write_inner is the previous value in this leaf. + // Unwrap is safe because the return value from `write_inner` is the previous value in this leaf. // It is impossible to set leaf value to `None` assert_eq!(current_value, written_value); } @@ -317,8 +322,8 @@ impl VmStorageOracle for StorageOracle { /// Returns the number of bytes needed to publish a slot. // Since we need to publish the state diffs onchain, for each of the updated storage slot -// we basically need to publish the following pair: (). -// While new_value is always 32 bytes long, for key we use the following optimization: +// we basically need to publish the following pair: `()`. +// While `new_value` is always 32 bytes long, for key we use the following optimization: // - The first time we publish it, we use 32 bytes. // Then, we remember a 8-byte id for this slot and assign it to it. We call this initial write. // - The second time we publish it, we will use this 8-byte instead of the 32 bytes of the entire key. diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/utils.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/utils.rs index 7d38ba1058df..5be62e384378 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/utils.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/old_vm/utils.rs @@ -122,7 +122,7 @@ pub(crate) fn vm_may_have_ended_inner( } (false, _) => None, (true, l) if l == outer_eh_location => { - // check r1,r2,r3 + // check `r1,r2,r3` if vm.local_state.flags.overflow_or_less_than_flag { Some(VmExecutionResult::Panic) } else { diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/tests/utils.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/tests/utils.rs index ff309f5d6497..ca04d2fedf55 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/tests/utils.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/tests/utils.rs @@ -61,8 +61,8 @@ pub(crate) fn read_test_contract() -> Vec { pub(crate) fn get_bootloader(test: &str) -> SystemContractCode { let bootloader_code = read_zbin_bytecode(format!( - "contracts/system-contracts/bootloader/tests/artifacts/{}.yul/{}.yul.zbin", - test, test + "contracts/system-contracts/bootloader/tests/artifacts/{}.yul.zbin", + test )); let bootloader_hash = hash_bytecode(&bootloader_code); diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/tracers/default_tracers.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/tracers/default_tracers.rs index 463bdaa4f359..1e7780edda24 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/tracers/default_tracers.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/tracers/default_tracers.rs @@ -4,6 +4,7 @@ use std::{ }; use zk_evm_1_3_3::{ + aux_structures::Timestamp, tracing::{ AfterDecodingData, AfterExecutionData, BeforeExecutionData, Tracer, VmLocalStateData, }, @@ -12,7 +13,6 @@ use zk_evm_1_3_3::{ zkevm_opcode_defs::{Opcode, RetOpcode}, }; use zksync_state::{StoragePtr, WriteStorage}; -use zksync_types::Timestamp; use crate::{ interface::{dyn_tracers::vm_1_3_3::DynTracer, tracer::VmExecutionStopReason, VmExecutionMode}, @@ -271,7 +271,7 @@ impl DefaultExecutionTracer { } fn current_frame_is_bootloader(local_state: &VmLocalState) -> bool { - // The current frame is bootloader if the callstack depth is 1. + // The current frame is bootloader if the call stack depth is 1. // Some of the near calls inside the bootloader can be out of gas, which is totally normal behavior // and it shouldn't result in `is_bootloader_out_of_gas` becoming true. local_state.callstack.inner.len() == 1 diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/tracers/refunds.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/tracers/refunds.rs index 6051cd7bb7d8..c72d947dbca5 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/tracers/refunds.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/tracers/refunds.rs @@ -6,12 +6,12 @@ use zk_evm_1_3_3::{ tracing::{BeforeExecutionData, VmLocalStateData}, vm_state::VmLocalState, }; +use zkevm_test_harness_1_3_3::witness::sort_storage_access::sort_storage_access_queries; use zksync_state::{StoragePtr, WriteStorage}; use zksync_system_constants::{PUBLISH_BYTECODE_OVERHEAD, SYSTEM_CONTEXT_ADDRESS}; use zksync_types::{ event::{extract_long_l2_to_l1_messages, extract_published_bytecodes}, l2_to_l1_log::L2ToL1Log, - zkevm_test_harness::witness::sort_storage_access::sort_storage_access_queries, L1BatchNumber, StorageKey, U256, }; use zksync_utils::{bytecode::bytecode_len_in_bytes, ceil_div_u256, u256_to_h256}; @@ -32,6 +32,7 @@ use crate::{ }, }, types::internals::ZkSyncVmState, + utils::fee::get_batch_base_fee, }, }; @@ -109,13 +110,14 @@ impl RefundsTracer { }); // For now, bootloader charges only for base fee. - let effective_gas_price = self.l1_batch.base_fee(); + let effective_gas_price = get_batch_base_fee(&self.l1_batch); let bootloader_eth_price_per_pubdata_byte = U256::from(effective_gas_price) * U256::from(current_ergs_per_pubdata_byte); - let fair_eth_price_per_pubdata_byte = - U256::from(eth_price_per_pubdata_byte(self.l1_batch.l1_gas_price)); + let fair_eth_price_per_pubdata_byte = U256::from(eth_price_per_pubdata_byte( + self.l1_batch.fee_input.l1_gas_price(), + )); // For now, L1 originated transactions are allowed to pay less than fair fee per pubdata, // so we should take it into account. @@ -125,7 +127,7 @@ impl RefundsTracer { ); let fair_fee_eth = U256::from(gas_spent_on_computation) - * U256::from(self.l1_batch.fair_l2_gas_price) + * U256::from(self.l1_batch.fee_input.fair_l2_gas_price()) + U256::from(pubdata_published) * eth_price_per_pubdata_byte_for_calculation; let pre_paid_eth = U256::from(tx_gas_limit) * U256::from(effective_gas_price); let refund_eth = pre_paid_eth.checked_sub(fair_fee_eth).unwrap_or_else(|| { @@ -208,8 +210,8 @@ impl ExecutionProcessing for RefundsTrace #[vise::register] static METRICS: vise::Global = vise::Global::new(); - // This means that the bootloader has informed the system (usually via VMHooks) - that some gas - // should be refunded back (see askOperatorForRefund in bootloader.yul for details). + // This means that the bootloader has informed the system (usually via `VMHooks`) - that some gas + // should be refunded back (see `askOperatorForRefund` in `bootloader.yul` for details). if let Some(bootloader_refund) = self.requested_refund() { assert!( self.operator_refund.is_none(), diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/tracers/result_tracer.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/tracers/result_tracer.rs index 8c6a5d1793f8..3ba396fd0c4c 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/tracers/result_tracer.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/tracers/result_tracer.rs @@ -53,7 +53,7 @@ impl ResultTracer { } fn current_frame_is_bootloader(local_state: &VmLocalState) -> bool { - // The current frame is bootloader if the callstack depth is 1. + // The current frame is bootloader if the call stack depth is 1. // Some of the near calls inside the bootloader can be out of gas, which is totally normal behavior // and it shouldn't result in `is_bootloader_out_of_gas` becoming true. local_state.callstack.inner.len() == 1 @@ -152,7 +152,7 @@ impl ResultTracer { }); } VmExecutionResult::Revert(output) => { - // Unlike VmHook::ExecutionResult, vm has completely finished and returned not only the revert reason, + // Unlike `VmHook::ExecutionResult`, vm has completely finished and returned not only the revert reason, // but with bytecode, which represents the type of error from the bootloader side let revert_reason = TxRevertReason::parse_error(&output); diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/tracers/utils.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/tracers/utils.rs index b2358602fe05..1f3d27d9d20e 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/tracers/utils.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/tracers/utils.rs @@ -55,7 +55,7 @@ impl VmHook { let value = data.src1_value.value; - // Only UMA opcodes in the bootloader serve for vm hooks + // Only `UMA` opcodes in the bootloader serve for vm hooks if !matches!(opcode_variant.opcode, Opcode::UMA(UMAOpcode::HeapWrite)) || heap_page != BOOTLOADER_HEAP_PAGE || fat_ptr.offset != VM_HOOK_POSITION * 32 diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/types/internals/transaction_data.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/types/internals/transaction_data.rs index 6d2fe36868b0..6fee52542fc1 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/types/internals/transaction_data.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/types/internals/transaction_data.rs @@ -11,7 +11,10 @@ use zksync_types::{ }; use zksync_utils::{address_to_h256, bytecode::hash_bytecode, bytes_to_be_words, h256_to_u256}; -use crate::vm_virtual_blocks::utils::overhead::{get_amortized_overhead, OverheadCoefficients}; +use crate::vm_virtual_blocks::{ + constants::MAX_GAS_PER_PUBDATA_BYTE, + utils::overhead::{get_amortized_overhead, OverheadCoefficients}, +}; /// This structure represents the data that is used by /// the Bootloader to describe the transaction. @@ -59,12 +62,22 @@ impl From for TransactionData { U256::zero() }; + // Ethereum transactions do not sign gas per pubdata limit, and so for them we need to use + // some default value. We use the maximum possible value that is allowed by the bootloader + // (i.e. we can not use u64::MAX, because the bootloader requires gas per pubdata for such + // transactions to be higher than `MAX_GAS_PER_PUBDATA_BYTE`). + let gas_per_pubdata_limit = if common_data.transaction_type.is_ethereum_type() { + MAX_GAS_PER_PUBDATA_BYTE.into() + } else { + common_data.fee.gas_per_pubdata_limit + }; + TransactionData { tx_type: (common_data.transaction_type as u32) as u8, from: common_data.initiator_address, to: execute_tx.execute.contract_address, gas_limit: common_data.fee.gas_limit, - pubdata_price_limit: common_data.fee.gas_per_pubdata_limit, + pubdata_price_limit: gas_per_pubdata_limit, max_fee_per_gas: common_data.fee.max_fee_per_gas, max_priority_fee_per_gas: common_data.fee.max_priority_fee_per_gas, paymaster: common_data.paymaster_params.paymaster, @@ -234,7 +247,7 @@ impl TransactionData { let l2_tx: L2Tx = self.clone().try_into().unwrap(); let transaction_request: TransactionRequest = l2_tx.into(); - // It is assumed that the TransactionData always has all the necessary components to recover the hash. + // It is assumed that the `TransactionData` always has all the necessary components to recover the hash. transaction_request .get_tx_hash(chain_id) .expect("Could not recover L2 transaction hash") diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/types/internals/vm_state.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/types/internals/vm_state.rs index c2dc400439dc..b4ca53206502 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/types/internals/vm_state.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/types/internals/vm_state.rs @@ -9,12 +9,10 @@ use zk_evm_1_3_3::{ STARTING_BASE_PAGE, STARTING_TIMESTAMP, }, }; +use zkevm_test_harness_1_3_3::INITIAL_MONOTONIC_CYCLE_COUNTER; use zksync_state::{StoragePtr, WriteStorage}; use zksync_system_constants::BOOTLOADER_ADDRESS; -use zksync_types::{ - block::MiniblockHasher, zkevm_test_harness::INITIAL_MONOTONIC_CYCLE_COUNTER, Address, - MiniblockNumber, -}; +use zksync_types::{block::MiniblockHasher, Address, MiniblockNumber}; use zksync_utils::h256_to_u256; use crate::{ diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/types/l1_batch_env.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/types/l1_batch_env.rs index 0e43863b1965..f86d8749c9ed 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/types/l1_batch_env.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/types/l1_batch_env.rs @@ -1,7 +1,7 @@ use zksync_types::U256; use zksync_utils::{address_to_u256, h256_to_u256}; -use crate::interface::L1BatchEnv; +use crate::{interface::L1BatchEnv, vm_virtual_blocks::utils::fee::get_batch_base_fee}; const OPERATOR_ADDRESS_SLOT: usize = 0; const PREV_BLOCK_HASH_SLOT: usize = 1; @@ -27,12 +27,18 @@ pub(crate) fn bootloader_initial_memory(l1_batch_env: &L1BatchEnv) -> Vec<(usize (PREV_BLOCK_HASH_SLOT, prev_block_hash), (NEW_BLOCK_TIMESTAMP_SLOT, U256::from(l1_batch_env.timestamp)), (NEW_BLOCK_NUMBER_SLOT, U256::from(l1_batch_env.number.0)), - (L1_GAS_PRICE_SLOT, U256::from(l1_batch_env.l1_gas_price)), + ( + L1_GAS_PRICE_SLOT, + U256::from(l1_batch_env.fee_input.l1_gas_price()), + ), ( FAIR_L2_GAS_PRICE_SLOT, - U256::from(l1_batch_env.fair_l2_gas_price), + U256::from(l1_batch_env.fee_input.fair_l2_gas_price()), + ), + ( + EXPECTED_BASE_FEE_SLOT, + U256::from(get_batch_base_fee(l1_batch_env)), ), - (EXPECTED_BASE_FEE_SLOT, U256::from(l1_batch_env.base_fee())), (SHOULD_SET_NEW_BLOCK_SLOT, should_set_new_block), ] } diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/utils/fee.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/utils/fee.rs index 6753e8197813..14133553b04b 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/utils/fee.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/utils/fee.rs @@ -1,29 +1,54 @@ //! Utility functions for vm -use zksync_system_constants::MAX_GAS_PER_PUBDATA_BYTE; +use zksync_types::fee_model::L1PeggedBatchFeeModelInput; use zksync_utils::ceil_div; -use crate::vm_virtual_blocks::old_vm::utils::eth_price_per_pubdata_byte; +use crate::{ + vm_latest::L1BatchEnv, + vm_virtual_blocks::{ + constants::MAX_GAS_PER_PUBDATA_BYTE, old_vm::utils::eth_price_per_pubdata_byte, + }, +}; /// Calculates the amount of gas required to publish one byte of pubdata -pub fn base_fee_to_gas_per_pubdata(l1_gas_price: u64, base_fee: u64) -> u64 { +pub(crate) fn base_fee_to_gas_per_pubdata(l1_gas_price: u64, base_fee: u64) -> u64 { let eth_price_per_pubdata_byte = eth_price_per_pubdata_byte(l1_gas_price); ceil_div(eth_price_per_pubdata_byte, base_fee) } /// Calculates the base fee and gas per pubdata for the given L1 gas price. -pub fn derive_base_fee_and_gas_per_pubdata(l1_gas_price: u64, fair_gas_price: u64) -> (u64, u64) { +pub(crate) fn derive_base_fee_and_gas_per_pubdata( + fee_input: L1PeggedBatchFeeModelInput, +) -> (u64, u64) { + let L1PeggedBatchFeeModelInput { + l1_gas_price, + fair_l2_gas_price, + } = fee_input; + let eth_price_per_pubdata_byte = eth_price_per_pubdata_byte(l1_gas_price); - // The baseFee is set in such a way that it is always possible for a transaction to + // The `baseFee` is set in such a way that it is always possible for a transaction to // publish enough public data while compensating us for it. let base_fee = std::cmp::max( - fair_gas_price, + fair_l2_gas_price, ceil_div(eth_price_per_pubdata_byte, MAX_GAS_PER_PUBDATA_BYTE), ); ( base_fee, - base_fee_to_gas_per_pubdata(l1_gas_price, base_fee), + base_fee_to_gas_per_pubdata(fee_input.l1_gas_price, base_fee), ) } + +pub(crate) fn get_batch_base_fee(l1_batch_env: &L1BatchEnv) -> u64 { + if let Some(base_fee) = l1_batch_env.enforced_base_fee { + return base_fee; + } + let (base_fee, _) = + derive_base_fee_and_gas_per_pubdata(l1_batch_env.fee_input.into_l1_pegged()); + base_fee +} + +pub(crate) fn get_batch_gas_per_pubdata(l1_batch_env: &L1BatchEnv) -> u64 { + derive_base_fee_and_gas_per_pubdata(l1_batch_env.fee_input.into_l1_pegged()).1 +} diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/utils/l2_blocks.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/utils/l2_blocks.rs index 5dd26c4c0277..e5832f7f5879 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/utils/l2_blocks.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/utils/l2_blocks.rs @@ -68,7 +68,7 @@ pub fn load_last_l2_block(storage: StoragePtr) -> Option u32 { - // Even if the gas limit is greater than the MAX_TX_ERGS_LIMIT, we assume that everything beyond MAX_TX_ERGS_LIMIT + // Even if the gas limit is greater than the `MAX_TX_ERGS_LIMIT`, we assume that everything beyond `MAX_TX_ERGS_LIMIT` // will be spent entirely on publishing bytecodes and so we derive the overhead solely based on the capped value let gas_limit = std::cmp::min(MAX_TX_ERGS_LIMIT, gas_limit); @@ -23,8 +23,8 @@ pub fn derive_overhead( let gas_limit = U256::from(gas_limit); let encoded_len = U256::from(encoded_len); - // The MAX_TX_ERGS_LIMIT is formed in a way that may fulfills a single-instance circuits - // if used in full. That is, within MAX_TX_ERGS_LIMIT it is possible to fully saturate all the single-instance + // The `MAX_TX_ERGS_LIMIT` is formed in a way that may fulfills a single-instance circuits + // if used in full. That is, within `MAX_TX_ERGS_LIMIT` it is possible to fully saturate all the single-instance // circuits. let overhead_for_single_instance_circuits = ceil_div_u256(gas_limit * max_block_overhead, MAX_TX_ERGS_LIMIT.into()); @@ -38,15 +38,17 @@ pub fn derive_overhead( // The overhead for occupying a single tx slot let tx_slot_overhead = ceil_div_u256(max_block_overhead, MAX_TXS_IN_BLOCK.into()); - // We use "ceil" here for formal reasons to allow easier approach for calculating the overhead in O(1) - // let max_pubdata_in_tx = ceil_div_u256(gas_limit, gas_price_per_pubdata); + // We use `ceil` here for formal reasons to allow easier approach for calculating the overhead in O(1) + // `let max_pubdata_in_tx = ceil_div_u256(gas_limit, gas_price_per_pubdata);` // The maximal potential overhead from pubdata // TODO (EVM-67): possibly use overhead for pubdata + // ``` // let pubdata_overhead = ceil_div_u256( // max_pubdata_in_tx * max_block_overhead, // MAX_PUBDATA_PER_BLOCK.into(), // ); + // ``` vec![ (coefficients.ergs_limit_overhead_coeficient @@ -64,7 +66,7 @@ pub fn derive_overhead( /// Contains the coefficients with which the overhead for transactions will be calculated. /// All of the coefficients should be <= 1. There are here to provide a certain "discount" for normal transactions /// at the risk of malicious transactions that may close the block prematurely. -/// IMPORTANT: to perform correct computations, `MAX_TX_ERGS_LIMIT / coefficients.ergs_limit_overhead_coeficient` MUST +/// IMPORTANT: to perform correct computations, `MAX_TX_ERGS_LIMIT / coefficients.ergs_limit_overhead_coefficient` MUST /// result in an integer number #[derive(Debug, Clone, Copy)] pub struct OverheadCoefficients { @@ -102,8 +104,8 @@ impl OverheadCoefficients { OverheadCoefficients::new_checked( 1.0, 1.0, // For L2 transactions we allow a certain default discount with regard to the number of ergs. - // Multiinstance circuits can in theory be spawned infinite times, while projected future limitations - // on gas per pubdata allow for roughly 800kk gas per L1 batch, so the rough trust "discount" on the proof's part + // Multi-instance circuits can in theory be spawned infinite times, while projected future limitations + // on gas per pubdata allow for roughly 800k gas per L1 batch, so the rough trust "discount" on the proof's part // to be paid by the users is 0.1. 0.1, ) @@ -132,28 +134,28 @@ pub(crate) fn get_amortized_overhead( let encoded_len = U256::from(encoded_len); // Derivation of overhead consists of 4 parts: - // 1. The overhead for taking up a transaction's slot. (O1): O1 = 1 / MAX_TXS_IN_BLOCK - // 2. The overhead for taking up the bootloader's memory (O2): O2 = encoded_len / BOOTLOADER_TX_ENCODING_SPACE - // 3. The overhead for possible usage of pubdata. (O3): O3 = max_pubdata_in_tx / MAX_PUBDATA_PER_BLOCK - // 4. The overhead for possible usage of all the single-instance circuits. (O4): O4 = gas_limit / MAX_TX_ERGS_LIMIT + // 1. The overhead for taking up a transaction's slot. `(O1): O1 = 1 / MAX_TXS_IN_BLOCK` + // 2. The overhead for taking up the bootloader's memory `(O2): O2 = encoded_len / BOOTLOADER_TX_ENCODING_SPACE` + // 3. The overhead for possible usage of pubdata. `(O3): O3 = max_pubdata_in_tx / MAX_PUBDATA_PER_BLOCK` + // 4. The overhead for possible usage of all the single-instance circuits. `(O4): O4 = gas_limit / MAX_TX_ERGS_LIMIT` // // The maximum of these is taken to derive the part of the block's overhead to be paid by the users: // - // max_overhead = max(O1, O2, O3, O4) - // overhead_gas = ceil(max_overhead * overhead_for_block_gas). Thus, overhead_gas is a function of - // tx_gas_limit, gas_per_pubdata_byte_limit and encoded_len. + // `max_overhead = max(O1, O2, O3, O4)` + // `overhead_gas = ceil(max_overhead * overhead_for_block_gas)`. Thus, `overhead_gas` is a function of + // `tx_gas_limit`, `gas_per_pubdata_byte_limit` and `encoded_len`. // // While it is possible to derive the overhead with binary search in O(log n), it is too expensive to be done // on L1, so here is a reference implementation of finding the overhead for transaction in O(1): // - // Given total_gas_limit = tx_gas_limit + overhead_gas, we need to find overhead_gas and tx_gas_limit, such that: - // 1. overhead_gas is maximal possible (the operator is paid fairly) - // 2. overhead_gas(tx_gas_limit, gas_per_pubdata_byte_limit, encoded_len) >= overhead_gas (the user does not overpay) + // Given `total_gas_limit = tx_gas_limit + overhead_gas`, we need to find `overhead_gas` and `tx_gas_limit`, such that: + // 1. `overhead_gas` is maximal possible (the operator is paid fairly) + // 2. `overhead_gas(tx_gas_limit, gas_per_pubdata_byte_limit, encoded_len) >= overhead_gas` (the user does not overpay) // The third part boils to the following 4 inequalities (at least one of these must hold): - // ceil(O1 * overhead_for_block_gas) >= overhead_gas - // ceil(O2 * overhead_for_block_gas) >= overhead_gas - // ceil(O3 * overhead_for_block_gas) >= overhead_gas - // ceil(O4 * overhead_for_block_gas) >= overhead_gas + // `ceil(O1 * overhead_for_block_gas) >= overhead_gas` + // `ceil(O2 * overhead_for_block_gas) >= overhead_gas` + // `ceil(O3 * overhead_for_block_gas) >= overhead_gas` + // `ceil(O4 * overhead_for_block_gas) >= overhead_gas` // // Now, we need to solve each of these separately: @@ -164,7 +166,7 @@ pub(crate) fn get_amortized_overhead( (coefficients.slot_overhead_coeficient * tx_slot_overhead as f64).floor() as u32 }; - // 2. The overhead for occupying the bootloader memory can be derived from encoded_len + // 2. The overhead for occupying the bootloader memory can be derived from `encoded_len` let overhead_for_length = { let overhead_for_length = ceil_div_u256( encoded_len * overhead_for_block_gas, @@ -177,13 +179,17 @@ pub(crate) fn get_amortized_overhead( }; // TODO (EVM-67): possibly include the overhead for pubdata. The formula below has not been properly maintained, - // since the pubdat is not published. If decided to use the pubdata overhead, it needs to be updated. + // since the pubdata is not published. If decided to use the pubdata overhead, it needs to be updated. + // ``` // 3. ceil(O3 * overhead_for_block_gas) >= overhead_gas // O3 = max_pubdata_in_tx / MAX_PUBDATA_PER_BLOCK = ceil(gas_limit / gas_per_pubdata_byte_limit) / MAX_PUBDATA_PER_BLOCK - // >= (gas_limit / (gas_per_pubdata_byte_limit * MAX_PUBDATA_PER_BLOCK). Throwing off the `ceil`, while may provide marginally lower + // >= (gas_limit / (gas_per_pubdata_byte_limit * MAX_PUBDATA_PER_BLOCK). + // ``` + // Throwing off the `ceil`, while may provide marginally lower // overhead to the operator, provides substantially easier formula to work with. // - // For better clarity, let's denote gas_limit = GL, MAX_PUBDATA_PER_BLOCK = MP, gas_per_pubdata_byte_limit = EP, overhead_for_block_gas = OB, total_gas_limit = TL, overhead_gas = OE + // For better clarity, let's denote `gas_limit = GL, MAX_PUBDATA_PER_BLOCK = MP, gas_per_pubdata_byte_limit = EP, overhead_for_block_gas = OB, total_gas_limit = TL, overhead_gas = OE` + // ``` // ceil(OB * (TL - OE) / (EP * MP)) >= OE // // OB * (TL - OE) / (MP * EP) > OE - 1 @@ -196,7 +202,7 @@ pub(crate) fn get_amortized_overhead( // + gas_per_pubdata_byte_limit * U256::from(MAX_PUBDATA_PER_BLOCK); // let denominator = // gas_per_pubdata_byte_limit * U256::from(MAX_PUBDATA_PER_BLOCK) + overhead_for_block_gas; - + // // // Corner case: if `total_gas_limit` = `gas_per_pubdata_byte_limit` = 0 // // then the numerator will be 0 and subtracting 1 will cause a panic, so we just return a zero. // if numerator.is_zero() { @@ -205,7 +211,7 @@ pub(crate) fn get_amortized_overhead( // (numerator - 1) / denominator // } // }; - + // // 4. K * ceil(O4 * overhead_for_block_gas) >= overhead_gas, where K is the discount // O4 = gas_limit / MAX_TX_ERGS_LIMIT. Using the notation from the previous equation: // ceil(OB * GL / MAX_TX_ERGS_LIMIT) >= (OE / K) diff --git a/core/lib/multivm/src/versions/vm_virtual_blocks/vm.rs b/core/lib/multivm/src/versions/vm_virtual_blocks/vm.rs index ed05e9514753..7afbaab076df 100644 --- a/core/lib/multivm/src/versions/vm_virtual_blocks/vm.rs +++ b/core/lib/multivm/src/versions/vm_virtual_blocks/vm.rs @@ -1,8 +1,10 @@ +use zkevm_test_harness_1_3_3::witness::sort_storage_access::sort_storage_access_queries; use zksync_state::{StoragePtr, WriteStorage}; use zksync_types::{l2_to_l1_log::UserL2ToL1Log, Transaction}; use zksync_utils::bytecode::CompressedBytecodeInfo; use crate::{ + glue::GlueInto, interface::{ BootloaderMemory, BytecodeCompressionError, CurrentExecutionState, L1BatchEnv, L2BlockEnv, SystemEnv, VmExecutionMode, VmExecutionResultAndLogs, VmInterface, @@ -89,7 +91,7 @@ impl VmInterface for Vm { let l2_to_l1_logs = l1_messages .into_iter() - .map(|log| UserL2ToL1Log(log.into())) + .map(|log| UserL2ToL1Log(log.glue_into())) .collect(); let total_log_queries = self.state.event_sink.get_log_queries() + self @@ -99,15 +101,30 @@ impl VmInterface for Vm { .len() + self.state.storage.get_final_log_queries().len(); + let storage_log_queries = self.state.storage.get_final_log_queries(); + + let deduped_storage_log_queries = + sort_storage_access_queries(storage_log_queries.iter().map(|log| &log.log_query)).1; + CurrentExecutionState { events, - storage_log_queries: self.state.storage.get_final_log_queries(), + storage_log_queries: storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), + deduplicated_storage_log_queries: deduped_storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), used_contract_hashes: self.get_used_contracts(), user_l2_to_l1_logs: l2_to_l1_logs, system_logs: vec![], total_log_queries, cycles_used: self.state.local_state.monotonic_cycle_counter, - deduplicated_events_logs, + deduplicated_events_logs: deduplicated_events_logs + .into_iter() + .map(GlueInto::glue_into) + .collect(), storage_refunds: Vec::new(), } } @@ -118,16 +135,28 @@ impl VmInterface for Vm { tracer: TracerDispatcher, tx: Transaction, with_compression: bool, - ) -> Result { + ) -> ( + Result<(), BytecodeCompressionError>, + VmExecutionResultAndLogs, + ) { self.push_transaction_with_compression(tx, with_compression); let result = self.inspect_inner(tracer, VmExecutionMode::OneTx); if self.has_unpublished_bytecodes() { - Err(BytecodeCompressionError::BytecodeCompressionFailed) + ( + Err(BytecodeCompressionError::BytecodeCompressionFailed), + result, + ) } else { - Ok(result) + (Ok(()), result) } } + fn has_enough_gas_for_batch_tip(&self) -> bool { + // For this version this overhead has not been calculated and it has not been used with those versions. + // We return some value just in case for backwards compatibility + true + } + fn record_vm_memory_metrics(&self) -> VmMemoryMetrics { self.record_vm_memory_metrics_inner() } diff --git a/core/lib/multivm/src/vm_instance.rs b/core/lib/multivm/src/vm_instance.rs index 6716aeaf146f..44b70db07d8b 100644 --- a/core/lib/multivm/src/vm_instance.rs +++ b/core/lib/multivm/src/vm_instance.rs @@ -5,8 +5,8 @@ use zksync_utils::bytecode::CompressedBytecodeInfo; use crate::{ glue::history_mode::HistoryMode, interface::{ - BootloaderMemory, CurrentExecutionState, FinishedL1Batch, L1BatchEnv, L2BlockEnv, - SystemEnv, VmExecutionMode, VmExecutionResultAndLogs, VmInterface, + BootloaderMemory, BytecodeCompressionError, CurrentExecutionState, FinishedL1Batch, + L1BatchEnv, L2BlockEnv, SystemEnv, VmExecutionMode, VmExecutionResultAndLogs, VmInterface, VmInterfaceHistoryEnabled, VmMemoryMetrics, }, tracers::TracerDispatcher, @@ -19,7 +19,8 @@ pub enum VmInstance { Vm1_3_2(crate::vm_1_3_2::Vm), VmVirtualBlocks(crate::vm_virtual_blocks::Vm), VmVirtualBlocksRefundsEnhancement(crate::vm_refunds_enhancement::Vm), - VmBoojumIntegration(crate::vm_latest::Vm), + VmBoojumIntegration(crate::vm_boojum_integration::Vm), + Vm1_4_1(crate::vm_latest::Vm), } macro_rules! dispatch_vm { @@ -31,6 +32,7 @@ macro_rules! dispatch_vm { VmInstance::VmVirtualBlocks(vm) => vm.$function($($params)*), VmInstance::VmVirtualBlocksRefundsEnhancement(vm) => vm.$function($($params)*), VmInstance::VmBoojumIntegration(vm) => vm.$function($($params)*), + VmInstance::Vm1_4_1(vm) => vm.$function($($params)*), } }; } @@ -86,7 +88,10 @@ impl VmInterface for VmInstance { &mut self, tx: zksync_types::Transaction, with_compression: bool, - ) -> Result { + ) -> ( + Result<(), BytecodeCompressionError>, + VmExecutionResultAndLogs, + ) { dispatch_vm!(self.execute_transaction_with_bytecode_compression(tx, with_compression)) } @@ -96,7 +101,10 @@ impl VmInterface for VmInstance { dispatcher: Self::TracerDispatcher, tx: zksync_types::Transaction, with_compression: bool, - ) -> Result { + ) -> ( + Result<(), BytecodeCompressionError>, + VmExecutionResultAndLogs, + ) { dispatch_vm!(self.inspect_transaction_with_bytecode_compression( dispatcher.into(), tx, @@ -108,6 +116,10 @@ impl VmInterface for VmInstance { dispatch_vm!(self.record_vm_memory_metrics()) } + fn has_enough_gas_for_batch_tip(&self) -> bool { + dispatch_vm!(self.has_enough_gas_for_batch_tip()) + } + /// Return the results of execution of all batch fn finish_batch(&mut self) -> FinishedL1Batch { dispatch_vm!(self.finish_batch()) @@ -188,9 +200,14 @@ impl VmInstance { VmInstance::VmVirtualBlocksRefundsEnhancement(vm) } VmVersion::VmBoojumIntegration => { - let vm = crate::vm_latest::Vm::new(l1_batch_env, system_env, storage_view); + let vm = + crate::vm_boojum_integration::Vm::new(l1_batch_env, system_env, storage_view); VmInstance::VmBoojumIntegration(vm) } + VmVersion::Vm1_4_1 => { + let vm = crate::vm_latest::Vm::new(l1_batch_env, system_env, storage_view); + VmInstance::Vm1_4_1(vm) + } } } } diff --git a/core/lib/node/Cargo.toml b/core/lib/node/Cargo.toml new file mode 100644 index 000000000000..bda2315f5361 --- /dev/null +++ b/core/lib/node/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "zksync_node" +version = "0.1.0" +edition = "2018" +authors = ["The Matter Labs Team "] +homepage = "https://zksync.io/" +repository = "https://github.com/matter-labs/zksync-era" +license = "MIT OR Apache-2.0" +keywords = ["blockchain", "zksync"] +categories = ["cryptography"] + +[dependencies] +prometheus_exporter = { path = "../prometheus_exporter" } +zksync_types = { path = "../types" } +zksync_health_check = { path = "../health_check" } +zksync_dal = { path = "../dal" } +zksync_config = { path = "../config" } +zksync_object_store = { path = "../object_store" } +zksync_core = { path = "../zksync_core" } +zksync_storage = { path = "../storage" } + +tracing = "0.1" +thiserror = "1" +async-trait = "0.1" +futures = "0.3" +anyhow = "1" +tokio = { version = "1", features = ["rt"] } + +[dev-dependencies] +zksync_env_config = { path = "../env_config" } +vlog = { path = "../vlog" } diff --git a/core/lib/node/examples/main_node.rs b/core/lib/node/examples/main_node.rs new file mode 100644 index 000000000000..afe64139e0ba --- /dev/null +++ b/core/lib/node/examples/main_node.rs @@ -0,0 +1,84 @@ +//! An incomplete example of how node initialization looks like. +//! This example defines a `ResourceProvider` that works using the main node env config, and +//! initializes a single task with a health check server. + +use zksync_config::{configs::chain::OperationsManagerConfig, DBConfig, PostgresConfig}; +use zksync_core::metadata_calculator::MetadataCalculatorConfig; +use zksync_dal::ConnectionPool; +use zksync_env_config::FromEnv; +use zksync_node::{ + implementations::{ + resource::pools::MasterPoolResource, + task::{ + healtcheck_server::HealthCheckTaskBuilder, + metadata_calculator::MetadataCalculatorTaskBuilder, + }, + }, + node::ZkSyncNode, + resource::{Resource, ResourceId, ResourceProvider, StoredResource}, +}; + +/// Resource provider for the main node. +/// It defines which resources the tasks will receive. This particular provider is stateless, e.g. it always uses +/// the main node env config, and always knows which resources to provide. +/// The resource provider can be dynamic, however. For example, we can define a resource provider which may use +/// different config load scheme (e.g. env variables / protobuf / yaml / toml), and which resources to provide +/// (e.g. decide whether we need MempoolIO or ExternalIO depending on some config). +#[derive(Debug)] +struct MainNodeResourceProvider; + +impl MainNodeResourceProvider { + fn master_pool_resource() -> anyhow::Result { + let config = PostgresConfig::from_env()?; + let mut master_pool = + ConnectionPool::builder(config.master_url()?, config.max_connections()?); + master_pool.set_statement_timeout(config.statement_timeout()); + + Ok(MasterPoolResource::new(master_pool)) + } +} + +#[async_trait::async_trait] +impl ResourceProvider for MainNodeResourceProvider { + async fn get_resource(&self, name: &ResourceId) -> Option> { + match name { + name if name == &MasterPoolResource::resource_id() => { + let resource = + Self::master_pool_resource().expect("Failed to create pools resource"); + Some(Box::new(resource)) + } + _ => None, + } + } +} + +fn main() -> anyhow::Result<()> { + #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. + let log_format = vlog::log_format_from_env(); + let _guard = vlog::ObservabilityBuilder::new() + .with_log_format(log_format) + .build(); + + // Create the node with specified resource provider. We don't need to add any resources explicitly, + // the task will request what they actually need. The benefit here is that we won't instantiate resources + // that are not used, which would be complex otherwise, since the task set is often dynamic. + let mut node = ZkSyncNode::new(MainNodeResourceProvider)?; + + // Add the metadata calculator task. + let merkle_tree_env_config = DBConfig::from_env()?.merkle_tree; + let operations_manager_env_config = OperationsManagerConfig::from_env()?; + let metadata_calculator_config = MetadataCalculatorConfig::for_main_node( + &merkle_tree_env_config, + &operations_manager_env_config, + ); + node.add_task(MetadataCalculatorTaskBuilder(metadata_calculator_config)); + + // Add the healthcheck server. + let healthcheck_config = zksync_config::ApiConfig::from_env()?.healthcheck; + node.add_task(HealthCheckTaskBuilder(healthcheck_config)); + + // Run the node until completion. + node.run()?; + + Ok(()) +} diff --git a/core/lib/node/src/implementations/mod.rs b/core/lib/node/src/implementations/mod.rs new file mode 100644 index 000000000000..b381595d68f9 --- /dev/null +++ b/core/lib/node/src/implementations/mod.rs @@ -0,0 +1,6 @@ +//! Implementations of resources and tasks. +//! These are temporarily provided by the framework crate itself, but will be moved to the separate crates +//! in the future. + +pub mod resource; +pub mod task; diff --git a/core/lib/node/src/implementations/resource/healthcheck.rs b/core/lib/node/src/implementations/resource/healthcheck.rs new file mode 100644 index 000000000000..5b752e33d59b --- /dev/null +++ b/core/lib/node/src/implementations/resource/healthcheck.rs @@ -0,0 +1,36 @@ +use std::{fmt, sync::Arc}; + +// Public re-exports from external crate to minimize the required dependencies. +pub use zksync_health_check::{CheckHealth, ReactiveHealthCheck}; + +use crate::resource::Resource; + +/// Wrapper for a generic health check. +#[derive(Clone)] +pub struct HealthCheckResource(Arc); + +impl HealthCheckResource { + pub fn new(check: impl CheckHealth + 'static) -> Self { + Self(Arc::new(check)) + } +} + +impl fmt::Debug for HealthCheckResource { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("HealthCheckResource") + .field("name", &self.0.name()) + .finish_non_exhaustive() + } +} + +impl Resource for HealthCheckResource { + fn resource_id() -> crate::resource::ResourceId { + "common/health_check".into() + } +} + +impl AsRef for HealthCheckResource { + fn as_ref(&self) -> &dyn CheckHealth { + self.0.as_ref() + } +} diff --git a/core/lib/node/src/implementations/resource/mod.rs b/core/lib/node/src/implementations/resource/mod.rs new file mode 100644 index 000000000000..7042d58ef59e --- /dev/null +++ b/core/lib/node/src/implementations/resource/mod.rs @@ -0,0 +1,3 @@ +pub mod healthcheck; +pub mod object_store; +pub mod pools; diff --git a/core/lib/node/src/implementations/resource/object_store.rs b/core/lib/node/src/implementations/resource/object_store.rs new file mode 100644 index 000000000000..093061a9b2d4 --- /dev/null +++ b/core/lib/node/src/implementations/resource/object_store.rs @@ -0,0 +1,15 @@ +use std::sync::Arc; + +use zksync_object_store::ObjectStore; + +use crate::resource::Resource; + +/// Wrapper for the object store. +#[derive(Debug, Clone)] +pub struct ObjectStoreResource(pub Arc); + +impl Resource for ObjectStoreResource { + fn resource_id() -> crate::resource::ResourceId { + "common/object_store".into() + } +} diff --git a/core/lib/node/src/implementations/resource/pools.rs b/core/lib/node/src/implementations/resource/pools.rs new file mode 100644 index 000000000000..c2194bddc72e --- /dev/null +++ b/core/lib/node/src/implementations/resource/pools.rs @@ -0,0 +1,75 @@ +use zksync_dal::{connection::ConnectionPoolBuilder, ConnectionPool}; + +use crate::resource::Resource; + +/// Represents a connection pool to the master database. +#[derive(Debug, Clone)] +pub struct MasterPoolResource(ConnectionPoolBuilder); + +impl Resource for MasterPoolResource { + fn resource_id() -> crate::resource::ResourceId { + "common/master_pool".into() + } +} + +impl MasterPoolResource { + pub fn new(builder: ConnectionPoolBuilder) -> Self { + Self(builder) + } + + pub async fn get(&self) -> anyhow::Result { + self.0.build().await + } + + pub async fn get_singleton(&self) -> anyhow::Result { + self.0.build_singleton().await + } +} + +/// Represents a connection pool to the replica database. +#[derive(Debug, Clone)] +pub struct ReplicaPoolResource(ConnectionPoolBuilder); + +impl Resource for ReplicaPoolResource { + fn resource_id() -> crate::resource::ResourceId { + "common/replica_pool".into() + } +} + +impl ReplicaPoolResource { + pub fn new(builder: ConnectionPoolBuilder) -> Self { + Self(builder) + } + + pub async fn get(&self) -> anyhow::Result { + self.0.build().await + } + + pub async fn get_singleton(&self) -> anyhow::Result { + self.0.build_singleton().await + } +} + +/// Represents a connection pool to the prover database. +#[derive(Debug, Clone)] +pub struct ProverPoolResource(ConnectionPoolBuilder); + +impl Resource for ProverPoolResource { + fn resource_id() -> crate::resource::ResourceId { + "common/prover_pool".into() + } +} + +impl ProverPoolResource { + pub fn new(builder: ConnectionPoolBuilder) -> Self { + Self(builder) + } + + pub async fn get(&self) -> anyhow::Result { + self.0.build().await + } + + pub async fn get_singleton(&self) -> anyhow::Result { + self.0.build_singleton().await + } +} diff --git a/core/lib/node/src/implementations/task/healtcheck_server.rs b/core/lib/node/src/implementations/task/healtcheck_server.rs new file mode 100644 index 000000000000..6350196da40e --- /dev/null +++ b/core/lib/node/src/implementations/task/healtcheck_server.rs @@ -0,0 +1,67 @@ +use std::fmt; + +use zksync_config::configs::api::HealthCheckConfig; +use zksync_core::api_server::healthcheck::HealthCheckHandle; + +use crate::{ + implementations::resource::healthcheck::HealthCheckResource, + node::{NodeContext, StopReceiver}, + resource::ResourceCollection, + task::{IntoZkSyncTask, TaskInitError, ZkSyncTask}, +}; + +/// Builder for a health check server. +/// +/// Spawned task collects all the health checks added by different tasks to the +/// corresponding resource collection and spawns an HTTP server exposing them. +#[derive(Debug)] +pub struct HealthCheckTaskBuilder(pub HealthCheckConfig); + +#[async_trait::async_trait] +impl IntoZkSyncTask for HealthCheckTaskBuilder { + fn task_name(&self) -> &'static str { + "healthcheck_server" + } + + async fn create( + self: Box, + mut node: NodeContext<'_>, + ) -> Result, TaskInitError> { + let healthchecks = node + .get_resource_or_default::>() + .await; + + let task = HealthCheckTask { + config: self.0, + healthchecks, + }; + + Ok(Box::new(task)) + } +} + +struct HealthCheckTask { + config: HealthCheckConfig, + healthchecks: ResourceCollection, +} + +impl fmt::Debug for HealthCheckTask { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("HealthCheckTask") + .field("config", &self.config) + .finish_non_exhaustive() + } +} + +#[async_trait::async_trait] +impl ZkSyncTask for HealthCheckTask { + async fn run(mut self: Box, mut stop_receiver: StopReceiver) -> anyhow::Result<()> { + let healthchecks = self.healthchecks.resolve().await; + + let handle = HealthCheckHandle::spawn_server(self.config.bind_addr(), healthchecks); + stop_receiver.0.changed().await?; + handle.stop().await; + + Ok(()) + } +} diff --git a/core/lib/node/src/implementations/task/metadata_calculator.rs b/core/lib/node/src/implementations/task/metadata_calculator.rs new file mode 100644 index 000000000000..0a61ad00abb8 --- /dev/null +++ b/core/lib/node/src/implementations/task/metadata_calculator.rs @@ -0,0 +1,81 @@ +use zksync_core::metadata_calculator::{MetadataCalculator, MetadataCalculatorConfig}; +use zksync_dal::ConnectionPool; +use zksync_storage::RocksDB; + +use crate::{ + implementations::resource::{ + healthcheck::HealthCheckResource, object_store::ObjectStoreResource, + pools::MasterPoolResource, + }, + node::{NodeContext, StopReceiver}, + resource::{Resource, ResourceCollection}, + task::{IntoZkSyncTask, TaskInitError, ZkSyncTask}, +}; + +/// Builder for a metadata calculator. +#[derive(Debug)] +pub struct MetadataCalculatorTaskBuilder(pub MetadataCalculatorConfig); + +#[derive(Debug)] +pub struct MetadataCalculatorTask { + metadata_calculator: MetadataCalculator, + main_pool: ConnectionPool, +} + +#[async_trait::async_trait] +impl IntoZkSyncTask for MetadataCalculatorTaskBuilder { + fn task_name(&self) -> &'static str { + "metadata_calculator" + } + + async fn create( + self: Box, + mut node: NodeContext<'_>, + ) -> Result, TaskInitError> { + let pool = node.get_resource::().await.ok_or( + TaskInitError::ResourceLacking(MasterPoolResource::resource_id()), + )?; + let main_pool = pool.get().await.unwrap(); + let object_store = node.get_resource::().await; // OK to be None. + + if object_store.is_none() { + tracing::info!( + "Object store is not provided, metadata calculator will run without it." + ); + } + + let metadata_calculator = + MetadataCalculator::new(self.0, object_store.map(|os| os.0)).await?; + + let healthchecks = node + .get_resource_or_default::>() + .await; + healthchecks + .push(HealthCheckResource::new( + metadata_calculator.tree_health_check(), + )) + .expect("Wiring stage"); + + Ok(Box::new(MetadataCalculatorTask { + metadata_calculator, + main_pool, + })) + } +} + +#[async_trait::async_trait] +impl ZkSyncTask for MetadataCalculatorTask { + async fn run(self: Box, stop_receiver: StopReceiver) -> anyhow::Result<()> { + let result = self + .metadata_calculator + .run(self.main_pool, stop_receiver.0) + .await; + + // Wait for all the instances of RocksDB to be destroyed. + tokio::task::spawn_blocking(RocksDB::await_rocksdb_termination) + .await + .unwrap(); + + result + } +} diff --git a/core/lib/node/src/implementations/task/mod.rs b/core/lib/node/src/implementations/task/mod.rs new file mode 100644 index 000000000000..d56e496cfb01 --- /dev/null +++ b/core/lib/node/src/implementations/task/mod.rs @@ -0,0 +1,3 @@ +pub mod healtcheck_server; +pub mod metadata_calculator; +pub mod prometheus_exporter; diff --git a/core/lib/node/src/implementations/task/prometheus_exporter.rs b/core/lib/node/src/implementations/task/prometheus_exporter.rs new file mode 100644 index 000000000000..17923efde95b --- /dev/null +++ b/core/lib/node/src/implementations/task/prometheus_exporter.rs @@ -0,0 +1,58 @@ +use prometheus_exporter::PrometheusExporterConfig; +use zksync_health_check::{HealthStatus, HealthUpdater, ReactiveHealthCheck}; + +use crate::{ + implementations::resource::healthcheck::HealthCheckResource, + node::{NodeContext, StopReceiver}, + resource::ResourceCollection, + task::{IntoZkSyncTask, TaskInitError, ZkSyncTask}, +}; + +/// Builder for a prometheus exporter. +#[derive(Debug)] +pub struct PrometheusExporterTaskBuilder(pub PrometheusExporterConfig); + +#[derive(Debug)] +pub struct PrometheusExporterTask { + config: PrometheusExporterConfig, + prometheus_health_updater: HealthUpdater, +} + +#[async_trait::async_trait] +impl IntoZkSyncTask for PrometheusExporterTaskBuilder { + fn task_name(&self) -> &'static str { + "prometheus_exporter" + } + + async fn create( + self: Box, + mut node: NodeContext<'_>, + ) -> Result, TaskInitError> { + let (prometheus_health_check, prometheus_health_updater) = + ReactiveHealthCheck::new("prometheus_exporter"); + + let healthchecks = node + .get_resource_or_default::>() + .await; + healthchecks + .push(HealthCheckResource::new(prometheus_health_check)) + .expect("Wiring stage"); + + Ok(Box::new(PrometheusExporterTask { + config: self.0, + prometheus_health_updater, + })) + } +} + +#[async_trait::async_trait] +impl ZkSyncTask for PrometheusExporterTask { + async fn run(self: Box, stop_receiver: StopReceiver) -> anyhow::Result<()> { + let prometheus_task = self.config.run(stop_receiver.0); + self.prometheus_health_updater + .update(HealthStatus::Ready.into()); + let res = prometheus_task.await; + drop(self.prometheus_health_updater); + res + } +} diff --git a/core/lib/node/src/lib.rs b/core/lib/node/src/lib.rs new file mode 100644 index 000000000000..c714f998a12a --- /dev/null +++ b/core/lib/node/src/lib.rs @@ -0,0 +1,24 @@ +//! # ZK Stack node initialization framework. +//! +//! ## Introduction +//! +//! This crate provides core abstractions that allow one to compose a ZK Stack node. +//! Main concepts used in this crate are: +//! - [`IntoZkSyncTask`](task::IntoZkSyncTask) - builder interface for tasks. +//! - [`ZkSyncTask`](task::ZkSyncTask) - a unit of work that can be executed by the node. +//! - [`Resource`](resource::Resource) - a piece of logic that can be shared between tasks. Most resources are +//! represented by generic interfaces and also serve as points of customization for tasks. +//! - [`ResourceProvider`](resource::ResourceProvider) - a trait that allows one to provide resources to the node. +//! - [`ZkSyncNode`](node::ZkSyncNode) - a container for tasks and resources that takes care of initialization, running +//! and shutting down. +//! +//! The general flow to compose a node is as follows: +//! - Create a [`ResourceProvider`](resource::ResourceProvider) that can provide all the resources that the node needs. +//! - Create a [`ZkSyncNode`](node::ZkSyncNode) with that [`ResourceProvider`](resource::ResourceProvider). +//! - Add tasks to the node. +//! - Run it. + +pub mod implementations; +pub mod node; +pub mod resource; +pub mod task; diff --git a/core/lib/node/src/node/context.rs b/core/lib/node/src/node/context.rs new file mode 100644 index 000000000000..897bc1c967ef --- /dev/null +++ b/core/lib/node/src/node/context.rs @@ -0,0 +1,101 @@ +use crate::{ + node::ZkSyncNode, + resource::{Resource, StoredResource}, + task::IntoZkSyncTask, +}; + +/// An interface to the node's resources provided to the tasks during initialization. +/// Provides the ability to fetch required resources, and also gives access to the Tokio runtime handle used by the node. +#[derive(Debug)] +pub struct NodeContext<'a> { + node: &'a mut ZkSyncNode, +} + +impl<'a> NodeContext<'a> { + pub(super) fn new(node: &'a mut ZkSyncNode) -> Self { + Self { node } + } + + /// Provides access to the runtime used by the node. + /// Can be used to spawn additional tasks within the same runtime. + /// If some tasks stores the handle to spawn additional tasks, it is expected to do all the required + /// cleanup. + /// + /// In most cases, however, it is recommended to use [`add_task`] method instead. + pub fn runtime_handle(&self) -> &tokio::runtime::Handle { + self.node.runtime.handle() + } + + /// Adds an additional task to the node. + /// This may be used if some task or its resource requires an additional routine for maintenance. + pub fn add_task(&mut self, builder: T) -> &mut Self { + self.node.add_task(builder); + self + } + + /// Attempts to retrieve the resource with the specified name. + /// Internally the resources are stored as [`std::any::Any`], and this method does the downcasting + /// on behalf of the caller. + /// + /// ## Panics + /// + /// Panics if the resource with the specified name exists, but is not of the requested type. + pub async fn get_resource(&mut self) -> Option { + #[allow(clippy::borrowed_box)] + let downcast_clone = |resource: &Box| { + resource + .downcast_ref::() + .unwrap_or_else(|| { + panic!( + "Resource {} is not of type {}", + T::resource_id(), + std::any::type_name::() + ) + }) + .clone() + }; + + let name = T::resource_id(); + // Check whether the resource is already available. + if let Some(resource) = self.node.resources.get(&name) { + return Some(downcast_clone(resource)); + } + + // Try to fetch the resource from the provider. + if let Some(resource) = self.node.resource_provider.get_resource(&name).await { + // First, ensure the type matches. + let downcasted = downcast_clone(&resource); + // Then, add it to the local resources. + self.node.resources.insert(name, resource); + return Some(downcasted); + } + + // No such resource. + // The requester is allowed to decide whether this is an error or not. + None + } + + /// Attempts to retrieve the resource with the specified name. + /// If the resource is not available, it is created using the provided closure. + pub async fn get_resource_or_insert_with T>( + &mut self, + f: F, + ) -> T { + if let Some(resource) = self.get_resource::().await { + return resource; + } + + // No such resource, insert a new one. + let resource = f(); + self.node + .resources + .insert(T::resource_id(), Box::new(resource.clone())); + resource + } + + /// Attempts to retrieve the resource with the specified name. + /// If the resource is not available, it is created using `T::default()`. + pub async fn get_resource_or_default(&mut self) -> T { + self.get_resource_or_insert_with(T::default).await + } +} diff --git a/core/lib/node/src/node/mod.rs b/core/lib/node/src/node/mod.rs new file mode 100644 index 000000000000..42b9c9ac60a4 --- /dev/null +++ b/core/lib/node/src/node/mod.rs @@ -0,0 +1,207 @@ +use std::{collections::HashMap, fmt}; + +use futures::{future::BoxFuture, FutureExt}; +use tokio::{runtime::Runtime, sync::watch}; + +pub use self::{context::NodeContext, stop_receiver::StopReceiver}; +use crate::{ + resource::{ResourceId, ResourceProvider, StoredResource}, + task::{IntoZkSyncTask, TaskInitError}, +}; + +mod context; +mod stop_receiver; + +/// "Manager" class of the node. Collects all the resources and tasks, +/// then runs tasks until completion. +/// +/// Initialization flow: +/// - Node instance is created with access to the resource provider. +/// - Task constructors are added to the node. At this step, tasks are not created yet. +/// - Optionally, a healthcheck task constructor is also added. +/// - Once the `run` method is invoked, node +/// - attempts to create every task. If there are no tasks, or at least task +/// constructor fails, the node will return an error. +/// - initializes the healthcheck task if it's provided. +/// - waits for any of the tasks to finish. +/// - sends stop signal to all the tasks. +/// - waits for the remaining tasks to finish. +/// - calls `after_node_shutdown` hook for every task that has provided it. +/// - returns the result of the task that has finished. +pub struct ZkSyncNode { + /// Primary source of resources for tasks. + resource_provider: Box, + /// Cache of resources that have been requested at least by one task. + resources: HashMap>, + /// List of task builders. + task_builders: Vec>, + + /// Sender used to stop the tasks. + stop_sender: watch::Sender, + /// Tokio runtime used to spawn tasks. + runtime: Runtime, +} + +impl fmt::Debug for ZkSyncNode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ZkSyncNode").finish_non_exhaustive() + } +} + +impl ZkSyncNode { + pub fn new(resource_provider: R) -> anyhow::Result { + if tokio::runtime::Handle::try_current().is_ok() { + anyhow::bail!( + "Detected a Tokio Runtime. ZkSyncNode manages its own runtime and does not support nested runtimes" + ); + } + let runtime = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap(); + + let (stop_sender, _stop_receiver) = watch::channel(false); + let self_ = Self { + resource_provider: Box::new(resource_provider), + resources: HashMap::default(), + task_builders: Vec::new(), + stop_sender, + runtime, + }; + + Ok(self_) + } + + /// Adds a task to the node. + /// + /// The task is not created at this point, instead, the constructor is stored in the node + /// and will be invoked during [`ZkSyncNode::run`] method. Any error returned by the constructor + /// will prevent the node from starting and will be propagated by the [`ZkSyncNode::run`] method. + pub fn add_task(&mut self, builder: T) -> &mut Self { + self.task_builders.push(Box::new(builder)); + self + } + + /// Runs the system. + pub fn run(mut self) -> anyhow::Result<()> { + // Initialize tasks. + let task_builders = std::mem::take(&mut self.task_builders); + + let mut tasks = Vec::new(); + + let mut errors: Vec<(String, TaskInitError)> = Vec::new(); + + let runtime_handle = self.runtime.handle().clone(); + for task_builder in task_builders { + let name = task_builder.task_name().to_string(); + let task_result = + runtime_handle.block_on(task_builder.create(NodeContext::new(&mut self))); + let task = match task_result { + Ok(task) => task, + Err(err) => { + // We don't want to bail on the first error, since it'll provide worse DevEx: + // People likely want to fix as much problems as they can in one go, rather than have + // to fix them one by one. + errors.push((name, err)); + continue; + } + }; + let after_node_shutdown = task.after_node_shutdown(); + let task_future = Box::pin(task.run(self.stop_receiver())); + let task_repr = TaskRepr { + name, + task: Some(task_future), + after_node_shutdown, + }; + tasks.push(task_repr); + } + + // Report all the errors we've met during the init. + if !errors.is_empty() { + for (task, error) in errors { + tracing::error!("Task {task} can't be initialized: {error}"); + } + anyhow::bail!("One or more task weren't able to start"); + } + + if tasks.is_empty() { + anyhow::bail!("No tasks to run"); + } + + // Wiring is now complete. + for resource in self.resources.values_mut() { + resource.stored_resource_wired(); + } + + // Prepare tasks for running. + let rt_handle = self.runtime.handle().clone(); + let join_handles: Vec<_> = tasks + .iter_mut() + .map(|task| { + let task = task.task.take().expect( + "Tasks are created by the node and must be Some prior to calling this method", + ); + rt_handle.spawn(task).fuse() + }) + .collect(); + + // Run the tasks until one of them exits. + // TODO (QIT-24): wrap every task into a timeout to prevent hanging. + let (resolved, idx, remaining) = self + .runtime + .block_on(futures::future::select_all(join_handles)); + let task_name = tasks[idx].name.clone(); + let failure = match resolved { + Ok(Ok(())) => { + tracing::info!("Task {task_name} completed"); + false + } + Ok(Err(err)) => { + tracing::error!("Task {task_name} exited with an error: {err}"); + true + } + Err(_) => { + tracing::error!("Task {task_name} panicked"); + true + } + }; + + // Send stop signal to remaining tasks and wait for them to finish. + // Given that we are shutting down, we do not really care about returned values. + self.stop_sender.send(true).ok(); + self.runtime.block_on(futures::future::join_all(remaining)); + + // Call after_node_shutdown hooks. + let local_set = tokio::task::LocalSet::new(); + let join_handles = tasks.iter_mut().filter_map(|task| { + task.after_node_shutdown + .take() + .map(|task| local_set.spawn_local(task)) + }); + local_set.block_on(&self.runtime, futures::future::join_all(join_handles)); + + if failure { + anyhow::bail!("Task {task_name} failed"); + } else { + Ok(()) + } + } + + pub(crate) fn stop_receiver(&self) -> StopReceiver { + StopReceiver(self.stop_sender.subscribe()) + } +} + +struct TaskRepr { + name: String, + task: Option>>, + after_node_shutdown: Option>, +} + +impl fmt::Debug for TaskRepr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("TaskRepr") + .field("name", &self.name) + .finish_non_exhaustive() + } +} diff --git a/core/lib/node/src/node/stop_receiver.rs b/core/lib/node/src/node/stop_receiver.rs new file mode 100644 index 000000000000..7a181b49a80d --- /dev/null +++ b/core/lib/node/src/node/stop_receiver.rs @@ -0,0 +1,16 @@ +use tokio::sync::watch; + +/// Represents a receiver for the stop signal. +/// This signal is sent when the node is shutting down. +/// Every task is expected to listen to this signal and stop its execution when it is received. +/// +/// This structure exists as a first-class entity instead of being a resource to make it more visible +/// and prevent tasks from hanging by accident. +#[derive(Debug, Clone)] +pub struct StopReceiver(pub watch::Receiver); + +impl StopReceiver { + pub fn new(receiver: watch::Receiver) -> Self { + Self(receiver) + } +} diff --git a/core/lib/node/src/resource/lazy_resource.rs b/core/lib/node/src/resource/lazy_resource.rs new file mode 100644 index 000000000000..3ec6e3cdb0bd --- /dev/null +++ b/core/lib/node/src/resource/lazy_resource.rs @@ -0,0 +1,92 @@ +use std::sync::Arc; + +use thiserror::Error; +use tokio::sync::watch; + +use super::{Resource, ResourceId}; +use crate::node::StopReceiver; + +/// A lazy resource represents a resource that isn't available at the time when the tasks start. +/// +/// Normally it's used to represent the resources that should be provided by one task to another one. +/// Lazy resources are aware of the node lifecycle, so attempt to resolve the resource won't hang +/// if the resource is never provided: the resolve future will fail once the stop signal is sent by the node. +#[derive(Debug)] +pub struct LazyResource { + resolve_sender: Arc>>, + stop_receiver: StopReceiver, +} + +impl Resource for LazyResource { + fn resource_id() -> ResourceId { + ResourceId::new("lazy") + T::resource_id() + } +} + +impl Clone for LazyResource { + fn clone(&self) -> Self { + Self { + resolve_sender: self.resolve_sender.clone(), + stop_receiver: self.stop_receiver.clone(), + } + } +} + +impl LazyResource { + /// Creates a new lazy resource. + /// Provided stop receiver will be used to prevent resolving from hanging if the resource is never provided. + pub fn new(stop_receiver: StopReceiver) -> Self { + let (resolve_sender, _resolve_receiver) = watch::channel(None); + + Self { + resolve_sender: Arc::new(resolve_sender), + stop_receiver, + } + } + + /// Returns a future that resolves to the resource once it is provided. + /// If the resource is never provided, the method will return an error once the node is shutting down. + pub async fn resolve(mut self) -> Result { + let mut resolve_receiver = self.resolve_sender.subscribe(); + if let Some(resource) = resolve_receiver.borrow().as_ref() { + return Ok(resource.clone()); + } + + tokio::select! { + _ = self.stop_receiver.0.changed() => { + Err(LazyResourceError::NodeShutdown) + } + _ = resolve_receiver.changed() => { + // ^ we can ignore the error on `changed`, since we hold a strong reference to the sender. + let resource = resolve_receiver.borrow().as_ref().expect("Can only change if provided").clone(); + Ok(resource) + } + } + } + + /// Provides the resource. + /// May be called at most once. Subsequent calls will return an error. + pub async fn provide(&mut self, resource: T) -> Result<(), LazyResourceError> { + let sent = self.resolve_sender.send_if_modified(|current| { + if current.is_some() { + return false; + } + *current = Some(resource.clone()); + true + }); + + if !sent { + return Err(LazyResourceError::ResourceAlreadyProvided); + } + + Ok(()) + } +} + +#[derive(Debug, Error)] +pub enum LazyResourceError { + #[error("Node is shutting down")] + NodeShutdown, + #[error("Resource is already provided")] + ResourceAlreadyProvided, +} diff --git a/core/lib/node/src/resource/mod.rs b/core/lib/node/src/resource/mod.rs new file mode 100644 index 000000000000..2ed10d56416d --- /dev/null +++ b/core/lib/node/src/resource/mod.rs @@ -0,0 +1,83 @@ +use std::{any::TypeId, fmt}; + +pub use self::{ + lazy_resource::LazyResource, resource_collection::ResourceCollection, resource_id::ResourceId, +}; + +mod lazy_resource; +mod resource_collection; +mod resource_id; + +/// A trait for anything that can be stored (and retrieved) as a resource. +/// Typically, the type that implements this trait also should implement `Clone` +/// since the same resource may be requested by several tasks and thus it would be an additional +/// bound on most methods that work with [`Resource`]. +pub trait Resource: 'static + Send + Sync + std::any::Any { + /// Unique identifier of the resource. + /// Used to fetch the resource from the provider. + /// + /// It is recommended to name resources in form of `/`, where `` is the name of the task + /// that will use this resource, or 'common' in case it is used by several tasks, and `` is the name + /// of the resource itself. + fn resource_id() -> ResourceId; + + fn on_resource_wired(&mut self) {} +} + +/// Internal, object-safe version of [`Resource`]. +/// Used to store resources in the node without knowing their exact type. +/// +/// This trait is implemented for any type that implements [`Resource`], so there is no need to +/// implement it manually. +pub trait StoredResource: 'static + std::any::Any + Send + Sync { + /// An object-safe version of [`Resource::resource_id`]. + fn stored_resource_id(&self) -> ResourceId; + + /// An object-safe version of [`Resource::on_resoure_wired`]. + fn stored_resource_wired(&mut self); +} + +impl StoredResource for T { + fn stored_resource_id(&self) -> ResourceId { + T::resource_id() + } + + fn stored_resource_wired(&mut self) { + Resource::on_resource_wired(self); + } +} + +impl dyn StoredResource { + /// Reimplementation of `Any::downcast_ref`. + /// Returns `Some` if the type is correct, and `None` otherwise. + // Note: This method is required as we cannot store objects as, for example, `dyn StoredResource + Any`, + // so we don't have access to `Any::downcast_ref` within the node. + pub(crate) fn downcast_ref(&self) -> Option<&T> { + if self.type_id() == TypeId::of::() { + // SAFETY: We just checked that the type is correct. + unsafe { Some(&*(self as *const dyn StoredResource as *const T)) } + } else { + None + } + } +} + +/// An entity that knows how to initialize resources. +/// +/// It exists to simplify the initialization process, as both tasks and *resources* can depend on other resources, +/// and by having an entity that can initialize the resource on demand we can avoid the need to provide resources +/// in any particular order. +/// +/// Node will only call `get_resource` method once per resource, and will cache the result. This guarantees that +/// all the resource consumers will interact with the same resource instance, which may be important for getting +/// the consistent state (e.g. to make sure that L1 gas price is the same for all the tasks). +#[async_trait::async_trait] +pub trait ResourceProvider: 'static + Send + Sync + fmt::Debug { + /// Returns a resource with the given name. + /// + /// In case it isn't possible to obtain the resource (for example, if some error occurred during initialization), + /// the provider is free to either return `None` (if it assumes that the node can continue without this resource), + /// or to panic. + // Note: we have to use `Box` here, since we can't use `Box` due to it not being object-safe. + async fn get_resource(&self, resource: &ResourceId) -> Option>; +} diff --git a/core/lib/node/src/resource/resource_collection.rs b/core/lib/node/src/resource/resource_collection.rs new file mode 100644 index 000000000000..05c12ad40662 --- /dev/null +++ b/core/lib/node/src/resource/resource_collection.rs @@ -0,0 +1,106 @@ +use std::{ + fmt, + sync::{Arc, Mutex}, +}; + +use thiserror::Error; +use tokio::sync::watch; + +use super::{Resource, ResourceId}; + +/// Collection of resources that can be extended during the initialization phase, and then resolved once +/// the wiring is complete. +/// +/// During component initialization, resource collections can be requested by the components in order to push new +/// elements there. Once the initialization is complete, it is no longer possible to push new elements, and the +/// collection can be resolved into a vector of resources. +/// +/// Collections implement `Clone`, so they can be consumed by several tasks. Every task that resolves the collection +/// is guaranteed to have the same set of resources. +/// +/// The purpose of this container is to allow different tasks to register their resource in a single place for some +/// other task to consume. For example, tasks may register their healthchecks, and then healthcheck task will observe +/// all the provided healthchecks. +pub struct ResourceCollection { + /// Collection of the resources. + resources: Arc>>, + /// Sender indicating that the wiring is complete. + wiring_complete_sender: Arc>, + /// Flag indicating that the collection has been resolved. + wired: watch::Receiver, +} + +impl Resource for ResourceCollection { + fn resource_id() -> ResourceId { + ResourceId::new("collection") + T::resource_id() + } + + fn on_resource_wired(&mut self) { + self.wiring_complete_sender.send(true).ok(); + } +} + +impl Default for ResourceCollection { + fn default() -> Self { + Self::new() + } +} + +impl Clone for ResourceCollection { + fn clone(&self) -> Self { + Self { + resources: self.resources.clone(), + wiring_complete_sender: self.wiring_complete_sender.clone(), + wired: self.wired.clone(), + } + } +} + +impl fmt::Debug for ResourceCollection { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ResourceCollection") + .field("resources", &"{..}") + .finish_non_exhaustive() + } +} + +#[derive(Debug, Error)] +pub enum ResourceCollectionError { + #[error("Adding resources to the collection is not allowed after the wiring is complete")] + AlreadyWired, +} + +impl ResourceCollection { + pub(crate) fn new() -> Self { + let (wiring_complete_sender, wired) = watch::channel(false); + Self { + resources: Arc::default(), + wiring_complete_sender: Arc::new(wiring_complete_sender), + wired, + } + } + + /// Adds a new element to the resource collection. + /// Returns an error if the wiring is already complete. + pub fn push(&self, resource: T) -> Result<(), ResourceCollectionError> { + // This check is sufficient, since no task is guaranteed to be running when the value changes. + if *self.wired.borrow() { + return Err(ResourceCollectionError::AlreadyWired); + } + + let mut handle = self.resources.lock().unwrap(); + handle.push(resource); + Ok(()) + } + + /// Waits until the wiring is complete, and resolves the collection into a vector of resources. + pub async fn resolve(mut self) -> Vec { + // Guaranteed not to hang on server shutdown, since the node will invoke the `on_wiring_complete` before any task + // is actually spawned (per framework rules). For most cases, this check will resolve immediately, unless + // some tasks would spawn something from the `IntoZkSyncTask` impl. + self.wired.changed().await.expect("Sender can't be dropped"); + + let handle = self.resources.lock().unwrap(); + (*handle).clone() + } +} diff --git a/core/lib/node/src/resource/resource_id.rs b/core/lib/node/src/resource/resource_id.rs new file mode 100644 index 000000000000..73f7f43c58a4 --- /dev/null +++ b/core/lib/node/src/resource/resource_id.rs @@ -0,0 +1,47 @@ +use std::{ + fmt, + ops::{Add, AddAssign}, +}; + +/// A unique identifier of the resource. +/// Typically, represented as a path-like string, e.g. `common/master_pool`. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ResourceId { + /// Path-like representation of the resource identifier. + /// Represented as a `Vec` for ID composability (e.g. collection IDs can be defined as + /// `ResourceId::from("collection") + Resource::resource_id()`). + id: Vec<&'static str>, +} + +impl ResourceId { + pub fn new(id: &'static str) -> Self { + Self { id: vec![id] } + } +} + +impl Add for ResourceId { + type Output = Self; + + fn add(mut self, rhs: ResourceId) -> Self::Output { + self.id.extend(rhs.id); + self + } +} + +impl AddAssign for ResourceId { + fn add_assign(&mut self, rhs: ResourceId) { + self.id.extend(rhs.id); + } +} + +impl From<&'static str> for ResourceId { + fn from(id: &'static str) -> Self { + Self { id: vec![id] } + } +} + +impl fmt::Display for ResourceId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.id.join("/")) + } +} diff --git a/core/lib/node/src/task/mod.rs b/core/lib/node/src/task/mod.rs new file mode 100644 index 000000000000..43f332a0f4d9 --- /dev/null +++ b/core/lib/node/src/task/mod.rs @@ -0,0 +1,70 @@ +//! Tasks define the "runnable" concept of the node, e.g. something that can be launched and runs until the node +//! is stopped. +//! +//! Task is normally defined by two types, one implementing two traits [`IntoZkSyncTask`], which acts like a +//! constructor, and another one, which implements [`ZkSyncTask`], providing an interface for `ZkSyncNode` to +//! implement the task lifecycle. + +use futures::future::BoxFuture; + +use crate::{ + node::{NodeContext, StopReceiver}, + resource::ResourceId, +}; + +/// Factory that can create a task. +#[async_trait::async_trait] +pub trait IntoZkSyncTask: 'static + Send + Sync { + /// Unique name of the task. + fn task_name(&self) -> &'static str; + + /// Creates a new task. + /// + /// `NodeContext` provides an interface to the utilities that task may need, e.g. ability to get resources + /// or spawn additional tasks. + async fn create( + self: Box, + node: NodeContext<'_>, + ) -> Result, TaskInitError>; +} + +/// A task implementation. +#[async_trait::async_trait] +pub trait ZkSyncTask: 'static + Send + Sync { + /// Runs the task. + /// + /// Once any of the task returns, the node will shutdown. + /// If the task returns an error, the node will spawn an error-level log message and will return a non-zero + /// exit code. + /// + /// `stop_receiver` argument contains a channel receiver that will change its value once the node requests + /// a shutdown. Every task is expected to either await or periodically check the state of channel and stop + /// its execution once the channel is changed. + /// + /// Each task is expected to perform the required cleanup after receiving the stop signal. + async fn run(self: Box, stop_receiver: StopReceiver) -> anyhow::Result<()>; + + /// Asynchronous hook that will be called after *each task* has finished their cleanup. + /// It is guaranteed that no other task is running at this point, e.g. `ZkSyncNode` will invoke + /// this hook sequentially for each task. + /// + /// This hook can be used to perform some cleanup that assumes exclusive access to the resources, e.g. + /// to rollback some state. + /// + /// *Note*: This hook **should not** be used to perform trivial task cleanup, e.g. to wait for the spawned + /// server to stop. By the time this hook is invoked, every component of the node is expected to stop. Not + /// following this rule may cause the tasks that properly implement this hook to malfunction. + fn after_node_shutdown(&self) -> Option> { + None + } +} + +/// An error that can occur during the task initialization. +#[derive(thiserror::Error, Debug)] +#[non_exhaustive] +pub enum TaskInitError { + #[error("Resource {0} is not provided")] + ResourceLacking(ResourceId), + #[error(transparent)] + Internal(#[from] anyhow::Error), +} diff --git a/core/lib/object_store/Cargo.toml b/core/lib/object_store/Cargo.toml index f1b27c76d027..d09fe10975ed 100644 --- a/core/lib/object_store/Cargo.toml +++ b/core/lib/object_store/Cargo.toml @@ -13,7 +13,7 @@ categories = ["cryptography"] vise = { git = "https://github.com/matter-labs/vise.git", version = "0.1.0", rev = "1c9cc500e92cf9ea052b230e114a6f9cce4fb2c1" } zksync_config = { path = "../config" } zksync_types = { path = "../types" } -zksync_protobuf = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "84cdd9e45fd84bc1fac0b394c899ae33aef91afa" } +zksync_protobuf = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } anyhow = "1.0" async-trait = "0.1" diff --git a/core/lib/object_store/src/gcs.rs b/core/lib/object_store/src/gcs.rs index 93ee39fdef2c..d2650a48ea50 100644 --- a/core/lib/object_store/src/gcs.rs +++ b/core/lib/object_store/src/gcs.rs @@ -63,17 +63,22 @@ impl fmt::Debug for GoogleCloudStorage { } } +#[derive(Debug, Clone)] +pub enum GoogleCloudStorageAuthMode { + AuthenticatedWithCredentialFile(String), + Authenticated, + Anonymous, +} + impl GoogleCloudStorage { pub async fn new( - credential_file_path: Option, + auth_mode: GoogleCloudStorageAuthMode, bucket_prefix: String, max_retries: u16, ) -> Self { - let client_config = retry(max_retries, || { - Self::get_client_config(credential_file_path.clone()) - }) - .await - .expect("failed fetching GCS client config after retries"); + let client_config = retry(max_retries, || Self::get_client_config(auth_mode.clone())) + .await + .expect("failed fetching GCS client config after retries"); Self { client: Client::new(client_config), @@ -83,15 +88,17 @@ impl GoogleCloudStorage { } async fn get_client_config( - credential_file_path: Option, + auth_mode: GoogleCloudStorageAuthMode, ) -> Result { - if let Some(path) = credential_file_path { - let cred_file = CredentialsFile::new_from_file(path) - .await - .expect("failed loading GCS credential file"); - ClientConfig::default().with_credentials(cred_file).await - } else { - ClientConfig::default().with_auth().await + match auth_mode { + GoogleCloudStorageAuthMode::AuthenticatedWithCredentialFile(path) => { + let cred_file = CredentialsFile::new_from_file(path) + .await + .expect("failed loading GCS credential file"); + ClientConfig::default().with_credentials(cred_file).await + } + GoogleCloudStorageAuthMode::Authenticated => ClientConfig::default().with_auth().await, + GoogleCloudStorageAuthMode::Anonymous => Ok(ClientConfig::default().anonymous()), } } diff --git a/core/lib/object_store/src/lib.rs b/core/lib/object_store/src/lib.rs index bf6630ef0606..0eddf3a61d53 100644 --- a/core/lib/object_store/src/lib.rs +++ b/core/lib/object_store/src/lib.rs @@ -39,6 +39,6 @@ pub mod _reexports { } pub use self::{ - objects::{AggregationsKey, CircuitKey, ClosedFormInputKey, FriCircuitKey, StoredObject}, + objects::StoredObject, raw::{Bucket, ObjectStore, ObjectStoreError, ObjectStoreFactory}, }; diff --git a/core/lib/object_store/src/objects.rs b/core/lib/object_store/src/objects.rs index dc9865a7c7c2..75c0f5460ad4 100644 --- a/core/lib/object_store/src/objects.rs +++ b/core/lib/object_store/src/objects.rs @@ -7,23 +7,10 @@ use flate2::{read::GzDecoder, write::GzEncoder, Compression}; use prost::Message; use zksync_protobuf::{decode, ProtoFmt}; use zksync_types::{ - aggregated_operations::L1BatchProofForL1, - proofs::{AggregationRound, PrepareBasicCircuitsJob}, snapshots::{ SnapshotFactoryDependencies, SnapshotStorageLogsChunk, SnapshotStorageLogsStorageKey, }, storage::witness_block_state::WitnessBlockState, - zkevm_test_harness::{ - abstract_zksync_circuit::concrete_circuits::ZkSyncCircuit, - bellman::bn256::Bn256, - encodings::{recursion_request::RecursionRequest, QueueSimulator}, - witness::{ - full_block_artifact::{BlockBasicCircuits, BlockBasicCircuitsPublicInputs}, - oracle::VmWitnessOracle, - }, - LeafAggregationOutputDataWitness, NodeAggregationOutputDataWitness, - SchedulerCircuitInstanceWitness, - }, L1BatchNumber, }; @@ -142,145 +129,6 @@ impl StoredObject for WitnessBlockState { serialize_using_bincode!(); } -impl StoredObject for PrepareBasicCircuitsJob { - const BUCKET: Bucket = Bucket::WitnessInput; - type Key<'a> = L1BatchNumber; - - fn encode_key(key: Self::Key<'_>) -> String { - format!("merkel_tree_paths_{key}.bin") - } - - serialize_using_bincode!(); -} - -impl StoredObject for BlockBasicCircuits { - const BUCKET: Bucket = Bucket::LeafAggregationWitnessJobs; - type Key<'a> = L1BatchNumber; - - fn encode_key(key: Self::Key<'_>) -> String { - format!("basic_circuits_{key}.bin") - } - - serialize_using_bincode!(); -} - -impl StoredObject for BlockBasicCircuitsPublicInputs { - const BUCKET: Bucket = Bucket::LeafAggregationWitnessJobs; - type Key<'a> = L1BatchNumber; - - fn encode_key(key: Self::Key<'_>) -> String { - format!("basic_circuits_inputs_{key}.bin") - } - - serialize_using_bincode!(); -} - -impl StoredObject for SchedulerCircuitInstanceWitness { - const BUCKET: Bucket = Bucket::SchedulerWitnessJobs; - type Key<'a> = L1BatchNumber; - - fn encode_key(key: Self::Key<'_>) -> String { - format!("scheduler_witness_{key}.bin") - } - - serialize_using_bincode!(); -} - -impl StoredObject for NodeAggregationOutputDataWitness { - const BUCKET: Bucket = Bucket::SchedulerWitnessJobs; - type Key<'a> = L1BatchNumber; - - fn encode_key(key: Self::Key<'_>) -> String { - format!("final_node_aggregations_{key}.bin") - } - - serialize_using_bincode!(); -} - -impl StoredObject for Vec> { - const BUCKET: Bucket = Bucket::NodeAggregationWitnessJobs; - type Key<'a> = L1BatchNumber; - - fn encode_key(key: Self::Key<'_>) -> String { - format!("aggregation_outputs_{key}.bin") - } - - serialize_using_bincode!(); -} - -impl StoredObject for Vec, 2, 2>> { - const BUCKET: Bucket = Bucket::NodeAggregationWitnessJobs; - type Key<'a> = L1BatchNumber; - - fn encode_key(key: Self::Key<'_>) -> String { - format!("leaf_layer_subqueues_{key}.bin") - } - - serialize_using_bincode!(); -} - -/// Storage key for a [AggregationWrapper`]. -#[derive(Debug, Clone, Copy)] -pub struct AggregationsKey { - pub block_number: L1BatchNumber, - pub circuit_id: u8, - pub depth: u16, -} - -/// Storage key for a [ClosedFormInputWrapper`]. -#[derive(Debug, Clone, Copy)] -pub struct ClosedFormInputKey { - pub block_number: L1BatchNumber, - pub circuit_id: u8, -} - -/// Storage key for a [`CircuitWrapper`]. -#[derive(Debug, Clone, Copy)] -pub struct FriCircuitKey { - pub block_number: L1BatchNumber, - pub sequence_number: usize, - pub circuit_id: u8, - pub aggregation_round: AggregationRound, - pub depth: u16, -} - -/// Storage key for a [`ZkSyncCircuit`]. -#[derive(Debug, Clone, Copy)] -pub struct CircuitKey<'a> { - pub block_number: L1BatchNumber, - pub sequence_number: usize, - pub circuit_type: &'a str, - pub aggregation_round: AggregationRound, -} - -impl StoredObject for ZkSyncCircuit> { - const BUCKET: Bucket = Bucket::ProverJobs; - type Key<'a> = CircuitKey<'a>; - - fn encode_key(key: Self::Key<'_>) -> String { - let CircuitKey { - block_number, - sequence_number, - circuit_type, - aggregation_round, - } = key; - format!("{block_number}_{sequence_number}_{circuit_type}_{aggregation_round:?}.bin") - } - - serialize_using_bincode!(); -} - -impl StoredObject for L1BatchProofForL1 { - const BUCKET: Bucket = Bucket::ProofsFri; - type Key<'a> = L1BatchNumber; - - fn encode_key(key: Self::Key<'_>) -> String { - format!("l1_batch_proof_{key}.bin") - } - - serialize_using_bincode!(); -} - impl dyn ObjectStore + '_ { /// Fetches the value for the given key if it exists. /// diff --git a/core/lib/object_store/src/raw.rs b/core/lib/object_store/src/raw.rs index 72e582deeb2b..61340343c734 100644 --- a/core/lib/object_store/src/raw.rs +++ b/core/lib/object_store/src/raw.rs @@ -3,7 +3,11 @@ use std::{error, fmt, sync::Arc}; use async_trait::async_trait; use zksync_config::configs::object_store::{ObjectStoreConfig, ObjectStoreMode}; -use crate::{file::FileBackedObjectStore, gcs::GoogleCloudStorage, mock::MockStore}; +use crate::{ + file::FileBackedObjectStore, + gcs::{GoogleCloudStorage, GoogleCloudStorageAuthMode}, + mock::MockStore, +}; /// Bucket for [`ObjectStore`] in which objects can be placed. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -88,7 +92,7 @@ impl error::Error for ObjectStoreError { /// /// [`StoredObject`]: crate::StoredObject #[async_trait] -pub trait ObjectStore: fmt::Debug + Send + Sync { +pub trait ObjectStore: 'static + fmt::Debug + Send + Sync { /// Fetches the value for the given key from the given bucket if it exists. /// /// # Errors @@ -178,14 +182,14 @@ impl ObjectStoreFactory { } /// Creates an [`ObjectStore`]. - pub async fn create_store(&self) -> Box { + pub async fn create_store(&self) -> Arc { match &self.origin { ObjectStoreOrigin::Config(config) => Self::create_from_config(config).await, - ObjectStoreOrigin::Mock(store) => Box::new(Arc::clone(store)), + ObjectStoreOrigin::Mock(store) => Arc::new(Arc::clone(store)), } } - async fn create_from_config(config: &ObjectStoreConfig) -> Box { + async fn create_from_config(config: &ObjectStoreConfig) -> Arc { let gcs_credential_file_path = match config.mode { ObjectStoreMode::GCSWithCredentialFile => Some(config.gcs_credential_file_path.clone()), _ => None, @@ -196,27 +200,40 @@ impl ObjectStoreFactory { "Initialized GoogleCloudStorage Object store without credential file" ); let store = GoogleCloudStorage::new( - gcs_credential_file_path, + GoogleCloudStorageAuthMode::Authenticated, config.bucket_base_url.clone(), config.max_retries, ) .await; - Box::new(store) + Arc::new(store) } ObjectStoreMode::GCSWithCredentialFile => { tracing::trace!("Initialized GoogleCloudStorage Object store with credential file"); let store = GoogleCloudStorage::new( - gcs_credential_file_path, + GoogleCloudStorageAuthMode::AuthenticatedWithCredentialFile( + gcs_credential_file_path + .expect("Credentials path must be provided for GCSWithCredentialFile"), + ), config.bucket_base_url.clone(), config.max_retries, ) .await; - Box::new(store) + Arc::new(store) } ObjectStoreMode::FileBacked => { tracing::trace!("Initialized FileBacked Object store"); let store = FileBackedObjectStore::new(config.file_backed_base_path.clone()).await; - Box::new(store) + Arc::new(store) + } + ObjectStoreMode::GCSAnonymousReadOnly => { + tracing::trace!("Initialized GoogleCloudStoragePublicReadOnly store"); + let store = GoogleCloudStorage::new( + GoogleCloudStorageAuthMode::Anonymous, + config.bucket_base_url.clone(), + config.max_retries, + ) + .await; + Arc::new(store) } } } diff --git a/core/lib/protobuf_config/Cargo.toml b/core/lib/protobuf_config/Cargo.toml new file mode 100644 index 000000000000..a91ca2188422 --- /dev/null +++ b/core/lib/protobuf_config/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "zksync_protobuf_config" +version = "0.1.0" +edition = "2021" +authors = ["The Matter Labs Team "] +homepage = "https://zksync.io/" +repository = "https://github.com/matter-labs/zksync-era" +license = "MIT OR Apache-2.0" +keywords = ["blockchain", "zksync"] +categories = ["cryptography"] + +links = "zksync_protobuf_config_proto" + +[dependencies] +serde_json = "1.0" +zksync_basic_types = { path = "../basic_types" } +zksync_config = { path = "../config" } +zksync_protobuf = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } +zksync_types = { path = "../types" } + +anyhow = "1.0" +prost = "0.12.1" + +[dev-dependencies] +rand = "0.8" +pretty_assertions = "1.4.0" + +[build-dependencies] +zksync_protobuf_build = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } + diff --git a/core/lib/protobuf_config/build.rs b/core/lib/protobuf_config/build.rs new file mode 100644 index 000000000000..66afd8fea6da --- /dev/null +++ b/core/lib/protobuf_config/build.rs @@ -0,0 +1,12 @@ +//! Generates rust code from protobufs. +fn main() { + zksync_protobuf_build::Config { + input_root: "src/proto".into(), + proto_root: "zksync/config".into(), + dependencies: vec![], + protobuf_crate: "::zksync_protobuf".parse().unwrap(), + is_public: true, + } + .generate() + .unwrap(); +} diff --git a/core/lib/protobuf_config/src/alerts.rs b/core/lib/protobuf_config/src/alerts.rs new file mode 100644 index 000000000000..9c314301934f --- /dev/null +++ b/core/lib/protobuf_config/src/alerts.rs @@ -0,0 +1,18 @@ +use zksync_config::configs::AlertsConfig; + +use crate::{proto, repr::ProtoRepr}; + +impl ProtoRepr for proto::Alerts { + type Type = AlertsConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + sporadic_crypto_errors_substrs: self.sporadic_crypto_errors_substrs.clone(), + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + sporadic_crypto_errors_substrs: this.sporadic_crypto_errors_substrs.clone(), + } + } +} diff --git a/core/lib/protobuf_config/src/api.rs b/core/lib/protobuf_config/src/api.rs new file mode 100644 index 000000000000..26173de29ff0 --- /dev/null +++ b/core/lib/protobuf_config/src/api.rs @@ -0,0 +1,222 @@ +use anyhow::Context as _; +use zksync_config::configs::{api, ApiConfig}; +use zksync_protobuf::required; + +use crate::{ + parse_h256, proto, + repr::{read_required_repr, ProtoRepr}, +}; + +impl ProtoRepr for proto::Api { + type Type = ApiConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + web3_json_rpc: read_required_repr(&self.web3_json_rpc).context("web3_json_rpc")?, + contract_verification: read_required_repr(&self.contract_verification) + .context("contract_verification")?, + prometheus: read_required_repr(&self.prometheus).context("prometheus")?, + healthcheck: read_required_repr(&self.healthcheck).context("healthcheck")?, + merkle_tree: read_required_repr(&self.merkle_tree).context("merkle_tree")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + web3_json_rpc: Some(ProtoRepr::build(&this.web3_json_rpc)), + contract_verification: Some(ProtoRepr::build(&this.contract_verification)), + prometheus: Some(ProtoRepr::build(&this.prometheus)), + healthcheck: Some(ProtoRepr::build(&this.healthcheck)), + merkle_tree: Some(ProtoRepr::build(&this.merkle_tree)), + } + } +} + +impl ProtoRepr for proto::Web3JsonRpc { + type Type = api::Web3JsonRpcConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + http_port: required(&self.http_port) + .and_then(|p| Ok((*p).try_into()?)) + .context("http_port")?, + http_url: required(&self.http_url).context("http_url")?.clone(), + ws_port: required(&self.ws_port) + .and_then(|p| Ok((*p).try_into()?)) + .context("ws_port")?, + ws_url: required(&self.ws_url).context("ws_url")?.clone(), + req_entities_limit: self.req_entities_limit, + filters_limit: self.filters_limit, + subscriptions_limit: self.subscriptions_limit, + pubsub_polling_interval: self.pubsub_polling_interval, + max_nonce_ahead: *required(&self.max_nonce_ahead).context("max_nonce_ahead")?, + gas_price_scale_factor: *required(&self.gas_price_scale_factor) + .context("gas_price_scale_factor")?, + request_timeout: self.request_timeout, + account_pks: self + .account_pks + .as_ref() + .map(|keys| { + keys.keys + .iter() + .enumerate() + .map(|(i, k)| parse_h256(k).context(i)) + .collect::>() + .context("keys") + }) + .transpose() + .context("account_pks")?, + estimate_gas_scale_factor: *required(&self.estimate_gas_scale_factor) + .context("estimate_gas_scale_factor")?, + estimate_gas_acceptable_overestimation: *required( + &self.estimate_gas_acceptable_overestimation, + ) + .context("acceptable_overestimation")?, + l1_to_l2_transactions_compatibility_mode: *required( + &self.l1_to_l2_transactions_compatibility_mode, + ) + .context("l1_to_l2_transactions_compatibility_mode")?, + max_tx_size: required(&self.max_tx_size) + .and_then(|x| Ok((*x).try_into()?)) + .context("max_tx_size")?, + vm_execution_cache_misses_limit: self + .vm_execution_cache_misses_limit + .map(|x| x.try_into()) + .transpose() + .context("vm_execution_cache_misses_limit")?, + vm_concurrency_limit: self + .vm_concurrency_limit + .map(|x| x.try_into()) + .transpose() + .context("vm_concurrency_limit")?, + factory_deps_cache_size_mb: self + .factory_deps_cache_size_mb + .map(|x| x.try_into()) + .transpose() + .context("factory_deps_cache_size_mb")?, + initial_writes_cache_size_mb: self + .initial_writes_cache_size_mb + .map(|x| x.try_into()) + .transpose() + .context("initial_writes_cache_size_mb")?, + latest_values_cache_size_mb: self + .latest_values_cache_size_mb + .map(|x| x.try_into()) + .transpose() + .context("latests_values_cache_size_mb")?, + fee_history_limit: self.fee_history_limit, + max_batch_request_size: self + .max_batch_request_size + .map(|x| x.try_into()) + .transpose() + .context("max_batch_requres_size")?, + max_response_body_size_mb: self + .max_response_body_size_mb + .map(|x| x.try_into()) + .transpose() + .context("max_response_body_size_mb")?, + websocket_requests_per_minute_limit: self + .websocket_requests_per_minute_limit + .map(|x| x.try_into()) + .transpose() + .context("websocket_requests_per_minute_limit")?, + tree_api_url: self.tree_api_url.clone(), + }) + } + fn build(this: &Self::Type) -> Self { + Self { + http_port: Some(this.http_port.into()), + http_url: Some(this.http_url.clone()), + ws_port: Some(this.ws_port.into()), + ws_url: Some(this.ws_url.clone()), + req_entities_limit: this.req_entities_limit, + filters_limit: this.filters_limit, + subscriptions_limit: this.subscriptions_limit, + pubsub_polling_interval: this.pubsub_polling_interval, + max_nonce_ahead: Some(this.max_nonce_ahead), + gas_price_scale_factor: Some(this.gas_price_scale_factor), + request_timeout: this.request_timeout, + account_pks: this.account_pks.as_ref().map(|keys| proto::PrivateKeys { + keys: keys.iter().map(|k| k.as_bytes().into()).collect(), + }), + estimate_gas_scale_factor: Some(this.estimate_gas_scale_factor), + estimate_gas_acceptable_overestimation: Some( + this.estimate_gas_acceptable_overestimation, + ), + l1_to_l2_transactions_compatibility_mode: Some( + this.l1_to_l2_transactions_compatibility_mode, + ), + max_tx_size: Some(this.max_tx_size.try_into().unwrap()), + vm_execution_cache_misses_limit: this + .vm_execution_cache_misses_limit + .map(|x| x.try_into().unwrap()), + vm_concurrency_limit: this.vm_concurrency_limit.map(|x| x.try_into().unwrap()), + factory_deps_cache_size_mb: this + .factory_deps_cache_size_mb + .map(|x| x.try_into().unwrap()), + initial_writes_cache_size_mb: this + .initial_writes_cache_size_mb + .map(|x| x.try_into().unwrap()), + latest_values_cache_size_mb: this + .latest_values_cache_size_mb + .map(|x| x.try_into().unwrap()), + fee_history_limit: this.fee_history_limit, + max_batch_request_size: this.max_batch_request_size.map(|x| x.try_into().unwrap()), + max_response_body_size_mb: this + .max_response_body_size_mb + .map(|x| x.try_into().unwrap()), + websocket_requests_per_minute_limit: this + .websocket_requests_per_minute_limit + .map(|x| x.into()), + tree_api_url: this.tree_api_url.clone(), + } + } +} + +impl ProtoRepr for proto::ContractVerificationApi { + type Type = api::ContractVerificationApiConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + port: required(&self.port) + .and_then(|p| Ok((*p).try_into()?)) + .context("port")?, + url: required(&self.url).context("url")?.clone(), + }) + } + fn build(this: &Self::Type) -> Self { + Self { + port: Some(this.port.into()), + url: Some(this.url.clone()), + } + } +} + +impl ProtoRepr for proto::HealthCheck { + type Type = api::HealthCheckConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + port: required(&self.port) + .and_then(|p| Ok((*p).try_into()?)) + .context("port")?, + }) + } + fn build(this: &Self::Type) -> Self { + Self { + port: Some(this.port.into()), + } + } +} + +impl ProtoRepr for proto::MerkleTreeApi { + type Type = api::MerkleTreeApiConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + port: required(&self.port) + .and_then(|p| Ok((*p).try_into()?)) + .context("port")?, + }) + } + fn build(this: &Self::Type) -> Self { + Self { + port: Some(this.port.into()), + } + } +} diff --git a/core/lib/protobuf_config/src/chain.rs b/core/lib/protobuf_config/src/chain.rs new file mode 100644 index 000000000000..fc775c763681 --- /dev/null +++ b/core/lib/protobuf_config/src/chain.rs @@ -0,0 +1,248 @@ +use anyhow::Context as _; +use zksync_basic_types::network::Network; +use zksync_config::configs; +use zksync_protobuf::required; + +use crate::{parse_h160, proto, repr::ProtoRepr}; + +impl proto::Network { + fn new(n: &Network) -> Self { + match n { + Network::Mainnet => Self::Mainnet, + Network::Rinkeby => Self::Rinkeby, + Network::Ropsten => Self::Ropsten, + Network::Goerli => Self::Goerli, + Network::Sepolia => Self::Sepolia, + Network::Localhost => Self::Localhost, + Network::Unknown => Self::Unknown, + Network::Test => Self::Test, + } + } + + fn parse(&self) -> Network { + match self { + Self::Mainnet => Network::Mainnet, + Self::Rinkeby => Network::Rinkeby, + Self::Ropsten => Network::Ropsten, + Self::Goerli => Network::Goerli, + Self::Sepolia => Network::Sepolia, + Self::Localhost => Network::Localhost, + Self::Unknown => Network::Unknown, + Self::Test => Network::Test, + } + } +} + +impl proto::FeeModelVersion { + fn new(n: &configs::chain::FeeModelVersion) -> Self { + use configs::chain::FeeModelVersion as From; + match n { + From::V1 => Self::V1, + From::V2 => Self::V2, + } + } + + fn parse(&self) -> configs::chain::FeeModelVersion { + use configs::chain::FeeModelVersion as To; + match self { + Self::V1 => To::V1, + Self::V2 => To::V2, + } + } +} + +impl ProtoRepr for proto::EthNetwork { + type Type = configs::chain::NetworkConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + network: required(&self.network) + .and_then(|x| Ok(proto::Network::try_from(*x)?)) + .context("network")? + .parse(), + zksync_network: required(&self.zksync_network) + .context("zksync_network")? + .clone(), + zksync_network_id: required(&self.zksync_network_id) + .and_then(|x| (*x).try_into().map_err(anyhow::Error::msg)) + .context("zksync_network_id")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + network: Some(proto::Network::new(&this.network).into()), + zksync_network: Some(this.zksync_network.clone()), + zksync_network_id: Some(this.zksync_network_id.as_u64()), + } + } +} + +impl ProtoRepr for proto::StateKeeper { + type Type = configs::chain::StateKeeperConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + transaction_slots: required(&self.transaction_slots) + .and_then(|x| Ok((*x).try_into()?)) + .context("transaction_slots")?, + block_commit_deadline_ms: *required(&self.block_commit_deadline_ms) + .context("block_commit_deadline_ms")?, + miniblock_commit_deadline_ms: *required(&self.miniblock_commit_deadline_ms) + .context("miniblock_commit_deadline_ms")?, + miniblock_seal_queue_capacity: required(&self.miniblock_seal_queue_capacity) + .and_then(|x| Ok((*x).try_into()?)) + .context("miniblock_seal_queue_capacity")?, + max_single_tx_gas: *required(&self.max_single_tx_gas).context("max_single_tx_gas")?, + max_allowed_l2_tx_gas_limit: *required(&self.max_allowed_l2_tx_gas_limit) + .context("max_allowed_l2_tx_gas_limit")?, + reject_tx_at_geometry_percentage: *required(&self.reject_tx_at_geometry_percentage) + .context("reject_tx_at_geometry_percentage")?, + reject_tx_at_eth_params_percentage: *required(&self.reject_tx_at_eth_params_percentage) + .context("reject_tx_at_eth_params_percentage")?, + reject_tx_at_gas_percentage: *required(&self.reject_tx_at_gas_percentage) + .context("reject_tx_at_gas_percentage")?, + close_block_at_geometry_percentage: *required(&self.close_block_at_geometry_percentage) + .context("close_block_at_geometry_percentage")?, + close_block_at_eth_params_percentage: *required( + &self.close_block_at_eth_params_percentage, + ) + .context("close_block_at_eth_params_percentage")?, + close_block_at_gas_percentage: *required(&self.close_block_at_gas_percentage) + .context("close_block_at_gas_percentage")?, + fee_account_addr: required(&self.fee_account_addr) + .and_then(|a| parse_h160(a)) + .context("fee_account_addr")?, + minimal_l2_gas_price: *required(&self.minimal_l2_gas_price) + .context("minimal_l2_gas_price")?, + compute_overhead_part: *required(&self.compute_overhead_part) + .context("compute_overhead_part")?, + pubdata_overhead_part: *required(&self.pubdata_overhead_part) + .context("pubdata_overhead_part")?, + batch_overhead_l1_gas: *required(&self.batch_overhead_l1_gas) + .context("batch_overhead_l1_gas")?, + max_gas_per_batch: *required(&self.max_gas_per_batch).context("max_gas_per_batch")?, + max_pubdata_per_batch: *required(&self.max_pubdata_per_batch) + .context("max_pubdata_per_batch")?, + fee_model_version: required(&self.fee_model_version) + .and_then(|x| Ok(proto::FeeModelVersion::try_from(*x)?)) + .context("fee_model_version")? + .parse(), + validation_computational_gas_limit: *required(&self.validation_computational_gas_limit) + .context("validation_computational_gas_limit")?, + save_call_traces: *required(&self.save_call_traces).context("save_call_traces")?, + virtual_blocks_interval: *required(&self.virtual_blocks_interval) + .context("virtual_blocks_interval")?, + virtual_blocks_per_miniblock: *required(&self.virtual_blocks_per_miniblock) + .context("virtual_blocks_per_miniblock")?, + upload_witness_inputs_to_gcs: *required(&self.upload_witness_inputs_to_gcs) + .context("upload_witness_inputs_to_gcs")?, + enum_index_migration_chunk_size: self + .enum_index_migration_chunk_size + .map(|x| x.try_into()) + .transpose() + .context("enum_index_migration_chunk_size")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + transaction_slots: Some(this.transaction_slots.try_into().unwrap()), + block_commit_deadline_ms: Some(this.block_commit_deadline_ms), + miniblock_commit_deadline_ms: Some(this.miniblock_commit_deadline_ms), + miniblock_seal_queue_capacity: Some( + this.miniblock_seal_queue_capacity.try_into().unwrap(), + ), + max_single_tx_gas: Some(this.max_single_tx_gas), + max_allowed_l2_tx_gas_limit: Some(this.max_allowed_l2_tx_gas_limit), + reject_tx_at_geometry_percentage: Some(this.reject_tx_at_geometry_percentage), + reject_tx_at_eth_params_percentage: Some(this.reject_tx_at_eth_params_percentage), + reject_tx_at_gas_percentage: Some(this.reject_tx_at_gas_percentage), + close_block_at_geometry_percentage: Some(this.close_block_at_geometry_percentage), + close_block_at_eth_params_percentage: Some(this.close_block_at_eth_params_percentage), + close_block_at_gas_percentage: Some(this.close_block_at_gas_percentage), + fee_account_addr: Some(this.fee_account_addr.as_bytes().into()), + minimal_l2_gas_price: Some(this.minimal_l2_gas_price), + compute_overhead_part: Some(this.compute_overhead_part), + pubdata_overhead_part: Some(this.pubdata_overhead_part), + batch_overhead_l1_gas: Some(this.batch_overhead_l1_gas), + max_gas_per_batch: Some(this.max_gas_per_batch), + max_pubdata_per_batch: Some(this.max_pubdata_per_batch), + fee_model_version: Some(proto::FeeModelVersion::new(&this.fee_model_version).into()), + validation_computational_gas_limit: Some(this.validation_computational_gas_limit), + save_call_traces: Some(this.save_call_traces), + virtual_blocks_interval: Some(this.virtual_blocks_interval), + virtual_blocks_per_miniblock: Some(this.virtual_blocks_per_miniblock), + upload_witness_inputs_to_gcs: Some(this.upload_witness_inputs_to_gcs), + enum_index_migration_chunk_size: this + .enum_index_migration_chunk_size + .as_ref() + .map(|x| (*x).try_into().unwrap()), + } + } +} + +impl ProtoRepr for proto::OperationsManager { + type Type = configs::chain::OperationsManagerConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + delay_interval: *required(&self.delay_interval).context("delay_interval")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + delay_interval: Some(this.delay_interval), + } + } +} + +impl ProtoRepr for proto::Mempool { + type Type = configs::chain::MempoolConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + sync_interval_ms: *required(&self.sync_interval_ms).context("sync_interval_ms")?, + sync_batch_size: required(&self.sync_batch_size) + .and_then(|x| Ok((*x).try_into()?)) + .context("sync_batch_size")?, + capacity: *required(&self.capacity).context("capacity")?, + stuck_tx_timeout: *required(&self.stuck_tx_timeout).context("stuck_tx_timeout")?, + remove_stuck_txs: *required(&self.remove_stuck_txs).context("remove_stuck_txs")?, + delay_interval: *required(&self.delay_interval).context("delay_interval")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + sync_interval_ms: Some(this.sync_interval_ms), + sync_batch_size: Some(this.sync_batch_size.try_into().unwrap()), + capacity: Some(this.capacity), + stuck_tx_timeout: Some(this.stuck_tx_timeout), + remove_stuck_txs: Some(this.remove_stuck_txs), + delay_interval: Some(this.delay_interval), + } + } +} + +impl ProtoRepr for proto::CircuitBreaker { + type Type = configs::chain::CircuitBreakerConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + sync_interval_ms: *required(&self.sync_interval_ms).context("sync_interval_ms")?, + http_req_max_retry_number: required(&self.http_req_max_retry_number) + .and_then(|x| Ok((*x).try_into()?)) + .context("http_req_max_retry_number")?, + http_req_retry_interval_sec: required(&self.http_req_retry_interval_sec) + .and_then(|x| Ok((*x).try_into()?)) + .context("http_req_retry_interval_sec")?, + replication_lag_limit_sec: self.replication_lag_limit_sec, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + sync_interval_ms: Some(this.sync_interval_ms), + http_req_max_retry_number: Some(this.http_req_max_retry_number.try_into().unwrap()), + http_req_retry_interval_sec: Some(this.http_req_retry_interval_sec.into()), + replication_lag_limit_sec: this.replication_lag_limit_sec, + } + } +} diff --git a/core/lib/protobuf_config/src/contract_verifier.rs b/core/lib/protobuf_config/src/contract_verifier.rs new file mode 100644 index 000000000000..caa109fdca36 --- /dev/null +++ b/core/lib/protobuf_config/src/contract_verifier.rs @@ -0,0 +1,27 @@ +use anyhow::Context as _; +use zksync_config::configs; +use zksync_protobuf::required; + +use crate::{proto, repr::ProtoRepr}; + +impl ProtoRepr for proto::ContractVerifier { + type Type = configs::ContractVerifierConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + compilation_timeout: *required(&self.compilation_timeout) + .context("compilation_timeout")?, + polling_interval: self.polling_interval, + prometheus_port: required(&self.prometheus_port) + .and_then(|x| Ok((*x).try_into()?)) + .context("prometheus_port")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + compilation_timeout: Some(this.compilation_timeout), + polling_interval: this.polling_interval, + prometheus_port: Some(this.prometheus_port.into()), + } + } +} diff --git a/core/lib/protobuf_config/src/contracts.rs b/core/lib/protobuf_config/src/contracts.rs new file mode 100644 index 000000000000..6521bd0bf810 --- /dev/null +++ b/core/lib/protobuf_config/src/contracts.rs @@ -0,0 +1,179 @@ +use anyhow::Context as _; +use zksync_config::configs; +use zksync_protobuf::required; + +use crate::{parse_h160, parse_h256, proto, repr::ProtoRepr}; + +impl proto::ProverAtGenesis { + fn new(x: &configs::contracts::ProverAtGenesis) -> Self { + use configs::contracts::ProverAtGenesis as From; + match x { + From::Fri => Self::Fri, + From::Old => Self::Old, + } + } + + fn parse(&self) -> configs::contracts::ProverAtGenesis { + use configs::contracts::ProverAtGenesis as To; + match self { + Self::Fri => To::Fri, + Self::Old => To::Old, + } + } +} + +impl ProtoRepr for proto::Contracts { + type Type = configs::ContractsConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + governance_addr: required(&self.governance_addr) + .and_then(|x| parse_h160(x)) + .context("governance_addr")?, + mailbox_facet_addr: required(&self.mailbox_facet_addr) + .and_then(|x| parse_h160(x)) + .context("mailbox_facet_addr")?, + executor_facet_addr: required(&self.executor_facet_addr) + .and_then(|x| parse_h160(x)) + .context("executor_facet_addr")?, + admin_facet_addr: required(&self.admin_facet_addr) + .and_then(|x| parse_h160(x)) + .context("admin_facet_addr")?, + getters_facet_addr: required(&self.getters_facet_addr) + .and_then(|x| parse_h160(x)) + .context("getters_facet_addr")?, + verifier_addr: required(&self.verifier_addr) + .and_then(|x| parse_h160(x)) + .context("verifier_addr")?, + diamond_init_addr: required(&self.diamond_init_addr) + .and_then(|x| parse_h160(x)) + .context("diamond_init_addr")?, + diamond_upgrade_init_addr: required(&self.diamond_upgrade_init_addr) + .and_then(|x| parse_h160(x)) + .context("diamond_upgrade_init_addr")?, + diamond_proxy_addr: required(&self.diamond_proxy_addr) + .and_then(|x| parse_h160(x)) + .context("diamond_proxy_addr")?, + validator_timelock_addr: required(&self.validator_timelock_addr) + .and_then(|x| parse_h160(x)) + .context("validator_timelock_addr")?, + genesis_tx_hash: required(&self.genesis_tx_hash) + .and_then(|x| parse_h256(x)) + .context("genesis_tx_hash")?, + l1_erc20_bridge_proxy_addr: required(&self.l1_erc20_bridge_proxy_addr) + .and_then(|x| parse_h160(x)) + .context("l1_erc20_bridge_proxy_addr")?, + l1_erc20_bridge_impl_addr: required(&self.l1_erc20_bridge_impl_addr) + .and_then(|x| parse_h160(x)) + .context("l1_erc20_bridge_impl_addr")?, + l2_erc20_bridge_addr: required(&self.l2_erc20_bridge_addr) + .and_then(|x| parse_h160(x)) + .context("l2_erc20_bridge_addr")?, + l1_weth_bridge_proxy_addr: self + .l1_weth_bridge_proxy_addr + .as_ref() + .map(|x| parse_h160(x)) + .transpose() + .context("l1_weth_bridge_proxy_addr")?, + l2_weth_bridge_addr: self + .l2_weth_bridge_addr + .as_ref() + .map(|x| parse_h160(x)) + .transpose() + .context("l2_weth_bridge_addr")?, + l1_allow_list_addr: required(&self.l1_allow_list_addr) + .and_then(|x| parse_h160(x)) + .context("l1_allow_list_addr")?, + l2_testnet_paymaster_addr: self + .l2_testnet_paymaster_addr + .as_ref() + .map(|x| parse_h160(x)) + .transpose() + .context("l2_testnet_paymaster_addr")?, + recursion_scheduler_level_vk_hash: required(&self.recursion_scheduler_level_vk_hash) + .and_then(|x| parse_h256(x)) + .context("recursion_scheduler_level_vk_hash")?, + recursion_node_level_vk_hash: required(&self.recursion_node_level_vk_hash) + .and_then(|x| parse_h256(x)) + .context("recursion_node_level_vk_hash")?, + recursion_leaf_level_vk_hash: required(&self.recursion_leaf_level_vk_hash) + .and_then(|x| parse_h256(x)) + .context("recursion_leaf_level_vk_hash")?, + recursion_circuits_set_vks_hash: required(&self.recursion_circuits_set_vks_hash) + .and_then(|x| parse_h256(x)) + .context("recursion_circuits_set_vks_hash")?, + l1_multicall3_addr: required(&self.l1_multicall3_addr) + .and_then(|x| parse_h160(x)) + .context("l1_multicall3_addr")?, + fri_recursion_scheduler_level_vk_hash: required( + &self.fri_recursion_scheduler_level_vk_hash, + ) + .and_then(|x| parse_h256(x)) + .context("fri_recursion_scheduler_level_vk_hash")?, + fri_recursion_node_level_vk_hash: required(&self.fri_recursion_node_level_vk_hash) + .and_then(|x| parse_h256(x)) + .context("fri_recursion_node_level_vk_hash")?, + fri_recursion_leaf_level_vk_hash: required(&self.fri_recursion_leaf_level_vk_hash) + .and_then(|x| parse_h256(x)) + .context("fri_recursion_leaf_level_vk_hash")?, + prover_at_genesis: required(&self.prover_at_genesis) + .and_then(|x| Ok(proto::ProverAtGenesis::try_from(*x)?)) + .context("prover_at_genesis")? + .parse(), + snark_wrapper_vk_hash: required(&self.snark_wrapper_vk_hash) + .and_then(|x| parse_h256(x)) + .context("snark_wrapper_vk_hash")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + governance_addr: Some(this.governance_addr.as_bytes().into()), + mailbox_facet_addr: Some(this.mailbox_facet_addr.as_bytes().into()), + executor_facet_addr: Some(this.executor_facet_addr.as_bytes().into()), + admin_facet_addr: Some(this.admin_facet_addr.as_bytes().into()), + getters_facet_addr: Some(this.getters_facet_addr.as_bytes().into()), + verifier_addr: Some(this.verifier_addr.as_bytes().into()), + diamond_init_addr: Some(this.diamond_init_addr.as_bytes().into()), + diamond_upgrade_init_addr: Some(this.diamond_upgrade_init_addr.as_bytes().into()), + diamond_proxy_addr: Some(this.diamond_proxy_addr.as_bytes().into()), + validator_timelock_addr: Some(this.validator_timelock_addr.as_bytes().into()), + genesis_tx_hash: Some(this.genesis_tx_hash.as_bytes().into()), + l1_erc20_bridge_proxy_addr: Some(this.l1_erc20_bridge_proxy_addr.as_bytes().into()), + l1_erc20_bridge_impl_addr: Some(this.l1_erc20_bridge_impl_addr.as_bytes().into()), + l2_erc20_bridge_addr: Some(this.l2_erc20_bridge_addr.as_bytes().into()), + l1_weth_bridge_proxy_addr: this + .l1_weth_bridge_proxy_addr + .as_ref() + .map(|x| x.as_bytes().into()), + l2_weth_bridge_addr: this + .l2_weth_bridge_addr + .as_ref() + .map(|x| x.as_bytes().into()), + l1_allow_list_addr: Some(this.l1_allow_list_addr.as_bytes().into()), + l2_testnet_paymaster_addr: this + .l2_testnet_paymaster_addr + .as_ref() + .map(|x| x.as_bytes().into()), + recursion_scheduler_level_vk_hash: Some( + this.recursion_scheduler_level_vk_hash.as_bytes().into(), + ), + recursion_node_level_vk_hash: Some(this.recursion_node_level_vk_hash.as_bytes().into()), + recursion_leaf_level_vk_hash: Some(this.recursion_leaf_level_vk_hash.as_bytes().into()), + recursion_circuits_set_vks_hash: Some( + this.recursion_circuits_set_vks_hash.as_bytes().into(), + ), + l1_multicall3_addr: Some(this.l1_multicall3_addr.as_bytes().into()), + fri_recursion_scheduler_level_vk_hash: Some( + this.fri_recursion_scheduler_level_vk_hash.as_bytes().into(), + ), + fri_recursion_node_level_vk_hash: Some( + this.fri_recursion_node_level_vk_hash.as_bytes().into(), + ), + fri_recursion_leaf_level_vk_hash: Some( + this.fri_recursion_leaf_level_vk_hash.as_bytes().into(), + ), + prover_at_genesis: Some(proto::ProverAtGenesis::new(&this.prover_at_genesis).into()), + snark_wrapper_vk_hash: Some(this.snark_wrapper_vk_hash.as_bytes().into()), + } + } +} diff --git a/core/lib/protobuf_config/src/database.rs b/core/lib/protobuf_config/src/database.rs new file mode 100644 index 000000000000..90e0b2bf42e1 --- /dev/null +++ b/core/lib/protobuf_config/src/database.rs @@ -0,0 +1,107 @@ +use anyhow::Context as _; +use zksync_config::configs; +use zksync_protobuf::required; + +use crate::{ + proto, + repr::{read_required_repr, ProtoRepr}, +}; + +impl proto::MerkleTreeMode { + fn new(x: &configs::database::MerkleTreeMode) -> Self { + use configs::database::MerkleTreeMode as From; + match x { + From::Full => Self::Full, + From::Lightweight => Self::Lightweight, + } + } + + fn parse(&self) -> configs::database::MerkleTreeMode { + use configs::database::MerkleTreeMode as To; + match self { + Self::Full => To::Full, + Self::Lightweight => To::Lightweight, + } + } +} + +impl ProtoRepr for proto::MerkleTree { + type Type = configs::database::MerkleTreeConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + path: required(&self.path).context("path")?.clone(), + mode: required(&self.mode) + .and_then(|x| Ok(proto::MerkleTreeMode::try_from(*x)?)) + .context("mode")? + .parse(), + multi_get_chunk_size: required(&self.multi_get_chunk_size) + .and_then(|x| Ok((*x).try_into()?)) + .context("multi_get_chunk_size")?, + block_cache_size_mb: required(&self.block_cache_size_mb) + .and_then(|x| Ok((*x).try_into()?)) + .context("block_cache_size_mb")?, + memtable_capacity_mb: required(&self.memtable_capacity_mb) + .and_then(|x| Ok((*x).try_into()?)) + .context("memtable_capacity_mb")?, + stalled_writes_timeout_sec: *required(&self.stalled_writes_timeout_sec) + .context("stalled_writes_timeout_sec")?, + max_l1_batches_per_iter: required(&self.max_l1_batches_per_iter) + .and_then(|x| Ok((*x).try_into()?)) + .context("max_l1_batches_per_iter")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + path: Some(this.path.clone()), + mode: Some(proto::MerkleTreeMode::new(&this.mode).into()), + multi_get_chunk_size: Some(this.multi_get_chunk_size.try_into().unwrap()), + block_cache_size_mb: Some(this.block_cache_size_mb.try_into().unwrap()), + memtable_capacity_mb: Some(this.memtable_capacity_mb.try_into().unwrap()), + stalled_writes_timeout_sec: Some(this.stalled_writes_timeout_sec), + max_l1_batches_per_iter: Some(this.max_l1_batches_per_iter.try_into().unwrap()), + } + } +} + +impl ProtoRepr for proto::Db { + type Type = configs::database::DBConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + state_keeper_db_path: required(&self.state_keeper_db_path) + .context("state_keeper_db_path")? + .clone(), + merkle_tree: read_required_repr(&self.merkle_tree).context("merkle_tree")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + state_keeper_db_path: Some(this.state_keeper_db_path.clone()), + merkle_tree: Some(ProtoRepr::build(&this.merkle_tree)), + } + } +} + +impl ProtoRepr for proto::Postgres { + type Type = configs::database::PostgresConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + master_url: self.master_url.clone(), + replica_url: self.replica_url.clone(), + prover_url: self.prover_url.clone(), + max_connections: self.max_connections, + statement_timeout_sec: self.statement_timeout_sec, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + master_url: this.master_url.clone(), + replica_url: this.replica_url.clone(), + prover_url: this.prover_url.clone(), + max_connections: this.max_connections, + statement_timeout_sec: this.statement_timeout_sec, + } + } +} diff --git a/core/lib/protobuf_config/src/eth_client.rs b/core/lib/protobuf_config/src/eth_client.rs new file mode 100644 index 000000000000..4965b2e95a67 --- /dev/null +++ b/core/lib/protobuf_config/src/eth_client.rs @@ -0,0 +1,22 @@ +use anyhow::Context as _; +use zksync_config::configs; +use zksync_protobuf::required; + +use crate::{proto, repr::ProtoRepr}; + +impl ProtoRepr for proto::EthClient { + type Type = configs::ETHClientConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + chain_id: *required(&self.chain_id).context("chain_id")?, + web3_url: required(&self.web3_url).context("web3_url")?.clone(), + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + chain_id: Some(this.chain_id), + web3_url: Some(this.web3_url.clone()), + } + } +} diff --git a/core/lib/protobuf_config/src/eth_sender.rs b/core/lib/protobuf_config/src/eth_sender.rs new file mode 100644 index 000000000000..6d6f430b2c71 --- /dev/null +++ b/core/lib/protobuf_config/src/eth_sender.rs @@ -0,0 +1,177 @@ +use anyhow::Context as _; +use zksync_config::configs; +use zksync_protobuf::required; + +use crate::{ + proto, + repr::{read_required_repr, ProtoRepr}, +}; + +impl proto::ProofSendingMode { + fn new(x: &configs::eth_sender::ProofSendingMode) -> Self { + use configs::eth_sender::ProofSendingMode as From; + match x { + From::OnlyRealProofs => Self::OnlyRealProofs, + From::OnlySampledProofs => Self::OnlySampledProofs, + From::SkipEveryProof => Self::SkipEveryProof, + } + } + + fn parse(&self) -> configs::eth_sender::ProofSendingMode { + use configs::eth_sender::ProofSendingMode as To; + match self { + Self::OnlyRealProofs => To::OnlyRealProofs, + Self::OnlySampledProofs => To::OnlySampledProofs, + Self::SkipEveryProof => To::SkipEveryProof, + } + } +} + +impl proto::ProofLoadingMode { + fn new(x: &configs::eth_sender::ProofLoadingMode) -> Self { + use configs::eth_sender::ProofLoadingMode as From; + match x { + From::OldProofFromDb => Self::OldProofFromDb, + From::FriProofFromGcs => Self::FriProofFromGcs, + } + } + + fn parse(&self) -> configs::eth_sender::ProofLoadingMode { + use configs::eth_sender::ProofLoadingMode as To; + match self { + Self::OldProofFromDb => To::OldProofFromDb, + Self::FriProofFromGcs => To::FriProofFromGcs, + } + } +} + +impl ProtoRepr for proto::EthSender { + type Type = configs::eth_sender::ETHSenderConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + sender: read_required_repr(&self.sender).context("sender")?, + gas_adjuster: read_required_repr(&self.gas_adjuster).context("gas_adjuster")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + sender: Some(ProtoRepr::build(&this.sender)), + gas_adjuster: Some(ProtoRepr::build(&this.gas_adjuster)), + } + } +} + +impl ProtoRepr for proto::Sender { + type Type = configs::eth_sender::SenderConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + aggregated_proof_sizes: self + .aggregated_proof_sizes + .iter() + .enumerate() + .map(|(i, x)| (*x).try_into().context(i)) + .collect::>() + .context("aggregated_proof_sizes")?, + wait_confirmations: self.wait_confirmations, + tx_poll_period: *required(&self.tx_poll_period).context("tx_poll_period")?, + aggregate_tx_poll_period: *required(&self.aggregate_tx_poll_period) + .context("aggregate_tx_poll_period")?, + max_txs_in_flight: *required(&self.max_txs_in_flight).context("max_txs_in_flight")?, + proof_sending_mode: required(&self.proof_sending_mode) + .and_then(|x| Ok(proto::ProofSendingMode::try_from(*x)?)) + .context("proof_sending_mode")? + .parse(), + max_aggregated_tx_gas: *required(&self.max_aggregated_tx_gas) + .context("max_aggregated_tx_gas")?, + max_eth_tx_data_size: required(&self.max_eth_tx_data_size) + .and_then(|x| Ok((*x).try_into()?)) + .context("max_eth_tx_data_size")?, + max_aggregated_blocks_to_commit: *required(&self.max_aggregated_blocks_to_commit) + .context("max_aggregated_blocks_to_commit")?, + max_aggregated_blocks_to_execute: *required(&self.max_aggregated_blocks_to_execute) + .context("max_aggregated_blocks_to_execute")?, + aggregated_block_commit_deadline: *required(&self.aggregated_block_commit_deadline) + .context("aggregated_block_commit_deadline")?, + aggregated_block_prove_deadline: *required(&self.aggregated_block_prove_deadline) + .context("aggregated_block_prove_deadline")?, + aggregated_block_execute_deadline: *required(&self.aggregated_block_execute_deadline) + .context("aggregated_block_execute_deadline")?, + timestamp_criteria_max_allowed_lag: required(&self.timestamp_criteria_max_allowed_lag) + .and_then(|x| Ok((*x).try_into()?)) + .context("timestamp_criteria_max_allowed_lag")?, + l1_batch_min_age_before_execute_seconds: self.l1_batch_min_age_before_execute_seconds, + max_acceptable_priority_fee_in_gwei: *required( + &self.max_acceptable_priority_fee_in_gwei, + ) + .context("max_acceptable_priority_fee_in_gwei")?, + proof_loading_mode: required(&self.proof_loading_mode) + .and_then(|x| Ok(proto::ProofLoadingMode::try_from(*x)?)) + .context("proof_loading_mode")? + .parse(), + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + aggregated_proof_sizes: this + .aggregated_proof_sizes + .iter() + .map(|x| (*x).try_into().unwrap()) + .collect(), + wait_confirmations: this.wait_confirmations, + tx_poll_period: Some(this.tx_poll_period), + aggregate_tx_poll_period: Some(this.aggregate_tx_poll_period), + max_txs_in_flight: Some(this.max_txs_in_flight), + proof_sending_mode: Some(proto::ProofSendingMode::new(&this.proof_sending_mode).into()), + max_aggregated_tx_gas: Some(this.max_aggregated_tx_gas), + max_eth_tx_data_size: Some(this.max_eth_tx_data_size.try_into().unwrap()), + max_aggregated_blocks_to_commit: Some(this.max_aggregated_blocks_to_commit), + max_aggregated_blocks_to_execute: Some(this.max_aggregated_blocks_to_execute), + aggregated_block_commit_deadline: Some(this.aggregated_block_commit_deadline), + aggregated_block_prove_deadline: Some(this.aggregated_block_prove_deadline), + aggregated_block_execute_deadline: Some(this.aggregated_block_execute_deadline), + timestamp_criteria_max_allowed_lag: Some( + this.timestamp_criteria_max_allowed_lag.try_into().unwrap(), + ), + l1_batch_min_age_before_execute_seconds: this.l1_batch_min_age_before_execute_seconds, + max_acceptable_priority_fee_in_gwei: Some(this.max_acceptable_priority_fee_in_gwei), + proof_loading_mode: Some(proto::ProofLoadingMode::new(&this.proof_loading_mode).into()), + } + } +} + +impl ProtoRepr for proto::GasAdjuster { + type Type = configs::eth_sender::GasAdjusterConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + default_priority_fee_per_gas: *required(&self.default_priority_fee_per_gas) + .context("default_priority_fee_per_gas")?, + max_base_fee_samples: required(&self.max_base_fee_samples) + .and_then(|x| Ok((*x).try_into()?)) + .context("max_base_fee_samples")?, + pricing_formula_parameter_a: *required(&self.pricing_formula_parameter_a) + .context("pricing_formula_parameter_a")?, + pricing_formula_parameter_b: *required(&self.pricing_formula_parameter_b) + .context("pricing_formula_parameter_b")?, + internal_l1_pricing_multiplier: *required(&self.internal_l1_pricing_multiplier) + .context("internal_l1_pricing_multiplier")?, + internal_enforced_l1_gas_price: self.internal_enforced_l1_gas_price, + poll_period: *required(&self.poll_period).context("poll_period")?, + max_l1_gas_price: self.max_l1_gas_price, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + default_priority_fee_per_gas: Some(this.default_priority_fee_per_gas), + max_base_fee_samples: Some(this.max_base_fee_samples.try_into().unwrap()), + pricing_formula_parameter_a: Some(this.pricing_formula_parameter_a), + pricing_formula_parameter_b: Some(this.pricing_formula_parameter_b), + internal_l1_pricing_multiplier: Some(this.internal_l1_pricing_multiplier), + internal_enforced_l1_gas_price: this.internal_enforced_l1_gas_price, + poll_period: Some(this.poll_period), + max_l1_gas_price: this.max_l1_gas_price, + } + } +} diff --git a/core/lib/protobuf_config/src/eth_watch.rs b/core/lib/protobuf_config/src/eth_watch.rs new file mode 100644 index 000000000000..42c1d20f5220 --- /dev/null +++ b/core/lib/protobuf_config/src/eth_watch.rs @@ -0,0 +1,23 @@ +use anyhow::Context as _; +use zksync_config::configs; +use zksync_protobuf::required; + +use crate::{proto, repr::ProtoRepr}; + +impl ProtoRepr for proto::EthWatch { + type Type = configs::ETHWatchConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + confirmations_for_eth_event: self.confirmations_for_eth_event, + eth_node_poll_interval: *required(&self.eth_node_poll_interval) + .context("eth_node_poll_interval")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + confirmations_for_eth_event: this.confirmations_for_eth_event, + eth_node_poll_interval: Some(this.eth_node_poll_interval), + } + } +} diff --git a/core/lib/protobuf_config/src/fri_proof_compressor.rs b/core/lib/protobuf_config/src/fri_proof_compressor.rs new file mode 100644 index 000000000000..5f1753c9dfa2 --- /dev/null +++ b/core/lib/protobuf_config/src/fri_proof_compressor.rs @@ -0,0 +1,49 @@ +use anyhow::Context as _; +use zksync_config::configs; +use zksync_protobuf::required; + +use crate::{proto, repr::ProtoRepr}; + +impl ProtoRepr for proto::FriProofCompressor { + type Type = configs::FriProofCompressorConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + compression_mode: required(&self.compression_mode) + .and_then(|x| Ok((*x).try_into()?)) + .context("compression_mode")?, + prometheus_listener_port: required(&self.prometheus_listener_port) + .and_then(|x| Ok((*x).try_into()?)) + .context("prometheus_listener_port")?, + prometheus_pushgateway_url: required(&self.prometheus_pushgateway_url) + .context("prometheus_pushgateway_url")? + .clone(), + prometheus_push_interval_ms: self.prometheus_push_interval_ms, + generation_timeout_in_secs: required(&self.generation_timeout_in_secs) + .and_then(|x| Ok((*x).try_into()?)) + .context("generation_timeout_in_secs")?, + max_attempts: *required(&self.max_attempts).context("max_attempts")?, + universal_setup_path: required(&self.universal_setup_path) + .context("universal_setup_path")? + .clone(), + universal_setup_download_url: required(&self.universal_setup_download_url) + .context("universal_setup_download_url")? + .clone(), + verify_wrapper_proof: *required(&self.verify_wrapper_proof) + .context("verify_wrapper_proof")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + compression_mode: Some(this.compression_mode.into()), + prometheus_listener_port: Some(this.prometheus_listener_port.into()), + prometheus_pushgateway_url: Some(this.prometheus_pushgateway_url.clone()), + prometheus_push_interval_ms: this.prometheus_push_interval_ms, + generation_timeout_in_secs: Some(this.generation_timeout_in_secs.into()), + max_attempts: Some(this.max_attempts), + universal_setup_path: Some(this.universal_setup_path.clone()), + universal_setup_download_url: Some(this.universal_setup_download_url.clone()), + verify_wrapper_proof: Some(this.verify_wrapper_proof), + } + } +} diff --git a/core/lib/protobuf_config/src/fri_prover.rs b/core/lib/protobuf_config/src/fri_prover.rs new file mode 100644 index 000000000000..bcd2d6a9d99b --- /dev/null +++ b/core/lib/protobuf_config/src/fri_prover.rs @@ -0,0 +1,98 @@ +use anyhow::Context as _; +use zksync_config::configs; +use zksync_protobuf::required; + +use crate::{proto, repr::ProtoRepr}; + +impl proto::SetupLoadMode { + fn new(x: &configs::fri_prover::SetupLoadMode) -> Self { + use configs::fri_prover::SetupLoadMode as From; + match x { + From::FromDisk => Self::FromDisk, + From::FromMemory => Self::FromMemory, + } + } + + fn parse(&self) -> configs::fri_prover::SetupLoadMode { + use configs::fri_prover::SetupLoadMode as To; + match self { + Self::FromDisk => To::FromDisk, + Self::FromMemory => To::FromMemory, + } + } +} + +impl ProtoRepr for proto::FriProver { + type Type = configs::FriProverConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + setup_data_path: required(&self.setup_data_path) + .context("setup_data_path")? + .clone(), + prometheus_port: required(&self.prometheus_port) + .and_then(|x| Ok((*x).try_into()?)) + .context("prometheus_port")?, + max_attempts: *required(&self.max_attempts).context("max_attempts")?, + generation_timeout_in_secs: required(&self.generation_timeout_in_secs) + .and_then(|x| Ok((*x).try_into()?)) + .context("generation_timeout_in_secs")?, + base_layer_circuit_ids_to_be_verified: required( + &self.base_layer_circuit_ids_to_be_verified, + ) + .context("base_layer_circuit_ids_to_be_verified")? + .clone(), + recursive_layer_circuit_ids_to_be_verified: required( + &self.recursive_layer_circuit_ids_to_be_verified, + ) + .context("recursive_layer_circuit_ids_to_be_verified")? + .clone(), + setup_load_mode: required(&self.setup_load_mode) + .and_then(|x| Ok(proto::SetupLoadMode::try_from(*x)?)) + .context("setup_load_mode")? + .parse(), + specialized_group_id: required(&self.specialized_group_id) + .and_then(|x| Ok((*x).try_into()?)) + .context("specialized_group_id")?, + witness_vector_generator_thread_count: self + .witness_vector_generator_thread_count + .map(|x| x.try_into()) + .transpose() + .context("witness_vector_generator_thread_count")?, + queue_capacity: required(&self.queue_capacity) + .and_then(|x| Ok((*x).try_into()?)) + .context("queue_capacity")?, + witness_vector_receiver_port: required(&self.witness_vector_receiver_port) + .and_then(|x| Ok((*x).try_into()?)) + .context("witness_vector_receiver_port")?, + zone_read_url: required(&self.zone_read_url) + .context("zone_read_url")? + .clone(), + shall_save_to_public_bucket: *required(&self.shall_save_to_public_bucket) + .context("shall_save_to_public_bucket")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + setup_data_path: Some(this.setup_data_path.clone()), + prometheus_port: Some(this.prometheus_port.into()), + max_attempts: Some(this.max_attempts), + generation_timeout_in_secs: Some(this.generation_timeout_in_secs.into()), + base_layer_circuit_ids_to_be_verified: Some( + this.base_layer_circuit_ids_to_be_verified.clone(), + ), + recursive_layer_circuit_ids_to_be_verified: Some( + this.recursive_layer_circuit_ids_to_be_verified.clone(), + ), + setup_load_mode: Some(proto::SetupLoadMode::new(&this.setup_load_mode).into()), + specialized_group_id: Some(this.specialized_group_id.into()), + witness_vector_generator_thread_count: this + .witness_vector_generator_thread_count + .map(|x| x.try_into().unwrap()), + queue_capacity: Some(this.queue_capacity.try_into().unwrap()), + witness_vector_receiver_port: Some(this.witness_vector_receiver_port.into()), + zone_read_url: Some(this.zone_read_url.clone()), + shall_save_to_public_bucket: Some(this.shall_save_to_public_bucket), + } + } +} diff --git a/core/lib/protobuf_config/src/fri_prover_gateway.rs b/core/lib/protobuf_config/src/fri_prover_gateway.rs new file mode 100644 index 000000000000..5d791635762d --- /dev/null +++ b/core/lib/protobuf_config/src/fri_prover_gateway.rs @@ -0,0 +1,34 @@ +use anyhow::Context as _; +use zksync_config::configs; +use zksync_protobuf::required; + +use crate::{proto, repr::ProtoRepr}; + +impl ProtoRepr for proto::FriProverGateway { + type Type = configs::FriProverGatewayConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + api_url: required(&self.api_url).context("api_url")?.clone(), + api_poll_duration_secs: required(&self.api_poll_duration_secs) + .and_then(|x| Ok((*x).try_into()?)) + .context("api_poll_duration_secs")?, + prometheus_listener_port: required(&self.prometheus_listener_port) + .and_then(|x| Ok((*x).try_into()?)) + .context("prometheus_listener_port")?, + prometheus_pushgateway_url: required(&self.prometheus_pushgateway_url) + .context("prometheus_pushgateway_url")? + .clone(), + prometheus_push_interval_ms: self.prometheus_push_interval_ms, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + api_url: Some(this.api_url.clone()), + api_poll_duration_secs: Some(this.api_poll_duration_secs.into()), + prometheus_listener_port: Some(this.prometheus_listener_port.into()), + prometheus_pushgateway_url: Some(this.prometheus_pushgateway_url.clone()), + prometheus_push_interval_ms: this.prometheus_push_interval_ms, + } + } +} diff --git a/core/lib/protobuf_config/src/fri_prover_group.rs b/core/lib/protobuf_config/src/fri_prover_group.rs new file mode 100644 index 000000000000..9c8454657612 --- /dev/null +++ b/core/lib/protobuf_config/src/fri_prover_group.rs @@ -0,0 +1,81 @@ +use std::collections::HashSet; + +use anyhow::Context as _; +use zksync_basic_types::basic_fri_types::CircuitIdRoundTuple; +use zksync_config::configs; +use zksync_protobuf::required; + +use crate::{proto, repr::ProtoRepr}; + +impl ProtoRepr for proto::CircuitIdRoundTuple { + type Type = CircuitIdRoundTuple; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + circuit_id: required(&self.circuit_id) + .and_then(|x| Ok((*x).try_into()?)) + .context("circuit_id")?, + aggregation_round: required(&self.aggregation_round) + .and_then(|x| Ok((*x).try_into()?)) + .context("aggregation_round")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + circuit_id: Some(this.circuit_id.into()), + aggregation_round: Some(this.aggregation_round.into()), + } + } +} + +fn read_vec(v: &[proto::CircuitIdRoundTuple]) -> anyhow::Result> { + v.iter() + .enumerate() + .map(|(i, x)| x.read().context(i)) + .collect() +} + +fn build_vec(v: &HashSet) -> Vec { + let mut v: Vec<_> = v.iter().cloned().collect(); + v.sort(); + v.iter().map(ProtoRepr::build).collect() +} + +impl ProtoRepr for proto::FriProverGroup { + type Type = configs::fri_prover_group::FriProverGroupConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + group_0: read_vec(&self.group_0).context("group_0")?, + group_1: read_vec(&self.group_1).context("group_1")?, + group_2: read_vec(&self.group_2).context("group_2")?, + group_3: read_vec(&self.group_3).context("group_3")?, + group_4: read_vec(&self.group_4).context("group_4")?, + group_5: read_vec(&self.group_5).context("group_5")?, + group_6: read_vec(&self.group_6).context("group_6")?, + group_7: read_vec(&self.group_7).context("group_7")?, + group_8: read_vec(&self.group_8).context("group_8")?, + group_9: read_vec(&self.group_9).context("group_9")?, + group_10: read_vec(&self.group_10).context("group_10")?, + group_11: read_vec(&self.group_11).context("group_11")?, + group_12: read_vec(&self.group_12).context("group_12")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + group_0: build_vec(&this.group_0), + group_1: build_vec(&this.group_1), + group_2: build_vec(&this.group_2), + group_3: build_vec(&this.group_3), + group_4: build_vec(&this.group_4), + group_5: build_vec(&this.group_5), + group_6: build_vec(&this.group_6), + group_7: build_vec(&this.group_7), + group_8: build_vec(&this.group_8), + group_9: build_vec(&this.group_9), + group_10: build_vec(&this.group_10), + group_11: build_vec(&this.group_11), + group_12: build_vec(&this.group_12), + } + } +} diff --git a/core/lib/protobuf_config/src/fri_witness_generator.rs b/core/lib/protobuf_config/src/fri_witness_generator.rs new file mode 100644 index 000000000000..fef20dcc3892 --- /dev/null +++ b/core/lib/protobuf_config/src/fri_witness_generator.rs @@ -0,0 +1,39 @@ +use anyhow::Context as _; +use zksync_config::configs; +use zksync_protobuf::required; + +use crate::{proto, repr::ProtoRepr}; + +impl ProtoRepr for proto::FriWitnessGenerator { + type Type = configs::FriWitnessGeneratorConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + generation_timeout_in_secs: required(&self.generation_timeout_in_secs) + .and_then(|x| Ok((*x).try_into()?)) + .context("generation_timeout_in_secs")?, + max_attempts: *required(&self.max_attempts).context("max_attempts")?, + blocks_proving_percentage: self + .blocks_proving_percentage + .map(|x| x.try_into()) + .transpose() + .context("blocks_proving_percentage")?, + dump_arguments_for_blocks: self.dump_arguments_for_blocks.clone(), + last_l1_batch_to_process: self.last_l1_batch_to_process, + force_process_block: self.force_process_block, + shall_save_to_public_bucket: *required(&self.shall_save_to_public_bucket) + .context("shall_save_to_public_bucket")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + generation_timeout_in_secs: Some(this.generation_timeout_in_secs.into()), + max_attempts: Some(this.max_attempts), + blocks_proving_percentage: this.blocks_proving_percentage.map(|x| x.into()), + dump_arguments_for_blocks: this.dump_arguments_for_blocks.clone(), + last_l1_batch_to_process: this.last_l1_batch_to_process, + force_process_block: this.force_process_block, + shall_save_to_public_bucket: Some(this.shall_save_to_public_bucket), + } + } +} diff --git a/core/lib/protobuf_config/src/fri_witness_vector_generator.rs b/core/lib/protobuf_config/src/fri_witness_vector_generator.rs new file mode 100644 index 000000000000..9c2b432a80a5 --- /dev/null +++ b/core/lib/protobuf_config/src/fri_witness_vector_generator.rs @@ -0,0 +1,56 @@ +use anyhow::Context as _; +use zksync_config::configs; +use zksync_protobuf::required; + +use crate::{proto, repr::ProtoRepr}; + +impl ProtoRepr for proto::FriWitnessVectorGenerator { + type Type = configs::FriWitnessVectorGeneratorConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + max_prover_reservation_duration_in_secs: required( + &self.max_prover_reservation_duration_in_secs, + ) + .and_then(|x| Ok((*x).try_into()?)) + .context("max_prover_reservation_duration_in_secs")?, + prover_instance_wait_timeout_in_secs: required( + &self.prover_instance_wait_timeout_in_secs, + ) + .and_then(|x| Ok((*x).try_into()?)) + .context("prover_instance_wait_timeout_in_secs")?, + prover_instance_poll_time_in_milli_secs: required( + &self.prover_instance_poll_time_in_milli_secs, + ) + .and_then(|x| Ok((*x).try_into()?)) + .context("prover_instance_poll_time_in_milli_secs")?, + prometheus_listener_port: required(&self.prometheus_listener_port) + .and_then(|x| Ok((*x).try_into()?)) + .context("prometheus_listener_port")?, + prometheus_pushgateway_url: required(&self.prometheus_pushgateway_url) + .context("prometheus_pushgateway_url")? + .clone(), + prometheus_push_interval_ms: self.prometheus_push_interval_ms, + specialized_group_id: required(&self.specialized_group_id) + .and_then(|x| Ok((*x).try_into()?)) + .context("specialized_group_id")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + max_prover_reservation_duration_in_secs: Some( + this.max_prover_reservation_duration_in_secs.into(), + ), + prover_instance_wait_timeout_in_secs: Some( + this.prover_instance_wait_timeout_in_secs.into(), + ), + prover_instance_poll_time_in_milli_secs: Some( + this.prover_instance_poll_time_in_milli_secs.into(), + ), + prometheus_listener_port: Some(this.prometheus_listener_port.into()), + prometheus_pushgateway_url: Some(this.prometheus_pushgateway_url.clone()), + prometheus_push_interval_ms: this.prometheus_push_interval_ms, + specialized_group_id: Some(this.specialized_group_id.into()), + } + } +} diff --git a/core/lib/protobuf_config/src/house_keeper.rs b/core/lib/protobuf_config/src/house_keeper.rs new file mode 100644 index 000000000000..00843db3a7cd --- /dev/null +++ b/core/lib/protobuf_config/src/house_keeper.rs @@ -0,0 +1,87 @@ +use anyhow::Context as _; +use zksync_config::configs; +use zksync_protobuf::required; + +use crate::{proto, repr::ProtoRepr}; + +impl ProtoRepr for proto::HouseKeeper { + type Type = configs::house_keeper::HouseKeeperConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + l1_batch_metrics_reporting_interval_ms: *required( + &self.l1_batch_metrics_reporting_interval_ms, + ) + .context("l1_batch_metrics_reporting_interval_ms")?, + gpu_prover_queue_reporting_interval_ms: *required( + &self.gpu_prover_queue_reporting_interval_ms, + ) + .context("gpu_prover_queue_reporting_interval_ms")?, + prover_job_retrying_interval_ms: *required(&self.prover_job_retrying_interval_ms) + .context("prover_job_retrying_interval_ms")?, + prover_stats_reporting_interval_ms: *required(&self.prover_stats_reporting_interval_ms) + .context("prover_stats_reporting_interval_ms")?, + witness_job_moving_interval_ms: *required(&self.witness_job_moving_interval_ms) + .context("witness_job_moving_interval_ms")?, + witness_generator_stats_reporting_interval_ms: *required( + &self.witness_generator_stats_reporting_interval_ms, + ) + .context("witness_generator_stats_reporting_interval_ms")?, + fri_witness_job_moving_interval_ms: *required(&self.fri_witness_job_moving_interval_ms) + .context("fri_witness_job_moving_interval_ms")?, + fri_prover_job_retrying_interval_ms: *required( + &self.fri_prover_job_retrying_interval_ms, + ) + .context("fri_prover_job_retrying_interval_ms")?, + fri_witness_generator_job_retrying_interval_ms: *required( + &self.fri_witness_generator_job_retrying_interval_ms, + ) + .context("fri_witness_generator_job_retrying_interval_ms")?, + prover_db_pool_size: *required(&self.prover_db_pool_size) + .context("prover_db_pool_size")?, + fri_prover_stats_reporting_interval_ms: *required( + &self.fri_prover_stats_reporting_interval_ms, + ) + .context("fri_prover_stats_reporting_interval_ms")?, + fri_proof_compressor_job_retrying_interval_ms: *required( + &self.fri_proof_compressor_job_retrying_interval_ms, + ) + .context("fri_proof_compressor_job_retrying_interval_ms")?, + fri_proof_compressor_stats_reporting_interval_ms: *required( + &self.fri_proof_compressor_stats_reporting_interval_ms, + ) + .context("fri_proof_compressor_stats_reporting_interval_ms")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + l1_batch_metrics_reporting_interval_ms: Some( + this.l1_batch_metrics_reporting_interval_ms, + ), + gpu_prover_queue_reporting_interval_ms: Some( + this.gpu_prover_queue_reporting_interval_ms, + ), + prover_job_retrying_interval_ms: Some(this.prover_job_retrying_interval_ms), + prover_stats_reporting_interval_ms: Some(this.prover_stats_reporting_interval_ms), + witness_job_moving_interval_ms: Some(this.witness_job_moving_interval_ms), + witness_generator_stats_reporting_interval_ms: Some( + this.witness_generator_stats_reporting_interval_ms, + ), + fri_witness_job_moving_interval_ms: Some(this.fri_witness_job_moving_interval_ms), + fri_prover_job_retrying_interval_ms: Some(this.fri_prover_job_retrying_interval_ms), + fri_witness_generator_job_retrying_interval_ms: Some( + this.fri_witness_generator_job_retrying_interval_ms, + ), + prover_db_pool_size: Some(this.prover_db_pool_size), + fri_prover_stats_reporting_interval_ms: Some( + this.fri_prover_stats_reporting_interval_ms, + ), + fri_proof_compressor_job_retrying_interval_ms: Some( + this.fri_proof_compressor_job_retrying_interval_ms, + ), + fri_proof_compressor_stats_reporting_interval_ms: Some( + this.fri_proof_compressor_stats_reporting_interval_ms, + ), + } + } +} diff --git a/core/lib/protobuf_config/src/lib.rs b/core/lib/protobuf_config/src/lib.rs new file mode 100644 index 000000000000..164fbfa7c55f --- /dev/null +++ b/core/lib/protobuf_config/src/lib.rs @@ -0,0 +1,43 @@ +//! Defined protobuf mapping for the config files. +//! It allows to encode the configs using: +//! * protobuf binary format +//! * protobuf text format +//! * protobuf json format + +mod alerts; +mod api; +mod chain; +mod contract_verifier; +mod contracts; +mod database; +mod eth_client; +mod eth_sender; +mod eth_watch; +mod fri_proof_compressor; +mod fri_prover; +mod fri_prover_gateway; +mod fri_prover_group; +mod fri_witness_generator; +mod fri_witness_vector_generator; +mod house_keeper; +mod object_store; +mod proof_data_handler; +mod snapshots_creator; +mod witness_generator; + +pub mod proto; +mod repr; +#[cfg(test)] +mod tests; +mod utils; + +use anyhow::Context as _; +use zksync_types::{H160, H256}; + +fn parse_h256(bytes: &[u8]) -> anyhow::Result { + Ok(<[u8; 32]>::try_from(bytes).context("invalid size")?.into()) +} + +fn parse_h160(bytes: &[u8]) -> anyhow::Result { + Ok(<[u8; 20]>::try_from(bytes).context("invalid size")?.into()) +} diff --git a/core/lib/protobuf_config/src/object_store.rs b/core/lib/protobuf_config/src/object_store.rs new file mode 100644 index 000000000000..b845007caa67 --- /dev/null +++ b/core/lib/protobuf_config/src/object_store.rs @@ -0,0 +1,60 @@ +use anyhow::Context as _; +use zksync_config::configs; +use zksync_protobuf::required; + +use crate::{proto, repr::ProtoRepr}; + +impl proto::ObjectStoreMode { + fn new(x: &configs::object_store::ObjectStoreMode) -> Self { + type From = configs::object_store::ObjectStoreMode; + match x { + From::GCS => Self::Gcs, + From::GCSWithCredentialFile => Self::GcsWithCredentialFile, + From::FileBacked => Self::FileBacked, + From::GCSAnonymousReadOnly => Self::GcsAnonymousReadOnly, + } + } + fn parse(&self) -> configs::object_store::ObjectStoreMode { + type To = configs::object_store::ObjectStoreMode; + match self { + Self::Gcs => To::GCS, + Self::GcsWithCredentialFile => To::GCSWithCredentialFile, + Self::FileBacked => To::FileBacked, + Self::GcsAnonymousReadOnly => To::GCSAnonymousReadOnly, + } + } +} + +impl ProtoRepr for proto::ObjectStore { + type Type = configs::ObjectStoreConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + bucket_base_url: required(&self.bucket_base_url) + .context("bucket_base_url")? + .clone(), + mode: required(&self.mode) + .and_then(|x| Ok(proto::ObjectStoreMode::try_from(*x)?)) + .context("mode")? + .parse(), + file_backed_base_path: required(&self.file_backed_base_path) + .context("file_backed_base_path")? + .clone(), + gcs_credential_file_path: required(&self.gcs_credential_file_path) + .context("gcs_credential_file_path")? + .clone(), + max_retries: required(&self.max_retries) + .and_then(|x| Ok((*x).try_into()?)) + .context("max_retries")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + bucket_base_url: Some(this.bucket_base_url.clone()), + mode: Some(proto::ObjectStoreMode::new(&this.mode).into()), + file_backed_base_path: Some(this.file_backed_base_path.clone()), + gcs_credential_file_path: Some(this.gcs_credential_file_path.clone()), + max_retries: Some(this.max_retries.into()), + } + } +} diff --git a/core/lib/protobuf_config/src/proof_data_handler.rs b/core/lib/protobuf_config/src/proof_data_handler.rs new file mode 100644 index 000000000000..38712eccf4ff --- /dev/null +++ b/core/lib/protobuf_config/src/proof_data_handler.rs @@ -0,0 +1,54 @@ +use anyhow::Context as _; +use zksync_config::configs; +use zksync_protobuf::required; + +use crate::{proto, repr::ProtoRepr}; + +impl proto::ProtocolVersionLoadingMode { + fn new(x: &configs::proof_data_handler::ProtocolVersionLoadingMode) -> Self { + type From = configs::proof_data_handler::ProtocolVersionLoadingMode; + match x { + From::FromDb => Self::FromDb, + From::FromEnvVar => Self::FromEnvVar, + } + } + fn parse(&self) -> configs::proof_data_handler::ProtocolVersionLoadingMode { + type To = configs::proof_data_handler::ProtocolVersionLoadingMode; + match self { + Self::FromDb => To::FromDb, + Self::FromEnvVar => To::FromEnvVar, + } + } +} + +impl ProtoRepr for proto::ProofDataHandler { + type Type = configs::ProofDataHandlerConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + http_port: required(&self.http_port) + .and_then(|x| Ok((*x).try_into()?)) + .context("http_port")?, + proof_generation_timeout_in_secs: required(&self.proof_generation_timeout_in_secs) + .and_then(|x| Ok((*x).try_into()?)) + .context("proof_generation_timeout_in_secs")?, + protocol_version_loading_mode: required(&self.protocol_version_loading_mode) + .and_then(|x| Ok(proto::ProtocolVersionLoadingMode::try_from(*x)?)) + .context("protocol_version_loading_mode")? + .parse(), + fri_protocol_version_id: required(&self.fri_protocol_version_id) + .and_then(|x| Ok((*x).try_into()?)) + .context("fri_protocol_version_id")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + http_port: Some(this.http_port.into()), + proof_generation_timeout_in_secs: Some(this.proof_generation_timeout_in_secs.into()), + protocol_version_loading_mode: Some( + proto::ProtocolVersionLoadingMode::new(&this.protocol_version_loading_mode).into(), + ), + fri_protocol_version_id: Some(this.fri_protocol_version_id.into()), + } + } +} diff --git a/core/lib/protobuf_config/src/proto/alerts.proto b/core/lib/protobuf_config/src/proto/alerts.proto new file mode 100644 index 000000000000..6d9905b79f78 --- /dev/null +++ b/core/lib/protobuf_config/src/proto/alerts.proto @@ -0,0 +1,7 @@ +syntax = "proto3"; + +package zksync.config; + +message Alerts { + repeated string sporadic_crypto_errors_substrs = 1; +} diff --git a/core/lib/protobuf_config/src/proto/api.proto b/core/lib/protobuf_config/src/proto/api.proto new file mode 100644 index 000000000000..ce13e45d3656 --- /dev/null +++ b/core/lib/protobuf_config/src/proto/api.proto @@ -0,0 +1,59 @@ +syntax = "proto3"; + +package zksync.config; + +import "zksync/config/utils.proto"; + +message PrivateKeys { + repeated bytes keys = 1; // H256 +} + +message Web3JsonRpc { + optional uint32 http_port = 1; // required; u16 + optional string http_url = 2; // required + optional uint32 ws_port = 3; // required; u16 + optional string ws_url = 4; // required + optional uint32 req_entities_limit = 5; // optional + optional uint32 filters_limit = 6; // optional + optional uint32 subscriptions_limit = 7; // optional + optional uint64 pubsub_polling_interval = 8; // optional + optional uint32 max_nonce_ahead = 9; // required + optional double gas_price_scale_factor = 10; // required + optional uint64 request_timeout = 11; // seconds + optional PrivateKeys account_pks = 12; // optional + optional double estimate_gas_scale_factor = 13; // required + optional uint32 estimate_gas_acceptable_overestimation = 14; // required + optional bool l1_to_l2_transactions_compatibility_mode = 15; // required + optional uint64 max_tx_size = 16; // required; B + optional uint64 vm_execution_cache_misses_limit = 17; // optional + optional uint64 vm_concurrency_limit = 18; // optional + optional uint64 factory_deps_cache_size_mb = 19; // optional; MB + optional uint64 initial_writes_cache_size_mb = 20; // optional; MB + optional uint64 latest_values_cache_size_mb = 21; // optional; MB + optional uint64 fee_history_limit = 22; // optional + optional uint64 max_batch_request_size = 23; // optional + optional uint64 max_response_body_size_mb = 24; // optional; MB + optional uint32 websocket_requests_per_minute_limit = 25; // optional + optional string tree_api_url = 26; // optional +} + +message ContractVerificationApi { + optional uint32 port = 1; // required; u16 + optional string url = 2; // required +} + +message HealthCheck { + optional uint32 port = 1; // required; u16 +} + +message MerkleTreeApi { + optional uint32 port = 1; // required; u16 +} + +message Api { + optional Web3JsonRpc web3_json_rpc = 1; // required + optional ContractVerificationApi contract_verification = 2; // required + optional Prometheus prometheus = 3; // required + optional HealthCheck healthcheck = 4; // required + optional MerkleTreeApi merkle_tree = 5; // required +} diff --git a/core/lib/protobuf_config/src/proto/chain.proto b/core/lib/protobuf_config/src/proto/chain.proto new file mode 100644 index 000000000000..8e08d47271b5 --- /dev/null +++ b/core/lib/protobuf_config/src/proto/chain.proto @@ -0,0 +1,76 @@ +syntax = "proto3"; + +package zksync.config; + +enum Network { + UNKNOWN = 0; + MAINNET = 1; + RINKEBY = 2; + ROPSTEN = 3; + GOERLI = 4; + SEPOLIA = 5; + LOCALHOST = 6; + TEST = 7; +} + +enum FeeModelVersion { + V1 = 0; + V2 = 1; +} + +message EthNetwork { + optional Network network = 1; // required + optional string zksync_network = 2; // required + optional uint64 zksync_network_id = 3; // required; L2ChainId +} + +message StateKeeper { + optional uint64 transaction_slots = 1; // required + optional uint64 block_commit_deadline_ms = 2; // required; ms + optional uint64 miniblock_commit_deadline_ms = 3; // required; ms + optional uint64 miniblock_seal_queue_capacity = 4; // required + optional uint32 max_single_tx_gas = 5; // required; gwei? + optional uint32 max_allowed_l2_tx_gas_limit = 6; // required; wei? + optional double reject_tx_at_geometry_percentage = 7; // required; % + optional double reject_tx_at_eth_params_percentage = 8; // required; % + optional double reject_tx_at_gas_percentage = 9; // required; % + optional double close_block_at_geometry_percentage = 10; // required; % + optional double close_block_at_eth_params_percentage = 11; // required; % + optional double close_block_at_gas_percentage = 12; // required; % + optional bytes fee_account_addr = 13; // required; H160 + optional uint64 minimal_l2_gas_price = 14; // required; wei? + optional double compute_overhead_part = 15; // required; [0,1] + optional double pubdata_overhead_part = 16; // required; [0,1] + optional uint64 batch_overhead_l1_gas = 17; // required; wei? + optional uint64 max_gas_per_batch = 18; // required; wei? + optional uint64 max_pubdata_per_batch = 19; // required; bytes? + optional FeeModelVersion fee_model_version = 20; // required + optional uint32 validation_computational_gas_limit = 21; // required; wei? + optional bool save_call_traces = 22; // required + optional uint32 virtual_blocks_interval = 23; // required + optional uint32 virtual_blocks_per_miniblock = 24; // required + optional bool upload_witness_inputs_to_gcs = 25; // required + optional uint64 enum_index_migration_chunk_size = 26; // optional +} + +message OperationsManager { + optional uint64 delay_interval = 1; // required; ms +} + +message Mempool { + optional uint64 sync_interval_ms = 1; // required; ms + optional uint64 sync_batch_size = 2; // required; ? + optional uint64 capacity = 3; // required; ? + optional uint64 stuck_tx_timeout = 4; // required; s + optional bool remove_stuck_txs = 5; // required + optional uint64 delay_interval = 6; // required; ms +} + +message CircuitBreaker { + optional uint64 sync_interval_ms = 1; // required; ms + optional uint64 http_req_max_retry_number = 2; // required + optional uint32 http_req_retry_interval_sec = 3; // required; s + optional uint32 replication_lag_limit_sec = 4; // optional; s +} + + diff --git a/core/lib/protobuf_config/src/proto/contract_verifier.proto b/core/lib/protobuf_config/src/proto/contract_verifier.proto new file mode 100644 index 000000000000..f76ba2b12274 --- /dev/null +++ b/core/lib/protobuf_config/src/proto/contract_verifier.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +package zksync.config; + +message ContractVerifier { + optional uint64 compilation_timeout = 1; // required; s + optional uint64 polling_interval = 2; // optional; ms + optional uint32 prometheus_port = 3; // required; u16 +} diff --git a/core/lib/protobuf_config/src/proto/contracts.proto b/core/lib/protobuf_config/src/proto/contracts.proto new file mode 100644 index 000000000000..1acda022cd90 --- /dev/null +++ b/core/lib/protobuf_config/src/proto/contracts.proto @@ -0,0 +1,39 @@ +syntax = "proto3"; + +package zksync.config; + +enum ProverAtGenesis { + FRI = 0; + OLD = 1; +} + +message Contracts { + optional bytes governance_addr = 1; // required; H160 + optional bytes mailbox_facet_addr = 2; // required; H160 + optional bytes executor_facet_addr = 3; // required; H160 + optional bytes admin_facet_addr = 4; // required; H160 + optional bytes getters_facet_addr = 5; // required; H160 + optional bytes verifier_addr = 6; // required; H160 + optional bytes diamond_init_addr = 7; // required; H160 + optional bytes diamond_upgrade_init_addr = 8; // required; H160 + optional bytes diamond_proxy_addr = 9; // required; H160 + optional bytes validator_timelock_addr = 10; // required; H160 + optional bytes genesis_tx_hash = 11; // required; H256 + optional bytes l1_erc20_bridge_proxy_addr = 12; // required; H160 + optional bytes l1_erc20_bridge_impl_addr = 13; // required; H160 + optional bytes l2_erc20_bridge_addr = 14; // required; H160 + optional bytes l1_weth_bridge_proxy_addr = 15; // optional; H160 + optional bytes l2_weth_bridge_addr = 16; // optional; H160 + optional bytes l1_allow_list_addr = 17; // required; H160 + optional bytes l2_testnet_paymaster_addr = 18; // optional; H160 + optional bytes recursion_scheduler_level_vk_hash = 19; // required; H256 + optional bytes recursion_node_level_vk_hash = 20; // required; H256 + optional bytes recursion_leaf_level_vk_hash = 21; // required; H256 + optional bytes recursion_circuits_set_vks_hash = 22; // required; H256 + optional bytes l1_multicall3_addr = 23; // required; H160 + optional bytes fri_recursion_scheduler_level_vk_hash = 24; // required; H256 + optional bytes fri_recursion_node_level_vk_hash = 25; // required; H256 + optional bytes fri_recursion_leaf_level_vk_hash = 26; // required; H256 + optional ProverAtGenesis prover_at_genesis = 27; // required + optional bytes snark_wrapper_vk_hash = 28; // required; H256 +} diff --git a/core/lib/protobuf_config/src/proto/database.proto b/core/lib/protobuf_config/src/proto/database.proto new file mode 100644 index 000000000000..64e1e7fd300e --- /dev/null +++ b/core/lib/protobuf_config/src/proto/database.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; + +package zksync.config; + +enum MerkleTreeMode { + FULL = 0; + LIGHTWEIGHT = 1; +} + +message MerkleTree { + optional string path = 1; // optional; fs path + optional MerkleTreeMode mode = 2; // optional + optional uint64 multi_get_chunk_size = 3; // optional; ? + optional uint64 block_cache_size_mb = 4; // optional; MB + optional uint64 memtable_capacity_mb = 5; // optional; MB + optional uint64 stalled_writes_timeout_sec = 6; // optional; s + optional uint64 max_l1_batches_per_iter = 7; // optional +} + +message DB { + optional string state_keeper_db_path = 1; // optional; fs path + optional MerkleTree merkle_tree = 2; // optional +} + +message Postgres { + optional string master_url = 1; // optional + optional string replica_url = 2; // optional + optional string prover_url = 3; // optional + optional uint32 max_connections = 4; // optional + optional uint64 statement_timeout_sec = 5; // optional; s +} diff --git a/core/lib/protobuf_config/src/proto/eth_client.proto b/core/lib/protobuf_config/src/proto/eth_client.proto new file mode 100644 index 000000000000..50723dc2dd15 --- /dev/null +++ b/core/lib/protobuf_config/src/proto/eth_client.proto @@ -0,0 +1,8 @@ +syntax = "proto3"; + +package zksync.config; + +message ETHClient { + optional uint64 chain_id = 1; // required; TODO: shouldn't it be Network? + optional string web3_url = 2; // required +} diff --git a/core/lib/protobuf_config/src/proto/eth_sender.proto b/core/lib/protobuf_config/src/proto/eth_sender.proto new file mode 100644 index 000000000000..b5e866d04126 --- /dev/null +++ b/core/lib/protobuf_config/src/proto/eth_sender.proto @@ -0,0 +1,51 @@ +syntax = "proto3"; + +package zksync.config; + +message ETHSender { + optional Sender sender = 1; // required + optional GasAdjuster gas_adjuster = 2; // required +} + +enum ProofSendingMode { + ONLY_REAL_PROOFS = 0; + ONLY_SAMPLED_PROOFS = 1; + SKIP_EVERY_PROOF = 2; +} + +enum ProofLoadingMode { + OLD_PROOF_FROM_DB = 0; + FRI_PROOF_FROM_GCS = 1; +} + +message Sender { + repeated uint64 aggregated_proof_sizes = 1; // ? + optional uint64 wait_confirmations = 2; // optional + optional uint64 tx_poll_period = 3; // required; s + optional uint64 aggregate_tx_poll_period = 4; // required; s + optional uint64 max_txs_in_flight = 5; // required + optional ProofSendingMode proof_sending_mode = 6; // required + optional uint32 max_aggregated_tx_gas = 7; // required; wei? + optional uint64 max_eth_tx_data_size = 8; // required; ? + optional uint32 max_aggregated_blocks_to_commit = 9; // required + optional uint32 max_aggregated_blocks_to_execute = 10; // required + optional uint64 aggregated_block_commit_deadline = 11; // required; ? + optional uint64 aggregated_block_prove_deadline = 12; // required; ? + optional uint64 aggregated_block_execute_deadline = 13; // required; ? + optional uint64 timestamp_criteria_max_allowed_lag = 14; // required; ? + optional uint64 l1_batch_min_age_before_execute_seconds = 15; // optional; s + optional uint64 max_acceptable_priority_fee_in_gwei = 16; // required; gwei + optional ProofLoadingMode proof_loading_mode = 17; // required + // operator_private_key? +} + +message GasAdjuster { + optional uint64 default_priority_fee_per_gas = 1; // required; wei? + optional uint64 max_base_fee_samples = 2; // required; wei? + optional double pricing_formula_parameter_a = 3; // required + optional double pricing_formula_parameter_b = 4; // required + optional double internal_l1_pricing_multiplier = 5; // required + optional uint64 internal_enforced_l1_gas_price = 6; // optional; wei? + optional uint64 poll_period = 7; // required; s + optional uint64 max_l1_gas_price = 8; // optional; wei? +} diff --git a/core/lib/protobuf_config/src/proto/eth_watch.proto b/core/lib/protobuf_config/src/proto/eth_watch.proto new file mode 100644 index 000000000000..fe78fd33238c --- /dev/null +++ b/core/lib/protobuf_config/src/proto/eth_watch.proto @@ -0,0 +1,8 @@ +syntax = "proto3"; + +package zksync.config; + +message ETHWatch { + optional uint64 confirmations_for_eth_event = 1; // optional + optional uint64 eth_node_poll_interval = 2; // required; ms +} diff --git a/core/lib/protobuf_config/src/proto/fri_proof_compressor.proto b/core/lib/protobuf_config/src/proto/fri_proof_compressor.proto new file mode 100644 index 000000000000..b8880936c5ef --- /dev/null +++ b/core/lib/protobuf_config/src/proto/fri_proof_compressor.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +package zksync.config; + +message FriProofCompressor { + optional uint32 compression_mode = 1; // required; u8 + optional uint32 prometheus_listener_port = 2; // required; u16 + optional string prometheus_pushgateway_url = 3; // required + optional uint64 prometheus_push_interval_ms = 4; // optional; ms + optional uint32 generation_timeout_in_secs = 5; // required; s + optional uint32 max_attempts = 6; // required + optional string universal_setup_path = 7; // required; fs path + optional string universal_setup_download_url = 8; // required + optional bool verify_wrapper_proof = 9; // required +} diff --git a/core/lib/protobuf_config/src/proto/fri_prover.proto b/core/lib/protobuf_config/src/proto/fri_prover.proto new file mode 100644 index 000000000000..5547bd9b8da9 --- /dev/null +++ b/core/lib/protobuf_config/src/proto/fri_prover.proto @@ -0,0 +1,24 @@ +syntax = "proto3"; + +package zksync.config; + +enum SetupLoadMode { + FROM_DISK = 0; + FROM_MEMORY = 1; +} + +message FriProver { + optional string setup_data_path = 1; // required; fs path? + optional uint32 prometheus_port = 2; // required; u16 + optional uint32 max_attempts = 3; // required + optional uint32 generation_timeout_in_secs = 4; // required; s + optional bytes base_layer_circuit_ids_to_be_verified = 5; // required + optional bytes recursive_layer_circuit_ids_to_be_verified = 6; // required + optional SetupLoadMode setup_load_mode = 7; // required + optional uint32 specialized_group_id = 8; // required; u8 + optional uint64 witness_vector_generator_thread_count = 9; // optional + optional uint64 queue_capacity = 10; // required + optional uint32 witness_vector_receiver_port = 11; // required; u16 + optional string zone_read_url = 12; // required + optional bool shall_save_to_public_bucket = 13; // required +} diff --git a/core/lib/protobuf_config/src/proto/fri_prover_gateway.proto b/core/lib/protobuf_config/src/proto/fri_prover_gateway.proto new file mode 100644 index 000000000000..716b761607c2 --- /dev/null +++ b/core/lib/protobuf_config/src/proto/fri_prover_gateway.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +package zksync.config; + +message FriProverGateway { + optional string api_url = 1; // required + optional uint32 api_poll_duration_secs = 2; // required; s + optional uint32 prometheus_listener_port = 3; // required; u16 + optional string prometheus_pushgateway_url = 4; // required + optional uint64 prometheus_push_interval_ms = 5; // optional; ms +} diff --git a/core/lib/protobuf_config/src/proto/fri_prover_group.proto b/core/lib/protobuf_config/src/proto/fri_prover_group.proto new file mode 100644 index 000000000000..8a4dd9511b41 --- /dev/null +++ b/core/lib/protobuf_config/src/proto/fri_prover_group.proto @@ -0,0 +1,24 @@ +syntax = "proto3"; + +package zksync.config; + +message CircuitIdRoundTuple { + optional uint32 circuit_id = 1; // required; u8 + optional uint32 aggregation_round = 2; // required; u8 +} + +message FriProverGroup { + repeated CircuitIdRoundTuple group_0 = 1; + repeated CircuitIdRoundTuple group_1 = 2; + repeated CircuitIdRoundTuple group_2 = 3; + repeated CircuitIdRoundTuple group_3 = 4; + repeated CircuitIdRoundTuple group_4 = 5; + repeated CircuitIdRoundTuple group_5 = 6; + repeated CircuitIdRoundTuple group_6 = 7; + repeated CircuitIdRoundTuple group_7 = 8; + repeated CircuitIdRoundTuple group_8 = 9; + repeated CircuitIdRoundTuple group_9 = 10; + repeated CircuitIdRoundTuple group_10 = 11; + repeated CircuitIdRoundTuple group_11 = 12; + repeated CircuitIdRoundTuple group_12 = 13; +} diff --git a/core/lib/protobuf_config/src/proto/fri_witness_generator.proto b/core/lib/protobuf_config/src/proto/fri_witness_generator.proto new file mode 100644 index 000000000000..dda7f1e8fef1 --- /dev/null +++ b/core/lib/protobuf_config/src/proto/fri_witness_generator.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; + +package zksync.config; + +message FriWitnessGenerator { + optional uint32 generation_timeout_in_secs = 1; // required; s + optional uint32 max_attempts = 2; // required + optional uint32 blocks_proving_percentage = 3; // optional; 0-100 + repeated uint32 dump_arguments_for_blocks = 4; + optional uint32 last_l1_batch_to_process = 5; // optional + optional uint32 force_process_block = 6; // optional + optional bool shall_save_to_public_bucket = 7; // required +} diff --git a/core/lib/protobuf_config/src/proto/fri_witness_vector_generator.proto b/core/lib/protobuf_config/src/proto/fri_witness_vector_generator.proto new file mode 100644 index 000000000000..5ec4c0eca291 --- /dev/null +++ b/core/lib/protobuf_config/src/proto/fri_witness_vector_generator.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; + +package zksync.config; + +message FriWitnessVectorGenerator { + optional uint32 max_prover_reservation_duration_in_secs = 1; // required; s + optional uint32 prover_instance_wait_timeout_in_secs = 2; // required; s + optional uint32 prover_instance_poll_time_in_milli_secs = 3; // required; ms + optional uint32 prometheus_listener_port = 4; // required; u16 + optional string prometheus_pushgateway_url = 5; // required + optional uint64 prometheus_push_interval_ms = 6; // optional; ms + optional uint32 specialized_group_id = 7; // required; u8 +} diff --git a/core/lib/protobuf_config/src/proto/house_keeper.proto b/core/lib/protobuf_config/src/proto/house_keeper.proto new file mode 100644 index 000000000000..d27fb6da71e2 --- /dev/null +++ b/core/lib/protobuf_config/src/proto/house_keeper.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; + +package zksync.config; + +message HouseKeeper { + optional uint64 l1_batch_metrics_reporting_interval_ms = 1; // required; ms + optional uint64 gpu_prover_queue_reporting_interval_ms = 2; // required; ms + optional uint64 prover_job_retrying_interval_ms = 3; // required; ms + optional uint64 prover_stats_reporting_interval_ms = 4; // required ms + optional uint64 witness_job_moving_interval_ms = 5; // required; ms + optional uint64 witness_generator_stats_reporting_interval_ms = 6; // required; ms + optional uint64 fri_witness_job_moving_interval_ms = 7; // required; ms + optional uint64 fri_prover_job_retrying_interval_ms = 8; // required; ms + optional uint64 fri_witness_generator_job_retrying_interval_ms = 9; // required; ms + optional uint32 prover_db_pool_size = 10; // required + optional uint64 fri_prover_stats_reporting_interval_ms = 11; // required; ms + optional uint64 fri_proof_compressor_job_retrying_interval_ms = 12; // required; ms + optional uint64 fri_proof_compressor_stats_reporting_interval_ms = 13; // required; ms +} diff --git a/core/lib/protobuf_config/src/proto/mod.rs b/core/lib/protobuf_config/src/proto/mod.rs new file mode 100644 index 000000000000..660bf4c5b4cc --- /dev/null +++ b/core/lib/protobuf_config/src/proto/mod.rs @@ -0,0 +1,2 @@ +#![allow(warnings)] +include!(concat!(env!("OUT_DIR"), "/src/proto/gen.rs")); diff --git a/core/lib/protobuf_config/src/proto/object_store.proto b/core/lib/protobuf_config/src/proto/object_store.proto new file mode 100644 index 000000000000..941799c07c20 --- /dev/null +++ b/core/lib/protobuf_config/src/proto/object_store.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; + +package zksync.config; + +enum ObjectStoreMode { + GCS = 0; + GCS_WITH_CREDENTIAL_FILE = 1; + FILE_BACKED = 2; + GCS_ANONYMOUS_READ_ONLY = 3; +} + +message ObjectStore { + optional string bucket_base_url = 1; // required; url + optional ObjectStoreMode mode = 2; // required + optional string file_backed_base_path = 3; // required; fs path + optional string gcs_credential_file_path = 4; // required; fs path + optional uint32 max_retries = 5; // required +} diff --git a/core/lib/protobuf_config/src/proto/proof_data_handler.proto b/core/lib/protobuf_config/src/proto/proof_data_handler.proto new file mode 100644 index 000000000000..a76e15ed5ce9 --- /dev/null +++ b/core/lib/protobuf_config/src/proto/proof_data_handler.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +package zksync.config; + +enum ProtocolVersionLoadingMode { + FROM_DB = 0; + FROM_ENV_VAR = 1; +} + +message ProofDataHandler { + optional uint32 http_port = 1; // required; u16 + optional uint32 proof_generation_timeout_in_secs = 2; // required; s + optional ProtocolVersionLoadingMode protocol_version_loading_mode = 3; // required + optional uint32 fri_protocol_version_id = 4; // required; u16 +} diff --git a/core/lib/protobuf_config/src/proto/snapshots_creator.proto b/core/lib/protobuf_config/src/proto/snapshots_creator.proto new file mode 100644 index 000000000000..27e4c66435d7 --- /dev/null +++ b/core/lib/protobuf_config/src/proto/snapshots_creator.proto @@ -0,0 +1,8 @@ +syntax = "proto3"; + +package zksync.config; + +message SnapshotsCreator { + optional uint64 storage_logs_chunk_size = 1; // optional + optional uint32 concurrent_queries_count = 2; // optional +} diff --git a/core/lib/protobuf_config/src/proto/utils.proto b/core/lib/protobuf_config/src/proto/utils.proto new file mode 100644 index 000000000000..40c6c10c756e --- /dev/null +++ b/core/lib/protobuf_config/src/proto/utils.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +package zksync.config; + +message Prometheus { + optional uint32 listener_port = 1; // required + optional string pushgateway_url = 2; // required + optional uint64 push_interval_ms = 3; +} diff --git a/core/lib/protobuf_config/src/proto/witness_generator.proto b/core/lib/protobuf_config/src/proto/witness_generator.proto new file mode 100644 index 000000000000..5836c5892e73 --- /dev/null +++ b/core/lib/protobuf_config/src/proto/witness_generator.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; + +package zksync.config; + +enum BasicWitnessGeneratorDataSource { + FROM_POSTGRES = 0; + FROM_POSTGRES_SHADOW_BLOB = 1; + FROM_BLOB = 2; +} + +message WitnessGenerator { + optional uint32 generation_timeout_in_secs = 1; // required; s + optional string initial_setup_key_path = 2; // required; fs path + optional string key_download_url = 3; // required; url + optional uint32 max_attempts = 4; // required + optional uint32 blocks_proving_percentage = 5; // optional; 0-100 (percentage) + repeated uint32 dump_arguments_for_blocks = 6; + optional uint32 last_l1_batch_to_process = 7; // optional + optional BasicWitnessGeneratorDataSource data_source = 8; // required +} diff --git a/core/lib/protobuf_config/src/repr.rs b/core/lib/protobuf_config/src/repr.rs new file mode 100644 index 000000000000..8b71ee63c847 --- /dev/null +++ b/core/lib/protobuf_config/src/repr.rs @@ -0,0 +1,15 @@ +use anyhow::Context as _; + +/// Trait reverse to `zksync_protobuf::ProtoFmt` for cases where +/// you would like to specify a custom proto encoding for an externally defined type. +pub(crate) trait ProtoRepr: + zksync_protobuf::build::prost_reflect::ReflectMessage + Default +{ + type Type; + fn read(&self) -> anyhow::Result; + fn build(this: &Self::Type) -> Self; +} + +pub(crate) fn read_required_repr(field: &Option

) -> anyhow::Result { + field.as_ref().context("missing field")?.read() +} diff --git a/core/lib/protobuf_config/src/snapshots_creator.rs b/core/lib/protobuf_config/src/snapshots_creator.rs new file mode 100644 index 000000000000..1ea5aada1203 --- /dev/null +++ b/core/lib/protobuf_config/src/snapshots_creator.rs @@ -0,0 +1,24 @@ +use anyhow::Context as _; +use zksync_config::configs; +use zksync_protobuf::required; + +use crate::{proto, repr::ProtoRepr}; + +impl ProtoRepr for proto::SnapshotsCreator { + type Type = configs::SnapshotsCreatorConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + storage_logs_chunk_size: *required(&self.storage_logs_chunk_size) + .context("storage_logs_chunk_size")?, + concurrent_queries_count: *required(&self.concurrent_queries_count) + .context("concurrent_queries_count")?, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + storage_logs_chunk_size: Some(this.storage_logs_chunk_size), + concurrent_queries_count: Some(this.concurrent_queries_count), + } + } +} diff --git a/core/lib/protobuf_config/src/tests.rs b/core/lib/protobuf_config/src/tests.rs new file mode 100644 index 000000000000..de4803a10085 --- /dev/null +++ b/core/lib/protobuf_config/src/tests.rs @@ -0,0 +1,92 @@ +use pretty_assertions::assert_eq; +use rand::Rng; +use zksync_config::testonly; + +use crate::{proto, repr::ProtoRepr}; + +fn encode(msg: &P::Type) -> Vec { + let msg = P::build(msg); + zksync_protobuf::canonical_raw(&msg.encode_to_vec(), &msg.descriptor()).unwrap() +} + +fn decode(bytes: &[u8]) -> anyhow::Result { + P::read(&P::decode(bytes)?) +} + +fn encode_json(msg: &P::Type) -> String { + let mut s = serde_json::Serializer::pretty(vec![]); + zksync_protobuf::serde::serialize_proto(&P::build(msg), &mut s).unwrap(); + String::from_utf8(s.into_inner()).unwrap() +} + +fn decode_json(json: &str) -> anyhow::Result { + let mut d = serde_json::Deserializer::from_str(json); + P::read(&zksync_protobuf::serde::deserialize_proto(&mut d)?) +} + +#[track_caller] +fn encode_decode(rng: &mut impl Rng) +where + P::Type: PartialEq + std::fmt::Debug + testonly::RandomConfig, +{ + for required_only in [false, true] { + let want: P::Type = testonly::Gen { + rng, + required_only, + decimal_fractions: false, + } + .gen(); + let got = decode::

(&encode::

(&want)).unwrap(); + assert_eq!(&want, &got, "binary encoding"); + + let want: P::Type = testonly::Gen { + rng, + required_only, + decimal_fractions: true, + } + .gen(); + let got = decode_json::

(&encode_json::

(&want)).unwrap(); + assert_eq!(&want, &got, "json encoding"); + } +} + +/// Tests config <-> proto (boilerplate) conversions. +#[test] +fn test_encoding() { + let rng = &mut rand::thread_rng(); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); + encode_decode::(rng); +} diff --git a/core/lib/protobuf_config/src/utils.rs b/core/lib/protobuf_config/src/utils.rs new file mode 100644 index 000000000000..d4089df01dfb --- /dev/null +++ b/core/lib/protobuf_config/src/utils.rs @@ -0,0 +1,28 @@ +use anyhow::Context as _; +use zksync_config::configs::PrometheusConfig; +use zksync_protobuf::required; + +use crate::{proto, repr::ProtoRepr}; + +impl ProtoRepr for proto::Prometheus { + type Type = PrometheusConfig; + fn read(&self) -> anyhow::Result { + Ok(PrometheusConfig { + listener_port: required(&self.listener_port) + .and_then(|p| Ok((*p).try_into()?)) + .context("listener_port")?, + pushgateway_url: required(&self.pushgateway_url) + .context("pushgateway_url")? + .clone(), + push_interval_ms: self.push_interval_ms, + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + listener_port: Some(this.listener_port.into()), + pushgateway_url: Some(this.pushgateway_url.clone()), + push_interval_ms: this.push_interval_ms, + } + } +} diff --git a/core/lib/protobuf_config/src/witness_generator.rs b/core/lib/protobuf_config/src/witness_generator.rs new file mode 100644 index 000000000000..d4513ebffb53 --- /dev/null +++ b/core/lib/protobuf_config/src/witness_generator.rs @@ -0,0 +1,68 @@ +use anyhow::Context as _; +use zksync_config::configs; +use zksync_protobuf::required; + +use crate::{proto, repr::ProtoRepr}; + +impl proto::BasicWitnessGeneratorDataSource { + fn new(x: &configs::witness_generator::BasicWitnessGeneratorDataSource) -> Self { + type From = configs::witness_generator::BasicWitnessGeneratorDataSource; + match x { + From::FromPostgres => Self::FromPostgres, + From::FromPostgresShadowBlob => Self::FromPostgresShadowBlob, + From::FromBlob => Self::FromBlob, + } + } + fn parse(&self) -> configs::witness_generator::BasicWitnessGeneratorDataSource { + type To = configs::witness_generator::BasicWitnessGeneratorDataSource; + match self { + Self::FromPostgres => To::FromPostgres, + Self::FromPostgresShadowBlob => To::FromPostgresShadowBlob, + Self::FromBlob => To::FromBlob, + } + } +} + +impl ProtoRepr for proto::WitnessGenerator { + type Type = configs::WitnessGeneratorConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + generation_timeout_in_secs: required(&self.generation_timeout_in_secs) + .and_then(|x| Ok((*x).try_into()?)) + .context("generation_timeout_in_secs")?, + initial_setup_key_path: required(&self.initial_setup_key_path) + .context("initial_setup_key_path")? + .clone(), + key_download_url: required(&self.key_download_url) + .context("key_download_url")? + .clone(), + max_attempts: *required(&self.max_attempts).context("max_attempts")?, + blocks_proving_percentage: self + .blocks_proving_percentage + .map(|x| x.try_into()) + .transpose() + .context("blocks_proving_percentage")?, + dump_arguments_for_blocks: self.dump_arguments_for_blocks.clone(), + last_l1_batch_to_process: self.last_l1_batch_to_process, + data_source: required(&self.data_source) + .and_then(|x| Ok(proto::BasicWitnessGeneratorDataSource::try_from(*x)?)) + .context("data_source")? + .parse(), + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + generation_timeout_in_secs: Some(this.generation_timeout_in_secs.into()), + initial_setup_key_path: Some(this.initial_setup_key_path.clone()), + key_download_url: Some(this.key_download_url.clone()), + max_attempts: Some(this.max_attempts), + blocks_proving_percentage: this.blocks_proving_percentage.map(|x| x.into()), + dump_arguments_for_blocks: this.dump_arguments_for_blocks.clone(), + last_l1_batch_to_process: this.last_l1_batch_to_process, + data_source: Some( + proto::BasicWitnessGeneratorDataSource::new(&this.data_source).into(), + ), + } + } +} diff --git a/core/lib/prover_interface/Cargo.toml b/core/lib/prover_interface/Cargo.toml new file mode 100644 index 000000000000..3bb9e65fe806 --- /dev/null +++ b/core/lib/prover_interface/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "zksync_prover_interface" +version = "0.1.0" +edition = "2018" +authors = ["The Matter Labs Team "] +homepage = "https://zksync.io/" +repository = "https://github.com/matter-labs/zksync-era" +license = "MIT OR Apache-2.0" +keywords = ["blockchain", "zksync"] +categories = ["cryptography"] +readme = "README.md" + +[dependencies] +zksync_types = { path = "../types" } +zksync_object_store = { path = "../object_store" } + +zkevm_test_harness = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.3.3" } + +serde = "1.0.90" +strum = { version = "0.24", features = ["derive"] } +serde_with = { version = "1", features = ["base64"] } +chrono = { version = "0.4", features = ["serde"] } + +[dev-dependencies] +tokio = { version = "1.21.2", features = ["full"] } +bincode = "1" diff --git a/core/lib/types/src/prover_server_api/mod.rs b/core/lib/prover_interface/src/api.rs similarity index 79% rename from core/lib/types/src/prover_server_api/mod.rs rename to core/lib/prover_interface/src/api.rs index fdbbd57624f8..85cf88c4f908 100644 --- a/core/lib/types/src/prover_server_api/mod.rs +++ b/core/lib/prover_interface/src/api.rs @@ -1,12 +1,14 @@ -use serde::{Deserialize, Serialize}; -use zksync_basic_types::L1BatchNumber; +//! Prover and server subsystems communicate via the API. +//! This module defines the types used in the API. -use crate::{ - aggregated_operations::L1BatchProofForL1, - proofs::PrepareBasicCircuitsJob, +use serde::{Deserialize, Serialize}; +use zksync_types::{ protocol_version::{FriProtocolVersionId, L1VerifierConfig}, + L1BatchNumber, }; +use crate::{inputs::PrepareBasicCircuitsJob, outputs::L1BatchProofForL1}; + #[derive(Debug, Serialize, Deserialize)] pub struct ProofGenerationData { pub l1_batch_number: L1BatchNumber, diff --git a/core/lib/prover_interface/src/inputs.rs b/core/lib/prover_interface/src/inputs.rs new file mode 100644 index 000000000000..44fe60edddd8 --- /dev/null +++ b/core/lib/prover_interface/src/inputs.rs @@ -0,0 +1,185 @@ +use std::{convert::TryInto, fmt::Debug}; + +use serde::{Deserialize, Serialize}; +use serde_with::{serde_as, Bytes}; +use zksync_object_store::{serialize_using_bincode, Bucket, StoredObject}; +use zksync_types::{L1BatchNumber, H256, U256}; + +const HASH_LEN: usize = H256::len_bytes(); + +/// Metadata emitted by a Merkle tree after processing single storage log. +#[serde_as] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct StorageLogMetadata { + #[serde_as(as = "Bytes")] + pub root_hash: [u8; HASH_LEN], + pub is_write: bool, + pub first_write: bool, + #[serde_as(as = "Vec")] + pub merkle_paths: Vec<[u8; HASH_LEN]>, + pub leaf_hashed_key: U256, + pub leaf_enumeration_index: u64, + // **NB.** For compatibility reasons, `#[serde_as(as = "Bytes")]` attributes are not added below. + pub value_written: [u8; HASH_LEN], + pub value_read: [u8; HASH_LEN], +} + +impl StorageLogMetadata { + pub fn leaf_hashed_key_array(&self) -> [u8; 32] { + let mut result = [0_u8; 32]; + self.leaf_hashed_key.to_little_endian(&mut result); + result + } + + pub fn into_merkle_paths_array(self) -> Box<[[u8; HASH_LEN]; PATH_LEN]> { + let actual_len = self.merkle_paths.len(); + self.merkle_paths.try_into().unwrap_or_else(|_| { + panic!( + "Unexpected length of Merkle paths in `StorageLogMetadata`: expected {}, got {}", + PATH_LEN, actual_len + ); + }) + } +} + +/// Witness data produced by the Merkle tree as a result of processing a single block. Used +/// as an input to the witness generator. +/// +/// # Stability +/// +/// This type is serialized using `bincode` to be passed from the metadata calculator +/// to the witness generator. As such, changes in its `serde` serialization +/// must be backwards-compatible. +/// +/// # Compact form +/// +/// In order to reduce storage space, this job supports a compact format. In this format, +/// only the first item in `merkle_paths` is guaranteed to have the full Merkle path (i.e., +/// 256 items with the current Merkle tree). The following items may have less hashes in their +/// Merkle paths; if this is the case, the starting hashes are skipped and are the same +/// as in the first path. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PrepareBasicCircuitsJob { + // Merkle paths and some auxiliary information for each read / write operation in a block. + merkle_paths: Vec, + next_enumeration_index: u64, +} + +impl StoredObject for PrepareBasicCircuitsJob { + const BUCKET: Bucket = Bucket::WitnessInput; + type Key<'a> = L1BatchNumber; + + fn encode_key(key: Self::Key<'_>) -> String { + format!("merkel_tree_paths_{key}.bin") + } + + serialize_using_bincode!(); +} + +impl PrepareBasicCircuitsJob { + /// Creates a new job with the specified leaf index and no included paths. + pub fn new(next_enumeration_index: u64) -> Self { + Self { + merkle_paths: vec![], + next_enumeration_index, + } + } + + /// Returns the next leaf index at the beginning of the block. + pub fn next_enumeration_index(&self) -> u64 { + self.next_enumeration_index + } + + /// Reserves additional capacity for Merkle paths. + pub fn reserve(&mut self, additional_capacity: usize) { + self.merkle_paths.reserve(additional_capacity); + } + + /// Pushes an additional Merkle path. + pub fn push_merkle_path(&mut self, mut path: StorageLogMetadata) { + let Some(first_path) = self.merkle_paths.first() else { + self.merkle_paths.push(path); + return; + }; + assert_eq!(first_path.merkle_paths.len(), path.merkle_paths.len()); + + let mut hash_pairs = path.merkle_paths.iter().zip(&first_path.merkle_paths); + let first_unique_idx = + hash_pairs.position(|(hash, first_path_hash)| hash != first_path_hash); + let first_unique_idx = first_unique_idx.unwrap_or(path.merkle_paths.len()); + path.merkle_paths = path.merkle_paths.split_off(first_unique_idx); + self.merkle_paths.push(path); + } + + /// Converts this job into an iterator over the contained Merkle paths. + pub fn into_merkle_paths(self) -> impl ExactSizeIterator { + let mut merkle_paths = self.merkle_paths; + if let [first, rest @ ..] = merkle_paths.as_mut_slice() { + for path in rest { + assert!( + path.merkle_paths.len() <= first.merkle_paths.len(), + "Merkle paths in `PrepareBasicCircuitsJob` are malformed; the first path is not \ + the longest one" + ); + let spliced_len = first.merkle_paths.len() - path.merkle_paths.len(); + let spliced_hashes = &first.merkle_paths[0..spliced_len]; + path.merkle_paths + .splice(0..0, spliced_hashes.iter().cloned()); + debug_assert_eq!(path.merkle_paths.len(), first.merkle_paths.len()); + } + } + merkle_paths.into_iter() + } +} + +/// Enriched `PrepareBasicCircuitsJob`. All the other fields are taken from the `l1_batches` table. +#[derive(Debug, Clone)] +pub struct BasicCircuitWitnessGeneratorInput { + pub block_number: L1BatchNumber, + pub previous_block_hash: H256, + pub previous_block_timestamp: u64, + pub block_timestamp: u64, + pub used_bytecodes_hashes: Vec, + pub initial_heap_content: Vec<(usize, U256)>, + pub merkle_paths_input: PrepareBasicCircuitsJob, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn prepare_basic_circuits_job_roundtrip() { + let zero_hash = [0_u8; 32]; + let logs = (0..10).map(|i| { + let mut merkle_paths = vec![zero_hash; 255]; + merkle_paths.push([i as u8; 32]); + StorageLogMetadata { + root_hash: zero_hash, + is_write: i % 2 == 0, + first_write: i % 3 == 0, + merkle_paths, + leaf_hashed_key: U256::from(i), + leaf_enumeration_index: i + 1, + value_written: [i as u8; 32], + value_read: [0; 32], + } + }); + let logs: Vec<_> = logs.collect(); + + let mut job = PrepareBasicCircuitsJob::new(4); + job.reserve(logs.len()); + for log in &logs { + job.push_merkle_path(log.clone()); + } + + // Check that Merkle paths are compacted. + for (i, log) in job.merkle_paths.iter().enumerate() { + let expected_merkle_path_len = if i == 0 { 256 } else { 1 }; + assert_eq!(log.merkle_paths.len(), expected_merkle_path_len); + } + + let logs_from_job: Vec<_> = job.into_merkle_paths().collect(); + assert_eq!(logs_from_job, logs); + } +} diff --git a/core/lib/prover_interface/src/lib.rs b/core/lib/prover_interface/src/lib.rs new file mode 100644 index 000000000000..31d66c2af1ea --- /dev/null +++ b/core/lib/prover_interface/src/lib.rs @@ -0,0 +1,9 @@ +//! Point of interaction of the core subsystem with the prover subsystem. +//! Defines the means of communication between the two subsystems without exposing the internal details of either. + +/// Types that define the API for interaction between prover and server subsystems. +pub mod api; +/// Inputs for proof generation provided by the core subsystem. +pub mod inputs; +/// Outputs of proof generation provided by the prover subsystem. +pub mod outputs; diff --git a/core/lib/prover_interface/src/outputs.rs b/core/lib/prover_interface/src/outputs.rs new file mode 100644 index 000000000000..ebadc6101467 --- /dev/null +++ b/core/lib/prover_interface/src/outputs.rs @@ -0,0 +1,38 @@ +use core::fmt; + +use serde::{Deserialize, Serialize}; +use zkevm_test_harness::{ + abstract_zksync_circuit::concrete_circuits::ZkSyncCircuit, + bellman::{bn256::Bn256, plonk::better_better_cs::proof::Proof}, + witness::oracle::VmWitnessOracle, +}; +use zksync_object_store::{serialize_using_bincode, Bucket, StoredObject}; +use zksync_types::L1BatchNumber; + +/// The only type of proof utilized by the core subsystem: a "final" proof that can be sent +/// to the L1 contract. +#[derive(Clone, Serialize, Deserialize)] +pub struct L1BatchProofForL1 { + pub aggregation_result_coords: [[u8; 32]; 4], + pub scheduler_proof: Proof>>, +} + +impl fmt::Debug for L1BatchProofForL1 { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter + .debug_struct("L1BatchProofForL1") + .field("aggregation_result_coords", &self.aggregation_result_coords) + .finish_non_exhaustive() + } +} + +impl StoredObject for L1BatchProofForL1 { + const BUCKET: Bucket = Bucket::ProofsFri; + type Key<'a> = L1BatchNumber; + + fn encode_key(key: Self::Key<'_>) -> String { + format!("l1_batch_proof_{key}.bin") + } + + serialize_using_bincode!(); +} diff --git a/core/lib/object_store/tests/integration.rs b/core/lib/prover_interface/tests/job_serialization.rs similarity index 92% rename from core/lib/object_store/tests/integration.rs rename to core/lib/prover_interface/tests/job_serialization.rs index 9db2061f17fd..a71f7ea3ae39 100644 --- a/core/lib/object_store/tests/integration.rs +++ b/core/lib/prover_interface/tests/job_serialization.rs @@ -1,11 +1,9 @@ -//! Integration tests for object store. +//! Integration tests for object store serialization of job objects. use tokio::fs; use zksync_object_store::{Bucket, ObjectStoreFactory}; -use zksync_types::{ - proofs::{PrepareBasicCircuitsJob, StorageLogMetadata}, - L1BatchNumber, -}; +use zksync_prover_interface::inputs::{PrepareBasicCircuitsJob, StorageLogMetadata}; +use zksync_types::L1BatchNumber; /// Tests compatibility of the `PrepareBasicCircuitsJob` serialization to the previously used /// one. diff --git a/core/lib/object_store/tests/snapshots/prepare-basic-circuits-job-full.bin b/core/lib/prover_interface/tests/snapshots/prepare-basic-circuits-job-full.bin similarity index 100% rename from core/lib/object_store/tests/snapshots/prepare-basic-circuits-job-full.bin rename to core/lib/prover_interface/tests/snapshots/prepare-basic-circuits-job-full.bin diff --git a/core/lib/prover_utils/Cargo.toml b/core/lib/prover_utils/Cargo.toml deleted file mode 100644 index 3afa050ace07..000000000000 --- a/core/lib/prover_utils/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "zksync_prover_utils" -version = "0.1.0" -edition = "2018" -authors = ["The Matter Labs Team "] -homepage = "https://zksync.io/" -repository = "https://github.com/matter-labs/zksync-era" -license = "MIT OR Apache-2.0" -keywords = ["blockchain", "zksync"] -categories = ["cryptography"] - -[dependencies] -zksync_config = { path = "../../lib/config" } -zksync_utils = { path = "../../lib/utils" } -zksync_types = { path = "../../lib/types" } -zksync_object_store = { path = "../../lib/object_store" } - -anyhow = "1.0" -reqwest = { version = "0.11", features = ["blocking"] } -regex = "1.7.2" -tokio = "1.27.0" -futures = { version = "0.3", features = ["compat"] } -ctrlc = { version = "3.1", features = ["termination"] } -toml_edit = "0.14.4" -async-trait = "0.1" -tracing = "0.1" diff --git a/core/lib/prover_utils/src/gcs_proof_fetcher.rs b/core/lib/prover_utils/src/gcs_proof_fetcher.rs deleted file mode 100644 index 26872701a1fe..000000000000 --- a/core/lib/prover_utils/src/gcs_proof_fetcher.rs +++ /dev/null @@ -1,22 +0,0 @@ -use zksync_object_store::{ObjectStore, ObjectStoreError}; -use zksync_types::{aggregated_operations::L1BatchProofForL1, L1BatchNumber}; - -pub async fn load_wrapped_fri_proofs_for_range( - from: L1BatchNumber, - to: L1BatchNumber, - blob_store: &dyn ObjectStore, -) -> Vec { - let mut proofs = Vec::new(); - for l1_batch_number in from.0..=to.0 { - let l1_batch_number = L1BatchNumber(l1_batch_number); - match blob_store.get(l1_batch_number).await { - Ok(proof) => proofs.push(proof), - Err(ObjectStoreError::KeyNotFound(_)) => (), // do nothing, proof is not ready yet - Err(err) => panic!( - "Failed to load proof for batch {}: {}", - l1_batch_number.0, err - ), - } - } - proofs -} diff --git a/core/lib/prover_utils/src/lib.rs b/core/lib/prover_utils/src/lib.rs deleted file mode 100644 index 0ee42ffee065..000000000000 --- a/core/lib/prover_utils/src/lib.rs +++ /dev/null @@ -1,126 +0,0 @@ -#![allow(clippy::upper_case_acronyms, clippy::derive_partial_eq_without_eq)] - -extern crate core; - -use std::{fs::create_dir_all, io::Cursor, path::Path, time::Duration}; - -use futures::{channel::mpsc, executor::block_on, SinkExt}; - -pub mod gcs_proof_fetcher; -pub mod periodic_job; -pub mod region_fetcher; -pub mod vk_commitment_helper; - -fn download_bytes(key_download_url: &str) -> reqwest::Result> { - tracing::info!("Downloading initial setup from {:?}", key_download_url); - - const DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(120); - let client = reqwest::blocking::Client::builder() - .timeout(DOWNLOAD_TIMEOUT) - .build() - .unwrap(); - - const DOWNLOAD_RETRIES: usize = 5; - let mut retry_count = 0; - - while retry_count < DOWNLOAD_RETRIES { - let bytes = client - .get(key_download_url) - .send() - .and_then(|response| response.bytes().map(|bytes| bytes.to_vec())); - match bytes { - Ok(bytes) => return Ok(bytes), - Err(_) => retry_count += 1, - } - - tracing::warn!("Failed to download keys. Backing off for 5 second"); - std::thread::sleep(Duration::from_secs(5)); - } - - client - .get(key_download_url) - .send() - .and_then(|response| response.bytes().map(|bytes| bytes.to_vec())) -} - -pub fn ensure_initial_setup_keys_present(initial_setup_key_path: &str, key_download_url: &str) { - if Path::new(initial_setup_key_path).exists() { - tracing::info!( - "Initial setup already present at {:?}", - initial_setup_key_path - ); - return; - } - - let bytes = download_bytes(key_download_url).expect("Failed downloading initial setup"); - let initial_setup_key_dir = Path::new(initial_setup_key_path).parent().unwrap(); - create_dir_all(initial_setup_key_dir).unwrap_or_else(|_| { - panic!( - "Failed creating dirs recursively: {:?}", - initial_setup_key_dir - ) - }); - let mut file = std::fs::File::create(initial_setup_key_path) - .expect("Cannot create file for the initial setup"); - let mut content = Cursor::new(bytes); - std::io::copy(&mut content, &mut file).expect("Cannot write the downloaded key to the file"); -} - -pub fn numeric_index_to_circuit_name(circuit_numeric_index: u8) -> Option<&'static str> { - match circuit_numeric_index { - 0 => Some("Scheduler"), - 1 => Some("Node aggregation"), - 2 => Some("Leaf aggregation"), - 3 => Some("Main VM"), - 4 => Some("Decommitts sorter"), - 5 => Some("Code decommitter"), - 6 => Some("Log demuxer"), - 7 => Some("Keccak"), - 8 => Some("SHA256"), - 9 => Some("ECRecover"), - 10 => Some("RAM permutation"), - 11 => Some("Storage sorter"), - 12 => Some("Storage application"), - 13 => Some("Initial writes pubdata rehasher"), - 14 => Some("Repeated writes pubdata rehasher"), - 15 => Some("Events sorter"), - 16 => Some("L1 messages sorter"), - 17 => Some("L1 messages rehasher"), - 18 => Some("L1 messages merklizer"), - _ => None, - } -} - -pub fn circuit_name_to_numeric_index(circuit_name: &str) -> Option { - match circuit_name { - "Scheduler" => Some(0), - "Node aggregation" => Some(1), - "Leaf aggregation" => Some(2), - "Main VM" => Some(3), - "Decommitts sorter" => Some(4), - "Code decommitter" => Some(5), - "Log demuxer" => Some(6), - "Keccak" => Some(7), - "SHA256" => Some(8), - "ECRecover" => Some(9), - "RAM permutation" => Some(10), - "Storage sorter" => Some(11), - "Storage application" => Some(12), - "Initial writes pubdata rehasher" => Some(13), - "Repeated writes pubdata rehasher" => Some(14), - "Events sorter" => Some(15), - "L1 messages sorter" => Some(16), - "L1 messages rehasher" => Some(17), - "L1 messages merklizer" => Some(18), - _ => None, - } -} - -pub fn get_stop_signal_receiver() -> mpsc::Receiver { - let (mut stop_signal_sender, stop_signal_receiver) = mpsc::channel(256); - ctrlc::set_handler(move || { - block_on(stop_signal_sender.send(true)).expect("Ctrl+C signal send"); - }) - .expect("Error setting Ctrl+C handler"); - stop_signal_receiver -} diff --git a/core/lib/prover_utils/src/region_fetcher.rs b/core/lib/prover_utils/src/region_fetcher.rs deleted file mode 100644 index d2c49dd068dc..000000000000 --- a/core/lib/prover_utils/src/region_fetcher.rs +++ /dev/null @@ -1,111 +0,0 @@ -use anyhow::Context as _; -use regex::Regex; -use reqwest::{ - header::{HeaderMap, HeaderValue}, - Method, -}; -use zksync_config::configs::ProverGroupConfig; -use zksync_utils::http_with_retries::send_request_with_retries; - -pub async fn get_region(prover_group_config: &ProverGroupConfig) -> anyhow::Result { - if let Some(region) = &prover_group_config.region_override { - return Ok(region.clone()); - } - let url = &prover_group_config.region_read_url; - fetch_from_url(url).await.context("fetch_from_url()") -} - -pub async fn get_zone(prover_group_config: &ProverGroupConfig) -> anyhow::Result { - if let Some(zone) = &prover_group_config.zone_override { - return Ok(zone.clone()); - } - let url = &prover_group_config.zone_read_url; - let data = fetch_from_url(url).await.context("fetch_from_url()")?; - parse_zone(&data).context("parse_zone") -} - -async fn fetch_from_url(url: &str) -> anyhow::Result { - let mut headers = HeaderMap::new(); - headers.insert("Metadata-Flavor", HeaderValue::from_static("Google")); - let response = send_request_with_retries(url, 5, Method::GET, Some(headers), None).await; - response - .map_err(|err| anyhow::anyhow!("Failed fetching response from url: {url}: {err:?}"))? - .text() - .await - .context("Failed to read response as text") -} - -fn parse_zone(data: &str) -> anyhow::Result { - // Statically provided Regex should always compile. - let re = Regex::new(r"^projects/\d+/zones/(\w+-\w+-\w+)$").unwrap(); - if let Some(caps) = re.captures(data) { - let zone = &caps[1]; - return Ok(zone.to_string()); - } - anyhow::bail!("failed to extract zone from: {data}"); -} - -#[cfg(test)] -mod tests { - use zksync_config::configs::ProverGroupConfig; - - use crate::region_fetcher::{get_region, get_zone, parse_zone}; - - #[test] - fn test_parse_zone() { - let data = "projects/295056426491/zones/us-central1-a"; - let zone = parse_zone(data).unwrap(); - assert_eq!(zone, "us-central1-a"); - } - - #[test] - fn test_parse_zone_panic() { - let data = "invalid data"; - assert!(parse_zone(data).is_err()); - } - - #[tokio::test] - async fn test_get_region_with_override() { - let config = ProverGroupConfig { - group_0_circuit_ids: vec![], - group_1_circuit_ids: vec![], - group_2_circuit_ids: vec![], - group_3_circuit_ids: vec![], - group_4_circuit_ids: vec![], - group_5_circuit_ids: vec![], - group_6_circuit_ids: vec![], - group_7_circuit_ids: vec![], - group_8_circuit_ids: vec![], - group_9_circuit_ids: vec![], - region_override: Some("us-central-1".to_string()), - region_read_url: "".to_string(), - zone_override: Some("us-central-1-b".to_string()), - zone_read_url: "".to_string(), - synthesizer_per_gpu: 0, - }; - - assert_eq!("us-central-1", get_region(&config).await.unwrap()); - } - - #[tokio::test] - async fn test_get_zone_with_override() { - let config = ProverGroupConfig { - group_0_circuit_ids: vec![], - group_1_circuit_ids: vec![], - group_2_circuit_ids: vec![], - group_3_circuit_ids: vec![], - group_4_circuit_ids: vec![], - group_5_circuit_ids: vec![], - group_6_circuit_ids: vec![], - group_7_circuit_ids: vec![], - group_8_circuit_ids: vec![], - group_9_circuit_ids: vec![], - region_override: Some("us-central-1".to_string()), - region_read_url: "".to_string(), - zone_override: Some("us-central-1-b".to_string()), - zone_read_url: "".to_string(), - synthesizer_per_gpu: 0, - }; - assert_eq!("us-central-1-b", get_zone(&config).await.unwrap()); - } -} diff --git a/core/tests/cross_external_nodes_checker/Cargo.toml b/core/lib/snapshots_applier/Cargo.toml similarity index 61% rename from core/tests/cross_external_nodes_checker/Cargo.toml rename to core/lib/snapshots_applier/Cargo.toml index 4f8285aef5a5..5b89bfe84753 100644 --- a/core/tests/cross_external_nodes_checker/Cargo.toml +++ b/core/lib/snapshots_applier/Cargo.toml @@ -1,26 +1,25 @@ [package] -name = "cross_external_nodes_checker" +name = "zksync_snapshots_applier" version = "0.1.0" -edition = "2018" +edition = "2021" authors = ["The Matter Labs Team "] homepage = "https://zksync.io/" repository = "https://github.com/matter-labs/zksync-era" license = "MIT OR Apache-2.0" keywords = ["blockchain", "zksync"] categories = ["cryptography"] -publish = false # We don't want to publish our binaries. [dependencies] +zksync_dal = { path = "../../lib/dal" } zksync_types = { path = "../../lib/types" } +zksync_object_store = { path = "../../lib/object_store" } zksync_web3_decl = { path = "../../lib/web3_decl" } zksync_utils = { path = "../../lib/utils" } -vlog = { path = "../../lib/vlog" } -serde_json = "1.0" + +vise = { git = "https://github.com/matter-labs/vise.git", version = "0.1.0", rev = "1c9cc500e92cf9ea052b230e114a6f9cce4fb2c1" } anyhow = "1.0" +async-trait = "0.1" tokio = { version = "1", features = ["time"] } -futures = "0.3" -envy = "0.4" -serde = { version = "1.0" } -ctrlc = { version = "3.1" } tracing = "0.1" +thiserror = "1.0" diff --git a/core/lib/snapshots_applier/src/lib.rs b/core/lib/snapshots_applier/src/lib.rs new file mode 100644 index 000000000000..48fc2a813c95 --- /dev/null +++ b/core/lib/snapshots_applier/src/lib.rs @@ -0,0 +1,347 @@ +//! Logic for applying application-level snapshots to Postgres storage. + +use std::{collections::HashMap, fmt}; + +use anyhow::Context as _; +use async_trait::async_trait; +use zksync_dal::{ConnectionPool, SqlxError, StorageProcessor}; +use zksync_object_store::{ObjectStore, ObjectStoreError}; +use zksync_types::{ + api::en::SyncBlock, + snapshots::{ + SnapshotFactoryDependencies, SnapshotHeader, SnapshotRecoveryStatus, SnapshotStorageLog, + SnapshotStorageLogsChunk, SnapshotStorageLogsStorageKey, + }, + MiniblockNumber, H256, +}; +use zksync_utils::bytecode::hash_bytecode; +use zksync_web3_decl::jsonrpsee::core::{client::Error, ClientError as RpcError}; + +use self::metrics::{InitialStage, StorageLogsChunksStage, METRICS}; + +mod metrics; +#[cfg(test)] +mod tests; + +#[derive(thiserror::Error, Debug)] +pub enum SnapshotsApplierError { + #[error("canceled")] + Canceled(String), + #[error(transparent)] + Fatal(#[from] anyhow::Error), + #[error(transparent)] + Retryable(anyhow::Error), +} + +impl SnapshotsApplierError { + fn canceled(message: &str) -> Self { + Self::Canceled(message.to_owned()) + } +} + +impl From for SnapshotsApplierError { + fn from(error: ObjectStoreError) -> Self { + match error { + ObjectStoreError::KeyNotFound(_) | ObjectStoreError::Serialization(_) => { + Self::Fatal(error.into()) + } + ObjectStoreError::Other(_) => Self::Retryable(error.into()), + } + } +} + +impl From for SnapshotsApplierError { + fn from(error: SqlxError) -> Self { + match error { + SqlxError::Database(_) + | SqlxError::RowNotFound + | SqlxError::ColumnNotFound(_) + | SqlxError::Configuration(_) + | SqlxError::TypeNotFound { .. } => Self::Fatal(error.into()), + _ => Self::Retryable(error.into()), + } + } +} + +impl From for SnapshotsApplierError { + fn from(error: RpcError) -> Self { + match error { + Error::Transport(_) | Error::RequestTimeout | Error::RestartNeeded(_) => { + Self::Retryable(error.into()) + } + _ => Self::Fatal(error.into()), + } + } +} + +/// Main node API used by the [`SnapshotsApplier`]. +#[async_trait] +pub trait SnapshotsApplierMainNodeClient: fmt::Debug + Send + Sync { + async fn fetch_l2_block(&self, number: MiniblockNumber) -> Result, RpcError>; + + async fn fetch_newest_snapshot(&self) -> Result, RpcError>; +} + +/// Applying application-level storage snapshots to the Postgres storage. +#[derive(Debug)] +pub struct SnapshotsApplier<'a> { + connection_pool: &'a ConnectionPool, + blob_store: &'a dyn ObjectStore, + applied_snapshot_status: SnapshotRecoveryStatus, +} + +impl<'a> SnapshotsApplier<'a> { + /// Recovers [`SnapshotRecoveryStatus`] from the storage and the main node. + async fn prepare_applied_snapshot_status( + storage: &mut StorageProcessor<'_>, + main_node_client: &dyn SnapshotsApplierMainNodeClient, + ) -> Result<(SnapshotRecoveryStatus, bool), SnapshotsApplierError> { + let latency = + METRICS.initial_stage_duration[&InitialStage::FetchMetadataFromMainNode].start(); + + let applied_snapshot_status = storage + .snapshot_recovery_dal() + .get_applied_snapshot_status() + .await?; + + if let Some(applied_snapshot_status) = applied_snapshot_status { + if !applied_snapshot_status + .storage_logs_chunks_processed + .contains(&false) + { + return Err(SnapshotsApplierError::canceled( + "This node has already been initialized from a snapshot", + )); + } + + let latency = latency.observe(); + tracing::info!("Re-initialized snapshots applier after reset/failure in {latency:?}"); + + Ok((applied_snapshot_status, false)) + } else { + if !storage.blocks_dal().is_genesis_needed().await? { + return Err(SnapshotsApplierError::canceled( + "This node has already been initialized without a snapshot", + )); + } + + let latency = latency.observe(); + tracing::info!("Initialized fresh snapshots applier in {latency:?}"); + + Ok(( + SnapshotsApplier::create_fresh_recovery_status(main_node_client).await?, + true, + )) + } + } + + pub async fn load_snapshot( + connection_pool: &'a ConnectionPool, + main_node_client: &dyn SnapshotsApplierMainNodeClient, + blob_store: &'a dyn ObjectStore, + ) -> Result<(), SnapshotsApplierError> { + let mut storage = connection_pool + .access_storage_tagged("snapshots_applier") + .await?; + let mut storage_transaction = storage.start_transaction().await?; + + let (applied_snapshot_status, created_from_scratch) = + Self::prepare_applied_snapshot_status(&mut storage_transaction, main_node_client) + .await?; + + let mut recovery = Self { + connection_pool, + blob_store, + applied_snapshot_status, + }; + + METRICS.storage_logs_chunks_count.set( + recovery + .applied_snapshot_status + .storage_logs_chunks_processed + .len(), + ); + METRICS.storage_logs_chunks_left_to_process.set( + recovery + .applied_snapshot_status + .storage_logs_chunks_left_to_process(), + ); + + if created_from_scratch { + recovery + .recover_factory_deps(&mut storage_transaction) + .await?; + storage_transaction + .snapshot_recovery_dal() + .insert_initial_recovery_status(&recovery.applied_snapshot_status) + .await?; + } + storage_transaction.commit().await?; + drop(storage); + + recovery.recover_storage_logs().await?; + Ok(()) + } + + async fn create_fresh_recovery_status( + main_node_client: &dyn SnapshotsApplierMainNodeClient, + ) -> Result { + let snapshot_response = main_node_client.fetch_newest_snapshot().await?; + + let snapshot = snapshot_response.ok_or(SnapshotsApplierError::canceled( + "Main node does not have any ready snapshots, skipping initialization from snapshot!", + ))?; + + let l1_batch_number = snapshot.l1_batch_number; + let miniblock_number = snapshot.miniblock_number; + tracing::info!( + "Found snapshot with data up to L1 batch #{l1_batch_number}, storage_logs are divided into {} chunk(s)", + snapshot.storage_logs_chunks.len() + ); + + let miniblock = main_node_client + .fetch_l2_block(miniblock_number) + .await? + .with_context(|| format!("miniblock #{miniblock_number} is missing on main node"))?; + let miniblock_root_hash = miniblock + .hash + .context("snapshot miniblock fetched from main node doesn't have hash set")?; + + Ok(SnapshotRecoveryStatus { + l1_batch_number, + l1_batch_root_hash: snapshot.last_l1_batch_with_metadata.metadata.root_hash, + miniblock_number: snapshot.miniblock_number, + miniblock_root_hash, + storage_logs_chunks_processed: vec![false; snapshot.storage_logs_chunks.len()], + }) + } + + async fn recover_factory_deps( + &mut self, + storage: &mut StorageProcessor<'_>, + ) -> Result<(), SnapshotsApplierError> { + let latency = METRICS.initial_stage_duration[&InitialStage::ApplyFactoryDeps].start(); + + tracing::debug!("Fetching factory dependencies from object store"); + let factory_deps: SnapshotFactoryDependencies = self + .blob_store + .get(self.applied_snapshot_status.l1_batch_number) + .await?; + tracing::debug!( + "Fetched {} factory dependencies from object store", + factory_deps.factory_deps.len() + ); + + let all_deps_hashmap: HashMap> = factory_deps + .factory_deps + .into_iter() + .map(|dep| (hash_bytecode(&dep.bytecode.0), dep.bytecode.0)) + .collect(); + storage + .storage_dal() + .insert_factory_deps( + self.applied_snapshot_status.miniblock_number, + &all_deps_hashmap, + ) + .await?; + + let latency = latency.observe(); + tracing::info!("Applied factory dependencies in {latency:?}"); + + Ok(()) + } + + async fn insert_initial_writes_chunk( + &mut self, + storage_logs: &[SnapshotStorageLog], + storage: &mut StorageProcessor<'_>, + ) -> Result<(), SnapshotsApplierError> { + storage + .storage_logs_dedup_dal() + .insert_initial_writes_from_snapshot(storage_logs) + .await?; + Ok(()) + } + + async fn insert_storage_logs_chunk( + &mut self, + storage_logs: &[SnapshotStorageLog], + storage: &mut StorageProcessor<'_>, + ) -> Result<(), SnapshotsApplierError> { + storage + .storage_logs_dal() + .insert_storage_logs_from_snapshot( + self.applied_snapshot_status.miniblock_number, + storage_logs, + ) + .await?; + Ok(()) + } + + #[tracing::instrument(level = "debug", err, skip(self))] + async fn recover_storage_logs_single_chunk( + &mut self, + chunk_id: u64, + ) -> Result<(), SnapshotsApplierError> { + tracing::info!("Processing storage logs chunk {chunk_id}"); + let latency = + METRICS.storage_logs_chunks_duration[&StorageLogsChunksStage::LoadFromGcs].start(); + + let storage_key = SnapshotStorageLogsStorageKey { + chunk_id, + l1_batch_number: self.applied_snapshot_status.l1_batch_number, + }; + let storage_snapshot_chunk: SnapshotStorageLogsChunk = + self.blob_store.get(storage_key).await?; + let storage_logs = &storage_snapshot_chunk.storage_logs; + let latency = latency.observe(); + tracing::info!( + "Loaded {} storage logs from GCS for chunk {chunk_id} in {latency:?}", + storage_logs.len() + ); + + let latency = + METRICS.storage_logs_chunks_duration[&StorageLogsChunksStage::SaveToPostgres].start(); + + let mut storage = self + .connection_pool + .access_storage_tagged("snapshots_applier") + .await?; + let mut storage_transaction = storage.start_transaction().await?; + + tracing::info!("Loading {} storage logs into Postgres", storage_logs.len()); + self.insert_storage_logs_chunk(storage_logs, &mut storage_transaction) + .await?; + self.insert_initial_writes_chunk(storage_logs, &mut storage_transaction) + .await?; + + self.applied_snapshot_status.storage_logs_chunks_processed[chunk_id as usize] = true; + storage_transaction + .snapshot_recovery_dal() + .mark_storage_logs_chunk_as_processed(chunk_id) + .await?; + storage_transaction.commit().await?; + + let chunks_left = METRICS.storage_logs_chunks_left_to_process.dec_by(1) - 1; + let latency = latency.observe(); + tracing::info!("Saved storage logs for chunk {chunk_id} in {latency:?}, there are {chunks_left} left to process"); + + Ok(()) + } + + pub async fn recover_storage_logs(mut self) -> Result<(), SnapshotsApplierError> { + for chunk_id in 0..self + .applied_snapshot_status + .storage_logs_chunks_processed + .len() + { + //TODO Add retries and parallelize this step + if !self.applied_snapshot_status.storage_logs_chunks_processed[chunk_id] { + self.recover_storage_logs_single_chunk(chunk_id as u64) + .await?; + } + } + + Ok(()) + } +} diff --git a/core/lib/snapshots_applier/src/metrics.rs b/core/lib/snapshots_applier/src/metrics.rs new file mode 100644 index 000000000000..e10270f79fe1 --- /dev/null +++ b/core/lib/snapshots_applier/src/metrics.rs @@ -0,0 +1,44 @@ +//! Metrics for the snapshot applier. + +use std::time::Duration; + +use vise::{Buckets, EncodeLabelSet, EncodeLabelValue, Family, Gauge, Histogram, Metrics, Unit}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelValue, EncodeLabelSet)] +#[metrics(label = "stage", rename_all = "snake_case")] +pub(crate) enum StorageLogsChunksStage { + LoadFromGcs, + SaveToPostgres, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelValue, EncodeLabelSet)] +#[metrics(label = "stage", rename_all = "snake_case")] +pub(crate) enum InitialStage { + FetchMetadataFromMainNode, + ApplyFactoryDeps, +} + +#[derive(Debug, Metrics)] +#[metrics(prefix = "snapshots_applier")] +pub(crate) struct SnapshotsApplierMetrics { + /// Number of chunks in the applied snapshot. Set when snapshots applier starts. + pub storage_logs_chunks_count: Gauge, + + /// Number of chunks left to apply. + pub storage_logs_chunks_left_to_process: Gauge, + + /// Total latency of applying snapshot. + #[metrics(buckets = Buckets::LATENCIES, unit = Unit::Seconds)] + pub snapshot_applying_duration: Histogram, + + /// Latency of initial recovery operation split by stage. + #[metrics(buckets = Buckets::LATENCIES, unit = Unit::Seconds)] + pub initial_stage_duration: Family>, + + /// Latency of storage log chunk processing split by stage. + #[metrics(buckets = Buckets::LATENCIES, unit = Unit::Seconds)] + pub storage_logs_chunks_duration: Family>, +} + +#[vise::register] +pub(crate) static METRICS: vise::Global = vise::Global::new(); diff --git a/core/lib/snapshots_applier/src/tests/mod.rs b/core/lib/snapshots_applier/src/tests/mod.rs new file mode 100644 index 000000000000..de750ef12f9b --- /dev/null +++ b/core/lib/snapshots_applier/src/tests/mod.rs @@ -0,0 +1,130 @@ +//! Snapshot applier tests. + +use std::collections::HashMap; + +use zksync_dal::ConnectionPool; +use zksync_object_store::ObjectStoreFactory; +use zksync_types::{ + snapshots::{ + SnapshotFactoryDependencies, SnapshotFactoryDependency, SnapshotHeader, + SnapshotRecoveryStatus, SnapshotStorageLog, SnapshotStorageLogsChunk, + SnapshotStorageLogsChunkMetadata, SnapshotStorageLogsStorageKey, + }, + Bytes, L1BatchNumber, MiniblockNumber, H256, +}; + +use self::utils::{l1_block_metadata, miniblock_metadata, random_storage_logs, MockMainNodeClient}; +use crate::SnapshotsApplier; + +mod utils; + +#[tokio::test] +async fn snapshots_creator_can_successfully_recover_db() { + let pool = ConnectionPool::test_pool().await; + let object_store_factory = ObjectStoreFactory::mock(); + let object_store = object_store_factory.create_store().await; + let mut client = MockMainNodeClient::default(); + let miniblock_number = MiniblockNumber(1234); + let l1_batch_number = L1BatchNumber(123); + let l1_batch_root_hash = H256::random(); + let miniblock_hash = H256::random(); + let factory_dep_bytes: Vec = (0..32).collect(); + let factory_deps = SnapshotFactoryDependencies { + factory_deps: vec![SnapshotFactoryDependency { + bytecode: Bytes::from(factory_dep_bytes), + }], + }; + object_store + .put(l1_batch_number, &factory_deps) + .await + .unwrap(); + + let mut all_snapshot_storage_logs = HashMap::::new(); + for chunk_id in 0..2 { + let chunk_storage_logs = SnapshotStorageLogsChunk { + storage_logs: random_storage_logs(l1_batch_number, chunk_id, 10), + }; + let chunk_key = SnapshotStorageLogsStorageKey { + l1_batch_number, + chunk_id, + }; + object_store + .put(chunk_key, &chunk_storage_logs) + .await + .unwrap(); + + all_snapshot_storage_logs.extend( + chunk_storage_logs + .storage_logs + .into_iter() + .map(|log| (log.key.hashed_key(), log)), + ); + } + + let snapshot_header = SnapshotHeader { + l1_batch_number, + miniblock_number, + last_l1_batch_with_metadata: l1_block_metadata(l1_batch_number, l1_batch_root_hash), + storage_logs_chunks: vec![ + SnapshotStorageLogsChunkMetadata { + chunk_id: 0, + filepath: "file0".to_string(), + }, + SnapshotStorageLogsChunkMetadata { + chunk_id: 1, + filepath: "file1".to_string(), + }, + ], + factory_deps_filepath: "some_filepath".to_string(), + }; + client.fetch_newest_snapshot_response = Some(snapshot_header); + client.fetch_l2_block_responses.insert( + miniblock_number, + miniblock_metadata(miniblock_number, l1_batch_number, miniblock_hash), + ); + + SnapshotsApplier::load_snapshot(&pool, &client, &object_store) + .await + .unwrap(); + + let mut storage = pool.access_storage().await.unwrap(); + let mut recovery_dal = storage.snapshot_recovery_dal(); + + let expected_status = SnapshotRecoveryStatus { + l1_batch_number, + l1_batch_root_hash, + miniblock_number, + miniblock_root_hash: miniblock_hash, + storage_logs_chunks_processed: vec![true, true], + }; + + let current_db_status = recovery_dal.get_applied_snapshot_status().await.unwrap(); + assert_eq!(current_db_status.unwrap(), expected_status); + + let all_initial_writes = storage + .storage_logs_dedup_dal() + .dump_all_initial_writes_for_tests() + .await; + assert_eq!(all_initial_writes.len(), all_snapshot_storage_logs.len()); + for initial_write in all_initial_writes { + let log = &all_snapshot_storage_logs[&initial_write.hashed_key]; + assert_eq!( + initial_write.l1_batch_number, + log.l1_batch_number_of_initial_write + ); + assert_eq!(initial_write.index, log.enumeration_index); + } + + let all_storage_logs = storage + .storage_logs_dal() + .dump_all_storage_logs_for_tests() + .await; + assert_eq!(all_storage_logs.len(), all_snapshot_storage_logs.len()); + for db_log in all_storage_logs { + let expected_log = &all_snapshot_storage_logs[&db_log.hashed_key]; + assert_eq!(db_log.address, *expected_log.key.address()); + assert_eq!(db_log.key, *expected_log.key.key()); + assert_eq!(db_log.value, expected_log.value); + assert_eq!(db_log.miniblock_number, miniblock_number); + } +} diff --git a/core/lib/snapshots_applier/src/tests/utils.rs b/core/lib/snapshots_applier/src/tests/utils.rs new file mode 100644 index 000000000000..418518774ae5 --- /dev/null +++ b/core/lib/snapshots_applier/src/tests/utils.rs @@ -0,0 +1,109 @@ +//! Test utils. + +use std::collections::HashMap; + +use async_trait::async_trait; +use zksync_types::{ + api::en::SyncBlock, + block::L1BatchHeader, + commitment::{L1BatchMetaParameters, L1BatchMetadata, L1BatchWithMetadata}, + snapshots::{SnapshotHeader, SnapshotStorageLog}, + AccountTreeId, L1BatchNumber, MiniblockNumber, ProtocolVersionId, StorageKey, StorageValue, + H160, H256, +}; +use zksync_web3_decl::jsonrpsee::core::ClientError as RpcError; + +use crate::SnapshotsApplierMainNodeClient; + +#[derive(Debug, Default)] +pub(super) struct MockMainNodeClient { + pub fetch_l2_block_responses: HashMap, + pub fetch_newest_snapshot_response: Option, +} + +#[async_trait] +impl SnapshotsApplierMainNodeClient for MockMainNodeClient { + async fn fetch_l2_block(&self, number: MiniblockNumber) -> Result, RpcError> { + Ok(self.fetch_l2_block_responses.get(&number).cloned()) + } + + async fn fetch_newest_snapshot(&self) -> Result, RpcError> { + Ok(self.fetch_newest_snapshot_response.clone()) + } +} + +pub(crate) fn miniblock_metadata( + number: MiniblockNumber, + l1_batch_number: L1BatchNumber, + hash: H256, +) -> SyncBlock { + SyncBlock { + number, + l1_batch_number, + last_in_batch: true, + timestamp: 0, + l1_gas_price: 0, + l2_fair_gas_price: 0, + fair_pubdata_price: None, + base_system_contracts_hashes: Default::default(), + operator_address: Default::default(), + transactions: None, + virtual_blocks: None, + hash: Some(hash), + protocol_version: Default::default(), + } +} + +pub(crate) fn l1_block_metadata( + l1_batch_number: L1BatchNumber, + root_hash: H256, +) -> L1BatchWithMetadata { + L1BatchWithMetadata { + header: L1BatchHeader::new( + l1_batch_number, + 0, + Default::default(), + ProtocolVersionId::default(), + ), + metadata: L1BatchMetadata { + root_hash, + rollup_last_leaf_index: 0, + merkle_root_hash: H256::zero(), + initial_writes_compressed: vec![], + repeated_writes_compressed: vec![], + commitment: H256::zero(), + l2_l1_messages_compressed: vec![], + l2_l1_merkle_root: H256::zero(), + block_meta_params: L1BatchMetaParameters { + zkporter_is_available: false, + bootloader_code_hash: H256::zero(), + default_aa_code_hash: H256::zero(), + }, + aux_data_hash: H256::zero(), + meta_parameters_hash: H256::zero(), + pass_through_data_hash: H256::zero(), + events_queue_commitment: None, + bootloader_initial_content_commitment: None, + state_diffs_compressed: vec![], + }, + factory_deps: vec![], + } +} + +pub(super) fn random_storage_logs( + l1_batch_number: L1BatchNumber, + chunk_id: u64, + logs_per_chunk: u64, +) -> Vec { + (0..logs_per_chunk) + .map(|x| SnapshotStorageLog { + key: StorageKey::new( + AccountTreeId::from_fixed_bytes(H160::random().to_fixed_bytes()), + H256::random(), + ), + value: StorageValue::random(), + l1_batch_number_of_initial_write: l1_batch_number, + enumeration_index: x + chunk_id * logs_per_chunk, + }) + .collect() +} diff --git a/core/lib/state/Cargo.toml b/core/lib/state/Cargo.toml index 87e433a4160e..fed7fa0c0157 100644 --- a/core/lib/state/Cargo.toml +++ b/core/lib/state/Cargo.toml @@ -23,5 +23,7 @@ tracing = "0.1" itertools = "0.10.3" [dev-dependencies] +assert_matches = "1.5.0" rand = "0.8.5" tempfile = "3.0.2" +test-casing = "0.1.2" diff --git a/core/lib/state/README.md b/core/lib/state/README.md index 0e98203bc473..fd01452aed39 100644 --- a/core/lib/state/README.md +++ b/core/lib/state/README.md @@ -5,7 +5,7 @@ component responsible for handling transaction execution and creating miniblocks All state keeper data is currently stored in Postgres. (Beside it, we provide an in-memory implementation for benchmarking / testing purposes.) We also keep a secondary copy for part of it in RocksDB for performance reasons. -Currently, we only duplicate the data needed by the [`vm`] crate. +Currently, we only duplicate the data needed by the [`multivm`] crate. [`zksync_core`]: ../zksync_core -[`vm`]: ../vm +[`multivm`]: ../multivm diff --git a/core/lib/state/src/in_memory.rs b/core/lib/state/src/in_memory.rs index d6058649a459..6dfc98434eb9 100644 --- a/core/lib/state/src/in_memory.rs +++ b/core/lib/state/src/in_memory.rs @@ -15,7 +15,7 @@ pub const IN_MEMORY_STORAGE_DEFAULT_NETWORK_ID: u32 = 270; /// In-memory storage. #[derive(Debug, Default, Clone)] pub struct InMemoryStorage { - pub(crate) state: HashMap, + pub(crate) state: HashMap, pub(crate) factory_deps: HashMap>, last_enum_index_set: u64, } @@ -68,7 +68,7 @@ impl InMemoryStorage { let state: HashMap<_, _> = state_without_indices .into_iter() .enumerate() - .map(|(idx, (key, value))| (key, (value, idx as u64 + 1))) + .map(|(idx, (key, value))| (key.hashed_key(), (value, idx as u64 + 1))) .collect(); let factory_deps = contracts @@ -86,7 +86,7 @@ impl InMemoryStorage { /// Sets the storage `value` at the specified `key`. pub fn set_value(&mut self, key: StorageKey, value: StorageValue) { - match self.state.entry(key) { + match self.state.entry(key.hashed_key()) { Entry::Occupied(mut entry) => { entry.get_mut().0 = value; } @@ -101,24 +101,19 @@ impl InMemoryStorage { pub fn store_factory_dep(&mut self, hash: H256, bytecode: Vec) { self.factory_deps.insert(hash, bytecode); } - - /// Get internal state of the storage. - pub fn get_state(&self) -> &HashMap { - &self.state - } } impl ReadStorage for &InMemoryStorage { fn read_value(&mut self, key: &StorageKey) -> StorageValue { self.state - .get(key) + .get(&key.hashed_key()) .map(|(value, _)| value) .copied() .unwrap_or_default() } fn is_write_initial(&mut self, key: &StorageKey) -> bool { - !self.state.contains_key(key) + !self.state.contains_key(&key.hashed_key()) } fn load_factory_dep(&mut self, hash: H256) -> Option> { @@ -126,7 +121,7 @@ impl ReadStorage for &InMemoryStorage { } fn get_enumeration_index(&mut self, key: &StorageKey) -> Option { - self.state.get(key).map(|(_, idx)| *idx) + self.state.get(&key.hashed_key()).map(|(_, idx)| *idx) } } diff --git a/core/lib/state/src/lib.rs b/core/lib/state/src/lib.rs index 3d54967c9ad6..f76f38846566 100644 --- a/core/lib/state/src/lib.rs +++ b/core/lib/state/src/lib.rs @@ -30,7 +30,7 @@ mod witness; pub use self::{ in_memory::{InMemoryStorage, IN_MEMORY_STORAGE_DEFAULT_NETWORK_ID}, postgres::{PostgresStorage, PostgresStorageCaches}, - rocksdb::RocksdbStorage, + rocksdb::{RocksbStorageBuilder, RocksdbStorage}, shadow_storage::ShadowStorage, storage_view::{StorageView, StorageViewMetrics}, witness::WitnessStorage, diff --git a/core/lib/state/src/postgres/tests.rs b/core/lib/state/src/postgres/tests.rs index 6514da136d56..75adcbba8c63 100644 --- a/core/lib/state/src/postgres/tests.rs +++ b/core/lib/state/src/postgres/tests.rs @@ -221,12 +221,15 @@ fn test_factory_deps_cache(pool: &ConnectionPool, rt_handle: Handle) { // insert the contracts let mut contracts = HashMap::new(); contracts.insert(H256::zero(), vec![1, 2, 3]); - storage.rt_handle.block_on( - storage - .connection - .storage_dal() - .insert_factory_deps(MiniblockNumber(0), &contracts), - ); + storage + .rt_handle + .block_on( + storage + .connection + .storage_dal() + .insert_factory_deps(MiniblockNumber(0), &contracts), + ) + .unwrap(); // Create the storage that should have the cache filled. let mut storage = PostgresStorage::new( diff --git a/core/lib/state/src/rocksdb/metrics.rs b/core/lib/state/src/rocksdb/metrics.rs index 997f4b42ed37..912bcdba251d 100644 --- a/core/lib/state/src/rocksdb/metrics.rs +++ b/core/lib/state/src/rocksdb/metrics.rs @@ -2,7 +2,7 @@ use std::time::Duration; -use vise::{Buckets, Gauge, Histogram, Metrics}; +use vise::{Buckets, EncodeLabelSet, EncodeLabelValue, Family, Gauge, Histogram, Metrics, Unit}; #[derive(Debug, Metrics)] #[metrics(prefix = "server_state_keeper_secondary_storage")] @@ -18,3 +18,36 @@ pub(super) struct RocksdbStorageMetrics { #[vise::register] pub(super) static METRICS: vise::Global = vise::Global::new(); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelValue, EncodeLabelSet)] +#[metrics(label = "stage", rename_all = "snake_case")] +pub(super) enum RecoveryStage { + LoadFactoryDeps, + SaveFactoryDeps, + LoadChunkStarts, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelValue, EncodeLabelSet)] +#[metrics(label = "stage", rename_all = "snake_case")] +pub(super) enum ChunkRecoveryStage { + LoadEntries, + SaveEntries, +} + +/// Recovery-related group of metrics. +#[derive(Debug, Metrics)] +#[metrics(prefix = "server_state_keeper_secondary_storage_recovery")] +pub(super) struct RocksdbRecoveryMetrics { + /// Number of chunks recovered. + pub recovered_chunk_count: Gauge, + /// Latency of a storage recovery stage (not related to the recovery of a particular chunk; + /// those metrics are tracked in the `chunk_latency` histogram). + #[metrics(buckets = Buckets::LATENCIES, unit = Unit::Seconds)] + pub latency: Family>, + /// Latency of a chunk recovery stage. + #[metrics(buckets = Buckets::LATENCIES, unit = Unit::Seconds)] + pub chunk_latency: Family>, +} + +#[vise::register] +pub(super) static RECOVERY_METRICS: vise::Global = vise::Global::new(); diff --git a/core/lib/state/src/rocksdb/mod.rs b/core/lib/state/src/rocksdb/mod.rs index 96d227271442..956307566af3 100644 --- a/core/lib/state/src/rocksdb/mod.rs +++ b/core/lib/state/src/rocksdb/mod.rs @@ -19,24 +19,37 @@ //! | Contracts | address (20 bytes) | `Vec` | Contract contents | //! | Factory deps | hash (32 bytes) | `Vec` | Bytecodes for new contracts that a certain contract may deploy. | -use std::{collections::HashMap, convert::TryInto, mem, path::Path, time::Instant}; - +use std::{ + collections::HashMap, + convert::TryInto, + mem, + path::{Path, PathBuf}, + time::Instant, +}; + +use anyhow::Context as _; use itertools::{Either, Itertools}; +use tokio::sync::watch; use zksync_dal::StorageProcessor; use zksync_storage::{db::NamedColumnFamily, RocksDB}; use zksync_types::{L1BatchNumber, StorageKey, StorageValue, H256, U256}; use zksync_utils::{h256_to_u256, u256_to_h256}; use self::metrics::METRICS; +#[cfg(test)] +use self::tests::RocksdbStorageEventListener; use crate::{InMemoryStorage, ReadStorage}; mod metrics; +mod recovery; +#[cfg(test)] +mod tests; -fn serialize_block_number(block_number: u32) -> [u8; 4] { +fn serialize_l1_batch_number(block_number: u32) -> [u8; 4] { block_number.to_le_bytes() } -fn deserialize_block_number(bytes: &[u8]) -> u32 { +fn deserialize_l1_batch_number(bytes: &[u8]) -> u32 { let bytes: [u8; 4] = bytes.try_into().expect("incorrect block number format"); u32::from_le_bytes(bytes) } @@ -96,85 +109,189 @@ impl StateValue { } } +/// Error emitted when [`RocksdbStorage`] is being updated. +#[derive(Debug)] +enum RocksdbSyncError { + Internal(anyhow::Error), + Interrupted, +} + +impl From for RocksdbSyncError { + fn from(err: anyhow::Error) -> Self { + Self::Internal(err) + } +} + /// [`ReadStorage`] implementation backed by RocksDB. #[derive(Debug)] pub struct RocksdbStorage { db: RocksDB, pending_patch: InMemoryStorage, enum_index_migration_chunk_size: usize, + /// Test-only listeners to events produced by the storage. + #[cfg(test)] + listener: RocksdbStorageEventListener, } -impl RocksdbStorage { - const BLOCK_NUMBER_KEY: &'static [u8] = b"block_number"; - const ENUM_INDEX_MIGRATION_CURSOR: &'static [u8] = b"enum_index_migration_cursor"; +/// Builder of [`RocksdbStorage`]. The storage data is inaccessible until the storage is [`Self::synchronize()`]d +/// with Postgres. +#[derive(Debug)] +pub struct RocksbStorageBuilder(RocksdbStorage); - fn is_special_key(key: &[u8]) -> bool { - key == Self::BLOCK_NUMBER_KEY || key == Self::ENUM_INDEX_MIGRATION_CURSOR +impl RocksbStorageBuilder { + /// Enables enum indices migration. + pub fn enable_enum_index_migration(&mut self, chunk_size: usize) { + self.0.enum_index_migration_chunk_size = chunk_size; + } + + /// Returns the last processed l1 batch number + 1. + /// + /// # Panics + /// + /// Panics on RocksDB errors. + pub async fn l1_batch_number(&self) -> Option { + self.0.l1_batch_number().await } - /// Creates a new storage with the provided RocksDB `path`. - pub fn new(path: &Path) -> Self { - let db = RocksDB::new(path); - Self { - db, - pending_patch: InMemoryStorage::default(), - enum_index_migration_chunk_size: 100, + /// Synchronizes this storage with Postgres using the provided connection. + /// + /// # Return value + /// + /// Returns `Ok(None)` if the update is interrupted using `stop_receiver`. + /// + /// # Errors + /// + /// - Errors if the local L1 batch number is greater than the last sealed L1 batch number + /// in Postgres. + pub async fn synchronize( + self, + storage: &mut StorageProcessor<'_>, + stop_receiver: &watch::Receiver, + ) -> anyhow::Result> { + let mut inner = self.0; + match inner.update_from_postgres(storage, stop_receiver).await { + Ok(()) => Ok(Some(inner)), + Err(RocksdbSyncError::Interrupted) => Ok(None), + Err(RocksdbSyncError::Internal(err)) => Err(err), } } - /// Enables enum indices migration. - pub fn enable_enum_index_migration(&mut self, chunk_size: usize) { - self.enum_index_migration_chunk_size = chunk_size; + /// Rolls back the state to a previous L1 batch number. + /// + /// # Errors + /// + /// Propagates RocksDB and Postgres errors. + pub async fn rollback( + mut self, + storage: &mut StorageProcessor<'_>, + last_l1_batch_to_keep: L1BatchNumber, + ) -> anyhow::Result<()> { + self.0.rollback(storage, last_l1_batch_to_keep).await } +} - /// Synchronizes this storage with Postgres using the provided connection. +impl RocksdbStorage { + const L1_BATCH_NUMBER_KEY: &'static [u8] = b"block_number"; + const ENUM_INDEX_MIGRATION_CURSOR: &'static [u8] = b"enum_index_migration_cursor"; + + /// Desired size of log chunks loaded from Postgres during snapshot recovery. + /// This is intentionally not configurable because chunks must be the same for the entire recovery + /// (i.e., not changed after a node restart). + const DESIRED_LOG_CHUNK_SIZE: u64 = 200_000; + + fn is_special_key(key: &[u8]) -> bool { + key == Self::L1_BATCH_NUMBER_KEY || key == Self::ENUM_INDEX_MIGRATION_CURSOR + } + + /// Creates a new storage builder with the provided RocksDB `path`. /// - /// # Panics + /// # Errors /// - /// Panics if the local L1 batch number is greater than the last sealed L1 batch number - /// in Postgres. - pub async fn update_from_postgres(&mut self, conn: &mut StorageProcessor<'_>) { + /// Propagates RocksDB I/O errors. + pub async fn builder(path: &Path) -> anyhow::Result { + Self::new(path.to_path_buf()) + .await + .map(RocksbStorageBuilder) + } + + async fn new(path: PathBuf) -> anyhow::Result { + tokio::task::spawn_blocking(move || { + Ok(Self { + db: RocksDB::new(&path).context("failed initializing state keeper RocksDB")?, + pending_patch: InMemoryStorage::default(), + enum_index_migration_chunk_size: 100, + #[cfg(test)] + listener: RocksdbStorageEventListener::default(), + }) + }) + .await + .context("panicked initializing state keeper RocksDB")? + } + + async fn update_from_postgres( + &mut self, + storage: &mut StorageProcessor<'_>, + stop_receiver: &watch::Receiver, + ) -> Result<(), RocksdbSyncError> { + let mut current_l1_batch_number = self + .ensure_ready(storage, Self::DESIRED_LOG_CHUNK_SIZE, stop_receiver) + .await?; + let latency = METRICS.update.start(); - let latest_l1_batch_number = conn + let Some(latest_l1_batch_number) = storage .blocks_dal() .get_sealed_l1_batch_number() .await - .unwrap(); - tracing::debug!( - "loading storage for l1 batch number {}", - latest_l1_batch_number.0 - ); + .context("failed fetching sealed L1 batch number")? + else { + // No L1 batches are persisted in Postgres; update is not necessary. + return Ok(()); + }; + tracing::debug!("Loading storage for l1 batch number {latest_l1_batch_number}"); - let mut current_l1_batch_number = self.l1_batch_number().0; - assert!( - current_l1_batch_number <= latest_l1_batch_number.0 + 1, - "L1 batch number in state keeper cache ({current_l1_batch_number}) is greater than \ - the last sealed L1 batch number in Postgres ({latest_l1_batch_number})" - ); + if current_l1_batch_number > latest_l1_batch_number + 1 { + let err = anyhow::anyhow!( + "L1 batch number in state keeper cache ({current_l1_batch_number}) is greater than \ + the last sealed L1 batch number in Postgres ({latest_l1_batch_number})" + ); + return Err(err.into()); + } - while current_l1_batch_number <= latest_l1_batch_number.0 { - let current_lag = latest_l1_batch_number.0 - current_l1_batch_number + 1; + while current_l1_batch_number <= latest_l1_batch_number { + if *stop_receiver.borrow() { + return Err(RocksdbSyncError::Interrupted); + } + let current_lag = latest_l1_batch_number.0 - current_l1_batch_number.0 + 1; METRICS.lag.set(current_lag.into()); - tracing::debug!("loading state changes for l1 batch {current_l1_batch_number}"); - let storage_logs = conn + tracing::debug!("Loading state changes for l1 batch {current_l1_batch_number}"); + let storage_logs = storage .storage_logs_dal() - .get_touched_slots_for_l1_batch(L1BatchNumber(current_l1_batch_number)) - .await; - self.apply_storage_logs(storage_logs, conn).await; + .get_touched_slots_for_l1_batch(current_l1_batch_number) + .await + .with_context(|| { + format!("failed loading touched slots for L1 batch {current_l1_batch_number}") + })?; + self.apply_storage_logs(storage_logs, storage).await?; - tracing::debug!("loading factory deps for l1 batch {current_l1_batch_number}"); - let factory_deps = conn + tracing::debug!("Loading factory deps for L1 batch {current_l1_batch_number}"); + let factory_deps = storage .blocks_dal() - .get_l1_batch_factory_deps(L1BatchNumber(current_l1_batch_number)) + .get_l1_batch_factory_deps(current_l1_batch_number) .await - .unwrap(); + .with_context(|| { + format!("failed loading factory deps for L1 batch {current_l1_batch_number}") + })?; for (hash, bytecode) in factory_deps { self.store_factory_dep(hash, bytecode); } current_l1_batch_number += 1; - self.save(L1BatchNumber(current_l1_batch_number)).await; + self.save(Some(current_l1_batch_number)) + .await + .with_context(|| format!("failed saving L1 batch #{current_l1_batch_number}"))?; + #[cfg(test)] + (self.listener.on_l1_batch_synced)(current_l1_batch_number - 1); } latency.observe(); @@ -187,50 +304,66 @@ impl RocksdbStorage { assert!(self.enum_index_migration_chunk_size > 0); // Enum indices must be at the storage. Run migration till the end. - while self.enum_migration_start_from().is_some() { - self.save_missing_enum_indices(conn).await; + while self.enum_migration_start_from().await.is_some() { + if *stop_receiver.borrow() { + return Err(RocksdbSyncError::Interrupted); + } + self.save_missing_enum_indices(storage).await?; } + Ok(()) } async fn apply_storage_logs( &mut self, storage_logs: HashMap, - conn: &mut StorageProcessor<'_>, - ) { - let (logs_with_known_indices, logs_with_unknown_indices): (Vec<_>, Vec<_>) = self - .process_transaction_logs(storage_logs) + storage: &mut StorageProcessor<'_>, + ) -> anyhow::Result<()> { + let db = self.db.clone(); + let processed_logs = + tokio::task::spawn_blocking(move || Self::process_transaction_logs(&db, storage_logs)) + .await + .context("panicked processing storage logs")?; + + let (logs_with_known_indices, logs_with_unknown_indices): (Vec<_>, Vec<_>) = processed_logs + .into_iter() .partition_map(|(key, StateValue { value, enum_index })| match enum_index { - Some(index) => Either::Left((key, (value, index))), - None => Either::Right((key, value)), + Some(index) => Either::Left((key.hashed_key(), (value, index))), + None => Either::Right((key.hashed_key(), value)), }); let keys_with_unknown_indices: Vec<_> = logs_with_unknown_indices .iter() - .map(|(key, _)| key.hashed_key()) + .map(|&(key, _)| key) .collect(); - let enum_indices_and_batches = conn + let enum_indices_and_batches = storage .storage_logs_dal() .get_l1_batches_and_indices_for_initial_writes(&keys_with_unknown_indices) - .await; - assert_eq!( - keys_with_unknown_indices.len(), - enum_indices_and_batches.len() + .await + .context("failed getting enumeration indices for storage logs")?; + anyhow::ensure!( + keys_with_unknown_indices.len() == enum_indices_and_batches.len(), + "Inconsistent Postgres data: not all new storage logs have enumeration indices" ); - self.pending_patch.state = - logs_with_known_indices - .into_iter() - .chain(logs_with_unknown_indices.into_iter().map(|(key, value)| { - (key, (value, enum_indices_and_batches[&key.hashed_key()].1)) - })) - .collect(); + self.pending_patch.state = logs_with_known_indices + .into_iter() + .chain( + logs_with_unknown_indices + .into_iter() + .map(|(key, value)| (key, (value, enum_indices_and_batches[&key].1))), + ) + .collect(); + Ok(()) } - async fn save_missing_enum_indices(&self, conn: &mut StorageProcessor<'_>) { - let (Some(start_from), true) = ( - self.enum_migration_start_from(), + async fn save_missing_enum_indices( + &self, + storage: &mut StorageProcessor<'_>, + ) -> anyhow::Result<()> { + let (true, Some(start_from)) = ( self.enum_index_migration_chunk_size > 0, + self.enum_migration_start_from().await, ) else { - return; + return Ok(()); }; let started_at = Instant::now(); @@ -238,91 +371,107 @@ impl RocksdbStorage { "RocksDB enum index migration is not finished, starting from key {start_from:0>64x}" ); - let mut write_batch = self.db.new_write_batch(); - let (keys, values): (Vec<_>, Vec<_>) = self - .db - .from_iterator_cf(StateKeeperColumnFamily::State, start_from.as_bytes()) - .filter_map(|(key, value)| { - if Self::is_special_key(&key) { - return None; - } - let state_value = StateValue::deserialize(&value); - (state_value.enum_index.is_none()) - .then(|| (H256::from_slice(&key), state_value.value)) - }) - .take(self.enum_index_migration_chunk_size) - .unzip(); - let enum_indices_and_batches = conn + let db = self.db.clone(); + let enum_index_migration_chunk_size = self.enum_index_migration_chunk_size; + let (keys, values): (Vec<_>, Vec<_>) = tokio::task::spawn_blocking(move || { + db.from_iterator_cf(StateKeeperColumnFamily::State, start_from.as_bytes()) + .filter_map(|(key, value)| { + if Self::is_special_key(&key) { + return None; + } + let state_value = StateValue::deserialize(&value); + state_value + .enum_index + .is_none() + .then(|| (H256::from_slice(&key), state_value.value)) + }) + .take(enum_index_migration_chunk_size) + .unzip() + }) + .await + .unwrap(); + + let enum_indices_and_batches = storage .storage_logs_dal() .get_l1_batches_and_indices_for_initial_writes(&keys) - .await; + .await + .context("failed getting enumeration indices for storage logs")?; assert_eq!(keys.len(), enum_indices_and_batches.len()); + let key_count = keys.len(); - for (key, value) in keys.iter().zip(values) { - let index = enum_indices_and_batches[key].1; - write_batch.put_cf( - StateKeeperColumnFamily::State, - key.as_bytes(), - &StateValue::new(value, Some(index)).serialize(), - ); - } - - let next_key = keys - .last() - .and_then(|last_key| h256_to_u256(*last_key).checked_add(U256::one())) - .map(u256_to_h256); - match (next_key, keys.len()) { - (Some(next_key), keys_len) if keys_len == self.enum_index_migration_chunk_size => { + let db = self.db.clone(); + tokio::task::spawn_blocking(move || { + let mut write_batch = db.new_write_batch(); + for (key, value) in keys.iter().zip(values) { + let index = enum_indices_and_batches[key].1; write_batch.put_cf( StateKeeperColumnFamily::State, - Self::ENUM_INDEX_MIGRATION_CURSOR, - next_key.as_bytes(), + key.as_bytes(), + &StateValue::new(value, Some(index)).serialize(), ); } - _ => { - write_batch.put_cf( - StateKeeperColumnFamily::State, - Self::ENUM_INDEX_MIGRATION_CURSOR, - &[], - ); - tracing::info!("RocksDB enum index migration finished"); + + let next_key = keys + .last() + .and_then(|last_key| h256_to_u256(*last_key).checked_add(U256::one())) + .map(u256_to_h256); + match (next_key, keys.len()) { + (Some(next_key), keys_len) if keys_len == enum_index_migration_chunk_size => { + write_batch.put_cf( + StateKeeperColumnFamily::State, + Self::ENUM_INDEX_MIGRATION_CURSOR, + next_key.as_bytes(), + ); + } + _ => { + write_batch.put_cf( + StateKeeperColumnFamily::State, + Self::ENUM_INDEX_MIGRATION_CURSOR, + &[], + ); + tracing::info!("RocksDB enum index migration finished"); + } } - } - self.db - .write(write_batch) - .expect("failed to save state data into rocksdb"); + db.write(write_batch) + .context("failed saving enum indices to RocksDB") + }) + .await + .context("panicked while saving enum indices to RocksDB")??; + tracing::info!( - "RocksDB enum index migration chunk took {:?}, migrated {} keys", - started_at.elapsed(), - keys.len() + "RocksDB enum index migration chunk took {:?}, migrated {key_count} keys", + started_at.elapsed() ); + Ok(()) } fn read_value_inner(&self, key: &StorageKey) -> Option { - self.read_state_value(key) - .map(|state_value| state_value.value) + Self::read_state_value(&self.db, key.hashed_key()).map(|state_value| state_value.value) } - fn read_state_value(&self, key: &StorageKey) -> Option { + fn read_state_value( + db: &RocksDB, + hashed_key: H256, + ) -> Option { let cf = StateKeeperColumnFamily::State; - self.db - .get_cf(cf, &Self::serialize_state_key(key)) + db.get_cf(cf, &Self::serialize_state_key(hashed_key)) .expect("failed to read rocksdb state value") .map(|value| StateValue::deserialize(&value)) } /// Returns storage logs to apply. fn process_transaction_logs( - &self, + db: &RocksDB, updates: HashMap, - ) -> impl Iterator + '_ { - updates.into_iter().filter_map(|(key, new_value)| { - if let Some(state_value) = self.read_state_value(&key) { + ) -> Vec<(StorageKey, StateValue)> { + let it = updates.into_iter().filter_map(move |(key, new_value)| { + if let Some(state_value) = Self::read_state_value(db, key.hashed_key()) { Some((key, StateValue::new(new_value, state_value.enum_index))) } else { (!new_value.is_zero()).then_some((key, StateValue::new(new_value, None))) } - }) + }); + it.collect() } /// Stores a factory dependency with the specified `hash` and `bytecode`. @@ -330,16 +479,11 @@ impl RocksdbStorage { self.pending_patch.factory_deps.insert(hash, bytecode); } - /// Rolls back the state to a previous L1 batch number. - /// - /// # Panics - /// - /// Panics on RocksDB errors. - pub async fn rollback( + async fn rollback( &mut self, connection: &mut StorageProcessor<'_>, last_l1_batch_to_keep: L1BatchNumber, - ) { + ) -> anyhow::Result<()> { tracing::info!("Rolling back state keeper storage to L1 batch #{last_l1_batch_to_keep}..."); tracing::info!("Getting logs that should be applied to rollback state..."); @@ -347,7 +491,8 @@ impl RocksdbStorage { let logs = connection .storage_logs_dal() .get_storage_logs_for_revert(last_l1_batch_to_keep) - .await; + .await + .context("failed getting logs for rollback")?; tracing::info!("Got {} logs, took {:?}", logs.len(), stage_start.elapsed()); tracing::info!("Getting number of last miniblock for L1 batch #{last_l1_batch_to_keep}..."); @@ -356,8 +501,10 @@ impl RocksdbStorage { .blocks_dal() .get_miniblock_range_of_l1_batch(last_l1_batch_to_keep) .await - .unwrap() - .expect("L1 batch should contain at least one miniblock"); + .with_context(|| { + format!("failed fetching miniblock range for L1 batch #{last_l1_batch_to_keep}") + })? + .context("L1 batch should contain at least one miniblock")?; tracing::info!( "Got miniblock number {last_miniblock_to_keep}, took {:?}", stage_start.elapsed() @@ -368,7 +515,10 @@ impl RocksdbStorage { let factory_deps = connection .storage_dal() .get_factory_deps_for_revert(last_miniblock_to_keep) - .await; + .await + .with_context(|| { + format!("failed fetching factory deps for miniblock #{last_miniblock_to_keep}") + })?; tracing::info!( "Got {} factory deps, took {:?}", factory_deps.len(), @@ -393,8 +543,8 @@ impl RocksdbStorage { } batch.put_cf( cf, - Self::BLOCK_NUMBER_KEY, - &serialize_block_number(last_l1_batch_to_keep.0 + 1), + Self::L1_BATCH_NUMBER_KEY, + &serialize_l1_batch_number(last_l1_batch_to_keep.0 + 1), ); let cf = StateKeeperColumnFamily::FactoryDeps; @@ -403,29 +553,31 @@ impl RocksdbStorage { } db.write(batch) - .expect("failed to save state data into RocksDB"); + .context("failed to save state data into RocksDB") }) .await - .unwrap(); + .context("panicked during revert")? } /// Saves the pending changes to RocksDB. Must be executed on a Tokio thread. - async fn save(&mut self, l1_batch_number: L1BatchNumber) { + async fn save(&mut self, l1_batch_number: Option) -> anyhow::Result<()> { let pending_patch = mem::take(&mut self.pending_patch); let db = self.db.clone(); let save_task = tokio::task::spawn_blocking(move || { let mut batch = db.new_write_batch(); let cf = StateKeeperColumnFamily::State; - batch.put_cf( - cf, - Self::BLOCK_NUMBER_KEY, - &serialize_block_number(l1_batch_number.0), - ); + if let Some(l1_batch_number) = l1_batch_number { + batch.put_cf( + cf, + Self::L1_BATCH_NUMBER_KEY, + &serialize_l1_batch_number(l1_batch_number.0), + ); + } for (key, (value, enum_index)) in pending_patch.state { batch.put_cf( cf, - &Self::serialize_state_key(&key), + &Self::serialize_state_key(key), &StateValue::new(value, Some(enum_index)).serialize(), ); } @@ -435,26 +587,31 @@ impl RocksdbStorage { batch.put_cf(cf, &hash.to_fixed_bytes(), value.as_ref()); } db.write(batch) - .expect("failed to save state data into rocksdb"); + .context("failed to save state data into RocksDB") }); - save_task.await.unwrap(); + save_task + .await + .context("panicked when saving state data into RocksDB")? } - /// Returns the last processed l1 batch number + 1 + /// Returns the last processed l1 batch number + 1. + /// /// # Panics + /// /// Panics on RocksDB errors. - pub fn l1_batch_number(&self) -> L1BatchNumber { + async fn l1_batch_number(&self) -> Option { let cf = StateKeeperColumnFamily::State; - let block_number = self - .db - .get_cf(cf, Self::BLOCK_NUMBER_KEY) - .expect("failed to fetch block number"); - let block_number = block_number.map_or(0, |bytes| deserialize_block_number(&bytes)); - L1BatchNumber(block_number) + let db = self.db.clone(); + let number_bytes = + tokio::task::spawn_blocking(move || db.get_cf(cf, Self::L1_BATCH_NUMBER_KEY)) + .await + .expect("failed getting L1 batch number from RocksDB") + .expect("failed getting L1 batch number from RocksDB"); + number_bytes.map(|bytes| L1BatchNumber(deserialize_l1_batch_number(&bytes))) } - fn serialize_state_key(key: &StorageKey) -> [u8; 32] { - key.hashed_key().to_fixed_bytes() + fn serialize_state_key(key: H256) -> [u8; 32] { + key.to_fixed_bytes() } /// Estimates the number of key–value entries in the VM state. @@ -463,16 +620,20 @@ impl RocksdbStorage { .estimated_number_of_entries(StateKeeperColumnFamily::State) } - fn enum_migration_start_from(&self) -> Option { - let value = self - .db - .get_cf( + async fn enum_migration_start_from(&self) -> Option { + let db = self.db.clone(); + let value = tokio::task::spawn_blocking(move || { + db.get_cf( StateKeeperColumnFamily::State, Self::ENUM_INDEX_MIGRATION_CURSOR, ) - .expect("failed to read `ENUM_INDEX_MIGRATION_CURSOR`"); + .expect("failed to read `ENUM_INDEX_MIGRATION_CURSOR`") + }) + .await + .unwrap(); + match value { - Some(v) if v.is_empty() => None, + Some(value) if value.is_empty() => None, Some(cursor) => Some(H256::from_slice(&cursor)), None => Some(H256::zero()), } @@ -498,250 +659,7 @@ impl ReadStorage for RocksdbStorage { fn get_enumeration_index(&mut self, key: &StorageKey) -> Option { // Can safely unwrap here since it indicates that the migration has not yet ended and boojum will // only be deployed when the migration is finished. - self.read_state_value(key) + Self::read_state_value(&self.db, key.hashed_key()) .map(|state_value| state_value.enum_index.unwrap()) } } - -#[cfg(test)] -mod tests { - use tempfile::TempDir; - use zksync_dal::ConnectionPool; - use zksync_types::{MiniblockNumber, StorageLog}; - - use super::*; - use crate::test_utils::{ - create_l1_batch, create_miniblock, gen_storage_logs, prepare_postgres, - }; - - #[tokio::test] - async fn rocksdb_storage_basics() { - let dir = TempDir::new().expect("cannot create temporary dir for state keeper"); - let mut storage = RocksdbStorage::new(dir.path()); - let mut storage_logs: HashMap<_, _> = gen_storage_logs(0..20) - .into_iter() - .map(|log| (log.key, log.value)) - .collect(); - let changed_keys = storage.process_transaction_logs(storage_logs.clone()); - storage.pending_patch.state = changed_keys - .map(|(key, state_value)| (key, (state_value.value, 1))) // enum index doesn't matter in the test - .collect(); - storage.save(L1BatchNumber(0)).await; - { - for (key, value) in &storage_logs { - assert!(!storage.is_write_initial(key)); - assert_eq!(storage.read_value(key), *value); - } - } - - // Overwrite some of the logs. - for log in storage_logs.values_mut().step_by(2) { - *log = StorageValue::zero(); - } - let changed_keys = storage.process_transaction_logs(storage_logs.clone()); - storage.pending_patch.state = changed_keys - .map(|(key, state_value)| (key, (state_value.value, 1))) // enum index doesn't matter in the test - .collect(); - storage.save(L1BatchNumber(1)).await; - - for (key, value) in &storage_logs { - assert!(!storage.is_write_initial(key)); - assert_eq!(storage.read_value(key), *value); - } - } - - #[tokio::test] - async fn rocksdb_storage_syncing_with_postgres() { - let pool = ConnectionPool::test_pool().await; - let mut conn = pool.access_storage().await.unwrap(); - prepare_postgres(&mut conn).await; - let storage_logs = gen_storage_logs(20..40); - create_miniblock(&mut conn, MiniblockNumber(1), storage_logs.clone()).await; - create_l1_batch(&mut conn, L1BatchNumber(1), &storage_logs).await; - - let dir = TempDir::new().expect("cannot create temporary dir for state keeper"); - let mut storage = RocksdbStorage::new(dir.path()); - storage.update_from_postgres(&mut conn).await; - - assert_eq!(storage.l1_batch_number(), L1BatchNumber(2)); - for log in &storage_logs { - assert_eq!(storage.read_value(&log.key), log.value); - } - } - - async fn insert_factory_deps( - conn: &mut StorageProcessor<'_>, - miniblock_number: MiniblockNumber, - indices: impl Iterator, - ) { - let factory_deps = indices - .map(|i| (H256::repeat_byte(i), vec![i; 64])) - .collect(); - conn.storage_dal() - .insert_factory_deps(miniblock_number, &factory_deps) - .await; - } - - #[tokio::test] - async fn rocksdb_storage_revert() { - let pool = ConnectionPool::test_pool().await; - let mut conn = pool.access_storage().await.unwrap(); - prepare_postgres(&mut conn).await; - let storage_logs = gen_storage_logs(20..40); - create_miniblock(&mut conn, MiniblockNumber(1), storage_logs[..10].to_vec()).await; - insert_factory_deps(&mut conn, MiniblockNumber(1), 0..1).await; - create_miniblock(&mut conn, MiniblockNumber(2), storage_logs[10..].to_vec()).await; - insert_factory_deps(&mut conn, MiniblockNumber(2), 1..3).await; - create_l1_batch(&mut conn, L1BatchNumber(1), &storage_logs).await; - - let inserted_storage_logs = gen_storage_logs(50..60); - let replaced_storage_logs: Vec<_> = storage_logs - .iter() - .step_by(2) - .map(|&log| StorageLog { - value: H256::repeat_byte(0xf0), - ..log - }) - .collect(); - - let mut new_storage_logs = inserted_storage_logs.clone(); - new_storage_logs.extend_from_slice(&replaced_storage_logs); - create_miniblock(&mut conn, MiniblockNumber(3), new_storage_logs).await; - insert_factory_deps(&mut conn, MiniblockNumber(3), 3..5).await; - create_l1_batch(&mut conn, L1BatchNumber(2), &inserted_storage_logs).await; - - let dir = TempDir::new().expect("cannot create temporary dir for state keeper"); - let mut storage = RocksdbStorage::new(dir.path()); - storage.update_from_postgres(&mut conn).await; - - // Perform some sanity checks before the revert. - assert_eq!(storage.l1_batch_number(), L1BatchNumber(3)); - { - for log in &inserted_storage_logs { - assert_eq!(storage.read_value(&log.key), log.value); - } - for log in &replaced_storage_logs { - assert_eq!(storage.read_value(&log.key), log.value); - } - - for i in 0..5 { - assert_eq!( - storage.load_factory_dep(H256::repeat_byte(i)).unwrap(), - [i; 64] - ); - } - } - - storage.rollback(&mut conn, L1BatchNumber(1)).await; - assert_eq!(storage.l1_batch_number(), L1BatchNumber(2)); - { - for log in &inserted_storage_logs { - assert_eq!(storage.read_value(&log.key), H256::zero()); - } - for log in &replaced_storage_logs { - assert_ne!(storage.read_value(&log.key), log.value); - } - - for i in 0..3 { - assert_eq!( - storage.load_factory_dep(H256::repeat_byte(i)).unwrap(), - [i; 64] - ); - } - for i in 3..5 { - assert!(storage.load_factory_dep(H256::repeat_byte(i)).is_none()); - } - } - } - - #[tokio::test] - async fn rocksdb_enum_index_migration() { - let pool = ConnectionPool::test_pool().await; - let mut conn = pool.access_storage().await.unwrap(); - prepare_postgres(&mut conn).await; - let storage_logs = gen_storage_logs(20..40); - create_miniblock(&mut conn, MiniblockNumber(1), storage_logs.clone()).await; - create_l1_batch(&mut conn, L1BatchNumber(1), &storage_logs).await; - - let enum_indices: HashMap<_, _> = conn - .storage_logs_dedup_dal() - .initial_writes_for_batch(L1BatchNumber(1)) - .await - .into_iter() - .collect(); - - let dir = TempDir::new().expect("cannot create temporary dir for state keeper"); - let mut storage = RocksdbStorage::new(dir.path()); - storage.update_from_postgres(&mut conn).await; - - assert_eq!(storage.l1_batch_number(), L1BatchNumber(2)); - // Check that enum indices are correct after syncing with postgres. - for log in &storage_logs { - let expected_index = enum_indices[&log.key.hashed_key()]; - assert_eq!( - storage.read_state_value(&log.key).unwrap().enum_index, - Some(expected_index) - ); - } - - // Remove enum indices for some keys. - let mut write_batch = storage.db.new_write_batch(); - for log in &storage_logs { - write_batch.put_cf( - StateKeeperColumnFamily::State, - log.key.hashed_key().as_bytes(), - log.value.as_bytes(), - ); - write_batch.delete_cf( - StateKeeperColumnFamily::State, - RocksdbStorage::ENUM_INDEX_MIGRATION_CURSOR, - ); - } - storage.db.write(write_batch).unwrap(); - - // Check that migration works as expected. - let ordered_keys_to_migrate: Vec = storage_logs - .iter() - .map(|log| log.key) - .sorted_by_key(StorageKey::hashed_key) - .collect(); - - storage.enable_enum_index_migration(10); - let start_from = storage.enum_migration_start_from(); - assert_eq!(start_from, Some(H256::zero())); - - // Migrate the first half. - storage.save_missing_enum_indices(&mut conn).await; - for key in ordered_keys_to_migrate.iter().take(10) { - let expected_index = enum_indices[&key.hashed_key()]; - assert_eq!( - storage.read_state_value(key).unwrap().enum_index, - Some(expected_index) - ); - } - assert!(storage - .read_state_value(&ordered_keys_to_migrate[10]) - .unwrap() - .enum_index - .is_none()); - - // Migrate the second half. - storage.save_missing_enum_indices(&mut conn).await; - for key in ordered_keys_to_migrate.iter().skip(10) { - let expected_index = enum_indices[&key.hashed_key()]; - assert_eq!( - storage.read_state_value(key).unwrap().enum_index, - Some(expected_index) - ); - } - - // 20 keys were processed but we haven't checked that no keys to migrate are left. - let start_from = storage.enum_migration_start_from(); - assert!(start_from.is_some()); - - // Check that migration will be marked as completed after the next iteration. - storage.save_missing_enum_indices(&mut conn).await; - let start_from = storage.enum_migration_start_from(); - assert!(start_from.is_none()); - } -} diff --git a/core/lib/state/src/rocksdb/recovery.rs b/core/lib/state/src/rocksdb/recovery.rs new file mode 100644 index 000000000000..dae4ae144be0 --- /dev/null +++ b/core/lib/state/src/rocksdb/recovery.rs @@ -0,0 +1,254 @@ +//! Logic for [`RocksdbStorage`] related to snapshot recovery. + +use std::ops; + +use anyhow::Context as _; +use tokio::sync::watch; +use zksync_dal::{storage_logs_dal::StorageRecoveryLogEntry, StorageProcessor}; +use zksync_types::{ + snapshots::{uniform_hashed_keys_chunk, SnapshotRecoveryStatus}, + L1BatchNumber, MiniblockNumber, H256, +}; + +use super::{ + metrics::{ChunkRecoveryStage, RecoveryStage, RECOVERY_METRICS}, + RocksdbStorage, RocksdbSyncError, StateValue, +}; + +#[derive(Debug)] +struct KeyChunk { + id: u64, + key_range: ops::RangeInclusive, + start_entry: Option, +} + +impl RocksdbStorage { + /// Ensures that this storage is ready for normal operation (i.e., updates by L1 batch). + /// + /// # Return value + /// + /// Returns the next L1 batch that should be fed to the storage. + pub(super) async fn ensure_ready( + &mut self, + storage: &mut StorageProcessor<'_>, + desired_log_chunk_size: u64, + stop_receiver: &watch::Receiver, + ) -> Result { + if let Some(number) = self.l1_batch_number().await { + return Ok(number); + } + + // Check whether we need to perform a snapshot migration. + let snapshot_recovery = storage + .snapshot_recovery_dal() + .get_applied_snapshot_status() + .await + .context("failed getting snapshot recovery info")?; + Ok(if let Some(snapshot_recovery) = snapshot_recovery { + self.recover_from_snapshot( + storage, + &snapshot_recovery, + desired_log_chunk_size, + stop_receiver, + ) + .await?; + snapshot_recovery.l1_batch_number + 1 + } else { + // No recovery snapshot; we're initializing the cache from the genesis + L1BatchNumber(0) + }) + } + + /// # Important + /// + /// `Self::L1_BATCH_NUMBER_KEY` must be set at the very end of the process. If it is set earlier, recovery is not fault-tolerant + /// (it would be considered complete even if it failed in the middle). + async fn recover_from_snapshot( + &mut self, + storage: &mut StorageProcessor<'_>, + snapshot_recovery: &SnapshotRecoveryStatus, + desired_log_chunk_size: u64, + stop_receiver: &watch::Receiver, + ) -> Result<(), RocksdbSyncError> { + if *stop_receiver.borrow() { + return Err(RocksdbSyncError::Interrupted); + } + tracing::info!("Recovering secondary storage from snapshot: {snapshot_recovery:?}"); + + self.recover_factory_deps(storage, snapshot_recovery) + .await?; + + if *stop_receiver.borrow() { + return Err(RocksdbSyncError::Interrupted); + } + let key_chunks = + Self::load_key_chunks(storage, snapshot_recovery, desired_log_chunk_size).await?; + + RECOVERY_METRICS.recovered_chunk_count.set(0); + for key_chunk in key_chunks { + if *stop_receiver.borrow() { + return Err(RocksdbSyncError::Interrupted); + } + + let chunk_id = key_chunk.id; + let Some(chunk_start) = key_chunk.start_entry else { + tracing::info!("Chunk {chunk_id} (hashed key range {key_chunk:?}) doesn't have entries in Postgres; skipping"); + RECOVERY_METRICS.recovered_chunk_count.inc_by(1); + continue; + }; + + // Check whether the chunk is already recovered. + let state_value = self.read_state_value_async(chunk_start.key).await; + if let Some(state_value) = state_value { + if state_value.value != chunk_start.value + || state_value.enum_index != Some(chunk_start.leaf_index) + { + let err = anyhow::anyhow!( + "Mismatch between entry for key {:?} in Postgres snapshot for miniblock #{} \ + ({chunk_start:?}) and RocksDB cache ({state_value:?}); the recovery procedure may be corrupted", + chunk_start.key, + snapshot_recovery.miniblock_number + ); + return Err(err.into()); + } + tracing::info!("Chunk {chunk_id} (hashed key range {key_chunk:?}) is already recovered; skipping"); + } else { + self.recover_logs_chunk( + storage, + snapshot_recovery.miniblock_number, + key_chunk.key_range.clone(), + ) + .await + .with_context(|| { + format!( + "failed recovering logs chunk {chunk_id} (hashed key range {:?})", + key_chunk.key_range + ) + })?; + + #[cfg(test)] + (self.listener.on_logs_chunk_recovered)(chunk_id); + } + RECOVERY_METRICS.recovered_chunk_count.inc_by(1); + } + + tracing::info!("All chunks recovered; finalizing recovery process"); + self.save(Some(snapshot_recovery.l1_batch_number + 1)) + .await?; + Ok(()) + } + + async fn recover_factory_deps( + &mut self, + storage: &mut StorageProcessor<'_>, + snapshot_recovery: &SnapshotRecoveryStatus, + ) -> anyhow::Result<()> { + // We don't expect that many factory deps; that's why we recover factory deps in any case. + let latency = RECOVERY_METRICS.latency[&RecoveryStage::LoadFactoryDeps].start(); + let factory_deps = storage + .snapshots_creator_dal() + .get_all_factory_deps(snapshot_recovery.miniblock_number) + .await + .context("Failed getting factory dependencies")?; + let latency = latency.observe(); + tracing::info!( + "Loaded {} factory dependencies from the snapshot in {latency:?}", + factory_deps.len() + ); + + let latency = RECOVERY_METRICS.latency[&RecoveryStage::SaveFactoryDeps].start(); + for (bytecode_hash, bytecode) in factory_deps { + self.store_factory_dep(bytecode_hash, bytecode); + } + self.save(None) + .await + .context("failed saving factory deps")?; + let latency = latency.observe(); + tracing::info!("Saved factory dependencies to RocksDB in {latency:?}"); + Ok(()) + } + + async fn load_key_chunks( + storage: &mut StorageProcessor<'_>, + snapshot_recovery: &SnapshotRecoveryStatus, + desired_log_chunk_size: u64, + ) -> anyhow::Result> { + let snapshot_miniblock = snapshot_recovery.miniblock_number; + let log_count = storage + .storage_logs_dal() + .count_miniblock_storage_logs(snapshot_miniblock) + .await + .with_context(|| { + format!("Failed getting number of logs for miniblock #{snapshot_miniblock}") + })?; + let chunk_count = log_count.div_ceil(desired_log_chunk_size); + tracing::info!( + "Estimated the number of chunks for recovery based on {log_count} logs: {chunk_count}" + ); + + let latency = RECOVERY_METRICS.latency[&RecoveryStage::LoadChunkStarts].start(); + let key_chunks: Vec<_> = (0..chunk_count) + .map(|chunk_id| uniform_hashed_keys_chunk(chunk_id, chunk_count)) + .collect(); + let chunk_starts = storage + .storage_logs_dal() + .get_chunk_starts_for_miniblock(snapshot_miniblock, &key_chunks) + .await + .context("Failed getting chunk starts")?; + let latency = latency.observe(); + tracing::info!("Loaded {chunk_count} chunk starts in {latency:?}"); + + let key_chunks = (0..chunk_count) + .zip(key_chunks) + .zip(chunk_starts) + .map(|((id, key_range), start_entry)| KeyChunk { + id, + key_range, + start_entry, + }) + .collect(); + Ok(key_chunks) + } + + async fn read_state_value_async(&self, hashed_key: H256) -> Option { + let db = self.db.clone(); + tokio::task::spawn_blocking(move || Self::read_state_value(&db, hashed_key)) + .await + .unwrap() + } + + async fn recover_logs_chunk( + &mut self, + storage: &mut StorageProcessor<'_>, + snapshot_miniblock: MiniblockNumber, + key_chunk: ops::RangeInclusive, + ) -> anyhow::Result<()> { + let latency = RECOVERY_METRICS.chunk_latency[&ChunkRecoveryStage::LoadEntries].start(); + let all_entries = storage + .storage_logs_dal() + .get_tree_entries_for_miniblock(snapshot_miniblock, key_chunk.clone()) + .await + .with_context(|| { + format!("Failed getting entries for chunk {key_chunk:?} in snapshot for miniblock #{snapshot_miniblock}") + })?; + let latency = latency.observe(); + tracing::debug!( + "Loaded {} log entries for chunk {key_chunk:?} in {latency:?}", + all_entries.len() + ); + + let latency = RECOVERY_METRICS.chunk_latency[&ChunkRecoveryStage::SaveEntries].start(); + self.pending_patch.state = all_entries + .into_iter() + .map(|entry| (entry.key, (entry.value, entry.leaf_index))) + .collect(); + self.save(None) + .await + .context("failed saving storage logs chunk")?; + let latency = latency.observe(); + tracing::debug!("Saved logs chunk {key_chunk:?} to RocksDB in {latency:?}"); + + tracing::info!("Recovered hashed key chunk {key_chunk:?}"); + Ok(()) + } +} diff --git a/core/lib/state/src/rocksdb/tests.rs b/core/lib/state/src/rocksdb/tests.rs new file mode 100644 index 000000000000..38ca942e6795 --- /dev/null +++ b/core/lib/state/src/rocksdb/tests.rs @@ -0,0 +1,495 @@ +//! Tests for [`RocksdbStorage`]. + +use std::fmt; + +use assert_matches::assert_matches; +use tempfile::TempDir; +use test_casing::test_casing; +use zksync_dal::ConnectionPool; +use zksync_types::{MiniblockNumber, StorageLog}; + +use super::*; +use crate::test_utils::{ + create_l1_batch, create_miniblock, gen_storage_logs, prepare_postgres, + prepare_postgres_for_snapshot_recovery, +}; + +pub(super) struct RocksdbStorageEventListener { + /// Called when an L1 batch is synced. + pub on_l1_batch_synced: Box, + /// Called when an storage logs chunk is recovered from a snapshot. + pub on_logs_chunk_recovered: Box, +} + +impl fmt::Debug for RocksdbStorageEventListener { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter + .debug_struct("RocksdbStorageEventListener") + .finish_non_exhaustive() + } +} + +impl Default for RocksdbStorageEventListener { + fn default() -> Self { + Self { + on_l1_batch_synced: Box::new(|_| { /* do nothing */ }), + on_logs_chunk_recovered: Box::new(|_| { /* do nothing */ }), + } + } +} + +#[tokio::test] +async fn rocksdb_storage_basics() { + let dir = TempDir::new().expect("cannot create temporary dir for state keeper"); + let mut storage = RocksdbStorage::new(dir.path().to_path_buf()).await.unwrap(); + let mut storage_logs: HashMap<_, _> = gen_storage_logs(0..20) + .into_iter() + .map(|log| (log.key, log.value)) + .collect(); + let changed_keys = RocksdbStorage::process_transaction_logs(&storage.db, storage_logs.clone()); + storage.pending_patch.state = changed_keys + .into_iter() + .map(|(key, state_value)| (key.hashed_key(), (state_value.value, 1))) // enum index doesn't matter in the test + .collect(); + storage.save(Some(L1BatchNumber(0))).await.unwrap(); + { + for (key, value) in &storage_logs { + assert!(!storage.is_write_initial(key)); + assert_eq!(storage.read_value(key), *value); + } + } + + // Overwrite some of the logs. + for log in storage_logs.values_mut().step_by(2) { + *log = StorageValue::zero(); + } + let changed_keys = RocksdbStorage::process_transaction_logs(&storage.db, storage_logs.clone()); + storage.pending_patch.state = changed_keys + .into_iter() + .map(|(key, state_value)| (key.hashed_key(), (state_value.value, 1))) // enum index doesn't matter in the test + .collect(); + storage.save(Some(L1BatchNumber(1))).await.unwrap(); + + for (key, value) in &storage_logs { + assert!(!storage.is_write_initial(key)); + assert_eq!(storage.read_value(key), *value); + } +} + +async fn sync_test_storage(dir: &TempDir, conn: &mut StorageProcessor<'_>) -> RocksdbStorage { + let (_stop_sender, stop_receiver) = watch::channel(false); + RocksdbStorage::builder(dir.path()) + .await + .expect("Failed initializing RocksDB") + .synchronize(conn, &stop_receiver) + .await + .unwrap() + .expect("Storage synchronization unexpectedly stopped") +} + +#[tokio::test] +async fn rocksdb_storage_syncing_with_postgres() { + let pool = ConnectionPool::test_pool().await; + let mut conn = pool.access_storage().await.unwrap(); + prepare_postgres(&mut conn).await; + let storage_logs = gen_storage_logs(20..40); + create_miniblock(&mut conn, MiniblockNumber(1), storage_logs.clone()).await; + create_l1_batch(&mut conn, L1BatchNumber(1), &storage_logs).await; + + let dir = TempDir::new().expect("cannot create temporary dir for state keeper"); + let mut storage = sync_test_storage(&dir, &mut conn).await; + + assert_eq!(storage.l1_batch_number().await, Some(L1BatchNumber(2))); + for log in &storage_logs { + assert_eq!(storage.read_value(&log.key), log.value); + } +} + +#[tokio::test] +async fn rocksdb_storage_syncing_fault_tolerance() { + let pool = ConnectionPool::test_pool().await; + let mut conn = pool.access_storage().await.unwrap(); + prepare_postgres(&mut conn).await; + let storage_logs = gen_storage_logs(100..200); + for (i, block_logs) in storage_logs.chunks(20).enumerate() { + let number = u32::try_from(i).unwrap() + 1; + create_miniblock(&mut conn, MiniblockNumber(number), block_logs.to_vec()).await; + create_l1_batch(&mut conn, L1BatchNumber(number), block_logs).await; + } + + let dir = TempDir::new().expect("cannot create temporary dir for state keeper"); + let (stop_sender, stop_receiver) = watch::channel(false); + let mut storage = RocksdbStorage::builder(dir.path()) + .await + .expect("Failed initializing RocksDB"); + let mut expected_l1_batch_number = L1BatchNumber(0); + storage.0.listener.on_l1_batch_synced = Box::new(move |number| { + assert_eq!(number, expected_l1_batch_number); + expected_l1_batch_number += 1; + if number == L1BatchNumber(2) { + stop_sender.send_replace(true); + } + }); + let storage = storage + .synchronize(&mut conn, &stop_receiver) + .await + .unwrap(); + assert!(storage.is_none()); + + // Resume storage syncing and check that it completes. + let storage = RocksdbStorage::builder(dir.path()) + .await + .expect("Failed initializing RocksDB"); + assert_eq!(storage.l1_batch_number().await, Some(L1BatchNumber(3))); + + let (_stop_sender, stop_receiver) = watch::channel(false); + let mut storage = storage + .synchronize(&mut conn, &stop_receiver) + .await + .unwrap() + .expect("Storage synchronization unexpectedly stopped"); + assert_eq!(storage.l1_batch_number().await, Some(L1BatchNumber(6))); + for log in &storage_logs { + assert_eq!(storage.read_value(&log.key), log.value); + assert!(!storage.is_write_initial(&log.key)); + } +} + +async fn insert_factory_deps( + conn: &mut StorageProcessor<'_>, + miniblock_number: MiniblockNumber, + indices: impl Iterator, +) { + let factory_deps = indices + .map(|i| (H256::repeat_byte(i), vec![i; 64])) + .collect(); + conn.storage_dal() + .insert_factory_deps(miniblock_number, &factory_deps) + .await + .unwrap(); +} + +#[tokio::test] +async fn rocksdb_storage_revert() { + let pool = ConnectionPool::test_pool().await; + let mut conn = pool.access_storage().await.unwrap(); + prepare_postgres(&mut conn).await; + let storage_logs = gen_storage_logs(20..40); + create_miniblock(&mut conn, MiniblockNumber(1), storage_logs[..10].to_vec()).await; + insert_factory_deps(&mut conn, MiniblockNumber(1), 0..1).await; + create_miniblock(&mut conn, MiniblockNumber(2), storage_logs[10..].to_vec()).await; + insert_factory_deps(&mut conn, MiniblockNumber(2), 1..3).await; + create_l1_batch(&mut conn, L1BatchNumber(1), &storage_logs).await; + + let inserted_storage_logs = gen_storage_logs(50..60); + let replaced_storage_logs: Vec<_> = storage_logs + .iter() + .step_by(2) + .map(|&log| StorageLog { + value: H256::repeat_byte(0xf0), + ..log + }) + .collect(); + + let mut new_storage_logs = inserted_storage_logs.clone(); + new_storage_logs.extend_from_slice(&replaced_storage_logs); + create_miniblock(&mut conn, MiniblockNumber(3), new_storage_logs).await; + insert_factory_deps(&mut conn, MiniblockNumber(3), 3..5).await; + create_l1_batch(&mut conn, L1BatchNumber(2), &inserted_storage_logs).await; + + let dir = TempDir::new().expect("cannot create temporary dir for state keeper"); + let mut storage = sync_test_storage(&dir, &mut conn).await; + + // Perform some sanity checks before the revert. + assert_eq!(storage.l1_batch_number().await, Some(L1BatchNumber(3))); + { + for log in &inserted_storage_logs { + assert_eq!(storage.read_value(&log.key), log.value); + } + for log in &replaced_storage_logs { + assert_eq!(storage.read_value(&log.key), log.value); + } + + for i in 0..5 { + assert_eq!( + storage.load_factory_dep(H256::repeat_byte(i)).unwrap(), + [i; 64] + ); + } + } + + storage.rollback(&mut conn, L1BatchNumber(1)).await.unwrap(); + assert_eq!(storage.l1_batch_number().await, Some(L1BatchNumber(2))); + { + for log in &inserted_storage_logs { + assert_eq!(storage.read_value(&log.key), H256::zero()); + } + for log in &replaced_storage_logs { + assert_ne!(storage.read_value(&log.key), log.value); + } + + for i in 0..3 { + assert_eq!( + storage.load_factory_dep(H256::repeat_byte(i)).unwrap(), + [i; 64] + ); + } + for i in 3..5 { + assert!(storage.load_factory_dep(H256::repeat_byte(i)).is_none()); + } + } +} + +#[tokio::test] +async fn rocksdb_enum_index_migration() { + let pool = ConnectionPool::test_pool().await; + let mut conn = pool.access_storage().await.unwrap(); + prepare_postgres(&mut conn).await; + let storage_logs = gen_storage_logs(20..40); + create_miniblock(&mut conn, MiniblockNumber(1), storage_logs.clone()).await; + create_l1_batch(&mut conn, L1BatchNumber(1), &storage_logs).await; + + let enum_indices: HashMap<_, _> = conn + .storage_logs_dedup_dal() + .initial_writes_for_batch(L1BatchNumber(1)) + .await + .into_iter() + .collect(); + + let dir = TempDir::new().expect("cannot create temporary dir for state keeper"); + let mut storage = sync_test_storage(&dir, &mut conn).await; + + assert_eq!(storage.l1_batch_number().await, Some(L1BatchNumber(2))); + // Check that enum indices are correct after syncing with Postgres. + for log in &storage_logs { + let expected_index = enum_indices[&log.key.hashed_key()]; + assert_eq!( + storage.get_enumeration_index(&log.key), + Some(expected_index) + ); + } + + // Remove enum indices for some keys. + let mut write_batch = storage.db.new_write_batch(); + for log in &storage_logs { + write_batch.put_cf( + StateKeeperColumnFamily::State, + log.key.hashed_key().as_bytes(), + log.value.as_bytes(), + ); + write_batch.delete_cf( + StateKeeperColumnFamily::State, + RocksdbStorage::ENUM_INDEX_MIGRATION_CURSOR, + ); + } + storage.db.write(write_batch).unwrap(); + + // Check that migration works as expected. + let ordered_keys_to_migrate: Vec = storage_logs + .iter() + .map(|log| log.key) + .sorted_by_key(StorageKey::hashed_key) + .collect(); + + storage.enum_index_migration_chunk_size = 10; + let start_from = storage.enum_migration_start_from().await; + assert_eq!(start_from, Some(H256::zero())); + + // Migrate the first half. + storage.save_missing_enum_indices(&mut conn).await.unwrap(); + for key in ordered_keys_to_migrate.iter().take(10) { + let expected_index = enum_indices[&key.hashed_key()]; + assert_eq!(storage.get_enumeration_index(key), Some(expected_index)); + } + let non_migrated_state_value = + RocksdbStorage::read_state_value(&storage.db, ordered_keys_to_migrate[10].hashed_key()) + .unwrap(); + assert!(non_migrated_state_value.enum_index.is_none()); + + // Migrate the second half. + storage.save_missing_enum_indices(&mut conn).await.unwrap(); + for key in ordered_keys_to_migrate.iter().skip(10) { + let expected_index = enum_indices[&key.hashed_key()]; + assert_eq!(storage.get_enumeration_index(key), Some(expected_index)); + } + + // 20 keys were processed but we haven't checked that no keys to migrate are left. + let start_from = storage.enum_migration_start_from().await; + assert!(start_from.is_some()); + + // Check that migration will be marked as completed after the next iteration. + storage.save_missing_enum_indices(&mut conn).await.unwrap(); + let start_from = storage.enum_migration_start_from().await; + assert!(start_from.is_none()); +} + +#[test_casing(4, [RocksdbStorage::DESIRED_LOG_CHUNK_SIZE, 20, 5, 1])] +#[tokio::test] +async fn low_level_snapshot_recovery(log_chunk_size: u64) { + let pool = ConnectionPool::test_pool().await; + let mut conn = pool.access_storage().await.unwrap(); + let (snapshot_recovery, mut storage_logs) = + prepare_postgres_for_snapshot_recovery(&mut conn).await; + + let dir = TempDir::new().expect("cannot create temporary dir for state keeper"); + let mut storage = RocksdbStorage::new(dir.path().to_path_buf()).await.unwrap(); + let (_stop_sender, stop_receiver) = watch::channel(false); + let next_l1_batch = storage + .ensure_ready(&mut conn, log_chunk_size, &stop_receiver) + .await + .unwrap(); + assert_eq!(next_l1_batch, snapshot_recovery.l1_batch_number + 1); + assert_eq!( + storage.l1_batch_number().await, + Some(snapshot_recovery.l1_batch_number + 1) + ); + + // Sort logs in the same order as enum indices are assigned (by full `StorageKey`). + storage_logs.sort_unstable_by_key(|log| log.key); + for (i, log) in storage_logs.iter().enumerate() { + assert_eq!(storage.read_value(&log.key), log.value); + let expected_index = i as u64 + 1; + assert_eq!( + storage.get_enumeration_index(&log.key), + Some(expected_index) + ); + } +} + +#[tokio::test] +async fn recovering_factory_deps_from_snapshot() { + let pool = ConnectionPool::test_pool().await; + let mut conn = pool.access_storage().await.unwrap(); + let (snapshot_recovery, _) = prepare_postgres_for_snapshot_recovery(&mut conn).await; + + let mut all_factory_deps = HashMap::new(); + for number in 0..snapshot_recovery.miniblock_number.0 { + let bytecode_hash = H256::from_low_u64_be(number.into()); + let bytecode = vec![u8::try_from(number).unwrap(); 1_024]; + all_factory_deps.insert(bytecode_hash, bytecode.clone()); + + let number = MiniblockNumber(number); + // FIXME (PLA-589): don't store miniblocks once the corresponding foreign keys are removed + create_miniblock(&mut conn, number, vec![]).await; + conn.storage_dal() + .insert_factory_deps(number, &HashMap::from([(bytecode_hash, bytecode)])) + .await + .unwrap(); + } + + let dir = TempDir::new().expect("cannot create temporary dir for state keeper"); + let mut storage = sync_test_storage(&dir, &mut conn).await; + + for (bytecode_hash, bytecode) in &all_factory_deps { + assert_eq!(storage.load_factory_dep(*bytecode_hash).unwrap(), *bytecode); + } +} + +#[tokio::test] +async fn recovering_from_snapshot_and_following_logs() { + let pool = ConnectionPool::test_pool().await; + let mut conn = pool.access_storage().await.unwrap(); + let (snapshot_recovery, mut storage_logs) = + prepare_postgres_for_snapshot_recovery(&mut conn).await; + + // Add some more storage logs. + let new_storage_logs = gen_storage_logs(500..600); + create_miniblock( + &mut conn, + snapshot_recovery.miniblock_number + 1, + new_storage_logs.clone(), + ) + .await; + create_l1_batch( + &mut conn, + snapshot_recovery.l1_batch_number + 1, + &new_storage_logs, + ) + .await; + + let updated_storage_logs: Vec<_> = storage_logs + .iter() + .step_by(3) + .copied() + .map(|mut log| { + log.value = H256::repeat_byte(0xff); + log + }) + .collect(); + create_miniblock( + &mut conn, + snapshot_recovery.miniblock_number + 2, + updated_storage_logs.clone(), + ) + .await; + create_l1_batch(&mut conn, snapshot_recovery.l1_batch_number + 2, &[]).await; + + let dir = TempDir::new().expect("cannot create temporary dir for state keeper"); + let mut storage = sync_test_storage(&dir, &mut conn).await; + + for (i, log) in new_storage_logs.iter().enumerate() { + assert_eq!(storage.read_value(&log.key), log.value); + let expected_index = (i + storage_logs.len()) as u64 + 1; + assert_eq!( + storage.get_enumeration_index(&log.key), + Some(expected_index) + ); + assert!(!storage.is_write_initial(&log.key)); + } + + for log in &updated_storage_logs { + assert_eq!(storage.read_value(&log.key), log.value); + assert!(storage.get_enumeration_index(&log.key).unwrap() <= storage_logs.len() as u64); + } + storage_logs.sort_unstable_by_key(|log| log.key); + for (i, log) in storage_logs.iter().enumerate() { + let expected_index = i as u64 + 1; + assert_eq!( + storage.get_enumeration_index(&log.key), + Some(expected_index) + ); + assert!(!storage.is_write_initial(&log.key)); + } +} + +#[tokio::test] +async fn recovery_fault_tolerance() { + let pool = ConnectionPool::test_pool().await; + let mut conn = pool.access_storage().await.unwrap(); + let (_, storage_logs) = prepare_postgres_for_snapshot_recovery(&mut conn).await; + let log_chunk_size = storage_logs.len() as u64 / 5; + + let dir = TempDir::new().expect("cannot create temporary dir for state keeper"); + let mut storage = RocksdbStorage::new(dir.path().to_path_buf()).await.unwrap(); + let (stop_sender, stop_receiver) = watch::channel(false); + let mut synced_chunk_count = 0_u64; + storage.listener.on_logs_chunk_recovered = Box::new(move |chunk_id| { + assert_eq!(chunk_id, synced_chunk_count); + synced_chunk_count += 1; + if synced_chunk_count == 2 { + stop_sender.send_replace(true); + } + }); + + let err = storage + .ensure_ready(&mut conn, log_chunk_size, &stop_receiver) + .await + .unwrap_err(); + assert_matches!(err, RocksdbSyncError::Interrupted); + drop(storage); + + // Resume recovery and check that no chunks are recovered twice. + let (_stop_sender, stop_receiver) = watch::channel(false); + let mut storage = RocksdbStorage::new(dir.path().to_path_buf()).await.unwrap(); + storage.listener.on_logs_chunk_recovered = Box::new(|chunk_id| { + assert!(chunk_id >= 2); + }); + storage + .ensure_ready(&mut conn, log_chunk_size, &stop_receiver) + .await + .unwrap(); + for log in &storage_logs { + assert_eq!(storage.read_value(&log.key), log.value); + assert!(!storage.is_write_initial(&log.key)); + } +} diff --git a/core/lib/state/src/test_utils.rs b/core/lib/state/src/test_utils.rs index 2a5664ae0602..9c4fca8285ee 100644 --- a/core/lib/state/src/test_utils.rs +++ b/core/lib/state/src/test_utils.rs @@ -4,7 +4,8 @@ use std::ops; use zksync_dal::StorageProcessor; use zksync_types::{ - block::{BlockGasCount, L1BatchHeader, MiniblockHeader}, + block::{L1BatchHeader, MiniblockHeader}, + snapshots::SnapshotRecoveryStatus, AccountTreeId, Address, L1BatchNumber, MiniblockNumber, ProtocolVersion, StorageKey, StorageLog, H256, }; @@ -32,6 +33,10 @@ pub(crate) async fn prepare_postgres(conn: &mut StorageProcessor<'_>) { .delete_l1_batches(L1BatchNumber(0)) .await .unwrap(); + conn.blocks_dal() + .delete_initial_writes(L1BatchNumber(0)) + .await + .unwrap(); } pub(crate) fn gen_storage_logs(indices: ops::Range) -> Vec { @@ -72,9 +77,10 @@ pub(crate) async fn create_miniblock( hash: H256::from_low_u64_be(u64::from(miniblock_number.0)), l1_tx_count: 0, l2_tx_count: 0, + fee_account_address: Address::default(), base_fee_per_gas: 0, - l1_gas_price: 0, - l2_fair_gas_price: 0, + batch_fee_input: Default::default(), + gas_per_pubdata_limit: 0, base_system_contracts_hashes: Default::default(), protocol_version: Some(Default::default()), virtual_blocks: 0, @@ -96,16 +102,9 @@ pub(crate) async fn create_l1_batch( l1_batch_number: L1BatchNumber, logs_for_initial_writes: &[StorageLog], ) { - let mut header = L1BatchHeader::new( - l1_batch_number, - 0, - Address::default(), - Default::default(), - Default::default(), - ); - header.is_finished = true; + let header = L1BatchHeader::new(l1_batch_number, 0, Default::default(), Default::default()); conn.blocks_dal() - .insert_l1_batch(&header, &[], BlockGasCount::default(), &[], &[]) + .insert_mock_l1_batch(&header) .await .unwrap(); conn.blocks_dal() @@ -119,3 +118,39 @@ pub(crate) async fn create_l1_batch( .insert_initial_writes(l1_batch_number, &written_keys) .await; } + +pub(crate) async fn prepare_postgres_for_snapshot_recovery( + conn: &mut StorageProcessor<'_>, +) -> (SnapshotRecoveryStatus, Vec) { + conn.protocol_versions_dal() + .save_protocol_version_with_tx(ProtocolVersion::default()) + .await; + + let snapshot_recovery = SnapshotRecoveryStatus { + l1_batch_number: L1BatchNumber(23), + l1_batch_root_hash: H256::zero(), // not used + miniblock_number: MiniblockNumber(42), + miniblock_root_hash: H256::zero(), // not used + storage_logs_chunks_processed: vec![true; 100], + }; + conn.snapshot_recovery_dal() + .insert_initial_recovery_status(&snapshot_recovery) + .await + .unwrap(); + + // FIXME (PLA-589): don't store miniblock / L1 batch once the corresponding foreign keys are removed + let snapshot_storage_logs = gen_storage_logs(100..200); + create_miniblock( + conn, + snapshot_recovery.miniblock_number, + snapshot_storage_logs.clone(), + ) + .await; + create_l1_batch( + conn, + snapshot_recovery.l1_batch_number, + &snapshot_storage_logs, + ) + .await; + (snapshot_recovery, snapshot_storage_logs) +} diff --git a/core/lib/storage/src/db.rs b/core/lib/storage/src/db.rs index f6237d49950a..e8402b96c62a 100644 --- a/core/lib/storage/src/db.rs +++ b/core/lib/storage/src/db.rs @@ -298,11 +298,11 @@ pub struct RocksDB { } impl RocksDB { - pub fn new(path: &Path) -> Self { + pub fn new(path: &Path) -> Result { Self::with_options(path, RocksDBOptions::default()) } - pub fn with_options(path: &Path, options: RocksDBOptions) -> Self { + pub fn with_options(path: &Path, options: RocksDBOptions) -> Result { let caches = RocksDBCaches::new(options.block_cache_capacity); let db_options = Self::rocksdb_options(None, None); let existing_cfs = DB::list_cf(&db_options, path).unwrap_or_else(|err| { @@ -354,7 +354,7 @@ impl RocksDB { ColumnFamilyDescriptor::new(cf_name, cf_options) }); - let db = DB::open_cf_descriptors(&db_options, path, cfs).expect("failed to init rocksdb"); + let db = DB::open_cf_descriptors(&db_options, path, cfs)?; let inner = Arc::new(RocksDBInner { db, db_name: CF::DB_NAME, @@ -371,12 +371,12 @@ impl RocksDB { ); inner.wait_for_writes_to_resume(&options.stalled_writes_retries); - Self { + Ok(Self { inner, sync_writes: false, stalled_writes_retries: options.stalled_writes_retries, _cf: PhantomData, - } + }) } /// Switches on sync writes in [`Self::write()`] and [`Self::put()`]. This has a performance @@ -529,7 +529,7 @@ impl RocksDB { .iterator_cf_opt(cf, options, IteratorMode::Start) .map(Result::unwrap) .fuse() - // ^ The rocksdb docs say that a raw iterator (which is used by the returned ordinary iterator) + // ^ The RocksDB docs say that a raw iterator (which is used by the returned ordinary iterator) // can become invalid "when it reaches the end of its defined range, or when it encounters an error." // We panic on RocksDB errors elsewhere and fuse it to prevent polling after the end of the range. // Thus, `unwrap()` should be safe. @@ -665,13 +665,15 @@ mod tests { #[test] fn changing_column_families() { let temp_dir = TempDir::new().unwrap(); - let db = RocksDB::::new(temp_dir.path()).with_sync_writes(); + let db = RocksDB::::new(temp_dir.path()) + .unwrap() + .with_sync_writes(); let mut batch = db.new_write_batch(); batch.put_cf(OldColumnFamilies::Default, b"test", b"value"); db.write(batch).unwrap(); drop(db); - let db = RocksDB::::new(temp_dir.path()); + let db = RocksDB::::new(temp_dir.path()).unwrap(); let value = db.get_cf(NewColumnFamilies::Default, b"test").unwrap(); assert_eq!(value.unwrap(), b"value"); } @@ -691,13 +693,15 @@ mod tests { #[test] fn default_column_family_does_not_need_to_be_explicitly_opened() { let temp_dir = TempDir::new().unwrap(); - let db = RocksDB::::new(temp_dir.path()).with_sync_writes(); + let db = RocksDB::::new(temp_dir.path()) + .unwrap() + .with_sync_writes(); let mut batch = db.new_write_batch(); batch.put_cf(OldColumnFamilies::Junk, b"test", b"value"); db.write(batch).unwrap(); drop(db); - let db = RocksDB::::new(temp_dir.path()); + let db = RocksDB::::new(temp_dir.path()).unwrap(); let value = db.get_cf(JunkColumnFamily, b"test").unwrap(); assert_eq!(value.unwrap(), b"value"); } @@ -705,7 +709,9 @@ mod tests { #[test] fn write_batch_can_be_restored_from_bytes() { let temp_dir = TempDir::new().unwrap(); - let db = RocksDB::::new(temp_dir.path()).with_sync_writes(); + let db = RocksDB::::new(temp_dir.path()) + .unwrap() + .with_sync_writes(); let mut batch = db.new_write_batch(); batch.put_cf(NewColumnFamilies::Default, b"test", b"value"); batch.put_cf(NewColumnFamilies::Default, b"test2", b"value2"); diff --git a/core/lib/types/Cargo.toml b/core/lib/types/Cargo.toml index 594160c27287..3a2a6e4eb54f 100644 --- a/core/lib/types/Cargo.toml +++ b/core/lib/types/Cargo.toml @@ -16,17 +16,12 @@ zksync_utils = { path = "../utils" } zksync_basic_types = { path = "../basic_types" } zksync_contracts = { path = "../contracts" } zksync_mini_merkle_tree = { path = "../mini_merkle_tree" } -# We need this import because we wanat DAL to be responsible for (de)serialization -codegen = { git = "https://github.com/matter-labs/solidity_plonk_verifier.git", branch = "dev" } -zkevm_test_harness = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.3.3" } -zk_evm_1_4_0 = { git = "https://github.com/matter-labs/era-zk_evm.git", branch = "v1.4.0", package = "zk_evm" } -zk_evm = { git = "https://github.com/matter-labs/era-zk_evm.git", tag = "v1.3.3-rc2" } -zksync_consensus_roles = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "84cdd9e45fd84bc1fac0b394c899ae33aef91afa" } -zksync_protobuf = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "84cdd9e45fd84bc1fac0b394c899ae33aef91afa" } +zksync_config = { path = "../config" } +zksync_protobuf = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } anyhow = "1.0.75" chrono = { version = "0.4", features = ["serde"] } -num = { version = "0.3.1", features = ["serde"] } +num = { version = "0.4.0", features = ["serde"] } once_cell = "1.7" rlp = "0.5" serde = "1.0.90" @@ -39,18 +34,12 @@ hex = "0.4" prost = "0.12.1" # Crypto stuff -# TODO (PLA-440): remove parity-crypto -parity-crypto = { version = "0.9", features = ["publickey"] } +secp256k1 = { version = "0.27", features = ["recovery", "global-context"] } blake2 = "0.10" -# TODO (PLA-440): remove parity-crypto -# `ethereum-types` version used in `parity-crypto` -ethereum_types_old = { package = "ethereum-types", version = "0.12.0" } - [dev-dependencies] -secp256k1 = { version = "0.27", features = ["recovery"] } tokio = { version = "1", features = ["rt", "macros"] } serde_with = { version = "1", features = ["hex"] } [build-dependencies] -zksync_protobuf_build = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "84cdd9e45fd84bc1fac0b394c899ae33aef91afa" } +zksync_protobuf_build = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } diff --git a/core/lib/types/src/aggregated_operations.rs b/core/lib/types/src/aggregated_operations.rs index 006eca562e71..dadfad265cb2 100644 --- a/core/lib/types/src/aggregated_operations.rs +++ b/core/lib/types/src/aggregated_operations.rs @@ -1,158 +1,4 @@ -use std::{fmt, ops, str::FromStr}; - -use codegen::serialize_proof; -use serde::{Deserialize, Serialize}; -use zkevm_test_harness::{ - abstract_zksync_circuit::concrete_circuits::ZkSyncCircuit, - bellman::{bn256::Bn256, plonk::better_better_cs::proof::Proof}, - witness::oracle::VmWitnessOracle, -}; -use zksync_basic_types::{ethabi::Token, L1BatchNumber}; - -use crate::{commitment::L1BatchWithMetadata, ProtocolVersionId, U256}; - -fn l1_batch_range_from_batches( - batches: &[L1BatchWithMetadata], -) -> ops::RangeInclusive { - let start = batches - .first() - .map(|l1_batch| l1_batch.header.number) - .unwrap_or_default(); - let end = batches - .last() - .map(|l1_batch| l1_batch.header.number) - .unwrap_or_default(); - start..=end -} - -#[derive(Debug, Clone)] -pub struct L1BatchCommitOperation { - pub last_committed_l1_batch: L1BatchWithMetadata, - pub l1_batches: Vec, -} - -impl L1BatchCommitOperation { - pub fn get_eth_tx_args(&self) -> Vec { - let stored_batch_info = self.last_committed_l1_batch.l1_header_data(); - let l1_batches_to_commit = self - .l1_batches - .iter() - .map(L1BatchWithMetadata::l1_commit_data) - .collect(); - - vec![stored_batch_info, Token::Array(l1_batches_to_commit)] - } - - pub fn l1_batch_range(&self) -> ops::RangeInclusive { - l1_batch_range_from_batches(&self.l1_batches) - } -} - -#[derive(Debug, Clone)] -pub struct L1BatchCreateProofOperation { - pub l1_batches: Vec, - pub proofs_to_pad: usize, -} - -#[derive(Clone, Serialize, Deserialize)] -pub struct L1BatchProofForL1 { - pub aggregation_result_coords: [[u8; 32]; 4], - pub scheduler_proof: Proof>>, -} - -impl fmt::Debug for L1BatchProofForL1 { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter - .debug_struct("L1BatchProofForL1") - .field("aggregation_result_coords", &self.aggregation_result_coords) - .finish_non_exhaustive() - } -} - -#[derive(Debug, Clone)] -pub struct L1BatchProofOperation { - pub prev_l1_batch: L1BatchWithMetadata, - pub l1_batches: Vec, - pub proofs: Vec, - pub should_verify: bool, -} - -impl L1BatchProofOperation { - pub fn get_eth_tx_args(&self) -> Vec { - let prev_l1_batch = self.prev_l1_batch.l1_header_data(); - let batches_arg = self - .l1_batches - .iter() - .map(L1BatchWithMetadata::l1_header_data) - .collect(); - let batches_arg = Token::Array(batches_arg); - - if self.should_verify { - // currently we only support submitting a single proof - assert_eq!(self.proofs.len(), 1); - assert_eq!(self.l1_batches.len(), 1); - - let L1BatchProofForL1 { - aggregation_result_coords, - scheduler_proof, - } = self.proofs.first().unwrap(); - - let (_, proof) = serialize_proof(scheduler_proof); - - let aggregation_result_coords = if self.l1_batches[0] - .header - .protocol_version - .unwrap() - .is_pre_boojum() - { - Token::Array( - aggregation_result_coords - .iter() - .map(|bytes| Token::Uint(U256::from_big_endian(bytes))) - .collect(), - ) - } else { - Token::Array(Vec::new()) - }; - let proof_input = Token::Tuple(vec![ - aggregation_result_coords, - Token::Array(proof.into_iter().map(Token::Uint).collect()), - ]); - - vec![prev_l1_batch, batches_arg, proof_input] - } else { - vec![ - prev_l1_batch, - batches_arg, - Token::Tuple(vec![Token::Array(vec![]), Token::Array(vec![])]), - ] - } - } - - pub fn l1_batch_range(&self) -> ops::RangeInclusive { - l1_batch_range_from_batches(&self.l1_batches) - } -} - -#[derive(Debug, Clone)] -pub struct L1BatchExecuteOperation { - pub l1_batches: Vec, -} - -impl L1BatchExecuteOperation { - pub fn get_eth_tx_args(&self) -> Vec { - vec![Token::Array( - self.l1_batches - .iter() - .map(L1BatchWithMetadata::l1_header_data) - .collect(), - )] - } - - pub fn l1_batch_range(&self) -> ops::RangeInclusive { - l1_batch_range_from_batches(&self.l1_batches) - } -} +use std::{fmt, str::FromStr}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum AggregatedActionType { @@ -193,45 +39,3 @@ impl FromStr for AggregatedActionType { } } } - -#[allow(clippy::large_enum_variant)] -#[derive(Debug, Clone)] -pub enum AggregatedOperation { - Commit(L1BatchCommitOperation), - PublishProofOnchain(L1BatchProofOperation), - Execute(L1BatchExecuteOperation), -} - -impl AggregatedOperation { - pub fn get_action_type(&self) -> AggregatedActionType { - match self { - Self::Commit(_) => AggregatedActionType::Commit, - Self::PublishProofOnchain(_) => AggregatedActionType::PublishProofOnchain, - Self::Execute(_) => AggregatedActionType::Execute, - } - } - - pub fn l1_batch_range(&self) -> ops::RangeInclusive { - match self { - Self::Commit(op) => op.l1_batch_range(), - Self::PublishProofOnchain(op) => op.l1_batch_range(), - Self::Execute(op) => op.l1_batch_range(), - } - } - - pub fn get_action_caption(&self) -> &'static str { - match self { - Self::Commit(_) => "commit", - Self::PublishProofOnchain(_) => "proof", - Self::Execute(_) => "execute", - } - } - - pub fn protocol_version(&self) -> ProtocolVersionId { - match self { - Self::Commit(op) => op.l1_batches[0].header.protocol_version.unwrap(), - Self::PublishProofOnchain(op) => op.l1_batches[0].header.protocol_version.unwrap(), - Self::Execute(op) => op.l1_batches[0].header.protocol_version.unwrap(), - } - } -} diff --git a/core/lib/types/src/api/en.rs b/core/lib/types/src/api/en.rs index d64e28981e70..6b74d6c63034 100644 --- a/core/lib/types/src/api/en.rs +++ b/core/lib/types/src/api/en.rs @@ -1,18 +1,11 @@ //! API types related to the External Node specific methods. use serde::{Deserialize, Serialize}; -use zk_evm::ethereum_types::Address; -use zksync_basic_types::{L1BatchNumber, MiniblockNumber, H256}; +use zksync_basic_types::{Address, L1BatchNumber, MiniblockNumber, H256}; use zksync_contracts::BaseSystemContractsHashes; use crate::ProtocolVersionId; -/// Protobuf-encoded consensus-related L2 block (= miniblock) fields. -/// See `zksync_dal::models::storage_sync::ConsensusBlockFields`. -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[serde(transparent)] -pub struct ConsensusBlockFields(pub zksync_basic_types::Bytes); - /// Representation of the L2 block, as needed for the EN synchronization. /// This structure has several fields that describe *L1 batch* rather than /// *L2 block*, thus they are the same for all the L2 blocks in the batch. @@ -34,6 +27,8 @@ pub struct SyncBlock { pub l1_gas_price: u64, /// L2 gas price used as VM parameter for the L1 batch corresponding to this L2 block. pub l2_fair_gas_price: u64, + /// The pubdata price used as VM parameter for the L1 batch corresponding to this L2 block. + pub fair_pubdata_price: Option, /// Hashes of the base system contracts used in for the L1 batch corresponding to this L2 block. pub base_system_contracts_hashes: BaseSystemContractsHashes, /// Address of the operator account who produced for the L1 batch corresponding to this L2 block. @@ -48,7 +43,4 @@ pub struct SyncBlock { pub hash: Option, /// Version of the protocol used for this block. pub protocol_version: ProtocolVersionId, - /// Consensus-related information about the block. Not present if consensus is not enabled - /// for the environment. - pub consensus: Option, } diff --git a/core/lib/types/src/api/mod.rs b/core/lib/types/src/api/mod.rs index 8051fd3cd068..9f00aee0cf71 100644 --- a/core/lib/types/src/api/mod.rs +++ b/core/lib/types/src/api/mod.rs @@ -568,7 +568,7 @@ pub enum DebugCallType { Create, } -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct DebugCall { pub r#type: DebugCallType, diff --git a/core/lib/types/src/block.rs b/core/lib/types/src/block.rs index 485f34196450..950c6f4e268f 100644 --- a/core/lib/types/src/block.rs +++ b/core/lib/types/src/block.rs @@ -1,16 +1,17 @@ use std::{fmt, ops}; use serde::{Deserialize, Serialize}; -use zksync_basic_types::{H2048, H256, U256}; +use zksync_basic_types::{Address, H2048, H256, U256}; use zksync_contracts::BaseSystemContractsHashes; use zksync_system_constants::SYSTEM_BLOCK_INFO_BLOCK_NUMBER_MULTIPLIER; use zksync_utils::concat_and_hash; use crate::{ + fee_model::BatchFeeInput, l2_to_l1_log::{SystemL2ToL1Log, UserL2ToL1Log}, priority_op_onchain_data::PriorityOpOnchainData, web3::signing::keccak256, - AccountTreeId, Address, L1BatchNumber, MiniblockNumber, ProtocolVersionId, Transaction, + AccountTreeId, L1BatchNumber, MiniblockNumber, ProtocolVersionId, Transaction, }; /// Represents a successfully deployed smart contract. @@ -34,12 +35,8 @@ impl DeployedContract { pub struct L1BatchHeader { /// Numeric ID of the block. Starts from 1, 0 block is considered genesis block and has no transactions. pub number: L1BatchNumber, - /// Whether block is sealed or not (doesn't correspond to committing/verifying it on the L1). - pub is_finished: bool, /// Timestamp when block was first created. pub timestamp: u64, - /// Address of the fee account that was used when block was created - pub fee_account_address: Address, /// Total number of processed priority operations in the block pub l1_tx_count: u16, /// Total number of processed txs that was requested offchain @@ -54,12 +51,6 @@ pub struct L1BatchHeader { pub bloom: H2048, /// Hashes of contracts used this block pub used_contract_hashes: Vec, - /// The EIP1559 base_fee used in this block. - pub base_fee_per_gas: u64, - /// The assumed L1 gas price within the block. - pub l1_gas_price: u64, - /// The L2 gas price that the operator agrees on. - pub l2_fair_gas_price: u64, pub base_system_contracts_hashes: BaseSystemContractsHashes, /// System logs are those emitted as part of the Vm execution. pub system_logs: Vec, @@ -69,17 +60,18 @@ pub struct L1BatchHeader { } /// Holder for the miniblock metadata that is not available from transactions themselves. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq)] pub struct MiniblockHeader { pub number: MiniblockNumber, pub timestamp: u64, pub hash: H256, pub l1_tx_count: u16, pub l2_tx_count: u16, + pub fee_account_address: Address, pub base_fee_per_gas: u64, // Min wei per gas that txs in this miniblock need to have. - pub l1_gas_price: u64, // L1 gas price assumed in the corresponding batch - pub l2_fair_gas_price: u64, // L2 gas price assumed in the corresponding batch + pub batch_fee_input: BatchFeeInput, + pub gas_per_pubdata_limit: u64, pub base_system_contracts_hashes: BaseSystemContractsHashes, pub protocol_version: Option, /// The maximal number of virtual blocks to be created in the miniblock. @@ -100,15 +92,12 @@ impl L1BatchHeader { pub fn new( number: L1BatchNumber, timestamp: u64, - fee_account_address: Address, base_system_contracts_hashes: BaseSystemContractsHashes, protocol_version: ProtocolVersionId, ) -> L1BatchHeader { Self { number, - is_finished: false, timestamp, - fee_account_address, l1_tx_count: 0, l2_tx_count: 0, priority_ops_onchain_data: vec![], @@ -116,9 +105,6 @@ impl L1BatchHeader { l2_to_l1_messages: vec![], bloom: H2048::default(), used_contract_hashes: vec![], - base_fee_per_gas: 0, - l1_gas_price: 0, - l2_fair_gas_price: 0, base_system_contracts_hashes, system_logs: vec![], protocol_version: Some(protocol_version), diff --git a/core/lib/types/src/circuit.rs b/core/lib/types/src/circuit.rs index 05f269c451ec..d97594913c47 100644 --- a/core/lib/types/src/circuit.rs +++ b/core/lib/types/src/circuit.rs @@ -1,13 +1,93 @@ -use zkevm_test_harness::{geometry_config::get_geometry_config, toolset::GeometryConfig}; +use std::ops::Add; -pub const LEAF_SPLITTING_FACTOR: usize = 50; -pub const NODE_SPLITTING_FACTOR: usize = 48; +use serde::{Deserialize, Serialize}; -/// Max number of basic circuits per L1 batch. -pub const SCHEDULER_UPPER_BOUND: u32 = (LEAF_SPLITTING_FACTOR * NODE_SPLITTING_FACTOR) as u32; +/// Holds information about number of cycles used per circuit type. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub struct CircuitCycleStatistic { + pub main_vm_cycles: u32, + pub ram_permutation_cycles: u32, + pub storage_application_cycles: u32, + pub storage_sorter_cycles: u32, + pub code_decommitter_cycles: u32, + pub code_decommitter_sorter_cycles: u32, + pub log_demuxer_cycles: u32, + pub events_sorter_cycles: u32, + pub keccak256_cycles: u32, + pub ecrecover_cycles: u32, + pub sha256_cycles: u32, +} -pub const LEAF_CIRCUIT_INDEX: u8 = 2; -pub const NODE_CIRCUIT_INDEX: u8 = 1; -pub const SCHEDULER_CIRCUIT_INDEX: u8 = 0; +impl CircuitCycleStatistic { + pub fn new() -> Self { + Self::default() + } +} -pub const GEOMETRY_CONFIG: GeometryConfig = get_geometry_config(); +/// Holds information about number of circuits used per circuit type. +#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize)] +pub struct CircuitStatistic { + pub main_vm: f32, + pub ram_permutation: f32, + pub storage_application: f32, + pub storage_sorter: f32, + pub code_decommitter: f32, + pub code_decommitter_sorter: f32, + pub log_demuxer: f32, + pub events_sorter: f32, + pub keccak256: f32, + pub ecrecover: f32, + pub sha256: f32, +} + +impl CircuitStatistic { + /// Rounds up numbers and adds them. + pub fn total(&self) -> usize { + self.main_vm.ceil() as usize + + self.ram_permutation.ceil() as usize + + self.storage_application.ceil() as usize + + self.storage_sorter.ceil() as usize + + self.code_decommitter.ceil() as usize + + self.code_decommitter_sorter.ceil() as usize + + self.log_demuxer.ceil() as usize + + self.events_sorter.ceil() as usize + + self.keccak256.ceil() as usize + + self.ecrecover.ceil() as usize + + self.sha256.ceil() as usize + } + + /// Adds numbers. + pub fn total_f32(&self) -> f32 { + self.main_vm + + self.ram_permutation + + self.storage_application + + self.storage_sorter + + self.code_decommitter + + self.code_decommitter_sorter + + self.log_demuxer + + self.events_sorter + + self.keccak256 + + self.ecrecover + + self.sha256 + } +} + +impl Add for CircuitStatistic { + type Output = CircuitStatistic; + + fn add(self, other: CircuitStatistic) -> CircuitStatistic { + CircuitStatistic { + main_vm: self.main_vm + other.main_vm, + ram_permutation: self.ram_permutation + other.ram_permutation, + storage_application: self.storage_application + other.storage_application, + storage_sorter: self.storage_sorter + other.storage_sorter, + code_decommitter: self.code_decommitter + other.code_decommitter, + code_decommitter_sorter: self.code_decommitter_sorter + other.code_decommitter_sorter, + log_demuxer: self.log_demuxer + other.log_demuxer, + events_sorter: self.events_sorter + other.events_sorter, + keccak256: self.keccak256 + other.keccak256, + ecrecover: self.ecrecover + other.ecrecover, + sha256: self.sha256 + other.sha256, + } + } +} diff --git a/core/lib/types/src/commitment.rs b/core/lib/types/src/commitment.rs index 91503b7401c1..6356769242c7 100644 --- a/core/lib/types/src/commitment.rs +++ b/core/lib/types/src/commitment.rs @@ -17,14 +17,13 @@ use zksync_utils::u256_to_h256; use crate::{ block::L1BatchHeader, - ethabi::Token, l2_to_l1_log::{L2ToL1Log, SystemL2ToL1Log, UserL2ToL1Log}, web3::signing::keccak256, writes::{ compress_state_diffs, InitialStorageWrite, RepeatedStorageWrite, StateDiffRecord, PADDED_ENCODED_STORAGE_DIFF_LEN_BYTES, }, - H256, KNOWN_CODES_STORAGE_ADDRESS, U256, + ProtocolVersionId, H256, KNOWN_CODES_STORAGE_ADDRESS, }; /// Type that can be serialized for commitment. @@ -131,98 +130,6 @@ impl L1BatchWithMetadata { }) } - pub fn l1_header_data(&self) -> Token { - Token::Tuple(vec![ - Token::Uint(U256::from(self.header.number.0)), - Token::FixedBytes(self.metadata.root_hash.as_bytes().to_vec()), - Token::Uint(U256::from(self.metadata.rollup_last_leaf_index)), - Token::Uint(U256::from(self.header.l1_tx_count)), - Token::FixedBytes( - self.header - .priority_ops_onchain_data_hash() - .as_bytes() - .to_vec(), - ), - Token::FixedBytes(self.metadata.l2_l1_merkle_root.as_bytes().to_vec()), - Token::Uint(U256::from(self.header.timestamp)), - Token::FixedBytes(self.metadata.commitment.as_bytes().to_vec()), - ]) - } - - pub fn l1_commit_data(&self) -> Token { - if self.header.protocol_version.unwrap().is_pre_boojum() { - Token::Tuple(vec![ - Token::Uint(U256::from(self.header.number.0)), - Token::Uint(U256::from(self.header.timestamp)), - Token::Uint(U256::from(self.metadata.rollup_last_leaf_index)), - Token::FixedBytes(self.metadata.merkle_root_hash.as_bytes().to_vec()), - Token::Uint(U256::from(self.header.l1_tx_count)), - Token::FixedBytes(self.metadata.l2_l1_merkle_root.as_bytes().to_vec()), - Token::FixedBytes( - self.header - .priority_ops_onchain_data_hash() - .as_bytes() - .to_vec(), - ), - Token::Bytes(self.metadata.initial_writes_compressed.clone()), - Token::Bytes(self.metadata.repeated_writes_compressed.clone()), - Token::Bytes(self.metadata.l2_l1_messages_compressed.clone()), - Token::Array( - self.header - .l2_to_l1_messages - .iter() - .map(|message| Token::Bytes(message.to_vec())) - .collect(), - ), - Token::Array( - self.factory_deps - .iter() - .map(|bytecode| Token::Bytes(bytecode.to_vec())) - .collect(), - ), - ]) - } else { - Token::Tuple(vec![ - Token::Uint(U256::from(self.header.number.0)), - Token::Uint(U256::from(self.header.timestamp)), - Token::Uint(U256::from(self.metadata.rollup_last_leaf_index)), - Token::FixedBytes(self.metadata.merkle_root_hash.as_bytes().to_vec()), - Token::Uint(U256::from(self.header.l1_tx_count)), - Token::FixedBytes( - self.header - .priority_ops_onchain_data_hash() - .as_bytes() - .to_vec(), - ), - Token::FixedBytes( - self.metadata - .bootloader_initial_content_commitment - .unwrap() - .as_bytes() - .to_vec(), - ), - Token::FixedBytes( - self.metadata - .events_queue_commitment - .unwrap() - .as_bytes() - .to_vec(), - ), - Token::Bytes(self.metadata.l2_l1_messages_compressed.clone()), - Token::Bytes( - self.header - .pubdata_input - .clone() - .unwrap_or(self.construct_pubdata()), - ), - ]) - } - } - - pub fn l1_commit_data_size(&self) -> usize { - crate::ethabi::encode(&[Token::Array(vec![self.l1_commit_data()])]).len() - } - /// Packs all pubdata needed for batch commitment in boojum into one bytes array. The packing contains the /// following: logs, messages, bytecodes, and compressed state diffs. /// This data is currently part of calldata but will be submitted as part of the blob section post EIP-4844. @@ -235,7 +142,7 @@ impl L1BatchWithMetadata { res.extend(l2_to_l1_log.0.to_bytes()); } - // Process and Pack Msgs + // Process and Pack Messages res.extend((self.header.l2_to_l1_messages.len() as u32).to_be_bytes()); for msg in &self.header.l2_to_l1_messages { res.extend((msg.len() as u32).to_be_bytes()); @@ -327,7 +234,7 @@ struct L1BatchAuxiliaryOutput { l2_l1_logs_merkle_root: H256, // Once cut over to boojum, these fields are no longer required as their values - // are covered by state_diffs_compressed and its hash. + // are covered by `state_diffs_compressed` and its hash. // Task to remove: PLA-640 initial_writes_compressed: Vec, initial_writes_hash: H256, @@ -336,16 +243,12 @@ struct L1BatchAuxiliaryOutput { // The fields below are necessary for boojum. system_logs_compressed: Vec, - #[allow(dead_code)] system_logs_linear_hash: H256, - #[allow(dead_code)] state_diffs_hash: H256, state_diffs_compressed: Vec, - #[allow(dead_code)] bootloader_heap_hash: H256, - #[allow(dead_code)] events_state_queue_hash: H256, - is_pre_boojum: bool, + protocol_version: ProtocolVersionId, } impl L1BatchAuxiliaryOutput { @@ -358,7 +261,7 @@ impl L1BatchAuxiliaryOutput { state_diffs: Vec, bootloader_heap_hash: H256, events_state_queue_hash: H256, - is_pre_boojum: bool, + protocol_version: ProtocolVersionId, ) -> Self { let state_diff_hash_from_logs = system_logs.iter().find_map(|log| { if log.0.key == u256_to_h256(STATE_DIFF_HASH_KEY.into()) { @@ -382,7 +285,7 @@ impl L1BatchAuxiliaryOutput { repeated_writes_compressed, system_logs_compressed, state_diffs_packed, - ) = if is_pre_boojum { + ) = if protocol_version.is_pre_boojum() { ( pre_boojum_serialize_commitments(&l2_l1_logs), pre_boojum_serialize_commitments(&initial_writes), @@ -408,7 +311,7 @@ impl L1BatchAuxiliaryOutput { let repeated_writes_hash = H256::from(keccak256(&repeated_writes_compressed)); let state_diffs_hash = H256::from(keccak256(&(state_diffs_packed))); - let serialized_logs = if is_pre_boojum { + let serialized_logs = if protocol_version.is_pre_boojum() { &l2_l1_logs_compressed[4..] } else { &l2_l1_logs_compressed @@ -418,7 +321,7 @@ impl L1BatchAuxiliaryOutput { .chunks(UserL2ToL1Log::SERIALIZED_SIZE) .map(|chunk| <[u8; UserL2ToL1Log::SERIALIZED_SIZE]>::try_from(chunk).unwrap()); // ^ Skip first 4 bytes of the serialized logs (i.e., the number of logs). - let min_tree_size = if is_pre_boojum { + let min_tree_size = if protocol_version.is_pre_boojum() { L2ToL1Log::PRE_BOOJUM_MIN_L2_L1_LOGS_TREE_SIZE } else { L2ToL1Log::MIN_L2_L1_LOGS_TREE_SIZE @@ -457,7 +360,7 @@ impl L1BatchAuxiliaryOutput { bootloader_heap_hash, events_state_queue_hash, - is_pre_boojum, + protocol_version, } } @@ -466,16 +369,27 @@ impl L1BatchAuxiliaryOutput { const SERIALIZED_SIZE: usize = 128; let mut result = Vec::with_capacity(SERIALIZED_SIZE); - if self.is_pre_boojum { + if self.protocol_version.is_pre_boojum() { result.extend(self.l2_l1_logs_merkle_root.as_bytes()); result.extend(self.l2_l1_logs_linear_hash.as_bytes()); result.extend(self.initial_writes_hash.as_bytes()); result.extend(self.repeated_writes_hash.as_bytes()); + } else if self.protocol_version.is_1_4_0() { + result.extend(self.system_logs_linear_hash.as_bytes()); + result.extend(self.state_diffs_hash.as_bytes()); + result.extend(self.bootloader_heap_hash.as_bytes()); + result.extend(self.events_state_queue_hash.as_bytes()); } else { result.extend(self.system_logs_linear_hash.as_bytes()); result.extend(self.state_diffs_hash.as_bytes()); result.extend(self.bootloader_heap_hash.as_bytes()); result.extend(self.events_state_queue_hash.as_bytes()); + + // For now, we are using zeroes as commitments to the KZG pubdata. + result.extend(H256::zero().as_bytes()); + result.extend(H256::zero().as_bytes()); + result.extend(H256::zero().as_bytes()); + result.extend(H256::zero().as_bytes()); } result } @@ -570,7 +484,7 @@ impl L1BatchCommitment { state_diffs: Vec, bootloader_heap_hash: H256, events_state_queue_hash: H256, - is_pre_boojum: bool, + protocol_version: ProtocolVersionId, ) -> Self { let meta_parameters = L1BatchMetaParameters { zkporter_is_available: ZKPORTER_IS_AVAILABLE, @@ -585,7 +499,7 @@ impl L1BatchCommitment { last_leaf_index: rollup_last_leaf_index, root_hash: rollup_root_hash, }, - // Despite the fact that zk_porter is not available we have to add params about it. + // Despite the fact that `zk_porter` is not available we have to add params about it. RootState { last_leaf_index: 0, root_hash: H256::zero(), @@ -600,7 +514,7 @@ impl L1BatchCommitment { state_diffs, bootloader_heap_hash, events_state_queue_hash, - is_pre_boojum, + protocol_version, ), meta_parameters, } @@ -677,7 +591,7 @@ mod tests { }, l2_to_l1_log::{L2ToL1Log, UserL2ToL1Log}, writes::{InitialStorageWrite, RepeatedStorageWrite}, - H256, U256, + ProtocolVersionId, H256, U256, }; #[serde_as] @@ -759,7 +673,7 @@ mod tests { vec![], H256::zero(), H256::zero(), - false, + ProtocolVersionId::latest(), ); let commitment = L1BatchCommitment { diff --git a/core/lib/types/src/eth_sender.rs b/core/lib/types/src/eth_sender.rs index 6c8d268888e2..7778d8252080 100644 --- a/core/lib/types/src/eth_sender.rs +++ b/core/lib/types/src/eth_sender.rs @@ -13,7 +13,7 @@ pub struct EthTx { impl std::fmt::Debug for EthTx { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // Do not print raw_tx + // Do not print `raw_tx` f.debug_struct("EthTx") .field("id", &self.id) .field("nonce", &self.nonce) diff --git a/core/lib/types/src/event.rs b/core/lib/types/src/event.rs index 01561912cceb..dc4bcdc6045b 100644 --- a/core/lib/types/src/event.rs +++ b/core/lib/types/src/event.rs @@ -204,7 +204,7 @@ fn extract_added_token_info_from_addresses( .collect() } -// moved from RuntimeContext +// moved from `RuntimeContext` // Extracts all the "long" L2->L1 messages that were submitted by the // L1Messenger contract pub fn extract_long_l2_to_l1_messages(all_generated_events: &[VmEvent]) -> Vec> { @@ -226,8 +226,8 @@ pub fn extract_long_l2_to_l1_messages(all_generated_events: &[VmEvent]) -> Vec Vec { @@ -370,9 +370,9 @@ mod tests { value.to_big_endian(&mut val_arr); let tokens = vec![ - /*l2ShardId*/ Token::Uint(U256::from(0)), - /*isService*/ Token::Bool(true), - /*txNumberInBlock*/ Token::Uint(tx_number), + /*`l2ShardId`*/ Token::Uint(U256::from(0)), + /*`isService`*/ Token::Bool(true), + /*`txNumberInBlock`*/ Token::Uint(tx_number), /*sender*/ Token::Address(sender), /*key*/ Token::FixedBytes(key_arr.to_vec()), /*value*/ Token::FixedBytes(val_arr.to_vec()), diff --git a/core/lib/types/src/fee.rs b/core/lib/types/src/fee.rs index 53e05fbb59a9..1f10d5d574bd 100644 --- a/core/lib/types/src/fee.rs +++ b/core/lib/types/src/fee.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use zksync_utils::ceil_div; -use crate::U256; +use crate::{circuit::CircuitStatistic, U256}; #[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)] #[serde(rename_all = "camelCase", tag = "result")] @@ -24,6 +24,7 @@ pub struct TransactionExecutionMetrics { pub computational_gas_used: u32, pub total_updated_values_size: usize, pub pubdata_published: u32, + pub circuit_statistic: CircuitStatistic, } #[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] diff --git a/core/lib/types/src/fee_model.rs b/core/lib/types/src/fee_model.rs new file mode 100644 index 000000000000..bb183b327db6 --- /dev/null +++ b/core/lib/types/src/fee_model.rs @@ -0,0 +1,260 @@ +use serde::{Deserialize, Serialize}; +use zksync_config::configs::chain::{FeeModelVersion, StateKeeperConfig}; +use zksync_system_constants::L1_GAS_PER_PUBDATA_BYTE; + +use crate::ProtocolVersionId; + +/// Fee input to be provided into the VM. It contains two options: +/// - `L1Pegged`: L1 gas price is provided to the VM, and the pubdata price is derived from it. Using this option is required for the +/// versions of Era prior to 1.4.1 integration. +/// - `PubdataIndependent`: L1 gas price and pubdata price are not necessarily dependent on one another. This options is more suitable for the +/// versions of Era after the 1.4.1 integration. It is expected that if a VM supports `PubdataIndependent` version, then it should also support `L1Pegged` version, but converting it into `PubdataIndependentBatchFeeModelInput` in-place. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum BatchFeeInput { + L1Pegged(L1PeggedBatchFeeModelInput), + PubdataIndependent(PubdataIndependentBatchFeeModelInput), +} + +impl BatchFeeInput { + // Sometimes for temporary usage or tests a "sensible" default, i.e. the one consisting of non-zero values is needed. + pub fn sensible_l1_pegged_default() -> Self { + Self::L1Pegged(L1PeggedBatchFeeModelInput { + l1_gas_price: 1_000_000_000, + fair_l2_gas_price: 100_000_000, + }) + } + + pub fn l1_pegged(l1_gas_price: u64, fair_l2_gas_price: u64) -> Self { + Self::L1Pegged(L1PeggedBatchFeeModelInput { + l1_gas_price, + fair_l2_gas_price, + }) + } + + pub fn pubdata_independent( + l1_gas_price: u64, + fair_l2_gas_price: u64, + fair_pubdata_price: u64, + ) -> Self { + Self::PubdataIndependent(PubdataIndependentBatchFeeModelInput { + l1_gas_price, + fair_l2_gas_price, + fair_pubdata_price, + }) + } +} + +impl Default for BatchFeeInput { + fn default() -> Self { + Self::L1Pegged(L1PeggedBatchFeeModelInput { + l1_gas_price: 0, + fair_l2_gas_price: 0, + }) + } +} + +impl BatchFeeInput { + pub fn into_l1_pegged(self) -> L1PeggedBatchFeeModelInput { + match self { + BatchFeeInput::L1Pegged(input) => input, + _ => panic!("Can not convert PubdataIndependentBatchFeeModelInput into L1PeggedBatchFeeModelInput"), + } + } + + pub fn fair_pubdata_price(&self) -> u64 { + match self { + BatchFeeInput::L1Pegged(input) => input.l1_gas_price * L1_GAS_PER_PUBDATA_BYTE as u64, + BatchFeeInput::PubdataIndependent(input) => input.fair_pubdata_price, + } + } + + pub fn fair_l2_gas_price(&self) -> u64 { + match self { + BatchFeeInput::L1Pegged(input) => input.fair_l2_gas_price, + BatchFeeInput::PubdataIndependent(input) => input.fair_l2_gas_price, + } + } + + pub fn l1_gas_price(&self) -> u64 { + match self { + BatchFeeInput::L1Pegged(input) => input.l1_gas_price, + BatchFeeInput::PubdataIndependent(input) => input.l1_gas_price, + } + } + + pub fn into_pubdata_independent(self) -> PubdataIndependentBatchFeeModelInput { + match self { + BatchFeeInput::PubdataIndependent(input) => input, + BatchFeeInput::L1Pegged(input) => PubdataIndependentBatchFeeModelInput { + fair_l2_gas_price: input.fair_l2_gas_price, + fair_pubdata_price: input.l1_gas_price * L1_GAS_PER_PUBDATA_BYTE as u64, + l1_gas_price: input.l1_gas_price, + }, + } + } + + pub fn for_protocol_version( + protocol_version: ProtocolVersionId, + fair_l2_gas_price: u64, + fair_pubdata_price: Option, + l1_gas_price: u64, + ) -> Self { + if protocol_version.is_post_1_4_1() { + Self::PubdataIndependent(PubdataIndependentBatchFeeModelInput { + fair_l2_gas_price, + fair_pubdata_price: fair_pubdata_price + .expect("Pubdata price must be provided for protocol version 1.4.1"), + l1_gas_price, + }) + } else { + Self::L1Pegged(L1PeggedBatchFeeModelInput { + fair_l2_gas_price, + l1_gas_price, + }) + } + } + + pub fn stricter(self, other: BatchFeeInput) -> Self { + match (self, other) { + (BatchFeeInput::L1Pegged(first), BatchFeeInput::L1Pegged(second)) => Self::l1_pegged( + first.l1_gas_price.max(second.l1_gas_price), + first.fair_l2_gas_price.max(second.fair_l2_gas_price), + ), + input @ (_, _) => { + let (first, second) = ( + input.0.into_pubdata_independent(), + input.1.into_pubdata_independent(), + ); + + Self::pubdata_independent( + first.l1_gas_price.max(second.l1_gas_price), + first.fair_l2_gas_price.max(second.fair_l2_gas_price), + first.fair_pubdata_price.max(second.fair_pubdata_price), + ) + } + } + } +} + +/// Pubdata is only published via calldata and so its price is pegged to the L1 gas price. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct L1PeggedBatchFeeModelInput { + /// Fair L2 gas price to provide + pub fair_l2_gas_price: u64, + /// The L1 gas price to provide to the VM. + pub l1_gas_price: u64, +} + +/// Pubdata price may be independent from L1 gas price. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct PubdataIndependentBatchFeeModelInput { + /// Fair L2 gas price to provide + pub fair_l2_gas_price: u64, + /// Fair pubdata price to provide. + pub fair_pubdata_price: u64, + /// The L1 gas price to provide to the VM. Even if some of the VM versions may not use this value, it is still maintained for backward compatibility. + pub l1_gas_price: u64, +} + +/// The enum which represents the version of the fee model. It is used to determine which fee model should be used for the batch. +/// - `V1`, the first model that was used in zkSync Era. In this fee model, the pubdata price must be pegged to the L1 gas price. +/// Also, the fair L2 gas price is expected to only include the proving/computation price for the operator and not the costs that come from +/// processing the batch on L1. +/// - `V2`, the second model that was used in zkSync Era. There the pubdata price might be independent from the L1 gas price. Also, +/// The fair L2 gas price is expected to both the proving/computation price for the operator and the costs that come from +/// processing the batch on L1. +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +pub enum FeeModelConfig { + V1(FeeModelConfigV1), + V2(FeeModelConfigV2), +} + +/// Config params for the first version of the fee model. Here, the pubdata price is pegged to the L1 gas price and +/// neither fair L2 gas price nor the pubdata price include the overhead for closing the batch +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +pub struct FeeModelConfigV1 { + /// The minimal acceptable L2 gas price, i.e. the price that should include the cost of computation/proving as well + /// as potentially premium for congestion. + /// Unlike the `V2`, this price will be directly used as the `fair_l2_gas_price` in the bootloader. + pub minimal_l2_gas_price: u64, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +pub struct FeeModelConfigV2 { + /// The minimal acceptable L2 gas price, i.e. the price that should include the cost of computation/proving as well + /// as potentially premium for congestion. + pub minimal_l2_gas_price: u64, + /// The constant that represents the possibility that a batch can be sealed because of overuse of computation resources. + /// It has range from 0 to 1. If it is 0, the compute will not depend on the cost for closing the batch. + /// If it is 1, the gas limit per batch will have to cover the entire cost of closing the batch. + pub compute_overhead_part: f64, + /// The constant that represents the possibility that a batch can be sealed because of overuse of pubdata. + /// It has range from 0 to 1. If it is 0, the pubdata will not depend on the cost for closing the batch. + /// If it is 1, the pubdata limit per batch will have to cover the entire cost of closing the batch. + pub pubdata_overhead_part: f64, + /// The constant amount of L1 gas that is used as the overhead for the batch. It includes the price for batch verification, etc. + pub batch_overhead_l1_gas: u64, + /// The maximum amount of gas that can be used by the batch. This value is derived from the circuits limitation per batch. + pub max_gas_per_batch: u64, + /// The maximum amount of pubdata that can be used by the batch. Note that if the calldata is used as pubdata, this variable should not exceed 128kb. + pub max_pubdata_per_batch: u64, +} + +impl Default for FeeModelConfig { + /// Config with all zeroes is not a valid config (since for instance having 0 max gas per batch may incur division by zero), + /// so we implement a sensible default config here. + fn default() -> Self { + Self::V1(FeeModelConfigV1 { + minimal_l2_gas_price: 100_000_000, + }) + } +} + +impl FeeModelConfig { + pub fn from_state_keeper_config(state_keeper_config: &StateKeeperConfig) -> Self { + match state_keeper_config.fee_model_version { + FeeModelVersion::V1 => Self::V1(FeeModelConfigV1 { + minimal_l2_gas_price: state_keeper_config.minimal_l2_gas_price, + }), + FeeModelVersion::V2 => Self::V2(FeeModelConfigV2 { + minimal_l2_gas_price: state_keeper_config.minimal_l2_gas_price, + compute_overhead_part: state_keeper_config.compute_overhead_part, + pubdata_overhead_part: state_keeper_config.pubdata_overhead_part, + batch_overhead_l1_gas: state_keeper_config.batch_overhead_l1_gas, + max_gas_per_batch: state_keeper_config.max_gas_per_batch, + max_pubdata_per_batch: state_keeper_config.max_pubdata_per_batch, + }), + } + } +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +pub struct FeeParamsV1 { + pub config: FeeModelConfigV1, + pub l1_gas_price: u64, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +pub struct FeeParamsV2 { + pub config: FeeModelConfigV2, + pub l1_gas_price: u64, + pub l1_pubdata_price: u64, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +pub enum FeeParams { + V1(FeeParamsV1), + V2(FeeParamsV2), +} + +impl FeeParams { + // Sometimes for temporary usage or tests a "sensible" default, i.e. the one consisting of non-zero values is needed. + pub fn sensible_v1_default() -> Self { + Self::V1(FeeParamsV1 { + config: FeeModelConfigV1 { + minimal_l2_gas_price: 100_000_000, + }, + l1_gas_price: 1_000_000_000, + }) + } +} diff --git a/core/lib/types/src/l1/mod.rs b/core/lib/types/src/l1/mod.rs index 16ce192bf8b3..a37f535cfd16 100644 --- a/core/lib/types/src/l1/mod.rs +++ b/core/lib/types/src/l1/mod.rs @@ -199,11 +199,11 @@ impl TryFrom for L1Tx { fn try_from(event: Log) -> Result { // TODO: refactor according to tx type let transaction_param_type = ParamType::Tuple(vec![ - ParamType::Uint(8), // txType + ParamType::Uint(8), // `txType` ParamType::Address, // sender ParamType::Address, // to ParamType::Uint(256), // gasLimit - ParamType::Uint(256), // gasPerPubdataLimit + ParamType::Uint(256), // `gasPerPubdataLimit` ParamType::Uint(256), // maxFeePerGas ParamType::Uint(256), // maxPriorityFeePerGas ParamType::Address, // paymaster @@ -214,7 +214,7 @@ impl TryFrom for L1Tx { ParamType::Bytes, // signature ParamType::Array(Box::new(ParamType::Uint(256))), // factory deps ParamType::Bytes, // paymaster input - ParamType::Bytes, // reservedDynamic + ParamType::Bytes, // `reservedDynamic` ]); let mut dec_ev = decode( @@ -302,7 +302,7 @@ impl TryFrom for L1Tx { let signature = transaction.remove(0).into_bytes().unwrap(); assert_eq!(signature.len(), 0); - // TODO (SMA-1621): check that reservedDynamic are constructed correctly. + // TODO (SMA-1621): check that `reservedDynamic` are constructed correctly. let _factory_deps_hashes = transaction.remove(0).into_array().unwrap(); let _paymaster_input = transaction.remove(0).into_bytes().unwrap(); let _reserved_dynamic = transaction.remove(0).into_bytes().unwrap(); diff --git a/core/lib/types/src/l2/error.rs b/core/lib/types/src/l2/error.rs index c157f95b09f4..4a7929415e19 100644 --- a/core/lib/types/src/l2/error.rs +++ b/core/lib/types/src/l2/error.rs @@ -1,4 +1,3 @@ -use parity_crypto::publickey::Error as ParityCryptoError; use serde::{Deserialize, Serialize}; use thiserror::Error; use zksync_basic_types::H256; @@ -13,6 +12,6 @@ pub enum TxCheckError { #[derive(Debug, Error)] pub enum SignError { - #[error("Failed to sign transaction")] - SignError(#[from] ParityCryptoError), + #[error("Failed to sign transaction: {0}")] + SignError(#[from] anyhow::Error), } diff --git a/core/lib/types/src/l2/mod.rs b/core/lib/types/src/l2/mod.rs index 61a505909b2b..2498f3490462 100644 --- a/core/lib/types/src/l2/mod.rs +++ b/core/lib/types/src/l2/mod.rs @@ -1,5 +1,6 @@ use std::convert::TryFrom; +use anyhow::Context as _; use num_enum::TryFromPrimitive; use rlp::{Rlp, RlpStream}; use serde::{Deserialize, Serialize}; @@ -26,15 +27,26 @@ pub mod error; pub enum TransactionType { // Native ECDSA Transaction LegacyTransaction = 0, - EIP2930Transaction = 1, EIP1559Transaction = 2, - // Eip 712 transaction with additional fields specified for zksync + // EIP 712 transaction with additional fields specified for zkSync EIP712Transaction = EIP_712_TX_TYPE as u32, PriorityOpTransaction = PRIORITY_OPERATION_L2_TX_TYPE as u32, ProtocolUpgradeTransaction = PROTOCOL_UPGRADE_TX_TYPE as u32, } +impl TransactionType { + /// Returns whether a transaction type is an Ethereum transaction type. + pub fn is_ethereum_type(&self) -> bool { + matches!( + self, + TransactionType::LegacyTransaction + | TransactionType::EIP2930Transaction + | TransactionType::EIP1559Transaction + ) + } +} + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct L2TxCommonData { @@ -194,7 +206,7 @@ impl L2Tx { ); let data = res.get_signed_bytes(chain_id); - res.set_signature(PackedEthSignature::sign_raw(private_key, &data)?); + res.set_signature(PackedEthSignature::sign_raw(private_key, &data).context("sign_raw")?); Ok(res) } @@ -289,7 +301,7 @@ impl L2Tx { fn signature_to_vrs(signature: &[u8], tx_type: u32) -> (Option, Option, Option) { let signature = if tx_type == LEGACY_TX_TYPE as u32 { // Note that we use `deserialize_packed_no_v_check` here, because we want to preserve the original `v` value. - // This is needed due to inconsistent behaviour on Ethereum where the `v` value is >= 27 for legacy transactions + // This is needed due to inconsistent behavior on Ethereum where the `v` value is >= 27 for legacy transactions // and is either 0 or 1 for other ones. PackedEthSignature::deserialize_packed_no_v_check(signature) } else { diff --git a/core/lib/types/src/l2_to_l1_log.rs b/core/lib/types/src/l2_to_l1_log.rs index 335e6e740be5..434e17e8bb2a 100644 --- a/core/lib/types/src/l2_to_l1_log.rs +++ b/core/lib/types/src/l2_to_l1_log.rs @@ -1,7 +1,4 @@ use serde::{Deserialize, Serialize}; -use zk_evm::reference_impls::event_sink::EventMessage; -use zk_evm_1_4_0::reference_impls::event_sink::EventMessage as EventMessage_1_4_0; -use zksync_utils::u256_to_h256; use crate::{commitment::SerializeCommitment, Address, H256}; @@ -66,32 +63,6 @@ impl L2ToL1Log { } } -impl From for L2ToL1Log { - fn from(m: EventMessage) -> Self { - Self { - shard_id: m.shard_id, - is_service: m.is_first, - tx_number_in_block: m.tx_number_in_block, - sender: m.address, - key: u256_to_h256(m.key), - value: u256_to_h256(m.value), - } - } -} - -impl From for L2ToL1Log { - fn from(m: EventMessage_1_4_0) -> Self { - Self { - shard_id: m.shard_id, - is_service: m.is_first, - tx_number_in_block: m.tx_number_in_block, - sender: m.address, - key: u256_to_h256(m.key), - value: u256_to_h256(m.value), - } - } -} - #[cfg(test)] mod tests { use zksync_basic_types::U256; diff --git a/core/lib/types/src/lib.rs b/core/lib/types/src/lib.rs index a7d7e71e0eff..27cffb360a3f 100644 --- a/core/lib/types/src/lib.rs +++ b/core/lib/types/src/lib.rs @@ -21,12 +21,6 @@ pub use protocol_version::{ProtocolUpgrade, ProtocolVersion, ProtocolVersionId}; pub use storage::*; pub use tx::{primitives::*, Execute}; pub use vm_version::VmVersion; -pub use zk_evm::{ - aux_structures::{LogQuery, Timestamp}, - reference_impls::event_sink::EventMessage, - zkevm_opcode_defs::FarCallOpcode, -}; -pub use zkevm_test_harness; pub use zksync_basic_types::*; use crate::{l2::TransactionType, protocol_version::ProtocolUpgradeTxCommonData}; @@ -36,9 +30,9 @@ pub mod block; pub mod circuit; pub mod commitment; pub mod contract_verification_api; -pub mod contracts; pub mod event; pub mod fee; +pub mod fee_model; pub mod l1; pub mod l2; pub mod l2_to_l1_log; @@ -51,16 +45,14 @@ pub mod system_contracts; pub mod tokens; pub mod tx; pub mod vm_trace; +pub mod zk_evm_types; pub mod api; pub mod eth_sender; pub mod helpers; -pub mod proofs; pub mod proto; -pub mod prover_server_api; pub mod transaction_request; pub mod utils; -pub mod vk_transform; pub mod vm_version; /// Denotes the first byte of the special zkSync's EIP-712-signed transaction. diff --git a/core/lib/types/src/proofs.rs b/core/lib/types/src/proofs.rs deleted file mode 100644 index a23b0f44416a..000000000000 --- a/core/lib/types/src/proofs.rs +++ /dev/null @@ -1,499 +0,0 @@ -use std::{ - convert::{TryFrom, TryInto}, - fmt::Debug, - net::IpAddr, - ops::Add, - str::FromStr, -}; - -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use serde_with::{serde_as, Bytes}; -use zkevm_test_harness::{ - abstract_zksync_circuit::concrete_circuits::ZkSyncCircuit, - bellman::{bn256::Bn256, plonk::better_better_cs::proof::Proof}, - encodings::{recursion_request::RecursionRequest, QueueSimulator}, - witness::{ - full_block_artifact::{BlockBasicCircuits, BlockBasicCircuitsPublicInputs}, - oracle::VmWitnessOracle, - }, - LeafAggregationOutputDataWitness, NodeAggregationOutputDataWitness, - SchedulerCircuitInstanceWitness, -}; -use zksync_basic_types::{L1BatchNumber, H256, U256}; - -const HASH_LEN: usize = H256::len_bytes(); - -/// Metadata emitted by a Merkle tree after processing single storage log. -#[serde_as] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct StorageLogMetadata { - #[serde_as(as = "Bytes")] - pub root_hash: [u8; HASH_LEN], - pub is_write: bool, - pub first_write: bool, - #[serde_as(as = "Vec")] - pub merkle_paths: Vec<[u8; HASH_LEN]>, - pub leaf_hashed_key: U256, - pub leaf_enumeration_index: u64, - // **NB.** For compatibility reasons, `#[serde_as(as = "Bytes")]` attrs are not added below. - pub value_written: [u8; HASH_LEN], - pub value_read: [u8; HASH_LEN], -} - -impl StorageLogMetadata { - pub fn leaf_hashed_key_array(&self) -> [u8; 32] { - let mut result = [0_u8; 32]; - self.leaf_hashed_key.to_little_endian(&mut result); - result - } - - pub fn into_merkle_paths_array(self) -> Box<[[u8; HASH_LEN]; PATH_LEN]> { - let actual_len = self.merkle_paths.len(); - self.merkle_paths.try_into().unwrap_or_else(|_| { - panic!( - "Unexpected length of Merkle paths in `StorageLogMetadata`: expected {}, got {}", - PATH_LEN, actual_len - ); - }) - } -} - -#[derive(Clone)] -pub struct WitnessGeneratorJobMetadata { - pub block_number: L1BatchNumber, - pub proofs: Vec>>>, -} - -/// Represents the sequential number of the proof aggregation round. -/// Mostly used to be stored in `aggregation_round` column in `prover_jobs` table -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] -pub enum AggregationRound { - BasicCircuits = 0, - LeafAggregation = 1, - NodeAggregation = 2, - Scheduler = 3, -} - -impl From for AggregationRound { - fn from(item: u8) -> Self { - match item { - 0 => AggregationRound::BasicCircuits, - 1 => AggregationRound::LeafAggregation, - 2 => AggregationRound::NodeAggregation, - 3 => AggregationRound::Scheduler, - _ => panic!("Invalid round"), - } - } -} - -impl AggregationRound { - pub fn next(&self) -> Option { - match self { - AggregationRound::BasicCircuits => Some(AggregationRound::LeafAggregation), - AggregationRound::LeafAggregation => Some(AggregationRound::NodeAggregation), - AggregationRound::NodeAggregation => Some(AggregationRound::Scheduler), - AggregationRound::Scheduler => None, - } - } -} - -impl std::fmt::Display for AggregationRound { - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str(match self { - Self::BasicCircuits => "basic_circuits", - Self::LeafAggregation => "leaf_aggregation", - Self::NodeAggregation => "node_aggregation", - Self::Scheduler => "scheduler", - }) - } -} - -impl FromStr for AggregationRound { - type Err = String; - - fn from_str(s: &str) -> Result { - match s { - "basic_circuits" => Ok(AggregationRound::BasicCircuits), - "leaf_aggregation" => Ok(AggregationRound::LeafAggregation), - "node_aggregation" => Ok(AggregationRound::NodeAggregation), - "scheduler" => Ok(AggregationRound::Scheduler), - other => Err(format!( - "{} is not a valid round name for witness generation", - other - )), - } - } -} - -impl TryFrom for AggregationRound { - type Error = (); - - fn try_from(v: i32) -> Result { - match v { - x if x == AggregationRound::BasicCircuits as i32 => Ok(AggregationRound::BasicCircuits), - x if x == AggregationRound::LeafAggregation as i32 => { - Ok(AggregationRound::LeafAggregation) - } - x if x == AggregationRound::NodeAggregation as i32 => { - Ok(AggregationRound::NodeAggregation) - } - x if x == AggregationRound::Scheduler as i32 => Ok(AggregationRound::Scheduler), - _ => Err(()), - } - } -} - -/// Witness data produced by the Merkle tree as a result of processing a single block. Used -/// as an input to the witness generator. -/// -/// # Stability -/// -/// This type is serialized using `bincode` to be passed from the metadata calculator -/// to the witness generator. As such, changes in its `serde` serialization -/// must be backwards-compatible. -/// -/// # Compact form -/// -/// In order to reduce storage space, this job supports a compact format. In this format, -/// only the first item in `merkle_paths` is guaranteed to have the full Merkle path (i.e., -/// 256 items with the current Merkle tree). The following items may have less hashes in their -/// Merkle paths; if this is the case, the starting hashes are skipped and are the same -/// as in the first path. -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct PrepareBasicCircuitsJob { - // Merkle paths and some auxiliary information for each read / write operation in a block. - merkle_paths: Vec, - next_enumeration_index: u64, -} - -impl PrepareBasicCircuitsJob { - /// Creates a new job with the specified leaf index and no included paths. - pub fn new(next_enumeration_index: u64) -> Self { - Self { - merkle_paths: vec![], - next_enumeration_index, - } - } - - /// Returns the next leaf index at the beginning of the block. - pub fn next_enumeration_index(&self) -> u64 { - self.next_enumeration_index - } - - /// Reserves additional capacity for Merkle paths. - pub fn reserve(&mut self, additional_capacity: usize) { - self.merkle_paths.reserve(additional_capacity); - } - - /// Pushes an additional Merkle path. - pub fn push_merkle_path(&mut self, mut path: StorageLogMetadata) { - let Some(first_path) = self.merkle_paths.first() else { - self.merkle_paths.push(path); - return; - }; - assert_eq!(first_path.merkle_paths.len(), path.merkle_paths.len()); - - let mut hash_pairs = path.merkle_paths.iter().zip(&first_path.merkle_paths); - let first_unique_idx = - hash_pairs.position(|(hash, first_path_hash)| hash != first_path_hash); - let first_unique_idx = first_unique_idx.unwrap_or(path.merkle_paths.len()); - path.merkle_paths = path.merkle_paths.split_off(first_unique_idx); - self.merkle_paths.push(path); - } - - /// Converts this job into an iterator over the contained Merkle paths. - pub fn into_merkle_paths(self) -> impl ExactSizeIterator { - let mut merkle_paths = self.merkle_paths; - if let [first, rest @ ..] = merkle_paths.as_mut_slice() { - for path in rest { - assert!( - path.merkle_paths.len() <= first.merkle_paths.len(), - "Merkle paths in `PrepareBasicCircuitsJob` are malformed; the first path is not \ - the longest one" - ); - let spliced_len = first.merkle_paths.len() - path.merkle_paths.len(); - let spliced_hashes = &first.merkle_paths[0..spliced_len]; - path.merkle_paths - .splice(0..0, spliced_hashes.iter().cloned()); - debug_assert_eq!(path.merkle_paths.len(), first.merkle_paths.len()); - } - } - merkle_paths.into_iter() - } -} - -/// Enriched `PrepareBasicCircuitsJob`. All the other fields are taken from the `l1_batches` table. -#[derive(Debug, Clone)] -pub struct BasicCircuitWitnessGeneratorInput { - pub block_number: L1BatchNumber, - pub previous_block_hash: H256, - pub previous_block_timestamp: u64, - pub block_timestamp: u64, - pub used_bytecodes_hashes: Vec, - pub initial_heap_content: Vec<(usize, U256)>, - pub merkle_paths_input: PrepareBasicCircuitsJob, -} - -#[derive(Clone)] -pub struct PrepareLeafAggregationCircuitsJob { - pub basic_circuits: BlockBasicCircuits, - pub basic_circuits_inputs: BlockBasicCircuitsPublicInputs, - pub basic_circuits_proofs: Vec>>>, -} - -#[derive(Clone)] -pub struct PrepareNodeAggregationCircuitJob { - pub previous_level_proofs: Vec>>>, - pub previous_level_leafs_aggregations: Vec>, - pub previous_sequence: Vec, 2, 2>>, -} - -#[derive(Clone)] -pub struct PrepareSchedulerCircuitJob { - pub incomplete_scheduler_witness: SchedulerCircuitInstanceWitness, - pub final_node_aggregations: NodeAggregationOutputDataWitness, - pub node_final_proof_level_proof: Proof>>, - pub previous_aux_hash: [u8; 32], - pub previous_meta_hash: [u8; 32], -} - -#[derive(Debug, Clone)] -pub struct ProverJobMetadata { - pub id: u32, - pub block_number: L1BatchNumber, - pub circuit_type: String, - pub aggregation_round: AggregationRound, - pub sequence_number: usize, -} - -#[derive(Debug, Clone)] -pub struct FriProverJobMetadata { - pub id: u32, - pub block_number: L1BatchNumber, - pub circuit_id: u8, - pub aggregation_round: AggregationRound, - pub sequence_number: usize, - pub depth: u16, - pub is_node_final_proof: bool, -} - -#[derive(Debug, Clone)] -pub struct LeafAggregationJobMetadata { - pub id: u32, - pub block_number: L1BatchNumber, - pub circuit_id: u8, - pub prover_job_ids_for_proofs: Vec, -} - -#[derive(Debug, Clone)] -pub struct NodeAggregationJobMetadata { - pub id: u32, - pub block_number: L1BatchNumber, - pub circuit_id: u8, - pub depth: u16, - pub prover_job_ids_for_proofs: Vec, -} - -#[derive(Debug)] -pub struct JobPosition { - pub aggregation_round: AggregationRound, - pub sequence_number: usize, -} - -#[derive(Debug, Default)] -pub struct ProverJobStatusFailed { - pub started_at: DateTime, - pub error: String, -} - -#[derive(Debug)] -pub struct ProverJobStatusSuccessful { - pub started_at: DateTime, - pub time_taken: chrono::Duration, -} - -impl Default for ProverJobStatusSuccessful { - fn default() -> Self { - ProverJobStatusSuccessful { - started_at: DateTime::default(), - time_taken: chrono::Duration::zero(), - } - } -} - -#[derive(Debug, Default)] -pub struct ProverJobStatusInProgress { - pub started_at: DateTime, -} - -#[derive(Debug)] -pub struct WitnessJobStatusSuccessful { - pub started_at: DateTime, - pub time_taken: chrono::Duration, -} - -impl Default for WitnessJobStatusSuccessful { - fn default() -> Self { - WitnessJobStatusSuccessful { - started_at: DateTime::default(), - time_taken: chrono::Duration::zero(), - } - } -} - -#[derive(Debug, Default)] -pub struct WitnessJobStatusFailed { - pub started_at: DateTime, - pub error: String, -} - -#[derive(Debug, strum::Display, strum::EnumString, strum::AsRefStr)] -pub enum ProverJobStatus { - #[strum(serialize = "queued")] - Queued, - #[strum(serialize = "in_progress")] - InProgress(ProverJobStatusInProgress), - #[strum(serialize = "successful")] - Successful(ProverJobStatusSuccessful), - #[strum(serialize = "failed")] - Failed(ProverJobStatusFailed), - #[strum(serialize = "skipped")] - Skipped, - #[strum(serialize = "ignored")] - Ignored, -} - -#[derive(Debug, strum::Display, strum::EnumString, strum::AsRefStr)] -pub enum WitnessJobStatus { - #[strum(serialize = "failed")] - Failed(WitnessJobStatusFailed), - #[strum(serialize = "skipped")] - Skipped, - #[strum(serialize = "successful")] - Successful(WitnessJobStatusSuccessful), - #[strum(serialize = "waiting_for_artifacts")] - WaitingForArtifacts, - #[strum(serialize = "waiting_for_proofs")] - WaitingForProofs, - #[strum(serialize = "in_progress")] - InProgress, - #[strum(serialize = "queued")] - Queued, -} - -#[derive(Debug)] -pub struct WitnessJobInfo { - pub block_number: L1BatchNumber, - pub created_at: DateTime, - pub updated_at: DateTime, - pub status: WitnessJobStatus, - pub position: JobPosition, -} - -#[derive(Debug)] -pub struct ProverJobInfo { - pub id: u32, - pub block_number: L1BatchNumber, - pub circuit_type: String, - pub position: JobPosition, - pub input_length: u64, - pub status: ProverJobStatus, - pub attempts: u32, - pub created_at: DateTime, - pub updated_at: DateTime, -} - -#[derive(Debug)] -pub struct JobExtendedStatistics { - pub successful_padding: L1BatchNumber, - pub queued_padding: L1BatchNumber, - pub queued_padding_len: u32, - pub active_area: Vec, -} - -#[derive(Debug, Clone, Copy, Default)] -pub struct JobCountStatistics { - pub queued: usize, - pub in_progress: usize, - pub failed: usize, - pub successful: usize, -} - -impl Add for JobCountStatistics { - type Output = JobCountStatistics; - - fn add(self, rhs: Self) -> Self::Output { - Self { - queued: self.queued + rhs.queued, - in_progress: self.in_progress + rhs.in_progress, - failed: self.failed + rhs.failed, - successful: self.successful + rhs.successful, - } - } -} - -#[derive(Debug)] -pub struct StuckJobs { - pub id: u64, - pub status: String, - pub attempts: u64, -} - -#[derive(Debug, Clone)] -pub struct SocketAddress { - pub host: IpAddr, - pub port: u16, -} - -#[derive(Debug, Copy, Clone)] -pub enum GpuProverInstanceStatus { - // The instance is available for processing. - Available, - // The instance is running at full capacity. - Full, - // The instance is reserved by an synthesizer. - Reserved, - // The instance is not alive anymore. - Dead, -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn prepare_basic_circuits_job_roundtrip() { - let zero_hash = [0_u8; 32]; - let logs = (0..10).map(|i| { - let mut merkle_paths = vec![zero_hash; 255]; - merkle_paths.push([i as u8; 32]); - StorageLogMetadata { - root_hash: zero_hash, - is_write: i % 2 == 0, - first_write: i % 3 == 0, - merkle_paths, - leaf_hashed_key: U256::from(i), - leaf_enumeration_index: i + 1, - value_written: [i as u8; 32], - value_read: [0; 32], - } - }); - let logs: Vec<_> = logs.collect(); - - let mut job = PrepareBasicCircuitsJob::new(4); - job.reserve(logs.len()); - for log in &logs { - job.push_merkle_path(log.clone()); - } - - // Check that Merkle paths are compacted. - for (i, log) in job.merkle_paths.iter().enumerate() { - let expected_merkle_path_len = if i == 0 { 256 } else { 1 }; - assert_eq!(log.merkle_paths.len(), expected_merkle_path_len); - } - - let logs_from_job: Vec<_> = job.into_merkle_paths().collect(); - assert_eq!(logs_from_job, logs); - } -} diff --git a/core/lib/types/src/protocol_version.rs b/core/lib/types/src/protocol_version.rs index b855cb92fdff..38caa0f8a20e 100644 --- a/core/lib/types/src/protocol_version.rs +++ b/core/lib/types/src/protocol_version.rs @@ -41,15 +41,17 @@ pub enum ProtocolVersionId { Version17, Version18, Version19, + Version20, + Version21, } impl ProtocolVersionId { pub fn latest() -> Self { - Self::Version18 + Self::Version20 } pub fn next() -> Self { - Self::Version19 + Self::Version21 } /// Returns VM version to be used by API for this protocol version. @@ -76,11 +78,27 @@ impl ProtocolVersionId { ProtocolVersionId::Version17 => VmVersion::VmVirtualBlocksRefundsEnhancement, ProtocolVersionId::Version18 => VmVersion::VmBoojumIntegration, ProtocolVersionId::Version19 => VmVersion::VmBoojumIntegration, + ProtocolVersionId::Version20 => VmVersion::Vm1_4_1, + ProtocolVersionId::Version21 => VmVersion::Vm1_4_1, } } + // It is possible that some external nodes do not store protocol versions for versions below 9. + // That's why we assume that whenever a protocol version is not present, version 9 is to be used. + pub fn last_potentially_undefined() -> Self { + Self::Version9 + } + pub fn is_pre_boojum(&self) -> bool { - self < &ProtocolVersionId::Version18 + self <= &Self::Version17 + } + + pub fn is_1_4_0(&self) -> bool { + self >= &ProtocolVersionId::Version18 && self < &ProtocolVersionId::Version20 + } + + pub fn is_post_1_4_1(&self) -> bool { + self >= &ProtocolVersionId::Version20 } } @@ -239,11 +257,11 @@ impl TryFrom for ProtocolUpgrade { }; let transaction_param_type = ParamType::Tuple(vec![ - ParamType::Uint(256), // txType + ParamType::Uint(256), // `txType` ParamType::Uint(256), // sender ParamType::Uint(256), // to ParamType::Uint(256), // gasLimit - ParamType::Uint(256), // gasPerPubdataLimit + ParamType::Uint(256), // `gasPerPubdataLimit` ParamType::Uint(256), // maxFeePerGas ParamType::Uint(256), // maxPriorityFeePerGas ParamType::Uint(256), // paymaster @@ -254,7 +272,7 @@ impl TryFrom for ProtocolUpgrade { ParamType::Bytes, // signature ParamType::Array(Box::new(ParamType::Uint(256))), // factory deps ParamType::Bytes, // paymaster input - ParamType::Bytes, // reservedDynamic + ParamType::Bytes, // `reservedDynamic` ]); let verifier_params_type = ParamType::Tuple(vec![ ParamType::FixedBytes(32), @@ -349,7 +367,7 @@ impl TryFrom for ProtocolUpgrade { let paymaster_input = transaction.remove(0).into_bytes().unwrap(); assert_eq!(paymaster_input.len(), 0); - // TODO (SMA-1621): check that reservedDynamic are constructed correctly. + // TODO (SMA-1621): check that `reservedDynamic` are constructed correctly. let reserved_dynamic = transaction.remove(0).into_bytes().unwrap(); assert_eq!(reserved_dynamic.len(), 0); @@ -695,6 +713,8 @@ impl From for VmVersion { ProtocolVersionId::Version17 => VmVersion::VmVirtualBlocksRefundsEnhancement, ProtocolVersionId::Version18 => VmVersion::VmBoojumIntegration, ProtocolVersionId::Version19 => VmVersion::VmBoojumIntegration, + ProtocolVersionId::Version20 => VmVersion::Vm1_4_1, + ProtocolVersionId::Version21 => VmVersion::Vm1_4_1, } } } diff --git a/core/lib/types/src/snapshots.rs b/core/lib/types/src/snapshots.rs index c4804880c2ac..2007c825902c 100644 --- a/core/lib/types/src/snapshots.rs +++ b/core/lib/types/src/snapshots.rs @@ -1,48 +1,63 @@ -use std::convert::TryFrom; +use std::{convert::TryFrom, ops}; use anyhow::Context; use serde::{Deserialize, Serialize}; use zksync_basic_types::{AccountTreeId, L1BatchNumber, MiniblockNumber, H256}; use zksync_protobuf::{required, ProtoFmt}; +use zksync_utils::u256_to_h256; -use crate::{commitment::L1BatchWithMetadata, Bytes, StorageKey, StorageValue}; +use crate::{commitment::L1BatchWithMetadata, Bytes, StorageKey, StorageValue, U256}; +/// Information about all snapshots persisted by the node. #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct AllSnapshots { + /// L1 batch numbers for complete snapshots. Ordered by descending number (i.e., 0th element + /// corresponds to the newest snapshot). pub snapshots_l1_batch_numbers: Vec, } -// used in dal to fetch certain snapshot data -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] +/// Storage snapshot metadata. Used in DAL to fetch certain snapshot data. +#[derive(Debug, Clone)] pub struct SnapshotMetadata { + /// L1 batch for the snapshot. The data in the snapshot captures node storage at the end of this batch. pub l1_batch_number: L1BatchNumber, + /// Path to the factory dependencies blob. pub factory_deps_filepath: String, - pub storage_logs_filepaths: Vec, + /// Paths to the storage log blobs. Ordered by the chunk ID. If a certain chunk is not produced yet, + /// the corresponding path is `None`. + pub storage_logs_filepaths: Vec>, +} + +impl SnapshotMetadata { + /// Checks whether a snapshot is complete (contains all information to restore from). + pub fn is_complete(&self) -> bool { + self.storage_logs_filepaths.iter().all(Option::is_some) + } } -//contains all data not contained in factory_deps/storage_logs files to perform restore process +/// Snapshot data returned by using JSON-RPC API. +/// Contains all data not contained in `factory_deps` / `storage_logs` files to perform restore process. #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct SnapshotHeader { pub l1_batch_number: L1BatchNumber, pub miniblock_number: MiniblockNumber, - //ordered by chunk ids + /// Ordered by chunk IDs. pub storage_logs_chunks: Vec, pub factory_deps_filepath: String, pub last_l1_batch_with_metadata: L1BatchWithMetadata, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct SnapshotStorageLogsChunkMetadata { pub chunk_id: u64, - // can be either be a file available under http(s) or local filesystem path + // can be either be a file available under HTTP(s) or local filesystem path pub filepath: String, } -#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct SnapshotStorageLogsStorageKey { pub l1_batch_number: L1BatchNumber, @@ -173,12 +188,100 @@ impl ProtoFmt for SnapshotStorageLogsChunk { } } +/// Status of snapshot recovery process stored in Postgres. #[derive(Debug, PartialEq)] pub struct SnapshotRecoveryStatus { pub l1_batch_number: L1BatchNumber, pub l1_batch_root_hash: H256, pub miniblock_number: MiniblockNumber, pub miniblock_root_hash: H256, - pub last_finished_chunk_id: Option, - pub total_chunk_count: u64, + pub storage_logs_chunks_processed: Vec, +} + +impl SnapshotRecoveryStatus { + /// Returns the number of storage log chunks left to process. + pub fn storage_logs_chunks_left_to_process(&self) -> usize { + self.storage_logs_chunks_processed + .iter() + .filter(|&&is_processed| !is_processed) + .count() + } +} + +/// Returns a chunk of `hashed_keys` with 0-based index `chunk_id` among `count`. Chunks do not intersect and jointly cover +/// the entire `hashed_key` space. If `hashed_key`s are uniformly distributed (which is the case), the returned ranges +/// are expected to contain the same number of entries. +/// +/// Used by multiple components during snapshot creation and recovery. +/// +/// # Panics +/// +/// Panics if `chunk_count == 0` or `chunk_id >= chunk_count`. +pub fn uniform_hashed_keys_chunk(chunk_id: u64, chunk_count: u64) -> ops::RangeInclusive { + assert!(chunk_count > 0, "`chunk_count` must be positive"); + assert!( + chunk_id < chunk_count, + "Chunk index {} exceeds count {}", + chunk_id, + chunk_count + ); + + let mut stride = U256::MAX / chunk_count; + let stride_minus_one = if stride < U256::MAX { + stride += U256::one(); + stride - 1 + } else { + stride // `stride` is really 1 << 256 == U256::MAX + 1 + }; + + let start = stride * chunk_id; + let (mut end, is_overflow) = stride_minus_one.overflowing_add(start); + if is_overflow { + end = U256::MAX; + } + u256_to_h256(start)..=u256_to_h256(end) +} + +#[cfg(test)] +mod tests { + use zksync_utils::h256_to_u256; + + use super::*; + + #[test] + fn chunking_is_correct() { + for chunks_count in (2..10).chain([42, 256, 500, 1_001, 12_345]) { + println!("Testing chunks_count={chunks_count}"); + let chunked_ranges: Vec<_> = (0..chunks_count) + .map(|chunk_id| uniform_hashed_keys_chunk(chunk_id, chunks_count)) + .collect(); + + assert_eq!(*chunked_ranges[0].start(), H256::zero()); + assert_eq!( + *chunked_ranges.last().unwrap().end(), + H256::repeat_byte(0xff) + ); + for window in chunked_ranges.windows(2) { + let [prev_chunk, next_chunk] = window else { + unreachable!(); + }; + assert_eq!( + h256_to_u256(*prev_chunk.end()) + 1, + h256_to_u256(*next_chunk.start()) + ); + } + + let chunk_sizes: Vec<_> = chunked_ranges + .iter() + .map(|chunk| h256_to_u256(*chunk.end()) - h256_to_u256(*chunk.start()) + 1) + .collect(); + + // Check that chunk sizes are roughly equal. Due to how chunks are constructed, the sizes + // of all chunks except for the last one are the same, and the last chunk size may be slightly smaller; + // the difference in sizes is lesser than the number of chunks. + let min_chunk_size = chunk_sizes.iter().copied().min().unwrap(); + let max_chunk_size = chunk_sizes.iter().copied().max().unwrap(); + assert!(max_chunk_size - min_chunk_size < U256::from(chunks_count)); + } + } } diff --git a/core/lib/types/src/storage/log.rs b/core/lib/types/src/storage/log.rs index 11756f7175ae..e5565cfb8165 100644 --- a/core/lib/types/src/storage/log.rs +++ b/core/lib/types/src/storage/log.rs @@ -1,13 +1,15 @@ use std::mem; use serde::{Deserialize, Serialize}; -use zk_evm::aux_structures::{LogQuery, Timestamp}; use zksync_basic_types::AccountTreeId; use zksync_utils::u256_to_h256; -use crate::{StorageKey, StorageValue, U256}; +use crate::{ + zk_evm_types::{LogQuery, Timestamp}, + StorageKey, StorageValue, U256, +}; -// TODO (SMA-1269): Refactor StorageLog/StorageLogQuery and StorageLogKind/StorageLongQueryType. +// TODO (SMA-1269): Refactor `StorageLog/StorageLogQuery and StorageLogKind/StorageLongQueryType`. #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub enum StorageLogKind { Read, diff --git a/core/lib/types/src/storage/mod.rs b/core/lib/types/src/storage/mod.rs index 46b98575f124..54694f63c504 100644 --- a/core/lib/types/src/storage/mod.rs +++ b/core/lib/types/src/storage/mod.rs @@ -67,7 +67,7 @@ fn get_address_mapping_key(address: &Address, position: H256) -> H256 { pub fn get_nonce_key(account: &Address) -> StorageKey { let nonce_manager = AccountTreeId::new(NONCE_HOLDER_ADDRESS); - // The `minNonce` (used as nonce for EOAs) is stored in a mapping inside the NONCE_HOLDER system contract + // The `minNonce` (used as nonce for EOAs) is stored in a mapping inside the `NONCE_HOLDER` system contract let key = get_address_mapping_key(account, H256::zero()); StorageKey::new(nonce_manager, key) diff --git a/core/lib/types/src/storage_writes_deduplicator.rs b/core/lib/types/src/storage_writes_deduplicator.rs index 14a5413ee6a0..19bf51b6eb03 100644 --- a/core/lib/types/src/storage_writes_deduplicator.rs +++ b/core/lib/types/src/storage_writes_deduplicator.rs @@ -219,10 +219,11 @@ impl StorageWritesDeduplicator { #[cfg(test)] mod tests { - use zk_evm::aux_structures::{LogQuery, Timestamp}; - use super::*; - use crate::H160; + use crate::{ + zk_evm_types::{LogQuery, Timestamp}, + H160, + }; fn storage_log_query( key: U256, diff --git a/core/lib/types/src/system_contracts.rs b/core/lib/types/src/system_contracts.rs index 7cd4107ad41e..464a562b9272 100644 --- a/core/lib/types/src/system_contracts.rs +++ b/core/lib/types/src/system_contracts.rs @@ -16,9 +16,9 @@ use crate::{ SHA256_PRECOMPILE_ADDRESS, SYSTEM_CONTEXT_ADDRESS, }; -// Note, that in the NONCE_HOLDER_ADDRESS's storage the nonces of accounts +// Note, that in the `NONCE_HOLDER_ADDRESS` storage the nonces of accounts // are stored in the following form: -// 2^128 * deployment_nonce + tx_nonce, +// `2^128 * deployment_nonce + tx_nonce`, // where `tx_nonce` should be number of transactions, the account has processed // and the `deployment_nonce` should be the number of contracts. pub const TX_NONCE_INCREMENT: U256 = U256([1, 0, 0, 0]); // 1 diff --git a/core/lib/types/src/transaction_request.rs b/core/lib/types/src/transaction_request.rs index e66c2495afe3..f42a74bd2c5a 100644 --- a/core/lib/types/src/transaction_request.rs +++ b/core/lib/types/src/transaction_request.rs @@ -4,7 +4,7 @@ use rlp::{DecoderError, Rlp, RlpStream}; use serde::{Deserialize, Serialize}; use thiserror::Error; use zksync_basic_types::H256; -use zksync_system_constants::{MAX_GAS_PER_PUBDATA_BYTE, USED_BOOTLOADER_MEMORY_BYTES}; +use zksync_system_constants::{DEFAULT_L2_TX_GAS_PER_PUBDATA_BYTE, MAX_ENCODED_TX_SIZE}; use zksync_utils::{ bytecode::{hash_bytecode, validate_bytecode, InvalidBytecodeError}, concat_and_hash, u256_to_h256, @@ -182,7 +182,7 @@ pub enum SerializationTransactionError { /// OversizedData is returned if the raw tx size is greater /// than some meaningful limit a user might use. This is not a consensus error /// making the transaction invalid, rather a DOS protection. - #[error("oversized data. max: {0}; actual: {0}")] + #[error("oversized data. max: {0}; actual: {1}")] OversizedData(usize, usize), #[error("gas per pub data limit is zero")] GasPerPubDataLimitZero, @@ -442,7 +442,7 @@ impl TransactionRequest { match self.transaction_type { // EIP-2930 (0x01) Some(x) if x == EIP_2930_TX_TYPE.into() => { - // rlp_opt(rlp, &self.chain_id); + // `rlp_opt(rlp, &self.chain_id);` rlp.append(&chain_id); rlp.append(&self.nonce); rlp.append(&self.gas_price); @@ -454,7 +454,7 @@ impl TransactionRequest { } // EIP-1559 (0x02) Some(x) if x == EIP_1559_TX_TYPE.into() => { - // rlp_opt(rlp, &self.chain_id); + // `rlp_opt(rlp, &self.chain_id);` rlp.append(&chain_id); rlp.append(&self.nonce); rlp_opt(rlp, &self.max_priority_fee_per_gas); @@ -743,8 +743,8 @@ impl TransactionRequest { } meta.gas_per_pubdata } else { - // For transactions that don't support corresponding field, a default is chosen. - U256::from(MAX_GAS_PER_PUBDATA_BYTE) + // For transactions that don't support corresponding field, a maximal default value is chosen. + DEFAULT_L2_TX_GAS_PER_PUBDATA_BYTE.into() }; let max_priority_fee_per_gas = self.max_priority_fee_per_gas.unwrap_or(self.gas_price); @@ -821,7 +821,7 @@ impl L2Tx { /// Ensures that encoded transaction size is not greater than `max_tx_size`. fn check_encoded_size(&self, max_tx_size: usize) -> Result<(), SerializationTransactionError> { - // since abi_encoding_len returns 32-byte words multiplication on 32 is needed + // since `abi_encoding_len` returns 32-byte words multiplication on 32 is needed let tx_size = self.abi_encoding_len() * 32; if tx_size > max_tx_size { return Err(SerializationTransactionError::OversizedData( @@ -882,7 +882,7 @@ impl TryFrom for L1Tx { type Error = SerializationTransactionError; fn try_from(tx: CallRequest) -> Result { // L1 transactions have no limitations on the transaction size. - let tx: L2Tx = L2Tx::from_request(tx.into(), USED_BOOTLOADER_MEMORY_BYTES)?; + let tx: L2Tx = L2Tx::from_request(tx.into(), MAX_ENCODED_TX_SIZE)?; // Note, that while the user has theoretically provided the fee for ETH on L1, // the payment to the operator as well as refunds happen on L2 and so all the ETH @@ -890,7 +890,7 @@ impl TryFrom for L1Tx { let total_needed_eth = tx.execute.value + tx.common_data.fee.max_fee_per_gas * tx.common_data.fee.gas_limit; - // Note, that we do not set refund_recipient here, to keep it explicitly 0, + // Note, that we do not set `refund_recipient` here, to keep it explicitly 0, // so that during fee estimation it is taken into account that the refund recipient may be a different address let common_data = L1TxCommonData { sender: tx.common_data.initiator_address, @@ -1396,7 +1396,7 @@ mod tests { let random_tx_max_size = 1_000_000; // bytes let private_key = H256::random(); let address = PackedEthSignature::address_from_private_key(&private_key).unwrap(); - // choose some number that devides on 8 and is > 1_000_000 + // choose some number that divides on 8 and is `> 1_000_000` let factory_dep = vec![2u8; 1600000]; let factory_deps: Vec> = factory_dep.chunks(32).map(|s| s.into()).collect(); let mut tx = TransactionRequest { @@ -1488,21 +1488,15 @@ mod tests { access_list: None, eip712_meta: None, }; - let l2_tx = L2Tx::from_request( - call_request_with_nonce.clone().into(), - USED_BOOTLOADER_MEMORY_BYTES, - ) - .unwrap(); + let l2_tx = L2Tx::from_request(call_request_with_nonce.clone().into(), MAX_ENCODED_TX_SIZE) + .unwrap(); assert_eq!(l2_tx.nonce(), Nonce(123u32)); let mut call_request_without_nonce = call_request_with_nonce; call_request_without_nonce.nonce = None; - let l2_tx = L2Tx::from_request( - call_request_without_nonce.into(), - USED_BOOTLOADER_MEMORY_BYTES, - ) - .unwrap(); + let l2_tx = + L2Tx::from_request(call_request_without_nonce.into(), MAX_ENCODED_TX_SIZE).unwrap(); assert_eq!(l2_tx.nonce(), Nonce(0u32)); } } diff --git a/core/lib/types/src/tx/execute.rs b/core/lib/types/src/tx/execute.rs index 50340230cb9e..21f0b401cce2 100644 --- a/core/lib/types/src/tx/execute.rs +++ b/core/lib/types/src/tx/execute.rs @@ -31,7 +31,7 @@ impl EIP712TypedStructure for Execute { builder.add_member("data", &self.calldata.as_slice()); // Factory deps are not included into the transaction signature, since they are parsed from the // transaction metadata. - // Note that for the deploy transactions all the dependencies are implicitly included into the "calldataHash" + // Note that for the deploy transactions all the dependencies are implicitly included into the `calldataHash` // field, because the deps are referenced in the bytecode of the "main" contract bytecode. } } diff --git a/core/lib/types/src/tx/primitives/ecdsa_signature.rs b/core/lib/types/src/tx/primitives/ecdsa_signature.rs new file mode 100644 index 000000000000..1cf5bec8a3d2 --- /dev/null +++ b/core/lib/types/src/tx/primitives/ecdsa_signature.rs @@ -0,0 +1,365 @@ +// Mostly copy-pasted from parity-crypto 0.9.0: +// https://github.com/paritytech/parity-common/blob/parity-crypto-v0.9.0/parity-crypto/src/publickey/keypair.rs +// https://github.com/paritytech/parity-common/blob/parity-crypto-v0.9.0/parity-crypto/src/publickey/ecdsa_signature.rs +// +// Reason: parity-crypto crate is not maintained, and it provides convenience wrappers over secp256k1 we rely on. +// For the time being, vendoring these files is more convenient than rewriting the rest of the codebase to use +// secp256k1 directly. +// +// Changes made: adapting the code for the newer version of secp256k1, stripping down some code we don't need, +// type replacements for the ease of use. + +// Copyright 2020 Parity Technologies +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Copied from parity-crypto 0.9.0 src/publickey/keypair.rs +// Key pair (public + secret) description. + +use std::{ + cmp::PartialEq, + fmt, + hash::{Hash, Hasher}, + ops::{Deref, DerefMut}, + str::FromStr, +}; + +use secp256k1::{ + ecdsa::{RecoverableSignature, RecoveryId}, + Message as SecpMessage, PublicKey, SecretKey, SECP256K1, +}; + +use crate::web3::{ + signing::keccak256, + types::{Address, H256, H512, H520}, +}; + +type Message = H256; +type Public = H512; +type Secret = H256; + +/// Convert public key into the address +pub(super) fn public_to_address(public: &Public) -> Address { + let hash = keccak256(public.as_bytes()); + let mut result = Address::zero(); + result.as_bytes_mut().copy_from_slice(&hash[12..]); + result +} + +#[derive(Debug, Clone, PartialEq)] +/// secp256k1 key pair +pub(super) struct KeyPair { + secret: Secret, + public: Public, +} + +impl fmt::Display for KeyPair { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + writeln!(f, "secret: {:x}", self.secret)?; + writeln!(f, "public: {:x}", self.public)?; + write!(f, "address: {:x}", self.address()) + } +} + +impl KeyPair { + /// Create a pair from secret key + pub(super) fn from_secret(secret: Secret) -> Result { + let context = &SECP256K1; + let s: SecretKey = SecretKey::from_slice(secret.as_bytes())?; + let pub_key = PublicKey::from_secret_key(context, &s); + let serialized = pub_key.serialize_uncompressed(); + + let mut public = Public::default(); + public.as_bytes_mut().copy_from_slice(&serialized[1..65]); + + let keypair = KeyPair { secret, public }; + + Ok(keypair) + } + + /// Returns public part of the keypair converted into Address + pub(super) fn address(&self) -> Address { + public_to_address(&self.public) + } +} + +// Copied from parity-crypto 0.9.0 `src/publickey/ecdsa_signature.rs` + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("secp256k1 error: {0}")] + Secp256k1(#[from] secp256k1::Error), + #[error("invalid signature")] + InvalidSignature, + #[error(transparent)] + Custom(anyhow::Error), +} + +/// Signature encoded as RSV components +#[repr(C)] +pub(super) struct Signature([u8; 65]); + +impl Signature { + /// Get a slice into the 'r' portion of the data. + pub(super) fn r(&self) -> &[u8] { + &self.0[0..32] + } + + /// Get a slice into the 's' portion of the data. + pub(super) fn s(&self) -> &[u8] { + &self.0[32..64] + } + + /// Get the recovery byte. + pub(super) fn v(&self) -> u8 { + self.0[64] + } + + /// Encode the signature into RSV array (V altered to be in "Electrum" notation). + pub(super) fn into_electrum(mut self) -> [u8; 65] { + self.0[64] += 27; + self.0 + } + + /// Parse bytes as a signature encoded as RSV (V in "Electrum" notation). + /// May return empty (invalid) signature if given data has invalid length. + #[cfg(test)] + pub(super) fn from_electrum(data: &[u8]) -> Self { + if data.len() != 65 || data[64] < 27 { + // fallback to empty (invalid) signature + return Signature::default(); + } + + let mut sig = [0u8; 65]; + sig.copy_from_slice(data); + sig[64] -= 27; + Signature(sig) + } + + /// Create a signature object from the RSV triple. + pub(super) fn from_rsv(r: &H256, s: &H256, v: u8) -> Self { + let mut sig = [0u8; 65]; + sig[0..32].copy_from_slice(r.as_ref()); + sig[32..64].copy_from_slice(s.as_ref()); + sig[64] = v; + Signature(sig) + } +} + +// manual implementation large arrays don't have trait impls by default. +impl PartialEq for Signature { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +// manual implementation required in Rust 1.13+, see `std::cmp::AssertParamIsEq`. +impl Eq for Signature {} + +// also manual for the same reason, but the pretty printing might be useful. +impl fmt::Debug for Signature { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + f.debug_struct("Signature") + .field("r", &hex::encode(&self.0[0..32])) + .field("s", &hex::encode(&self.0[32..64])) + .field("v", &hex::encode(&self.0[64..65])) + .finish() + } +} + +impl fmt::Display for Signature { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(f, "{}", hex::encode(self.0)) + } +} + +impl FromStr for Signature { + type Err = Error; + + fn from_str(s: &str) -> Result { + match hex::decode(s) { + Ok(ref hex) if hex.len() == 65 => { + let mut data = [0; 65]; + data.copy_from_slice(&hex[0..65]); + Ok(Signature(data)) + } + _ => Err(Error::InvalidSignature), + } + } +} + +impl Default for Signature { + fn default() -> Self { + Signature([0; 65]) + } +} + +impl Hash for Signature { + fn hash(&self, state: &mut H) { + H520::from(self.0).hash(state); + } +} + +impl Clone for Signature { + fn clone(&self) -> Self { + Signature(self.0) + } +} + +impl From<[u8; 65]> for Signature { + fn from(s: [u8; 65]) -> Self { + Signature(s) + } +} + +impl From for H520 { + fn from(s: Signature) -> Self { + H520::from(s.0) + } +} + +impl From for Signature { + fn from(bytes: H520) -> Self { + Signature(bytes.into()) + } +} + +impl Deref for Signature { + type Target = [u8; 65]; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Signature { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +/// Signs message with the given secret key. +/// Returns the corresponding signature. +pub(super) fn sign(secret: &Secret, message: &Message) -> Result { + let context = &SECP256K1; + let sec = SecretKey::from_slice(secret.as_ref())?; + let s = context.sign_ecdsa_recoverable(&SecpMessage::from_slice(&message[..])?, &sec); + let (rec_id, data) = s.serialize_compact(); + let mut data_arr = [0; 65]; + + // no need to check if s is low, it always is + data_arr[0..64].copy_from_slice(&data[0..64]); + data_arr[64] = rec_id.to_i32() as u8; + Ok(Signature(data_arr)) +} + +/// Recovers the public key from the signature for the message +pub(super) fn recover(signature: &Signature, message: &Message) -> Result { + let rsig = RecoverableSignature::from_compact( + &signature[0..64], + RecoveryId::from_i32(signature[64] as i32)?, + )?; + let pubkey = &SECP256K1.recover_ecdsa(&SecpMessage::from_slice(&message[..])?, &rsig)?; + let serialized = pubkey.serialize_uncompressed(); + let mut public = Public::default(); + public.as_bytes_mut().copy_from_slice(&serialized[1..65]); + Ok(public) +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use super::{recover, sign, KeyPair, Message, Secret, Signature}; + + #[test] + fn from_secret() { + let secret = Secret::from_slice( + &hex::decode("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65") + .unwrap(), + ); + let _ = KeyPair::from_secret(secret).unwrap(); + } + + #[test] + fn keypair_display() { + let expected = +"secret: a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65 +public: 8ce0db0b0359ffc5866ba61903cc2518c3675ef2cf380a7e54bde7ea20e6fa1ab45b7617346cd11b7610001ee6ae5b0155c41cad9527cbcdff44ec67848943a4 +address: 5b073e9233944b5e729e46d618f0d8edf3d9c34a".to_owned(); + let secret = Secret::from_slice( + &hex::decode("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65") + .unwrap(), + ); + let kp = KeyPair::from_secret(secret).unwrap(); + assert_eq!(format!("{}", kp), expected); + } + + #[test] + fn vrs_conversion() { + // given + let secret = Secret::from_slice(&[1u8; 32]); + let message = + Message::from_str("0000000000000000000000000000000000000000000000000000000000000001") + .unwrap(); + let signature = sign(&secret, &message).expect("can sign a non-zero message"); + + // when + let vrs = signature.clone().into_electrum(); + let from_vrs = Signature::from_electrum(&vrs); + + // then + assert_eq!(signature, from_vrs); + } + + #[test] + fn signature_to_and_from_str() { + let secret = Secret::from_slice(&[1u8; 32]); + let message = + Message::from_str("0000000000000000000000000000000000000000000000000000000000000001") + .unwrap(); + let signature = sign(&secret, &message).expect("can sign a non-zero message"); + let string = format!("{}", signature); + let deserialized = Signature::from_str(&string).unwrap(); + assert_eq!(signature, deserialized); + } + + #[test] + fn sign_and_recover_public() { + let secret = Secret::from_slice(&[1u8; 32]); + let keypair = KeyPair::from_secret(secret).unwrap(); + let message = + Message::from_str("0000000000000000000000000000000000000000000000000000000000000001") + .unwrap(); + let signature = sign(&keypair.secret, &message).unwrap(); + assert_eq!(&keypair.public, &recover(&signature, &message).unwrap()); + } + + #[test] + fn sign_and_recover_public_works_with_zeroed_messages() { + let secret = Secret::from_slice(&[1u8; 32]); + let keypair = KeyPair::from_secret(secret).unwrap(); + let signature = sign(&keypair.secret, &Message::zero()).unwrap(); + let zero_message = Message::zero(); + assert_eq!( + &keypair.public, + &recover(&signature, &zero_message).unwrap() + ); + } + + #[test] + fn recover_allowing_all_zero_message_can_recover_from_all_zero_messages() { + let secret = Secret::from_slice(&[1u8; 32]); + let keypair = KeyPair::from_secret(secret).unwrap(); + let signature = sign(&keypair.secret, &Message::zero()).unwrap(); + let zero_message = Message::zero(); + assert_eq!( + &keypair.public, + &recover(&signature, &zero_message).unwrap() + ) + } +} diff --git a/core/lib/types/src/tx/primitives/eip712_signature/struct_builder.rs b/core/lib/types/src/tx/primitives/eip712_signature/struct_builder.rs index 2093042b9f7a..1b3260993ea9 100644 --- a/core/lib/types/src/tx/primitives/eip712_signature/struct_builder.rs +++ b/core/lib/types/src/tx/primitives/eip712_signature/struct_builder.rs @@ -87,7 +87,7 @@ pub(crate) struct EncodeBuilder { impl EncodeBuilder { /// Returns the concatenation of the encoded member values in the order that they appear in the type. pub fn encode_data(&self) -> Vec { - // encodeData(s : 𝕊) = enc(value₁) ‖ enc(value₂) ‖ … ‖ enc(valueₙ). + // `encodeData(s : 𝕊) = enc(value₁) ‖ enc(value₂) ‖ … ‖ enc(valueₙ).` self.members.iter().map(|(_, data)| *data).collect() } diff --git a/core/lib/types/src/tx/primitives/eip712_signature/typed_structure.rs b/core/lib/types/src/tx/primitives/eip712_signature/typed_structure.rs index daf1c9698ee1..421944e5d46f 100644 --- a/core/lib/types/src/tx/primitives/eip712_signature/typed_structure.rs +++ b/core/lib/types/src/tx/primitives/eip712_signature/typed_structure.rs @@ -123,7 +123,7 @@ pub trait EIP712TypedStructure: Serialize { } fn hash_struct(&self) -> H256 { - // hashStruct(s : 𝕊) = keccak256(keccak256(encodeType(typeOf(s))) ‖ encodeData(s)). + // `hashStruct(s : 𝕊) = keccak256(keccak256(encodeType(typeOf(s))) ‖ encodeData(s)).` let type_hash = { let encode_type = self.encode_type(); keccak256(encode_type.as_bytes()) diff --git a/core/lib/types/src/tx/primitives/mod.rs b/core/lib/types/src/tx/primitives/mod.rs index a26475a03cd0..1e486837c96b 100644 --- a/core/lib/types/src/tx/primitives/mod.rs +++ b/core/lib/types/src/tx/primitives/mod.rs @@ -1,3 +1,4 @@ +pub(crate) mod ecdsa_signature; pub mod eip712_signature; pub mod packed_eth_signature; diff --git a/core/lib/types/src/tx/primitives/packed_eth_signature.rs b/core/lib/types/src/tx/primitives/packed_eth_signature.rs index c165f6a36b21..2c0f014e8ee2 100644 --- a/core/lib/types/src/tx/primitives/packed_eth_signature.rs +++ b/core/lib/types/src/tx/primitives/packed_eth_signature.rs @@ -1,18 +1,17 @@ -use ethereum_types_old::H256 as ParityCryptoH256; -use parity_crypto::{ - publickey::{ - public_to_address, recover, sign, Error as ParityCryptoError, KeyPair, - Signature as ETHSignature, - }, - Keccak256, -}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use thiserror::Error; use zksync_basic_types::{Address, H256}; use zksync_utils::ZeroPrefixHexSerde; -use crate::tx::primitives::eip712_signature::typed_structure::{ - EIP712TypedStructure, Eip712Domain, +use crate::{ + tx::primitives::{ + ecdsa_signature::{ + public_to_address, recover, sign, Error as ParityCryptoError, KeyPair, + Signature as ETHSignature, + }, + eip712_signature::typed_structure::{EIP712TypedStructure, Eip712Domain}, + }, + web3::signing::keccak256, }; /// Struct used for working with Ethereum signatures created using eth_sign (using geth, ethers.js, etc) @@ -78,11 +77,7 @@ impl PackedEthSignature { private_key: &H256, signed_bytes: &H256, ) -> Result { - let private_key = ParityCryptoH256::from_slice(&private_key.0); - let signed_bytes = ParityCryptoH256::from_slice(&signed_bytes.0); - - let secret_key = private_key.into(); - let signature = sign(&secret_key, &signed_bytes)?; + let signature = sign(private_key, signed_bytes)?; Ok(PackedEthSignature(signature)) } @@ -93,11 +88,8 @@ impl PackedEthSignature { domain: &Eip712Domain, typed_struct: &impl EIP712TypedStructure, ) -> Result { - let private_key = ParityCryptoH256::from_slice(&private_key.0); - let secret_key = private_key.into(); - let signed_bytes = - ParityCryptoH256::from(Self::typed_data_to_signed_bytes(domain, typed_struct).0); - let signature = sign(&secret_key, &signed_bytes)?; + let signed_bytes = H256::from(Self::typed_data_to_signed_bytes(domain, typed_struct).0); + let signature = sign(private_key, &signed_bytes)?; Ok(PackedEthSignature(signature)) } @@ -109,11 +101,11 @@ impl PackedEthSignature { bytes.extend_from_slice("\x19\x01".as_bytes()); bytes.extend_from_slice(domain.hash_struct().as_bytes()); bytes.extend_from_slice(typed_struct.hash_struct().as_bytes()); - bytes.keccak256().into() + keccak256(&bytes).into() } pub fn message_to_signed_bytes(msg: &[u8]) -> H256 { - msg.keccak256().into() + keccak256(msg).into() } /// Checks signature and returns Ethereum address of the signer. @@ -123,7 +115,7 @@ impl PackedEthSignature { &self, signed_bytes: &H256, ) -> Result { - let signed_bytes = ParityCryptoH256::from_slice(&signed_bytes.0); + let signed_bytes = H256::from_slice(&signed_bytes.0); let public_key = recover(&self.0, &signed_bytes)?; let address = public_to_address(&public_key); Ok(Address::from(address.0)) @@ -131,14 +123,14 @@ impl PackedEthSignature { /// Get Ethereum address from private key. pub fn address_from_private_key(private_key: &H256) -> Result { - let private_key = ParityCryptoH256::from_slice(&private_key.0); - let address = KeyPair::from_secret(private_key.into())?.address(); + let private_key = H256::from_slice(&private_key.0); + let address = KeyPair::from_secret(private_key)?.address(); Ok(Address::from(address.0)) } pub fn from_rsv(r: &H256, s: &H256, v: u8) -> Self { - let r = ParityCryptoH256::from_slice(&r.0); - let s = ParityCryptoH256::from_slice(&s.0); + let r = H256::from_slice(&r.0); + let s = H256::from_slice(&s.0); PackedEthSignature(ETHSignature::from_rsv(&r, &s, v)) } @@ -169,7 +161,7 @@ impl PackedEthSignature { } } - Err(ParityCryptoError::Custom("Invalid v".to_string())) + Err(ParityCryptoError::Custom(anyhow::format_err!("Invalid v"))) } } diff --git a/core/lib/types/src/tx/tx_execution_info.rs b/core/lib/types/src/tx/tx_execution_info.rs index d19757ee970b..7b2b0dbd27e4 100644 --- a/core/lib/types/src/tx/tx_execution_info.rs +++ b/core/lib/types/src/tx/tx_execution_info.rs @@ -1,6 +1,7 @@ use std::ops::{Add, AddAssign}; use crate::{ + circuit::CircuitStatistic, commitment::SerializeCommitment, fee::TransactionExecutionMetrics, l2_to_l1_log::L2ToL1Log, @@ -69,6 +70,7 @@ pub struct ExecutionMetrics { pub cycles_used: u32, pub computational_gas_used: u32, pub pubdata_published: u32, + pub circuit_statistic: CircuitStatistic, } impl ExecutionMetrics { @@ -86,6 +88,7 @@ impl ExecutionMetrics { cycles_used: tx_metrics.cycles_used, computational_gas_used: tx_metrics.computational_gas_used, pubdata_published: tx_metrics.pubdata_published, + circuit_statistic: tx_metrics.circuit_statistic, } } @@ -119,6 +122,7 @@ impl Add for ExecutionMetrics { cycles_used: self.cycles_used + other.cycles_used, computational_gas_used: self.computational_gas_used + other.computational_gas_used, pubdata_published: self.pubdata_published + other.pubdata_published, + circuit_statistic: self.circuit_statistic + other.circuit_statistic, } } } diff --git a/core/lib/types/src/utils.rs b/core/lib/types/src/utils.rs index 7828f2d1262b..b13887000cb2 100644 --- a/core/lib/types/src/utils.rs +++ b/core/lib/types/src/utils.rs @@ -48,7 +48,7 @@ pub fn storage_key_for_standard_token_balance( token_contract: AccountTreeId, address: &Address, ) -> StorageKey { - // We have different implementation of the standard erc20 contract and native + // We have different implementation of the standard ERC20 contract and native // eth contract. The key for the balance is different for each. let key = if token_contract.address() == &L2_ETH_TOKEN_ADDRESS { key_for_eth_balance(address) diff --git a/core/lib/types/src/vm_trace.rs b/core/lib/types/src/vm_trace.rs index d3a94d51fa5a..9d36900e3961 100644 --- a/core/lib/types/src/vm_trace.rs +++ b/core/lib/types/src/vm_trace.rs @@ -5,11 +5,10 @@ use std::{ }; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use zk_evm::zkevm_opcode_defs::FarCallOpcode; use zksync_system_constants::BOOTLOADER_ADDRESS; use zksync_utils::u256_to_h256; -use crate::{Address, U256}; +use crate::{zk_evm_types::FarCallOpcode, Address, U256}; #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] pub enum VmTrace { diff --git a/core/lib/types/src/vm_version.rs b/core/lib/types/src/vm_version.rs index 0f0fe4d337fc..2a4e9dc3ef2e 100644 --- a/core/lib/types/src/vm_version.rs +++ b/core/lib/types/src/vm_version.rs @@ -8,11 +8,12 @@ pub enum VmVersion { VmVirtualBlocks, VmVirtualBlocksRefundsEnhancement, VmBoojumIntegration, + Vm1_4_1, } impl VmVersion { /// Returns the latest supported VM version. pub const fn latest() -> VmVersion { - Self::VmBoojumIntegration + Self::Vm1_4_1 } } diff --git a/core/lib/types/src/zk_evm_types.rs b/core/lib/types/src/zk_evm_types.rs new file mode 100644 index 000000000000..a7973ab36fec --- /dev/null +++ b/core/lib/types/src/zk_evm_types.rs @@ -0,0 +1,30 @@ +use zksync_basic_types::{Address, U256}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(u8)] +pub enum FarCallOpcode { + Normal = 0, + Delegate, + Mimic, +} + +/// Struct representing the VM timestamp +#[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, PartialOrd, Ord, +)] +pub struct Timestamp(pub u32); + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] +pub struct LogQuery { + pub timestamp: Timestamp, + pub tx_number_in_block: u16, + pub aux_byte: u8, + pub shard_id: u8, + pub address: Address, + pub key: U256, + pub read_value: U256, + pub written_value: U256, + pub rw_flag: bool, + pub rollback: bool, + pub is_service: bool, +} diff --git a/core/lib/utils/Cargo.toml b/core/lib/utils/Cargo.toml index 64b100d257ec..5561f9b36da0 100644 --- a/core/lib/utils/Cargo.toml +++ b/core/lib/utils/Cargo.toml @@ -14,8 +14,8 @@ zksync_basic_types = { path = "../../lib/basic_types" } zk_evm = { git = "https://github.com/matter-labs/era-zk_evm.git", tag = "v1.3.3-rc2" } vlog = { path = "../../lib/vlog" } -num = { version = "0.3.1", features = ["serde"] } -bigdecimal = { version = "0.2.2", features = ["serde"] } +bigdecimal = { version = "0.3.0", features = ["serde"] } +num = { version = "0.4.0", features = ["serde"] } serde = { version = "1.0", features = ["derive"] } tokio = { version = "1", features = ["time"] } tracing = "0.1" diff --git a/core/lib/utils/src/bytecode.rs b/core/lib/utils/src/bytecode.rs index c533642d240f..f9554c6f72bd 100644 --- a/core/lib/utils/src/bytecode.rs +++ b/core/lib/utils/src/bytecode.rs @@ -58,7 +58,7 @@ pub fn compress_bytecode(code: &[u8]) -> Result, FailedToCompressBytecod return Err(FailedToCompressBytecodeError::DictionaryOverflow); } - // Fill the dictionary with the pmost popular chunks. + // Fill the dictionary with the most popular chunks. // The most popular chunks will be encoded with the smallest indexes, so that // the 255 most popular chunks will be encoded with one zero byte. // And the encoded data will be filled with more zeros, so @@ -214,9 +214,9 @@ mod test { let example_code = hex::decode("0000000000000000111111111111111111111111111111112222222222222222") .unwrap(); - // The size of the dictionary should be 0x0003 - // The dictionary itself should put the most common chunk first, i.e. 0x1111111111111111 - // Then, the ordering does not matter, but the algorithm will return the one with the highest position, i.e. 0x2222222222222222 + // The size of the dictionary should be `0x0003` + // The dictionary itself should put the most common chunk first, i.e. `0x1111111111111111` + // Then, the ordering does not matter, but the algorithm will return the one with the highest position, i.e. `0x2222222222222222` let expected_encoding = hex::decode("00031111111111111111222222222222222200000000000000000002000000000001") .unwrap(); diff --git a/core/lib/utils/src/wait_for_tasks.rs b/core/lib/utils/src/wait_for_tasks.rs index 74bb57f1fdb4..eddb2db47334 100644 --- a/core/lib/utils/src/wait_for_tasks.rs +++ b/core/lib/utils/src/wait_for_tasks.rs @@ -25,7 +25,7 @@ pub async fn wait_for_tasks( } } Ok(Err(err)) => { - let err = format!("One of the tokio actors unexpectedly finished with error: {err}"); + let err = format!("One of the tokio actors unexpectedly finished with error: {err:#}"); tracing::error!("{err}"); vlog::capture_message(&err, vlog::AlertLevel::Warning); if let Some(graceful_shutdown) = graceful_shutdown { @@ -36,9 +36,7 @@ pub async fn wait_for_tasks( let is_panic = error.is_panic(); let panic_message = try_extract_panic_message(error); - tracing::info!( - "One of the tokio actors unexpectedly finished with error: {panic_message}" - ); + tracing::info!("One of the tokio actors panicked: {panic_message}"); if is_panic { if let Some(particular_alerts) = particular_crypto_alerts { diff --git a/core/lib/test_account/Cargo.toml b/core/lib/vm_utils/Cargo.toml similarity index 67% rename from core/lib/test_account/Cargo.toml rename to core/lib/vm_utils/Cargo.toml index 572b5c2d09c7..f2efb0c8773a 100644 --- a/core/lib/test_account/Cargo.toml +++ b/core/lib/vm_utils/Cargo.toml @@ -1,21 +1,21 @@ [package] -name = "zksync_test_account" +name = "vm_utils" version = "0.1.0" -edition = "2018" +edition = "2021" authors = ["The Matter Labs Team "] homepage = "https://zksync.io/" repository = "https://github.com/matter-labs/zksync-era" license = "MIT OR Apache-2.0" keywords = ["blockchain", "zksync"] categories = ["cryptography"] -readme = "README.md" [dependencies] +multivm = { path = "../multivm" } zksync_types = { path = "../types" } -zksync_system_constants = { path = "../constants" } +zksync_dal = { path = "../dal" } +zksync_state = { path = "../state" } +tokio = { version = "1" } +anyhow = "1.0" +tracing = "0.1" zksync_utils = { path = "../utils" } -zksync_eth_signer = { path = "../eth_signer" } zksync_contracts = { path = "../contracts" } - -hex = "0.4" -ethabi = "18.0.0" diff --git a/core/lib/zksync_core/src/basic_witness_input_producer/vm_interactions.rs b/core/lib/vm_utils/src/lib.rs similarity index 91% rename from core/lib/zksync_core/src/basic_witness_input_producer/vm_interactions.rs rename to core/lib/vm_utils/src/lib.rs index e655112fade2..a04ad45f7483 100644 --- a/core/lib/zksync_core/src/basic_witness_input_producer/vm_interactions.rs +++ b/core/lib/vm_utils/src/lib.rs @@ -1,3 +1,5 @@ +pub mod storage; + use anyhow::{anyhow, Context}; use multivm::{ interface::{VmInterface, VmInterfaceHistoryEnabled}, @@ -9,14 +11,14 @@ use zksync_dal::StorageProcessor; use zksync_state::{PostgresStorage, StoragePtr, StorageView, WriteStorage}; use zksync_types::{L1BatchNumber, L2ChainId, Transaction}; -use crate::state_keeper::io::common::load_l1_batch_params; +use crate::storage::load_l1_batch_params; -pub(super) type VmAndStorage<'a> = ( +pub type VmAndStorage<'a> = ( VmInstance>, HistoryEnabled>, StoragePtr>>, ); -pub(super) fn create_vm( +pub fn create_vm( rt_handle: Handle, l1_batch_number: L1BatchNumber, mut connection: StorageProcessor<'_>, @@ -39,10 +41,10 @@ pub(super) fn create_vm( .block_on( connection .blocks_dal() - .get_fee_address_for_l1_batch(l1_batch_number), + .get_fee_address_for_miniblock(miniblock_number + 1), )? .with_context(|| { - format!("l1_batch_number {l1_batch_number:?} must have fee_address_account") + format!("l1_batch_number {l1_batch_number:?} must have fee_account_address") })?; // In the state keeper, this value is used to reject execution. @@ -66,7 +68,7 @@ pub(super) fn create_vm( Ok((vm, storage_view)) } -pub(super) fn execute_tx( +pub fn execute_tx( tx: &Transaction, vm: &mut VmInstance, ) -> anyhow::Result<()> { @@ -74,6 +76,7 @@ pub(super) fn execute_tx( vm.make_snapshot(); if vm .execute_transaction_with_bytecode_compression(tx.clone(), true) + .0 .is_ok() { vm.pop_snapshot_no_rollback(); @@ -84,6 +87,7 @@ pub(super) fn execute_tx( vm.rollback_to_the_latest_snapshot(); if vm .execute_transaction_with_bytecode_compression(tx.clone(), false) + .0 .is_err() { return Err(anyhow!("compression can't fail if we don't apply it")); diff --git a/core/lib/vm_utils/src/storage.rs b/core/lib/vm_utils/src/storage.rs new file mode 100644 index 000000000000..53298e44562b --- /dev/null +++ b/core/lib/vm_utils/src/storage.rs @@ -0,0 +1,163 @@ +use std::time::{Duration, Instant}; + +use multivm::{ + interface::{L1BatchEnv, L2BlockEnv, SystemEnv, TxExecutionMode}, + vm_latest::constants::BLOCK_GAS_LIMIT, +}; +use zksync_contracts::BaseSystemContracts; +use zksync_dal::StorageProcessor; +use zksync_types::{ + fee_model::BatchFeeInput, Address, L1BatchNumber, L2ChainId, MiniblockNumber, + ProtocolVersionId, H256, U256, ZKPORTER_IS_AVAILABLE, +}; +use zksync_utils::{h256_to_u256, u256_to_h256}; + +pub async fn load_l1_batch_params( + storage: &mut StorageProcessor<'_>, + current_l1_batch_number: L1BatchNumber, + fee_account: Address, + validation_computational_gas_limit: u32, + chain_id: L2ChainId, +) -> Option<(SystemEnv, L1BatchEnv)> { + // If miniblock doesn't exist (for instance if it's pending), it means that there is no unsynced state (i.e. no transactions + // were executed after the last sealed batch). + let pending_miniblock_number = { + let (_, last_miniblock_number_included_in_l1_batch) = storage + .blocks_dal() + .get_miniblock_range_of_l1_batch(current_l1_batch_number - 1) + .await + .unwrap() + .unwrap(); + last_miniblock_number_included_in_l1_batch + 1 + }; + let pending_miniblock_header = storage + .blocks_dal() + .get_miniblock_header(pending_miniblock_number) + .await + .unwrap()?; + + tracing::info!("Getting previous batch hash"); + let (previous_l1_batch_hash, _) = + wait_for_prev_l1_batch_params(storage, current_l1_batch_number).await; + + tracing::info!("Getting previous miniblock hash"); + let prev_miniblock_hash = storage + .blocks_dal() + .get_miniblock_header(pending_miniblock_number - 1) + .await + .unwrap() + .unwrap() + .hash; + + let base_system_contracts = storage + .storage_dal() + .get_base_system_contracts( + pending_miniblock_header + .base_system_contracts_hashes + .bootloader, + pending_miniblock_header + .base_system_contracts_hashes + .default_aa, + ) + .await; + + tracing::info!("Previous l1_batch_hash: {}", previous_l1_batch_hash); + Some(l1_batch_params( + current_l1_batch_number, + fee_account, + pending_miniblock_header.timestamp, + previous_l1_batch_hash, + pending_miniblock_header.batch_fee_input, + pending_miniblock_number, + prev_miniblock_hash, + base_system_contracts, + validation_computational_gas_limit, + pending_miniblock_header + .protocol_version + .expect("`protocol_version` must be set for pending miniblock"), + pending_miniblock_header.virtual_blocks, + chain_id, + )) +} + +pub async fn wait_for_prev_l1_batch_params( + storage: &mut StorageProcessor<'_>, + number: L1BatchNumber, +) -> (U256, u64) { + if number == L1BatchNumber(0) { + return (U256::default(), 0); + } + wait_for_l1_batch_params_unchecked(storage, number - 1).await +} + +/// # Warning +/// +/// If invoked for a `L1BatchNumber` of a non-existent l1 batch, will block current thread indefinitely. +async fn wait_for_l1_batch_params_unchecked( + storage: &mut StorageProcessor<'_>, + number: L1BatchNumber, +) -> (U256, u64) { + // If the state root is not known yet, this duration will be used to back off in the while loops + const SAFE_STATE_ROOT_INTERVAL: Duration = Duration::from_millis(100); + + let stage_started_at: Instant = Instant::now(); + loop { + let data = storage + .blocks_dal() + .get_l1_batch_state_root_and_timestamp(number) + .await + .unwrap(); + if let Some((root_hash, timestamp)) = data { + tracing::trace!( + "Waiting for hash of L1 batch #{number} took {:?}", + stage_started_at.elapsed() + ); + return (h256_to_u256(root_hash), timestamp); + } + + tokio::time::sleep(SAFE_STATE_ROOT_INTERVAL).await; + } +} + +/// Returns the parameters required to initialize the VM for the next L1 batch. +#[allow(clippy::too_many_arguments)] +pub fn l1_batch_params( + current_l1_batch_number: L1BatchNumber, + fee_account: Address, + l1_batch_timestamp: u64, + previous_batch_hash: U256, + fee_input: BatchFeeInput, + first_miniblock_number: MiniblockNumber, + prev_miniblock_hash: H256, + base_system_contracts: BaseSystemContracts, + validation_computational_gas_limit: u32, + protocol_version: ProtocolVersionId, + virtual_blocks: u32, + chain_id: L2ChainId, +) -> (SystemEnv, L1BatchEnv) { + ( + SystemEnv { + zk_porter_available: ZKPORTER_IS_AVAILABLE, + version: protocol_version, + base_system_smart_contracts: base_system_contracts, + gas_limit: BLOCK_GAS_LIMIT, + execution_mode: TxExecutionMode::VerifyExecute, + default_validation_computational_gas_limit: validation_computational_gas_limit, + chain_id, + }, + L1BatchEnv { + previous_batch_hash: Some(u256_to_h256(previous_batch_hash)), + number: current_l1_batch_number, + timestamp: l1_batch_timestamp, + fee_input, + fee_account, + enforced_base_fee: None, + first_l2_block: L2BlockEnv { + number: first_miniblock_number.0, + timestamp: l1_batch_timestamp, + prev_block_hash: prev_miniblock_hash, + max_virtual_blocks_to_create: virtual_blocks, + }, + }, + ) +} diff --git a/core/lib/web3_decl/Cargo.toml b/core/lib/web3_decl/Cargo.toml index f88ae989fecf..df82880d3c85 100644 --- a/core/lib/web3_decl/Cargo.toml +++ b/core/lib/web3_decl/Cargo.toml @@ -15,7 +15,7 @@ serde = "1.0" serde_json = "1.0" rlp = "0.5.0" thiserror = "1.0" -bigdecimal = { version = "0.2.2", features = ["serde"] } +bigdecimal = { version = "0.3.0", features = ["serde"] } jsonrpsee = { version = "0.21.0", default-features = false, features = [ "macros", ] } diff --git a/core/lib/web3_decl/src/error.rs b/core/lib/web3_decl/src/error.rs index 13f88c66c651..f2c77c743c54 100644 --- a/core/lib/web3_decl/src/error.rs +++ b/core/lib/web3_decl/src/error.rs @@ -1,12 +1,16 @@ //! Definition of errors that can occur in the zkSync Web3 API. use thiserror::Error; -use zksync_types::api::SerializationTransactionError; +use zksync_types::{api::SerializationTransactionError, L1BatchNumber, MiniblockNumber}; #[derive(Debug, Error)] pub enum Web3Error { #[error("Block with such an ID doesn't exist yet")] NoBlock, + #[error("Block with such an ID is pruned; the first retained block is {0}")] + PrunedBlock(MiniblockNumber), + #[error("L1 batch with such an ID is pruned; the first retained L1 batch is {0}")] + PrunedL1Batch(L1BatchNumber), #[error("Request timeout")] RequestTimeout, #[error("Internal error")] diff --git a/core/lib/web3_decl/src/namespaces/eth.rs b/core/lib/web3_decl/src/namespaces/eth.rs index 5ed49355fdd1..8fa3b1532056 100644 --- a/core/lib/web3_decl/src/namespaces/eth.rs +++ b/core/lib/web3_decl/src/namespaces/eth.rs @@ -3,7 +3,7 @@ use jsonrpsee::{ proc_macros::rpc, }; use zksync_types::{ - api::{BlockIdVariant, BlockNumber, Transaction, TransactionVariant}, + api::{BlockId, BlockIdVariant, BlockNumber, Transaction, TransactionVariant}, transaction_request::CallRequest, Address, H256, }; @@ -86,6 +86,9 @@ pub trait EthNamespace { block_number: BlockNumber, ) -> RpcResult>; + #[method(name = "getBlockReceipts")] + async fn get_block_receipts(&self, block_id: BlockId) -> RpcResult>; + #[method(name = "getBlockTransactionCountByHash")] async fn get_block_transaction_count_by_hash( &self, diff --git a/core/lib/web3_decl/src/namespaces/zks.rs b/core/lib/web3_decl/src/namespaces/zks.rs index 1a8922dcb28b..a9eddaa03122 100644 --- a/core/lib/web3_decl/src/namespaces/zks.rs +++ b/core/lib/web3_decl/src/namespaces/zks.rs @@ -8,6 +8,7 @@ use zksync_types::{ TransactionDetails, }, fee::Fee, + fee_model::FeeParams, transaction_request::CallRequest, Address, L1BatchNumber, MiniblockNumber, H256, U256, U64, }; @@ -101,6 +102,9 @@ pub trait ZksNamespace { #[method(name = "getL1GasPrice")] async fn get_l1_gas_price(&self) -> RpcResult; + #[method(name = "getFeeParams")] + async fn get_fee_params(&self) -> RpcResult; + #[method(name = "getProtocolVersion")] async fn get_protocol_version( &self, diff --git a/core/lib/zksync_core/Cargo.toml b/core/lib/zksync_core/Cargo.toml index ce89e099397a..032e58d2bcd1 100644 --- a/core/lib/zksync_core/Cargo.toml +++ b/core/lib/zksync_core/Cargo.toml @@ -9,27 +9,31 @@ license = "MIT OR Apache-2.0" keywords = ["blockchain", "zksync"] categories = ["cryptography"] +links = "zksync_core_proto" + [dependencies] vise = { git = "https://github.com/matter-labs/vise.git", version = "0.1.0", rev = "1c9cc500e92cf9ea052b230e114a6f9cce4fb2c1" } zksync_state = { path = "../state" } +vm_utils = { path = "../vm_utils" } zksync_types = { path = "../types" } zksync_dal = { path = "../dal" } zksync_config = { path = "../config" } +zksync_env_config = { path = "../env_config" } zksync_utils = { path = "../utils" } zksync_contracts = { path = "../contracts" } zksync_system_constants = { path = "../../lib/constants" } zksync_commitment_utils = { path = "../commitment_utils" } zksync_eth_client = { path = "../eth_client" } zksync_eth_signer = { path = "../eth_signer" } +zksync_l1_contract_interface = { path = "../l1_contract_interface" } zksync_mempool = { path = "../mempool" } -zksync_prover_utils = { path = "../prover_utils" } zksync_queued_job_processor = { path = "../queued_job_processor" } zksync_circuit_breaker = { path = "../circuit_breaker" } zksync_storage = { path = "../storage" } zksync_merkle_tree = { path = "../merkle_tree" } zksync_mini_merkle_tree = { path = "../mini_merkle_tree" } -zksync_verification_key_generator_and_server = { path = "../../bin/verification_key_generator_and_server" } prometheus_exporter = { path = "../prometheus_exporter" } +zksync_prover_interface = { path = "../prover_interface" } zksync_web3_decl = { path = "../web3_decl", default-features = false, features = [ "server", "client", @@ -39,13 +43,16 @@ zksync_health_check = { path = "../health_check" } vlog = { path = "../vlog" } multivm = { path = "../multivm" } + # Consensus dependenices -zksync_concurrency = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "84cdd9e45fd84bc1fac0b394c899ae33aef91afa" } -zksync_consensus_roles = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "84cdd9e45fd84bc1fac0b394c899ae33aef91afa" } -zksync_consensus_storage = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "84cdd9e45fd84bc1fac0b394c899ae33aef91afa" } -zksync_consensus_executor = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "84cdd9e45fd84bc1fac0b394c899ae33aef91afa" } -zksync_consensus_bft = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "84cdd9e45fd84bc1fac0b394c899ae33aef91afa" } -zksync_protobuf = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "84cdd9e45fd84bc1fac0b394c899ae33aef91afa" } +zksync_concurrency = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } +zksync_consensus_crypto = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } +zksync_consensus_roles = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } +zksync_consensus_storage = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } +zksync_consensus_executor = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } +zksync_consensus_bft = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } +zksync_consensus_utils = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } +zksync_protobuf = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } prost = "0.12.1" serde = { version = "1.0", features = ["derive"] } @@ -64,7 +71,7 @@ async-trait = "0.1" bitflags = "1.3.2" num = { version = "0.3.1", features = ["serde"] } -bigdecimal = { version = "0.2.2", features = ["serde"] } +bigdecimal = { version = "0.3.0", features = ["serde"] } reqwest = { version = "0.11", features = ["blocking", "json"] } hex = "0.4" lru = { version = "0.12.1", default-features = false } @@ -78,7 +85,6 @@ axum = { version = "0.6.19", default-features = false, features = [ ] } once_cell = "1.7" - actix-rt = "2.2.0" actix-cors = "0.6.0-beta.2" actix-web = "4.0.0-beta.8" @@ -86,7 +92,7 @@ actix-web = "4.0.0-beta.8" tracing = "0.1.26" [dev-dependencies] -zksync_test_account = { path = "../test_account" } +zksync_test_account = { path = "../../tests/test_account" } assert_matches = "1.5" jsonrpsee = "0.21.0" @@ -94,4 +100,4 @@ tempfile = "3.0.2" test-casing = "0.1.2" [build-dependencies] -zksync_protobuf_build = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "84cdd9e45fd84bc1fac0b394c899ae33aef91afa" } +zksync_protobuf_build = { version = "0.1.0", git = "https://github.com/matter-labs/era-consensus.git", rev = "5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" } diff --git a/core/lib/zksync_core/build.rs b/core/lib/zksync_core/build.rs index 7e8cc45bb8ce..25b323b9ff1e 100644 --- a/core/lib/zksync_core/build.rs +++ b/core/lib/zksync_core/build.rs @@ -5,8 +5,8 @@ fn main() { proto_root: "zksync/core/consensus".into(), dependencies: vec![], protobuf_crate: "::zksync_protobuf".parse().unwrap(), - is_public: false, + is_public: true, } .generate() - .expect("generate()"); + .unwrap(); } diff --git a/core/lib/zksync_core/src/api_server/contract_verification/mod.rs b/core/lib/zksync_core/src/api_server/contract_verification/mod.rs index a1bf980a49a1..27d36429d035 100644 --- a/core/lib/zksync_core/src/api_server/contract_verification/mod.rs +++ b/core/lib/zksync_core/src/api_server/contract_verification/mod.rs @@ -13,7 +13,7 @@ mod api_decl; mod api_impl; mod metrics; -fn start_server(api: RestApi, bind_to: SocketAddr, threads: usize) -> Server { +fn start_server(api: RestApi, bind_to: SocketAddr) -> Server { HttpServer::new(move || { let api = api.clone(); App::new() @@ -26,13 +26,12 @@ fn start_server(api: RestApi, bind_to: SocketAddr, threads: usize) -> Server { .allow_any_method(), ) .service(api.into_scope()) - // Endpoint needed for js isReachable + // Endpoint needed for js `isReachable` .route( "/favicon.ico", web::get().to(|| async { HttpResponse::Ok().finish() }), ) }) - .workers(threads) .bind(bind_to) .unwrap() .shutdown_timeout(60) @@ -58,10 +57,9 @@ pub fn start_server_thread_detached( actix_rt::System::new().block_on(async move { let bind_address = api_config.bind_addr(); - let threads = api_config.threads_per_server as usize; let api = RestApi::new(master_connection_pool, replica_connection_pool); - let server = start_server(api, bind_address, threads); + let server = start_server(api, bind_address); let close_handle = server.handle(); actix_rt::spawn(async move { if stop_receiver.changed().await.is_ok() { diff --git a/core/lib/zksync_core/src/api_server/execution_sandbox/apply.rs b/core/lib/zksync_core/src/api_server/execution_sandbox/apply.rs index 4360519d1e51..f987af3aa4bd 100644 --- a/core/lib/zksync_core/src/api_server/execution_sandbox/apply.rs +++ b/core/lib/zksync_core/src/api_server/execution_sandbox/apply.rs @@ -8,12 +8,14 @@ use std::time::{Duration, Instant}; +use anyhow::Context as _; use multivm::{ interface::{L1BatchEnv, L2BlockEnv, SystemEnv, VmInterface}, + utils::adjust_pubdata_price_for_tx, vm_latest::{constants::BLOCK_GAS_LIMIT, HistoryDisabled}, VmInstance, }; -use zksync_dal::{ConnectionPool, SqlxError, StorageProcessor}; +use zksync_dal::{ConnectionPool, StorageProcessor}; use zksync_state::{PostgresStorage, ReadStorage, StorageView, WriteStorage}; use zksync_system_constants::{ SYSTEM_CONTEXT_ADDRESS, SYSTEM_CONTEXT_CURRENT_L2_BLOCK_INFO_POSITION, @@ -22,6 +24,7 @@ use zksync_system_constants::{ use zksync_types::{ api, block::{pack_block_info, unpack_block_info, MiniblockHasher}, + fee_model::BatchFeeInput, get_nonce_key, utils::{decompose_full_nonce, nonces_to_full_nonce, storage_key_for_eth_balance}, AccountTreeId, L1BatchNumber, MiniblockNumber, Nonce, ProtocolVersionId, StorageKey, @@ -33,11 +36,16 @@ use super::{ vm_metrics::{self, SandboxStage, SANDBOX_METRICS}, BlockArgs, TxExecutionArgs, TxSharedArgs, VmPermit, }; +use crate::utils::projected_first_l1_batch; #[allow(clippy::too_many_arguments)] pub(super) fn apply_vm_in_sandbox( vm_permit: VmPermit, shared_args: TxSharedArgs, + // If `true`, then the batch's L1/pubdata gas price will be adjusted so that the transaction's gas per pubdata limit is <= + // to the one in the block. This is often helpful in case we want the transaction validation to work regardless of the + // current L1 prices for gas or pubdata. + adjust_pubdata_price: bool, execution_args: &TxExecutionArgs, connection_pool: &ConnectionPool, tx: Transaction, @@ -46,14 +54,14 @@ pub(super) fn apply_vm_in_sandbox( &mut VmInstance>, HistoryDisabled>, Transaction, ) -> T, -) -> T { +) -> anyhow::Result { let stage_started_at = Instant::now(); let span = tracing::debug_span!("initialization").entered(); let rt_handle = vm_permit.rt_handle(); let mut connection = rt_handle .block_on(connection_pool.access_storage_tagged("api")) - .unwrap(); + .context("failed acquiring DB connection")?; let connection_acquire_time = stage_started_at.elapsed(); // We don't want to emit too many logs. if connection_acquire_time > Duration::from_millis(10) { @@ -69,9 +77,10 @@ pub(super) fn apply_vm_in_sandbox( vm_l1_batch_number, l1_batch_timestamp, protocol_version, + historical_fee_input, } = rt_handle .block_on(block_args.resolve_block_info(&mut connection)) - .expect("Failed resolving block numbers"); + .with_context(|| format!("failed resolving block numbers for {block_args:?}"))?; let resolve_time = resolve_started_at.elapsed(); // We don't want to emit too many logs. if resolve_time > Duration::from_millis(10) { @@ -88,8 +97,12 @@ pub(super) fn apply_vm_in_sandbox( } let mut l2_block_info_to_reset = None; - let current_l2_block_info = - rt_handle.block_on(read_l2_block_info(&mut connection, state_l2_block_number)); + let current_l2_block_info = rt_handle + .block_on(StoredL2BlockInfo::new( + &mut connection, + state_l2_block_number, + )) + .context("failed reading L2 block info")?; let next_l2_block_info = if block_args.is_pending_miniblock() { L2BlockEnv { number: current_l2_block_info.l2_block_number + 1, @@ -102,7 +115,7 @@ pub(super) fn apply_vm_in_sandbox( } else if current_l2_block_info.l2_block_number == 0 { // Special case: // - For environments, where genesis block was created before virtual block upgrade it doesn't matter what we put here. - // - Otherwise, we need to put actual values here. We cannot create next l2 block with block_number=0 and max_virtual_blocks_to_create=0 + // - Otherwise, we need to put actual values here. We cannot create next L2 block with block_number=0 and `max_virtual_blocks_to_create=0` // because of SystemContext requirements. But, due to intrinsics of SystemContext, block.number still will be resolved to 0. L2BlockEnv { number: 1, @@ -113,10 +126,13 @@ pub(super) fn apply_vm_in_sandbox( } else { // We need to reset L2 block info in storage to process transaction in the current block context. // Actual resetting will be done after `storage_view` is created. - let prev_l2_block_info = rt_handle.block_on(read_l2_block_info( - &mut connection, - state_l2_block_number - 1, - )); + let prev_l2_block_info = rt_handle + .block_on(StoredL2BlockInfo::new( + &mut connection, + state_l2_block_number - 1, + )) + .context("failed reading previous L2 block info")?; + l2_block_info_to_reset = Some(prev_l2_block_info); L2BlockEnv { number: current_l2_block_info.l2_block_number, @@ -175,14 +191,26 @@ pub(super) fn apply_vm_in_sandbox( let TxSharedArgs { operator_account, - l1_gas_price, - fair_l2_gas_price, + fee_input, base_system_contracts, validation_computational_gas_limit, chain_id, .. } = shared_args; + // In case we are executing in a past block, we'll + // use the historical fee data. + let fee_input = historical_fee_input.unwrap_or(fee_input); + let fee_input = if adjust_pubdata_price { + adjust_pubdata_price_for_tx( + fee_input, + tx.gas_per_pubdata_byte_limit(), + protocol_version.into(), + ) + } else { + fee_input + }; + let system_env = SystemEnv { zk_porter_available: ZKPORTER_IS_AVAILABLE, version: protocol_version, @@ -193,13 +221,11 @@ pub(super) fn apply_vm_in_sandbox( default_validation_computational_gas_limit: validation_computational_gas_limit, chain_id, }; - let l1_batch_env = L1BatchEnv { previous_batch_hash: None, number: vm_l1_batch_number, timestamp: l1_batch_timestamp, - l1_gas_price, - fair_l2_gas_price, + fee_input, fee_account: *operator_account.address(), enforced_base_fee: execution_args.enforced_base_fee, first_l2_block: next_l2_block_info, @@ -234,63 +260,66 @@ pub(super) fn apply_vm_in_sandbox( ); drop(vm_permit); // Ensure that the permit lives until this point - result + Ok(result) } #[derive(Debug, Clone, Copy)] struct StoredL2BlockInfo { - pub l2_block_number: u32, - pub l2_block_timestamp: u64, - pub l2_block_hash: H256, - pub txs_rolling_hash: H256, + l2_block_number: u32, + l2_block_timestamp: u64, + l2_block_hash: H256, + txs_rolling_hash: H256, } -async fn read_l2_block_info( - connection: &mut StorageProcessor<'_>, - miniblock_number: MiniblockNumber, -) -> StoredL2BlockInfo { - let l2_block_info_key = StorageKey::new( - AccountTreeId::new(SYSTEM_CONTEXT_ADDRESS), - SYSTEM_CONTEXT_CURRENT_L2_BLOCK_INFO_POSITION, - ); - let l2_block_info = connection - .storage_web3_dal() - .get_historical_value_unchecked(&l2_block_info_key, miniblock_number) - .await - .unwrap(); - let (l2_block_number, l2_block_timestamp) = unpack_block_info(h256_to_u256(l2_block_info)); - - let l2_block_txs_rolling_hash_key = StorageKey::new( - AccountTreeId::new(SYSTEM_CONTEXT_ADDRESS), - SYSTEM_CONTEXT_CURRENT_TX_ROLLING_HASH_POSITION, - ); - let txs_rolling_hash = connection - .storage_web3_dal() - .get_historical_value_unchecked(&l2_block_txs_rolling_hash_key, miniblock_number) - .await - .unwrap(); - - let l2_block_hash = connection - .blocks_web3_dal() - .get_miniblock_hash(miniblock_number) - .await - .unwrap() - .unwrap(); - - StoredL2BlockInfo { - l2_block_number: l2_block_number as u32, - l2_block_timestamp, - l2_block_hash, - txs_rolling_hash, +impl StoredL2BlockInfo { + async fn new( + connection: &mut StorageProcessor<'_>, + miniblock_number: MiniblockNumber, + ) -> anyhow::Result { + let l2_block_info_key = StorageKey::new( + AccountTreeId::new(SYSTEM_CONTEXT_ADDRESS), + SYSTEM_CONTEXT_CURRENT_L2_BLOCK_INFO_POSITION, + ); + let l2_block_info = connection + .storage_web3_dal() + .get_historical_value_unchecked(&l2_block_info_key, miniblock_number) + .await + .context("failed reading L2 block info from VM state")?; + let (l2_block_number, l2_block_timestamp) = unpack_block_info(h256_to_u256(l2_block_info)); + + let l2_block_txs_rolling_hash_key = StorageKey::new( + AccountTreeId::new(SYSTEM_CONTEXT_ADDRESS), + SYSTEM_CONTEXT_CURRENT_TX_ROLLING_HASH_POSITION, + ); + let txs_rolling_hash = connection + .storage_web3_dal() + .get_historical_value_unchecked(&l2_block_txs_rolling_hash_key, miniblock_number) + .await + .context("failed reading transaction rolling hash from VM state")?; + + let l2_block_hash = connection + .blocks_web3_dal() + .get_miniblock_hash(miniblock_number) + .await + .with_context(|| format!("failed getting hash for miniblock #{miniblock_number}"))? + .with_context(|| format!("miniblock #{miniblock_number} disappeared from Postgres"))?; + + Ok(Self { + l2_block_number: l2_block_number as u32, + l2_block_timestamp, + l2_block_hash, + txs_rolling_hash, + }) } } #[derive(Debug)] -struct ResolvedBlockInfo { +pub(crate) struct ResolvedBlockInfo { pub state_l2_block_number: MiniblockNumber, pub vm_l1_batch_number: L1BatchNumber, pub l1_batch_timestamp: u64, pub protocol_version: ProtocolVersionId, + pub historical_fee_input: Option, } impl BlockArgs { @@ -301,64 +330,78 @@ impl BlockArgs { ) } - async fn resolve_block_info( + pub(crate) fn is_estimate_like(&self) -> bool { + matches!( + self.block_id, + api::BlockId::Number(api::BlockNumber::Pending) + | api::BlockId::Number(api::BlockNumber::Latest) + | api::BlockId::Number(api::BlockNumber::Committed) + ) + } + + pub(crate) async fn resolve_block_info( &self, connection: &mut StorageProcessor<'_>, - ) -> Result { - let (state_l2_block_number, vm_l1_batch_number, l1_batch_timestamp) = - if self.is_pending_miniblock() { - let sealed_l1_batch_number = connection - .blocks_web3_dal() - .get_sealed_l1_batch_number() - .await?; - let sealed_miniblock_header = connection - .blocks_dal() - .get_last_sealed_miniblock_header() - .await - .unwrap() - .expect("At least one miniblock must exist"); - - // Timestamp of the next L1 batch must be greater than the timestamp of the last miniblock. - let l1_batch_timestamp = - seconds_since_epoch().max(sealed_miniblock_header.timestamp + 1); - ( - sealed_miniblock_header.number, - sealed_l1_batch_number + 1, - l1_batch_timestamp, - ) - } else { - let l1_batch_number = connection - .storage_web3_dal() - .resolve_l1_batch_number_of_miniblock(self.resolved_block_number) - .await? - .expected_l1_batch(); - let l1_batch_timestamp = self.l1_batch_timestamp_s.unwrap_or_else(|| { - panic!( + ) -> anyhow::Result { + let (state_l2_block_number, vm_l1_batch_number, l1_batch_timestamp); + + if self.is_pending_miniblock() { + let sealed_l1_batch_number = + connection.blocks_dal().get_sealed_l1_batch_number().await?; + let sealed_miniblock_header = connection + .blocks_dal() + .get_last_sealed_miniblock_header() + .await? + .context("no miniblocks in storage")?; + + vm_l1_batch_number = match sealed_l1_batch_number { + Some(number) => number + 1, + None => projected_first_l1_batch(connection).await?, + }; + state_l2_block_number = sealed_miniblock_header.number; + // Timestamp of the next L1 batch must be greater than the timestamp of the last miniblock. + l1_batch_timestamp = seconds_since_epoch().max(sealed_miniblock_header.timestamp + 1); + } else { + vm_l1_batch_number = connection + .storage_web3_dal() + .resolve_l1_batch_number_of_miniblock(self.resolved_block_number) + .await? + .expected_l1_batch(); + l1_batch_timestamp = self.l1_batch_timestamp_s.unwrap_or_else(|| { + panic!( "L1 batch timestamp is `None`, `block_id`: {:?}, `resolved_block_number`: {}", self.block_id, self.resolved_block_number.0 ); - }); - - ( - self.resolved_block_number, - l1_batch_number, - l1_batch_timestamp, - ) - }; + }); + state_l2_block_number = self.resolved_block_number; + }; + + let historical_fee_input = if !self.is_estimate_like() { + let miniblock_header = connection + .blocks_dal() + .get_miniblock_header(self.resolved_block_number) + .await? + .context("The resolved miniblock is not in storage")?; + + Some(miniblock_header.batch_fee_input) + } else { + None + }; // Blocks without version specified are considered to be of `Version9`. // TODO: remove `unwrap_or` when protocol version ID will be assigned for each block. let protocol_version = connection .blocks_dal() .get_miniblock_protocol_version_id(state_l2_block_number) - .await - .unwrap() - .unwrap_or(ProtocolVersionId::Version9); + .await? + .unwrap_or(ProtocolVersionId::last_potentially_undefined()); + Ok(ResolvedBlockInfo { state_l2_block_number, vm_l1_batch_number, l1_batch_timestamp, protocol_version, + historical_fee_input, }) } } diff --git a/core/lib/zksync_core/src/api_server/execution_sandbox/error.rs b/core/lib/zksync_core/src/api_server/execution_sandbox/error.rs index c5928cfd8470..9d6d635a344c 100644 --- a/core/lib/zksync_core/src/api_server/execution_sandbox/error.rs +++ b/core/lib/zksync_core/src/api_server/execution_sandbox/error.rs @@ -64,6 +64,9 @@ impl From for SandboxExecutionError { Halt::ValidationOutOfGas => Self::AccountValidationFailed( "The validation of the transaction ran out of gas".to_string(), ), + Halt::FailedToPublishCompressedBytecodes => { + Self::UnexpectedVMBehavior("Failed to publish compressed bytecodes".to_string()) + } } } } diff --git a/core/lib/zksync_core/src/api_server/execution_sandbox/execute.rs b/core/lib/zksync_core/src/api_server/execution_sandbox/execute.rs index c900dd4e5a5a..20b5d7815507 100644 --- a/core/lib/zksync_core/src/api_server/execution_sandbox/execute.rs +++ b/core/lib/zksync_core/src/api_server/execution_sandbox/execute.rs @@ -1,7 +1,8 @@ //! Implementation of "executing" methods, e.g. `eth_call`. +use anyhow::Context as _; use multivm::{ - interface::{TxExecutionMode, VmExecutionMode, VmExecutionResultAndLogs, VmInterface}, + interface::{TxExecutionMode, VmExecutionResultAndLogs, VmInterface}, tracers::StorageInvocations, vm_latest::constants::ETH_CALL_GAS_LIMIT, MultiVMTracer, @@ -13,6 +14,8 @@ use zksync_types::{ PackedEthSignature, Transaction, U256, }; +#[cfg(test)] +use super::testonly::MockTransactionExecutor; use super::{apply, vm_metrics, ApiTracer, BlockArgs, TxSharedArgs, VmPermit}; #[derive(Debug)] @@ -73,115 +76,129 @@ impl TxExecutionArgs { } } -pub(crate) async fn execute_tx_eth_call( - vm_permit: VmPermit, - shared_args: TxSharedArgs, - connection_pool: ConnectionPool, - mut tx: L2Tx, - block_args: BlockArgs, - vm_execution_cache_misses_limit: Option, - custom_tracers: Vec, -) -> VmExecutionResultAndLogs { - let enforced_base_fee = tx.common_data.fee.max_fee_per_gas.as_u64(); - let execution_args = - TxExecutionArgs::for_eth_call(enforced_base_fee, vm_execution_cache_misses_limit); - - if tx.common_data.signature.is_empty() { - tx.common_data.signature = PackedEthSignature::default().serialize_packed().into(); - } - - // Protection against infinite-loop eth_calls and alike: - // limiting the amount of gas the call can use. - // We can't use BLOCK_ERGS_LIMIT here since the VM itself has some overhead. - tx.common_data.fee.gas_limit = ETH_CALL_GAS_LIMIT.into(); - let (vm_result, _) = execute_tx_in_sandbox( - vm_permit, - shared_args, - execution_args, - connection_pool, - tx.into(), - block_args, - custom_tracers, - ) - .await; - - vm_result +#[derive(Debug, Clone)] +pub(crate) struct TransactionExecutionOutput { + /// Output of the VM. + pub vm: VmExecutionResultAndLogs, + /// Execution metrics. + pub metrics: TransactionExecutionMetrics, + /// Were published bytecodes OK? + pub are_published_bytecodes_ok: bool, } -#[tracing::instrument(skip_all)] -pub(crate) async fn execute_tx_with_pending_state( - vm_permit: VmPermit, - mut shared_args: TxSharedArgs, - execution_args: TxExecutionArgs, - connection_pool: ConnectionPool, - tx: Transaction, -) -> (VmExecutionResultAndLogs, TransactionExecutionMetrics) { - let mut connection = connection_pool.access_storage_tagged("api").await.unwrap(); - let block_args = BlockArgs::pending(&mut connection).await; - drop(connection); - // In order for execution to pass smoothlessly, we need to ensure that block's required gasPerPubdata will be - // <= to the one in the transaction itself. - shared_args.adjust_l1_gas_price(tx.gas_per_pubdata_byte_limit()); - - execute_tx_in_sandbox( - vm_permit, - shared_args, - execution_args, - connection_pool, - tx, - block_args, - vec![], - ) - .await +/// Executor of transactions. +#[derive(Debug)] +pub(crate) enum TransactionExecutor { + Real, + #[cfg(test)] + Mock(MockTransactionExecutor), } -/// This method assumes that (block with number `resolved_block_number` is present in DB) -/// or (`block_id` is `pending` and block with number `resolved_block_number - 1` is present in DB) -#[allow(clippy::too_many_arguments)] -#[tracing::instrument(skip_all)] -async fn execute_tx_in_sandbox( - vm_permit: VmPermit, - shared_args: TxSharedArgs, - execution_args: TxExecutionArgs, - connection_pool: ConnectionPool, - tx: Transaction, - block_args: BlockArgs, - custom_tracers: Vec, -) -> (VmExecutionResultAndLogs, TransactionExecutionMetrics) { - let total_factory_deps = tx - .execute - .factory_deps - .as_ref() - .map_or(0, |deps| deps.len() as u16); - - let execution_result = tokio::task::spawn_blocking(move || { - let span = span!(Level::DEBUG, "execute_in_sandbox").entered(); - let result = apply::apply_vm_in_sandbox( - vm_permit, - shared_args, - &execution_args, - &connection_pool, - tx, - block_args, - |vm, tx| { - vm.push_transaction(tx); - let storage_invocation_tracer = - StorageInvocations::new(execution_args.missed_storage_invocation_limit); - let custom_tracers: Vec<_> = custom_tracers - .into_iter() - .map(|tracer| tracer.into_boxed()) - .chain(vec![storage_invocation_tracer.into_tracer_pointer()]) - .collect(); - vm.inspect(custom_tracers.into(), VmExecutionMode::OneTx) - }, - ); - span.exit(); - result - }) - .await - .unwrap(); - - let tx_execution_metrics = - vm_metrics::collect_tx_execution_metrics(total_factory_deps, &execution_result); - (execution_result, tx_execution_metrics) +impl TransactionExecutor { + /// This method assumes that (block with number `resolved_block_number` is present in DB) + /// or (`block_id` is `pending` and block with number `resolved_block_number - 1` is present in DB) + #[allow(clippy::too_many_arguments)] + #[tracing::instrument(skip_all)] + pub async fn execute_tx_in_sandbox( + &self, + vm_permit: VmPermit, + shared_args: TxSharedArgs, + // If `true`, then the batch's L1/pubdata gas price will be adjusted so that the transaction's gas per pubdata limit is <= + // to the one in the block. This is often helpful in case we want the transaction validation to work regardless of the + // current L1 prices for gas or pubdata. + adjust_pubdata_price: bool, + execution_args: TxExecutionArgs, + connection_pool: ConnectionPool, + tx: Transaction, + block_args: BlockArgs, + custom_tracers: Vec, + ) -> anyhow::Result { + #[cfg(test)] + if let Self::Mock(mock_executor) = self { + return mock_executor.execute_tx(&tx); + } + + let total_factory_deps = tx + .execute + .factory_deps + .as_ref() + .map_or(0, |deps| deps.len() as u16); + + let (published_bytecodes, execution_result) = tokio::task::spawn_blocking(move || { + let span = span!(Level::DEBUG, "execute_in_sandbox").entered(); + let result = apply::apply_vm_in_sandbox( + vm_permit, + shared_args, + adjust_pubdata_price, + &execution_args, + &connection_pool, + tx, + block_args, + |vm, tx| { + let storage_invocation_tracer = + StorageInvocations::new(execution_args.missed_storage_invocation_limit); + let custom_tracers: Vec<_> = custom_tracers + .into_iter() + .map(|tracer| tracer.into_boxed()) + .chain(vec![storage_invocation_tracer.into_tracer_pointer()]) + .collect(); + vm.inspect_transaction_with_bytecode_compression( + custom_tracers.into(), + tx, + true, + ) + }, + ); + span.exit(); + result + }) + .await + .context("transaction execution panicked")??; + + let metrics = + vm_metrics::collect_tx_execution_metrics(total_factory_deps, &execution_result); + Ok(TransactionExecutionOutput { + vm: execution_result, + metrics, + are_published_bytecodes_ok: published_bytecodes.is_ok(), + }) + } + + #[allow(clippy::too_many_arguments)] + pub async fn execute_tx_eth_call( + &self, + vm_permit: VmPermit, + shared_args: TxSharedArgs, + connection_pool: ConnectionPool, + mut tx: L2Tx, + block_args: BlockArgs, + vm_execution_cache_misses_limit: Option, + custom_tracers: Vec, + ) -> anyhow::Result { + let enforced_base_fee = tx.common_data.fee.max_fee_per_gas.as_u64(); + let execution_args = + TxExecutionArgs::for_eth_call(enforced_base_fee, vm_execution_cache_misses_limit); + + if tx.common_data.signature.is_empty() { + tx.common_data.signature = PackedEthSignature::default().serialize_packed().into(); + } + + // Protection against infinite-loop eth_calls and alike: + // limiting the amount of gas the call can use. + // We can't use `BLOCK_ERGS_LIMIT` here since the VM itself has some overhead. + tx.common_data.fee.gas_limit = ETH_CALL_GAS_LIMIT.into(); + let output = self + .execute_tx_in_sandbox( + vm_permit, + shared_args, + false, + execution_args, + connection_pool, + tx.into(), + block_args, + custom_tracers, + ) + .await?; + Ok(output.vm) + } } diff --git a/core/lib/zksync_core/src/api_server/execution_sandbox/mod.rs b/core/lib/zksync_core/src/api_server/execution_sandbox/mod.rs index 461be71c089f..3c3a8e9a36ad 100644 --- a/core/lib/zksync_core/src/api_server/execution_sandbox/mod.rs +++ b/core/lib/zksync_core/src/api_server/execution_sandbox/mod.rs @@ -1,18 +1,21 @@ use std::{sync::Arc, time::Duration}; -use multivm::vm_latest::utils::fee::derive_base_fee_and_gas_per_pubdata; +use anyhow::Context as _; use tokio::runtime::Handle; -use zksync_dal::{ConnectionPool, SqlxError, StorageProcessor}; +use zksync_dal::{ConnectionPool, StorageProcessor}; use zksync_state::{PostgresStorage, PostgresStorageCaches, ReadStorage, StorageView}; use zksync_system_constants::PUBLISH_BYTECODE_OVERHEAD; -use zksync_types::{api, AccountTreeId, L2ChainId, MiniblockNumber, U256}; +use zksync_types::{ + api, fee_model::BatchFeeInput, AccountTreeId, L1BatchNumber, L2ChainId, MiniblockNumber, +}; use zksync_utils::bytecode::{compress_bytecode, hash_bytecode}; use self::vm_metrics::SandboxStage; pub(super) use self::{ error::SandboxExecutionError, - execute::{execute_tx_eth_call, execute_tx_with_pending_state, TxExecutionArgs}, + execute::{TransactionExecutor, TxExecutionArgs}, tracers::ApiTracer, + validate::ValidationError, vm_metrics::{SubmitTxStage, SANDBOX_METRICS}, }; use super::tx_sender::MultiVMBaseSystemContracts; @@ -21,6 +24,10 @@ use super::tx_sender::MultiVMBaseSystemContracts; mod apply; mod error; mod execute; +#[cfg(test)] +pub(super) mod testonly; +#[cfg(test)] +mod tests; mod tracers; mod validate; mod vm_metrics; @@ -141,39 +148,17 @@ impl VmConcurrencyLimiter { } } -pub(super) fn adjust_l1_gas_price_for_tx( - l1_gas_price: u64, - fair_l2_gas_price: u64, - tx_gas_per_pubdata_limit: U256, -) -> u64 { - let (_, current_pubdata_price) = - derive_base_fee_and_gas_per_pubdata(l1_gas_price, fair_l2_gas_price); - if U256::from(current_pubdata_price) <= tx_gas_per_pubdata_limit { - // The current pubdata price is small enough - l1_gas_price - } else { - // gasPerPubdata = ceil(17 * l1gasprice / fair_l2_gas_price) - // gasPerPubdata <= 17 * l1gasprice / fair_l2_gas_price + 1 - // fair_l2_gas_price(gasPerPubdata - 1) / 17 <= l1gasprice - let l1_gas_price = U256::from(fair_l2_gas_price) - * (tx_gas_per_pubdata_limit - U256::from(1u32)) - / U256::from(17); - - l1_gas_price.as_u64() - } -} - async fn get_pending_state( connection: &mut StorageProcessor<'_>, -) -> (api::BlockId, MiniblockNumber) { +) -> anyhow::Result<(api::BlockId, MiniblockNumber)> { let block_id = api::BlockId::Number(api::BlockNumber::Pending); let resolved_block_number = connection .blocks_web3_dal() .resolve_block_id(block_id) .await - .unwrap() - .expect("Pending block should be present"); - (block_id, resolved_block_number) + .with_context(|| format!("failed resolving block ID {block_id:?}"))? + .context("pending block should always be present in Postgres")?; + Ok((block_id, resolved_block_number)) } /// Returns the number of the pubdata that the transaction will spend on factory deps. @@ -182,14 +167,17 @@ pub(super) async fn get_pubdata_for_factory_deps( connection_pool: &ConnectionPool, factory_deps: &[Vec], storage_caches: PostgresStorageCaches, -) -> u32 { +) -> anyhow::Result { if factory_deps.is_empty() { - return 0; // Shortcut for the common case allowing to not acquire DB connections etc. + return Ok(0); // Shortcut for the common case allowing to not acquire DB connections etc. } - let mut connection = connection_pool.access_storage_tagged("api").await.unwrap(); - let (_, block_number) = get_pending_state(&mut connection).await; - drop(connection); + let mut storage = connection_pool + .access_storage_tagged("api") + .await + .context("failed acquiring DB connection")?; + let (_, block_number) = get_pending_state(&mut storage).await?; + drop(storage); let rt_handle = Handle::current(); let connection_pool = connection_pool.clone(); @@ -197,7 +185,7 @@ pub(super) async fn get_pubdata_for_factory_deps( tokio::task::spawn_blocking(move || { let connection = rt_handle .block_on(connection_pool.access_storage_tagged("api")) - .unwrap(); + .context("failed acquiring DB connection")?; let storage = PostgresStorage::new(rt_handle, connection, block_number, false) .with_caches(storage_caches); let mut storage_view = StorageView::new(storage); @@ -214,24 +202,79 @@ pub(super) async fn get_pubdata_for_factory_deps( }; length as u32 + PUBLISH_BYTECODE_OVERHEAD }); - effective_lengths.sum() + anyhow::Ok(effective_lengths.sum()) }) .await - .unwrap() + .context("computing pubdata dependencies size panicked")? } /// Arguments for VM execution not specific to a particular transaction. #[derive(Debug, Clone)] pub(crate) struct TxSharedArgs { pub operator_account: AccountTreeId, - pub l1_gas_price: u64, - pub fair_l2_gas_price: u64, + pub fee_input: BatchFeeInput, pub base_system_contracts: MultiVMBaseSystemContracts, pub caches: PostgresStorageCaches, pub validation_computational_gas_limit: u32, pub chain_id: L2ChainId, } +/// Information about first L1 batch / miniblock in the node storage. +#[derive(Debug, Clone, Copy)] +pub(crate) struct BlockStartInfo { + /// Projected number of the first locally available miniblock. This miniblock is **not** + /// guaranteed to be present in the storage! + pub first_miniblock: MiniblockNumber, + /// Projected number of the first locally available L1 batch. This L1 batch is **not** + /// guaranteed to be present in the storage! + pub first_l1_batch: L1BatchNumber, +} + +impl BlockStartInfo { + pub async fn new(storage: &mut StorageProcessor<'_>) -> anyhow::Result { + let snapshot_recovery = storage + .snapshot_recovery_dal() + .get_applied_snapshot_status() + .await + .context("failed getting snapshot recovery status")?; + let snapshot_recovery = snapshot_recovery.as_ref(); + Ok(Self { + first_miniblock: snapshot_recovery + .map_or(MiniblockNumber(0), |recovery| recovery.miniblock_number + 1), + first_l1_batch: snapshot_recovery + .map_or(L1BatchNumber(0), |recovery| recovery.l1_batch_number + 1), + }) + } + + /// Checks whether a block with the specified ID is pruned and returns an error if it is. + /// The `Err` variant wraps the first non-pruned miniblock. + pub fn ensure_not_pruned_block(&self, block: api::BlockId) -> Result<(), MiniblockNumber> { + match block { + api::BlockId::Number(api::BlockNumber::Number(number)) + if number < self.first_miniblock.0.into() => + { + Err(self.first_miniblock) + } + api::BlockId::Number(api::BlockNumber::Earliest) + if self.first_miniblock > MiniblockNumber(0) => + { + Err(self.first_miniblock) + } + _ => Ok(()), + } + } +} + +#[derive(Debug, thiserror::Error)] +pub(crate) enum BlockArgsError { + #[error("Block is pruned; first retained block is {0}")] + Pruned(MiniblockNumber), + #[error("Block is missing, but can appear in the future")] + Missing, + #[error("Database error")] + Database(#[from] anyhow::Error), +} + /// Information about a block provided to VM. #[derive(Debug, Clone, Copy)] pub(crate) struct BlockArgs { @@ -241,50 +284,63 @@ pub(crate) struct BlockArgs { } impl BlockArgs { - async fn pending(connection: &mut StorageProcessor<'_>) -> Self { - let (block_id, resolved_block_number) = get_pending_state(connection).await; - Self { + pub(crate) async fn pending(connection: &mut StorageProcessor<'_>) -> anyhow::Result { + let (block_id, resolved_block_number) = get_pending_state(connection).await?; + Ok(Self { block_id, resolved_block_number, l1_batch_timestamp_s: None, - } + }) } /// Loads block information from DB. pub async fn new( connection: &mut StorageProcessor<'_>, block_id: api::BlockId, - ) -> Result, SqlxError> { + start_info: BlockStartInfo, + ) -> Result { + // We need to check that `block_id` is present in Postgres or can be present in the future + // (i.e., it does not refer to a pruned block). If called for a pruned block, the returned value + // (specifically, `l1_batch_timestamp_s`) will be nonsensical. + start_info + .ensure_not_pruned_block(block_id) + .map_err(BlockArgsError::Pruned)?; + if block_id == api::BlockId::Number(api::BlockNumber::Pending) { - return Ok(Some(BlockArgs::pending(connection).await)); + return Ok(BlockArgs::pending(connection).await?); } let resolved_block_number = connection .blocks_web3_dal() .resolve_block_id(block_id) - .await?; + .await + .with_context(|| format!("failed resolving block ID {block_id:?}"))?; let Some(resolved_block_number) = resolved_block_number else { - return Ok(None); + return Err(BlockArgsError::Missing); }; - let l1_batch_number = connection + let l1_batch = connection .storage_web3_dal() .resolve_l1_batch_number_of_miniblock(resolved_block_number) - .await? - .expected_l1_batch(); + .await + .with_context(|| { + format!("failed resolving L1 batch number of miniblock #{resolved_block_number}") + })?; let l1_batch_timestamp_s = connection .blocks_web3_dal() - .get_expected_l1_batch_timestamp(l1_batch_number) - .await?; - assert!( - l1_batch_timestamp_s.is_some(), - "Missing batch timestamp for non-pending block" - ); - Ok(Some(Self { + .get_expected_l1_batch_timestamp(&l1_batch) + .await + .with_context(|| format!("failed getting timestamp for {l1_batch:?}"))?; + if l1_batch_timestamp_s.is_none() { + // Can happen after snapshot recovery if no miniblocks are persisted yet. In this case, + // we cannot proceed; the issue will be resolved shortly. + return Err(BlockArgsError::Missing); + } + Ok(Self { block_id, resolved_block_number, l1_batch_timestamp_s, - })) + }) } pub fn resolved_block_number(&self) -> MiniblockNumber { diff --git a/core/lib/zksync_core/src/api_server/execution_sandbox/testonly.rs b/core/lib/zksync_core/src/api_server/execution_sandbox/testonly.rs new file mode 100644 index 000000000000..4eb33d45f2c5 --- /dev/null +++ b/core/lib/zksync_core/src/api_server/execution_sandbox/testonly.rs @@ -0,0 +1,79 @@ +use std::collections::HashMap; + +use multivm::interface::{ExecutionResult, VmExecutionResultAndLogs}; +use zksync_types::{ + fee::TransactionExecutionMetrics, l2::L2Tx, ExecuteTransactionCommon, Transaction, H256, +}; + +use super::{ + execute::{TransactionExecutionOutput, TransactionExecutor}, + validate::ValidationError, +}; + +#[derive(Debug, Default)] +pub(crate) struct MockTransactionExecutor { + call_responses: HashMap, TransactionExecutionOutput>, + tx_responses: HashMap, +} + +impl MockTransactionExecutor { + pub fn insert_call_response(&mut self, calldata: Vec, result: ExecutionResult) { + let output = TransactionExecutionOutput { + vm: VmExecutionResultAndLogs { + result, + logs: Default::default(), + statistics: Default::default(), + refunds: Default::default(), + }, + metrics: TransactionExecutionMetrics::default(), + are_published_bytecodes_ok: true, + }; + self.call_responses.insert(calldata, output); + } + + pub fn insert_tx_response(&mut self, tx_hash: H256, result: ExecutionResult) { + let output = TransactionExecutionOutput { + vm: VmExecutionResultAndLogs { + result, + logs: Default::default(), + statistics: Default::default(), + refunds: Default::default(), + }, + metrics: TransactionExecutionMetrics::default(), + are_published_bytecodes_ok: true, + }; + self.tx_responses.insert(tx_hash, output); + } + + pub fn validate_tx(&self, tx: &L2Tx) -> Result<(), ValidationError> { + self.tx_responses + .get(&tx.hash()) + .unwrap_or_else(|| panic!("Validating unexpected transaction: {tx:?}")); + Ok(()) + } + + pub fn execute_tx(&self, tx: &Transaction) -> anyhow::Result { + if let ExecuteTransactionCommon::L2(data) = &tx.common_data { + if data.input.is_none() { + // `Transaction` was obtained from a `CallRequest` + return Ok(self + .call_responses + .get(tx.execute.calldata()) + .unwrap_or_else(|| panic!("Executing unexpected call: {tx:?}")) + .clone()); + } + } + + Ok(self + .tx_responses + .get(&tx.hash()) + .unwrap_or_else(|| panic!("Executing unexpected transaction: {tx:?}")) + .clone()) + } +} + +impl From for TransactionExecutor { + fn from(executor: MockTransactionExecutor) -> Self { + Self::Mock(executor) + } +} diff --git a/core/lib/zksync_core/src/api_server/execution_sandbox/tests.rs b/core/lib/zksync_core/src/api_server/execution_sandbox/tests.rs new file mode 100644 index 000000000000..d18bf5dafd01 --- /dev/null +++ b/core/lib/zksync_core/src/api_server/execution_sandbox/tests.rs @@ -0,0 +1,155 @@ +//! Tests for the VM execution sandbox. + +use assert_matches::assert_matches; + +use super::*; +use crate::{ + genesis::{ensure_genesis_state, GenesisParams}, + utils::testonly::{create_miniblock, prepare_empty_recovery_snapshot}, +}; + +#[tokio::test] +async fn creating_block_args() { + let pool = ConnectionPool::test_pool().await; + let mut storage = pool.access_storage().await.unwrap(); + ensure_genesis_state(&mut storage, L2ChainId::default(), &GenesisParams::mock()) + .await + .unwrap(); + let miniblock = create_miniblock(1); + storage + .blocks_dal() + .insert_miniblock(&miniblock) + .await + .unwrap(); + + let pending_block_args = BlockArgs::pending(&mut storage).await.unwrap(); + assert_eq!( + pending_block_args.block_id, + api::BlockId::Number(api::BlockNumber::Pending) + ); + assert_eq!(pending_block_args.resolved_block_number, MiniblockNumber(2)); + assert_eq!(pending_block_args.l1_batch_timestamp_s, None); + + let start_info = BlockStartInfo::new(&mut storage).await.unwrap(); + assert_eq!(start_info.first_miniblock, MiniblockNumber(0)); + assert_eq!(start_info.first_l1_batch, L1BatchNumber(0)); + + let latest_block = api::BlockId::Number(api::BlockNumber::Latest); + let latest_block_args = BlockArgs::new(&mut storage, latest_block, start_info) + .await + .unwrap(); + assert_eq!(latest_block_args.block_id, latest_block); + assert_eq!(latest_block_args.resolved_block_number, MiniblockNumber(1)); + assert_eq!( + latest_block_args.l1_batch_timestamp_s, + Some(miniblock.timestamp) + ); + + let earliest_block = api::BlockId::Number(api::BlockNumber::Earliest); + let earliest_block_args = BlockArgs::new(&mut storage, earliest_block, start_info) + .await + .unwrap(); + assert_eq!(earliest_block_args.block_id, earliest_block); + assert_eq!( + earliest_block_args.resolved_block_number, + MiniblockNumber(0) + ); + assert_eq!(earliest_block_args.l1_batch_timestamp_s, Some(0)); + + let missing_block = api::BlockId::Number(100.into()); + let err = BlockArgs::new(&mut storage, missing_block, start_info) + .await + .unwrap_err(); + assert_matches!(err, BlockArgsError::Missing); +} + +#[tokio::test] +async fn creating_block_args_after_snapshot_recovery() { + let pool = ConnectionPool::test_pool().await; + let mut storage = pool.access_storage().await.unwrap(); + let snapshot_recovery = prepare_empty_recovery_snapshot(&mut storage, 23).await; + + let pending_block_args = BlockArgs::pending(&mut storage).await.unwrap(); + assert_eq!( + pending_block_args.block_id, + api::BlockId::Number(api::BlockNumber::Pending) + ); + assert_eq!( + pending_block_args.resolved_block_number, + snapshot_recovery.miniblock_number + 1 + ); + assert_eq!(pending_block_args.l1_batch_timestamp_s, None); + + let start_info = BlockStartInfo::new(&mut storage).await.unwrap(); + assert_eq!( + start_info.first_miniblock, + snapshot_recovery.miniblock_number + 1 + ); + assert_eq!( + start_info.first_l1_batch, + snapshot_recovery.l1_batch_number + 1 + ); + + let latest_block = api::BlockId::Number(api::BlockNumber::Latest); + let err = BlockArgs::new(&mut storage, latest_block, start_info) + .await + .unwrap_err(); + assert_matches!(err, BlockArgsError::Missing); + + let pruned_blocks = [ + api::BlockNumber::Earliest, + 0.into(), + snapshot_recovery.miniblock_number.0.into(), + ]; + for pruned_block in pruned_blocks { + let pruned_block = api::BlockId::Number(pruned_block); + let err = BlockArgs::new(&mut storage, pruned_block, start_info) + .await + .unwrap_err(); + assert_matches!(err, BlockArgsError::Pruned(_)); + } + + let missing_blocks = [ + api::BlockNumber::from(snapshot_recovery.miniblock_number.0 + 2), + 100.into(), + ]; + for missing_block in missing_blocks { + let missing_block = api::BlockId::Number(missing_block); + let err = BlockArgs::new(&mut storage, missing_block, start_info) + .await + .unwrap_err(); + assert_matches!(err, BlockArgsError::Missing); + } + + let miniblock = create_miniblock(snapshot_recovery.miniblock_number.0 + 1); + storage + .blocks_dal() + .insert_miniblock(&miniblock) + .await + .unwrap(); + + let latest_block_args = BlockArgs::new(&mut storage, latest_block, start_info) + .await + .unwrap(); + assert_eq!(latest_block_args.block_id, latest_block); + assert_eq!(latest_block_args.resolved_block_number, miniblock.number); + assert_eq!( + latest_block_args.l1_batch_timestamp_s, + Some(miniblock.timestamp) + ); + + for pruned_block in pruned_blocks { + let pruned_block = api::BlockId::Number(pruned_block); + let err = BlockArgs::new(&mut storage, pruned_block, start_info) + .await + .unwrap_err(); + assert_matches!(err, BlockArgsError::Pruned(_)); + } + for missing_block in missing_blocks { + let missing_block = api::BlockId::Number(missing_block); + let err = BlockArgs::new(&mut storage, missing_block, start_info) + .await + .unwrap_err(); + assert_matches!(err, BlockArgsError::Missing); + } +} diff --git a/core/lib/zksync_core/src/api_server/execution_sandbox/tracers.rs b/core/lib/zksync_core/src/api_server/execution_sandbox/tracers.rs index 719f6da0b4a9..e6add9a9e3b1 100644 --- a/core/lib/zksync_core/src/api_server/execution_sandbox/tracers.rs +++ b/core/lib/zksync_core/src/api_server/execution_sandbox/tracers.rs @@ -14,7 +14,7 @@ pub(crate) enum ApiTracer { impl ApiTracer { pub fn into_boxed< S: WriteStorage, - H: HistoryMode + multivm::HistoryMode + 'static, + H: HistoryMode + multivm::HistoryMode + 'static, >( self, ) -> MultiVmTracerPointer { diff --git a/core/lib/zksync_core/src/api_server/execution_sandbox/validate.rs b/core/lib/zksync_core/src/api_server/execution_sandbox/validate.rs index df70d02fe44b..a2439816d817 100644 --- a/core/lib/zksync_core/src/api_server/execution_sandbox/validate.rs +++ b/core/lib/zksync_core/src/api_server/execution_sandbox/validate.rs @@ -1,67 +1,59 @@ use std::collections::HashSet; +use anyhow::Context as _; use multivm::{ interface::{ExecutionResult, VmExecutionMode, VmInterface}, tracers::{ - validator::{ValidationError, ValidationTracer, ValidationTracerParams}, + validator::{self, ValidationTracer, ValidationTracerParams}, StorageInvocations, }, vm_latest::HistoryDisabled, MultiVMTracer, }; use zksync_dal::{ConnectionPool, StorageProcessor}; -use zksync_types::{l2::L2Tx, Transaction, TRUSTED_ADDRESS_SLOTS, TRUSTED_TOKEN_SLOTS, U256}; +use zksync_types::{l2::L2Tx, Transaction, TRUSTED_ADDRESS_SLOTS, TRUSTED_TOKEN_SLOTS}; use super::{ - adjust_l1_gas_price_for_tx, apply, + apply, + execute::TransactionExecutor, vm_metrics::{SandboxStage, EXECUTION_METRICS, SANDBOX_METRICS}, BlockArgs, TxExecutionArgs, TxSharedArgs, VmPermit, }; -impl TxSharedArgs { - pub async fn validate_tx_with_pending_state( - mut self, - vm_permit: VmPermit, - connection_pool: ConnectionPool, - tx: L2Tx, - computational_gas_limit: u32, - ) -> Result<(), ValidationError> { - let mut connection = connection_pool.access_storage_tagged("api").await.unwrap(); - let block_args = BlockArgs::pending(&mut connection).await; - drop(connection); - self.adjust_l1_gas_price(tx.common_data.fee.gas_per_pubdata_limit); - self.validate_tx_in_sandbox( - connection_pool, - vm_permit, - tx, - block_args, - computational_gas_limit, - ) - .await - } - - // In order for validation to pass smoothlessly, we need to ensure that block's required gasPerPubdata will be - // <= to the one in the transaction itself. - pub fn adjust_l1_gas_price(&mut self, gas_per_pubdata_limit: U256) { - self.l1_gas_price = adjust_l1_gas_price_for_tx( - self.l1_gas_price, - self.fair_l2_gas_price, - gas_per_pubdata_limit, - ); - } +/// Validation error used by the sandbox. Besides validation errors returned by VM, it also includes an internal error +/// variant (e.g., for DB-related errors). +#[derive(Debug, thiserror::Error)] +pub(crate) enum ValidationError { + #[error("VM validation error: {0}")] + Vm(validator::ValidationError), + #[error("Internal error")] + Internal(#[from] anyhow::Error), +} - async fn validate_tx_in_sandbox( - self, +impl TransactionExecutor { + pub(crate) async fn validate_tx_in_sandbox( + &self, connection_pool: ConnectionPool, vm_permit: VmPermit, tx: L2Tx, + shared_args: TxSharedArgs, block_args: BlockArgs, computational_gas_limit: u32, ) -> Result<(), ValidationError> { + #[cfg(test)] + if let Self::Mock(mock) = self { + return mock.validate_tx(&tx); + } + let stage_latency = SANDBOX_METRICS.sandbox[&SandboxStage::ValidateInSandbox].start(); - let mut connection = connection_pool.access_storage_tagged("api").await.unwrap(); + let mut connection = connection_pool + .access_storage_tagged("api") + .await + .context("failed acquiring DB connection")?; let validation_params = - get_validation_params(&mut connection, &tx, computational_gas_limit).await; + get_validation_params(&mut connection, &tx, computational_gas_limit) + .await + .context("failed getting validation params")?; drop(connection); let execution_args = TxExecutionArgs::for_validation(&tx); @@ -71,7 +63,8 @@ impl TxSharedArgs { let span = tracing::debug_span!("validate_in_sandbox").entered(); let result = apply::apply_vm_in_sandbox( vm_permit, - self, + shared_args, + true, &execution_args, &connection_pool, tx, @@ -95,9 +88,11 @@ impl TxSharedArgs { ); let result = match (result.result, validation_result.get()) { - (_, Some(err)) => Err(ValidationError::ViolatedRule(err.clone())), + (_, Some(err)) => { + Err(validator::ValidationError::ViolatedRule(err.clone())) + } (ExecutionResult::Halt { reason }, _) => { - Err(ValidationError::FailedTx(reason)) + Err(validator::ValidationError::FailedTx(reason)) } (_, None) => Ok(()), }; @@ -111,28 +106,32 @@ impl TxSharedArgs { result }) .await - .unwrap(); + .context("transaction validation panicked")??; stage_latency.observe(); - validation_result + validation_result.map_err(ValidationError::Vm) } } -// Some slots can be marked as "trusted". That is needed for slots which can not be -// trusted to change between validation and execution in general case, but -// sometimes we can safely rely on them to not change often. +/// Some slots can be marked as "trusted". That is needed for slots which can not be +/// trusted to change between validation and execution in general case, but +/// sometimes we can safely rely on them to not change often. async fn get_validation_params( connection: &mut StorageProcessor<'_>, tx: &L2Tx, computational_gas_limit: u32, -) -> ValidationTracerParams { +) -> anyhow::Result { let method_latency = EXECUTION_METRICS.get_validation_params.start(); let user_address = tx.common_data.initiator_address; let paymaster_address = tx.common_data.paymaster_params.paymaster; // This method assumes that the number of tokens is relatively low. When it grows // we may need to introduce some kind of caching. - let all_tokens = connection.tokens_dal().get_all_l2_token_addresses().await; + let all_tokens = connection + .tokens_dal() + .get_all_l2_token_addresses() + .await + .context("failed getting addresses of L2 tokens")?; EXECUTION_METRICS.tokens_amount.set(all_tokens.len()); let span = tracing::debug_span!("compute_trusted_slots_for_validation").entered(); @@ -156,12 +155,12 @@ async fn get_validation_params( span.exit(); method_latency.observe(); - ValidationTracerParams { + Ok(ValidationTracerParams { user_address, paymaster_address, trusted_slots, trusted_addresses, trusted_address_slots, computational_gas_limit, - } + }) } diff --git a/core/lib/zksync_core/src/api_server/execution_sandbox/vm_metrics.rs b/core/lib/zksync_core/src/api_server/execution_sandbox/vm_metrics.rs index 6842fe438f83..c23631ab4352 100644 --- a/core/lib/zksync_core/src/api_server/execution_sandbox/vm_metrics.rs +++ b/core/lib/zksync_core/src/api_server/execution_sandbox/vm_metrics.rs @@ -240,5 +240,6 @@ pub(super) fn collect_tx_execution_metrics( computational_gas_used: result.statistics.computational_gas_used, total_updated_values_size: writes_metrics.total_updated_values_size, pubdata_published: result.statistics.pubdata_published, + circuit_statistic: result.statistics.circuit_statistic, } } diff --git a/core/lib/zksync_core/src/api_server/healthcheck.rs b/core/lib/zksync_core/src/api_server/healthcheck.rs index 58444c30dc94..cbf8c9d6faf4 100644 --- a/core/lib/zksync_core/src/api_server/healthcheck.rs +++ b/core/lib/zksync_core/src/api_server/healthcheck.rs @@ -4,9 +4,9 @@ use axum::{extract::State, http::StatusCode, routing::get, Json, Router}; use tokio::sync::watch; use zksync_health_check::{AppHealth, CheckHealth}; -type SharedHealthchecks = Arc<[Box]>; - -async fn check_health(health_checks: State) -> (StatusCode, Json) { +async fn check_health>( + health_checks: State>, +) -> (StatusCode, Json) { let response = AppHealth::new(&health_checks).await; let response_code = if response.is_ready() { StatusCode::OK @@ -16,14 +16,16 @@ async fn check_health(health_checks: State) -> (StatusCode, (response_code, Json(response)) } -async fn run_server( +async fn run_server( bind_address: &SocketAddr, - health_checks: Vec>, + health_checks: Vec, mut stop_receiver: watch::Receiver, -) { +) where + T: AsRef + Send + Sync + 'static, +{ let mut health_check_names = HashSet::with_capacity(health_checks.len()); for check in &health_checks { - let health_check_name = check.name(); + let health_check_name = check.as_ref().name(); if !health_check_names.insert(health_check_name) { tracing::warn!( "Health check with name `{health_check_name}` is defined multiple times; only the last mention \ @@ -35,7 +37,7 @@ async fn run_server( "Starting healthcheck server with checks {health_check_names:?} on {bind_address}" ); - let health_checks = SharedHealthchecks::from(health_checks); + let health_checks = Arc::from(health_checks); let app = Router::new() .route("/health", get(check_health)) .with_state(health_checks); @@ -60,7 +62,10 @@ pub struct HealthCheckHandle { } impl HealthCheckHandle { - pub fn spawn_server(addr: SocketAddr, healthchecks: Vec>) -> Self { + pub fn spawn_server(addr: SocketAddr, healthchecks: Vec) -> Self + where + T: AsRef + Send + Sync + 'static, + { let (stop_sender, stop_receiver) = watch::channel(false); let server = tokio::spawn(async move { run_server(&addr, healthchecks, stop_receiver).await; @@ -74,7 +79,7 @@ impl HealthCheckHandle { pub async fn stop(self) { // Paradoxically, `hyper` server is quite slow to shut down if it isn't queried during shutdown: - // https://github.com/hyperium/hyper/issues/3188. It is thus recommended to set a timeout for shutdown. + // . It is thus recommended to set a timeout for shutdown. const GRACEFUL_SHUTDOWN_WAIT: Duration = Duration::from_secs(10); self.stop_sender.send(true).ok(); diff --git a/core/lib/zksync_core/src/api_server/tree/mod.rs b/core/lib/zksync_core/src/api_server/tree/mod.rs index 00a5fd285546..a6b6d51fbaae 100644 --- a/core/lib/zksync_core/src/api_server/tree/mod.rs +++ b/core/lib/zksync_core/src/api_server/tree/mod.rs @@ -73,7 +73,7 @@ impl IntoResponse for TreeApiError { } }; - // Loosely conforms to HTTP Problem Details RFC: https://datatracker.ietf.org/doc/html/rfc7807 + // Loosely conforms to HTTP Problem Details RFC: let body = serde_json::json!({ "type": "/errors#l1-batch-not-found", "title": title, diff --git a/core/lib/zksync_core/src/api_server/tx_sender/mod.rs b/core/lib/zksync_core/src/api_server/tx_sender/mod.rs index 3766c8a4ee19..7d5f1ab483fe 100644 --- a/core/lib/zksync_core/src/api_server/tx_sender/mod.rs +++ b/core/lib/zksync_core/src/api_server/tx_sender/mod.rs @@ -1,34 +1,27 @@ //! Helper module to submit transactions into the zkSync Network. -use std::{cmp, num::NonZeroU32, sync::Arc, time::Instant}; +use std::{cmp, sync::Arc, time::Instant}; -use governor::{ - clock::MonotonicClock, - middleware::NoOpMiddleware, - state::{InMemoryState, NotKeyed}, - Quota, RateLimiter, -}; +use anyhow::Context as _; use multivm::{ interface::VmExecutionResultAndLogs, - vm_latest::{ - constants::{BLOCK_GAS_LIMIT, MAX_PUBDATA_PER_BLOCK}, - utils::{ - fee::derive_base_fee_and_gas_per_pubdata, - overhead::{derive_overhead, OverheadCoefficients}, - }, - }, + utils::{adjust_pubdata_price_for_tx, derive_base_fee_and_gas_per_pubdata, derive_overhead}, + vm_latest::constants::{BLOCK_GAS_LIMIT, MAX_PUBDATA_PER_BLOCK}, }; use zksync_config::configs::{api::Web3JsonRpcConfig, chain::StateKeeperConfig}; use zksync_contracts::BaseSystemContracts; -use zksync_dal::{transactions_dal::L2TxSubmissionResult, ConnectionPool}; +use zksync_dal::{transactions_dal::L2TxSubmissionResult, ConnectionPool, StorageProcessor}; use zksync_state::PostgresStorageCaches; +use zksync_system_constants::DEFAULT_L2_TX_GAS_PER_PUBDATA_BYTE; use zksync_types::{ fee::{Fee, TransactionExecutionMetrics}, + fee_model::BatchFeeInput, get_code_key, get_intrinsic_constants, + l1::is_l1_tx_type, l2::{error::TxCheckError::TxDuplication, L2Tx}, utils::storage_key_for_eth_balance, - AccountTreeId, Address, ExecuteTransactionCommon, L2ChainId, Nonce, PackedEthSignature, - ProtocolVersionId, Transaction, H160, H256, MAX_GAS_PER_PUBDATA_BYTE, MAX_L2_TX_GAS_LIMIT, + AccountTreeId, Address, ExecuteTransactionCommon, L2ChainId, MiniblockNumber, Nonce, + PackedEthSignature, ProtocolVersionId, Transaction, VmVersion, H160, H256, MAX_L2_TX_GAS_LIMIT, MAX_NEW_FACTORY_DEPS, U256, }; use zksync_utils::h256_to_u256; @@ -37,23 +30,21 @@ pub(super) use self::{proxy::TxProxy, result::SubmitTxError}; use crate::{ api_server::{ execution_sandbox::{ - adjust_l1_gas_price_for_tx, execute_tx_eth_call, execute_tx_with_pending_state, - get_pubdata_for_factory_deps, BlockArgs, SubmitTxStage, TxExecutionArgs, TxSharedArgs, - VmConcurrencyLimiter, VmPermit, SANDBOX_METRICS, + get_pubdata_for_factory_deps, BlockArgs, BlockStartInfo, SubmitTxStage, + TransactionExecutor, TxExecutionArgs, TxSharedArgs, VmConcurrencyLimiter, VmPermit, + SANDBOX_METRICS, }, tx_sender::result::ApiCallResult, }, - l1_gas_price::L1GasPriceProvider, + fee_model::BatchFeeModelInputProvider, metrics::{TxStage, APP_METRICS}, - state_keeper::seal_criteria::{ConditionalSealer, SealData}, + state_keeper::seal_criteria::{ConditionalSealer, NoopSealer, SealData}, }; mod proxy; mod result; - -/// Type alias for the rate limiter implementation. -type TxSenderRateLimiter = - RateLimiter>; +#[cfg(test)] +pub(crate) mod tests; #[derive(Debug, Clone)] pub struct MultiVMBaseSystemContracts { @@ -65,6 +56,10 @@ pub struct MultiVMBaseSystemContracts { pub(crate) post_virtual_blocks_finish_upgrade_fix: BaseSystemContracts, /// Contracts to be used for post-boojum protocol versions. pub(crate) post_boojum: BaseSystemContracts, + /// Contracts to be used after the allow-list removal upgrade + pub(crate) post_allowlist_removal: BaseSystemContracts, + /// Contracts to be used after the 1.4.1 upgrade + pub(crate) post_1_4_1: BaseSystemContracts, } impl MultiVMBaseSystemContracts { @@ -88,7 +83,9 @@ impl MultiVMBaseSystemContracts { | ProtocolVersionId::Version15 | ProtocolVersionId::Version16 | ProtocolVersionId::Version17 => self.post_virtual_blocks_finish_upgrade_fix, - ProtocolVersionId::Version18 | ProtocolVersionId::Version19 => self.post_boojum, + ProtocolVersionId::Version18 => self.post_boojum, + ProtocolVersionId::Version19 => self.post_allowlist_removal, + ProtocolVersionId::Version20 | ProtocolVersionId::Version21 => self.post_1_4_1, } } } @@ -119,6 +116,8 @@ impl ApiContracts { post_virtual_blocks_finish_upgrade_fix: BaseSystemContracts::estimate_gas_post_virtual_blocks_finish_upgrade_fix(), post_boojum: BaseSystemContracts::estimate_gas_post_boojum(), + post_allowlist_removal: BaseSystemContracts::estimate_gas_post_allowlist_removal(), + post_1_4_1: BaseSystemContracts::estimate_gas_post_1_4_1(), }, eth_call: MultiVMBaseSystemContracts { pre_virtual_blocks: BaseSystemContracts::playground_pre_virtual_blocks(), @@ -126,6 +125,8 @@ impl ApiContracts { post_virtual_blocks_finish_upgrade_fix: BaseSystemContracts::playground_post_virtual_blocks_finish_upgrade_fix(), post_boojum: BaseSystemContracts::playground_post_boojum(), + post_allowlist_removal: BaseSystemContracts::playground_post_allowlist_removal(), + post_1_4_1: BaseSystemContracts::playground_post_1_4_1(), }, } } @@ -140,13 +141,10 @@ pub struct TxSenderBuilder { replica_connection_pool: ConnectionPool, /// Connection pool for write requests. If not set, `proxy` must be set. master_connection_pool: Option, - /// Rate limiter for tx submissions. - rate_limiter: Option, /// Proxy to submit transactions to the network. If not set, `master_connection_pool` must be set. proxy: Option, - /// Actual state keeper configuration, required for tx verification. - /// If not set, transactions would not be checked against seal criteria. - state_keeper_config: Option, + /// Batch sealer used to check whether transaction can be executed by the sequencer. + sealer: Option>, } impl TxSenderBuilder { @@ -155,21 +153,14 @@ impl TxSenderBuilder { config, replica_connection_pool, master_connection_pool: None, - rate_limiter: None, proxy: None, - state_keeper_config: None, + sealer: None, } } - pub fn with_rate_limiter(self, transactions_per_sec: u32) -> Self { - let rate_limiter = RateLimiter::direct_with_clock( - Quota::per_second(NonZeroU32::new(transactions_per_sec).unwrap()), - &MonotonicClock, - ); - Self { - rate_limiter: Some(rate_limiter), - ..self - } + pub fn with_sealer(mut self, sealer: Arc) -> Self { + self.sealer = Some(sealer); + self } pub fn with_tx_proxy(mut self, main_node_url: &str) -> Self { @@ -182,34 +173,32 @@ impl TxSenderBuilder { self } - pub fn with_state_keeper_config(mut self, state_keeper_config: StateKeeperConfig) -> Self { - self.state_keeper_config = Some(state_keeper_config); - self - } - - pub async fn build( + pub async fn build( self, - l1_gas_price_source: Arc, + batch_fee_input_provider: Arc, vm_concurrency_limiter: Arc, api_contracts: ApiContracts, storage_caches: PostgresStorageCaches, - ) -> TxSender { + ) -> TxSender { assert!( self.master_connection_pool.is_some() || self.proxy.is_some(), "Either master connection pool or proxy must be set" ); + // Use noop sealer if no sealer was explicitly provided. + let sealer = self.sealer.unwrap_or_else(|| Arc::new(NoopSealer)); + TxSender(Arc::new(TxSenderInner { sender_config: self.config, master_connection_pool: self.master_connection_pool, replica_connection_pool: self.replica_connection_pool, - l1_gas_price_source, + batch_fee_input_provider, api_contracts, - rate_limiter: self.rate_limiter, proxy: self.proxy, - state_keeper_config: self.state_keeper_config, vm_concurrency_limiter, storage_caches, + sealer, + executor: TransactionExecutor::Real, })) } } @@ -224,9 +213,9 @@ pub struct TxSenderConfig { pub gas_price_scale_factor: f64, pub max_nonce_ahead: u32, pub max_allowed_l2_tx_gas_limit: u32, - pub fair_l2_gas_price: u64, pub vm_execution_cache_misses_limit: Option, pub validation_computational_gas_limit: u32, + pub l1_to_l2_transactions_compatibility_mode: bool, pub chain_id: L2ChainId, } @@ -241,54 +230,44 @@ impl TxSenderConfig { gas_price_scale_factor: web3_json_config.gas_price_scale_factor, max_nonce_ahead: web3_json_config.max_nonce_ahead, max_allowed_l2_tx_gas_limit: state_keeper_config.max_allowed_l2_tx_gas_limit, - fair_l2_gas_price: state_keeper_config.fair_l2_gas_price, vm_execution_cache_misses_limit: web3_json_config.vm_execution_cache_misses_limit, validation_computational_gas_limit: state_keeper_config .validation_computational_gas_limit, + l1_to_l2_transactions_compatibility_mode: web3_json_config + .l1_to_l2_transactions_compatibility_mode, chain_id, } } } -pub struct TxSenderInner { +pub struct TxSenderInner { pub(super) sender_config: TxSenderConfig, pub master_connection_pool: Option, pub replica_connection_pool: ConnectionPool, // Used to keep track of gas prices for the fee ticker. - pub l1_gas_price_source: Arc, + pub batch_fee_input_provider: Arc, pub(super) api_contracts: ApiContracts, - /// Optional rate limiter that will limit the amount of transactions per second sent from a single entity. - rate_limiter: Option, /// Optional transaction proxy to be used for transaction submission. pub(super) proxy: Option, - /// An up-to-date version of the state keeper config. - /// This field may be omitted on the external node, since the configuration may change unexpectedly. - /// If this field is set to `None`, `TxSender` will assume that any transaction is executable. - state_keeper_config: Option, /// Used to limit the amount of VMs that can be executed simultaneously. pub(super) vm_concurrency_limiter: Arc, // Caches used in VM execution. storage_caches: PostgresStorageCaches, + /// Batch sealer used to check whether transaction can be executed by the sequencer. + sealer: Arc, + pub(super) executor: TransactionExecutor, } -pub struct TxSender(pub(super) Arc>); - -// Custom implementation is required due to generic param: -// Even though it's under `Arc`, compiler doesn't generate the `Clone` implementation unless -// an unnecessary bound is added. -impl Clone for TxSender { - fn clone(&self) -> Self { - Self(self.0.clone()) - } -} +#[derive(Clone)] +pub struct TxSender(pub(super) Arc); -impl std::fmt::Debug for TxSender { +impl std::fmt::Debug for TxSender { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("TxSender").finish() } } -impl TxSender { +impl TxSender { pub(crate) fn vm_concurrency_limiter(&self) -> Arc { Arc::clone(&self.0.vm_concurrency_limiter) } @@ -297,46 +276,61 @@ impl TxSender { self.0.storage_caches.clone() } + async fn acquire_replica_connection(&self) -> anyhow::Result> { + self.0 + .replica_connection_pool + .access_storage_tagged("api") + .await + .context("failed acquiring connection to replica DB") + } + #[tracing::instrument(skip(self, tx))] pub async fn submit_tx(&self, tx: L2Tx) -> Result { - if let Some(rate_limiter) = &self.0.rate_limiter { - if rate_limiter.check().is_err() { - return Err(SubmitTxError::RateLimitExceeded); - } - } - let stage_latency = SANDBOX_METRICS.submit_tx[&SubmitTxStage::Validate].start(); self.validate_tx(&tx).await?; stage_latency.observe(); let stage_latency = SANDBOX_METRICS.submit_tx[&SubmitTxStage::DryRun].start(); - let shared_args = self.shared_args(); + let shared_args = self.shared_args().await; let vm_permit = self.0.vm_concurrency_limiter.acquire().await; let vm_permit = vm_permit.ok_or(SubmitTxError::ServerShuttingDown)?; + let mut connection = self.acquire_replica_connection().await?; + let block_args = BlockArgs::pending(&mut connection).await?; + drop(connection); - let (_, tx_metrics) = execute_tx_with_pending_state( - vm_permit.clone(), - shared_args.clone(), - TxExecutionArgs::for_validation(&tx), - self.0.replica_connection_pool.clone(), - tx.clone().into(), - ) - .await; + let execution_output = self + .0 + .executor + .execute_tx_in_sandbox( + vm_permit.clone(), + shared_args.clone(), + true, + TxExecutionArgs::for_validation(&tx), + self.0.replica_connection_pool.clone(), + tx.clone().into(), + block_args, + vec![], + ) + .await?; tracing::info!( "Submit tx {:?} with execution metrics {:?}", tx.hash(), - tx_metrics + execution_output.metrics ); stage_latency.observe(); let stage_latency = SANDBOX_METRICS.submit_tx[&SubmitTxStage::VerifyExecute].start(); let computational_gas_limit = self.0.sender_config.validation_computational_gas_limit; - let validation_result = shared_args - .validate_tx_with_pending_state( - vm_permit, + let validation_result = self + .0 + .executor + .validate_tx_in_sandbox( self.0.replica_connection_pool.clone(), + vm_permit, tx.clone(), + shared_args, + block_args, computational_gas_limit, ) .await; @@ -345,9 +339,12 @@ impl TxSender { if let Err(err) = validation_result { return Err(err.into()); } + if !execution_output.are_published_bytecodes_ok { + return Err(SubmitTxError::FailedToPublishCompressedBytecodes); + } let stage_started_at = Instant::now(); - self.ensure_tx_executable(tx.clone().into(), &tx_metrics, true)?; + self.ensure_tx_executable(tx.clone().into(), &execution_output.metrics, true)?; if let Some(proxy) = &self.0.proxy { // We're running an external node: we have to proxy the transaction to the main node. @@ -371,7 +368,7 @@ impl TxSender { let nonce = tx.common_data.nonce.0; let hash = tx.hash(); - let expected_nonce = self.get_expected_nonce(&tx).await; + let initiator_account = tx.initiator_account(); let submission_res_handle = self .0 .master_connection_pool @@ -381,17 +378,25 @@ impl TxSender { .await .unwrap() .transactions_dal() - .insert_transaction_l2(tx, tx_metrics) + .insert_transaction_l2(tx, execution_output.metrics) .await; APP_METRICS.processed_txs[&TxStage::Mempool(submission_res_handle)].inc(); match submission_res_handle { - L2TxSubmissionResult::AlreadyExecuted => Err(SubmitTxError::NonceIsTooLow( - expected_nonce.0, - expected_nonce.0 + self.0.sender_config.max_nonce_ahead, - nonce, - )), + L2TxSubmissionResult::AlreadyExecuted => { + let Nonce(expected_nonce) = self + .get_expected_nonce(initiator_account) + .await + .with_context(|| { + format!("failed getting expected nonce for {initiator_account:?}") + })?; + Err(SubmitTxError::NonceIsTooLow( + expected_nonce, + expected_nonce + self.0.sender_config.max_nonce_ahead, + nonce, + )) + } L2TxSubmissionResult::Duplicate => Err(SubmitTxError::IncorrectTx(TxDuplication(hash))), _ => { SANDBOX_METRICS.submit_tx[&SubmitTxStage::DbInsert] @@ -401,11 +406,10 @@ impl TxSender { } } - fn shared_args(&self) -> TxSharedArgs { + async fn shared_args(&self) -> TxSharedArgs { TxSharedArgs { operator_account: AccountTreeId::new(self.0.sender_config.fee_account_addr), - l1_gas_price: self.0.l1_gas_price_source.estimate_effective_gas_price(), - fair_l2_gas_price: self.0.sender_config.fair_l2_gas_price, + fee_input: self.0.batch_fee_input_provider.get_batch_fee_input().await, base_system_contracts: self.0.api_contracts.eth_call.clone(), caches: self.storage_caches(), validation_computational_gas_limit: self @@ -424,6 +428,8 @@ impl TxSender { return Err(SubmitTxError::GasLimitIsTooBig); } + let fee_input = self.0.batch_fee_input_provider.get_batch_fee_input().await; + // TODO (SMA-1715): do not subsidize the overhead for the transaction if tx.common_data.fee.gas_limit > self.0.sender_config.max_allowed_l2_tx_gas_limit.into() { @@ -434,7 +440,7 @@ impl TxSender { ); return Err(SubmitTxError::GasLimitIsTooBig); } - if tx.common_data.fee.max_fee_per_gas < self.0.sender_config.fair_l2_gas_price.into() { + if tx.common_data.fee.max_fee_per_gas < fee_input.fair_l2_gas_price().into() { tracing::info!( "Submitted Tx is Unexecutable {:?} because of MaxFeePerGasTooLow {}", tx.hash(), @@ -457,19 +463,12 @@ impl TxSender { )); } - let l1_gas_price = self.0.l1_gas_price_source.estimate_effective_gas_price(); - let (_, gas_per_pubdata_byte) = derive_base_fee_and_gas_per_pubdata( - l1_gas_price, - self.0.sender_config.fair_l2_gas_price, - ); - let effective_gas_per_pubdata = cmp::min( - tx.common_data.fee.gas_per_pubdata_limit, - gas_per_pubdata_byte.into(), - ); - let intrinsic_consts = get_intrinsic_constants(); - let min_gas_limit = U256::from(intrinsic_consts.l2_tx_intrinsic_gas) - + U256::from(intrinsic_consts.l2_tx_intrinsic_pubdata) * effective_gas_per_pubdata; + assert!( + intrinsic_consts.l2_tx_intrinsic_pubdata == 0, + "Currently we assume that the L2 transactions do not have any intrinsic pubdata" + ); + let min_gas_limit = U256::from(intrinsic_consts.l2_tx_intrinsic_gas); if tx.common_data.fee.gas_limit < min_gas_limit { return Err(SubmitTxError::IntrinsicGas); } @@ -484,19 +483,27 @@ impl TxSender { } async fn validate_account_nonce(&self, tx: &L2Tx) -> Result<(), SubmitTxError> { - let expected_nonce = self.get_expected_nonce(tx).await; + let Nonce(expected_nonce) = self + .get_expected_nonce(tx.initiator_account()) + .await + .with_context(|| { + format!( + "failed getting expected nonce for {:?}", + tx.initiator_account() + ) + })?; - if tx.common_data.nonce.0 < expected_nonce.0 { + if tx.common_data.nonce.0 < expected_nonce { Err(SubmitTxError::NonceIsTooLow( - expected_nonce.0, - expected_nonce.0 + self.0.sender_config.max_nonce_ahead, + expected_nonce, + expected_nonce + self.0.sender_config.max_nonce_ahead, tx.nonce().0, )) } else { - let max_nonce = expected_nonce.0 + self.0.sender_config.max_nonce_ahead; - if !(expected_nonce.0..=max_nonce).contains(&tx.common_data.nonce.0) { + let max_nonce = expected_nonce + self.0.sender_config.max_nonce_ahead; + if !(expected_nonce..=max_nonce).contains(&tx.common_data.nonce.0) { Err(SubmitTxError::NonceIsTooHigh( - expected_nonce.0, + expected_nonce, max_nonce, tx.nonce().0, )) @@ -506,44 +513,44 @@ impl TxSender { } } - async fn get_expected_nonce(&self, tx: &L2Tx) -> Nonce { - let mut connection = self - .0 - .replica_connection_pool - .access_storage_tagged("api") - .await - .unwrap(); - - let latest_block_number = connection - .blocks_web3_dal() + async fn get_expected_nonce(&self, initiator_account: Address) -> anyhow::Result { + let mut storage = self.acquire_replica_connection().await?; + let latest_block_number = storage + .blocks_dal() .get_sealed_miniblock_number() .await - .unwrap(); - let nonce = connection + .context("failed getting sealed miniblock number")?; + let latest_block_number = match latest_block_number { + Some(number) => number, + None => { + // We don't have miniblocks in the storage yet. Use the snapshot miniblock number instead. + let start = BlockStartInfo::new(&mut storage).await?; + MiniblockNumber(start.first_miniblock.saturating_sub(1)) + } + }; + + let nonce = storage .storage_web3_dal() - .get_address_historical_nonce(tx.initiator_account(), latest_block_number) + .get_address_historical_nonce(initiator_account, latest_block_number) .await - .unwrap(); - Nonce(nonce.as_u32()) + .with_context(|| { + format!("failed getting nonce for address {initiator_account:?} at miniblock #{latest_block_number}") + })?; + let nonce = u32::try_from(nonce) + .map_err(|err| anyhow::anyhow!("failed converting nonce to u32: {err}"))?; + Ok(Nonce(nonce)) } async fn validate_enough_balance(&self, tx: &L2Tx) -> Result<(), SubmitTxError> { let paymaster = tx.common_data.paymaster_params.paymaster; - - // The paymaster is expected to pay for the tx, - // whatever balance the user has, we don't care. + // The paymaster is expected to pay for the tx; whatever balance the user has, we don't care. if paymaster != Address::default() { return Ok(()); } - let balance = self.get_balance(&tx.common_data.initiator_address).await; - + let balance = self.get_balance(&tx.common_data.initiator_address).await?; // Estimate the minimum fee price user will agree to. - let gas_price = cmp::min( - tx.common_data.fee.max_fee_per_gas, - U256::from(self.0.sender_config.fair_l2_gas_price) - + tx.common_data.fee.max_priority_fee_per_gas, - ); + let gas_price = tx.common_data.fee.max_fee_per_gas; let max_fee = tx.common_data.fee.gas_limit * gas_price; let max_fee_and_value = max_fee + tx.execute.value; @@ -558,21 +565,16 @@ impl TxSender { } } - async fn get_balance(&self, initiator_address: &H160) -> U256 { + async fn get_balance(&self, initiator_address: &H160) -> anyhow::Result { let eth_balance_key = storage_key_for_eth_balance(initiator_address); - let balance = self - .0 - .replica_connection_pool - .access_storage_tagged("api") - .await - .unwrap() + .acquire_replica_connection() + .await? .storage_dal() .get_by_key(ð_balance_key) - .await + .await? .unwrap_or_default(); - - h256_to_u256(balance) + Ok(h256_to_u256(balance)) } /// Given the gas_limit to be used for the body of the transaction, @@ -582,17 +584,20 @@ impl TxSender { &self, vm_permit: VmPermit, mut tx: Transaction, - gas_per_pubdata_byte: u64, tx_gas_limit: u32, - l1_gas_price: u64, + gas_price_per_pubdata: u32, + fee_model_params: BatchFeeInput, + block_args: BlockArgs, base_fee: u64, - ) -> (VmExecutionResultAndLogs, TransactionExecutionMetrics) { + vm_version: VmVersion, + ) -> anyhow::Result<(VmExecutionResultAndLogs, TransactionExecutionMetrics)> { let gas_limit_with_overhead = tx_gas_limit + derive_overhead( tx_gas_limit, - gas_per_pubdata_byte as u32, + gas_price_per_pubdata, tx.encoding_len(), - OverheadCoefficients::from_tx_type(tx.tx_format() as u8), + tx.tx_format() as u8, + vm_version, ); match &mut tx.common_data { @@ -615,28 +620,33 @@ impl TxSender { } } - let shared_args = self.shared_args_for_gas_estimate(l1_gas_price); + let shared_args = self.shared_args_for_gas_estimate(fee_model_params); let vm_execution_cache_misses_limit = self.0.sender_config.vm_execution_cache_misses_limit; let execution_args = TxExecutionArgs::for_gas_estimate(vm_execution_cache_misses_limit, &tx, base_fee); - let (exec_result, tx_metrics) = execute_tx_with_pending_state( - vm_permit, - shared_args, - execution_args, - self.0.replica_connection_pool.clone(), - tx.clone(), - ) - .await; - - (exec_result, tx_metrics) + let execution_output = self + .0 + .executor + .execute_tx_in_sandbox( + vm_permit, + shared_args, + true, + execution_args, + self.0.replica_connection_pool.clone(), + tx.clone(), + block_args, + vec![], + ) + .await?; + Ok((execution_output.vm, execution_output.metrics)) } - fn shared_args_for_gas_estimate(&self, l1_gas_price: u64) -> TxSharedArgs { + fn shared_args_for_gas_estimate(&self, fee_input: BatchFeeInput) -> TxSharedArgs { let config = &self.0.sender_config; + TxSharedArgs { operator_account: AccountTreeId::new(config.fee_account_addr), - l1_gas_price, - fair_l2_gas_price: config.fair_l2_gas_price, + fee_input, // We want to bypass the computation gas limit check for gas estimation validation_computational_gas_limit: BLOCK_GAS_LIMIT, base_system_contracts: self.0.api_contracts.estimate_gas.clone(), @@ -652,24 +662,35 @@ impl TxSender { acceptable_overestimation: u32, ) -> Result { let estimation_started_at = Instant::now(); - let l1_gas_price = { - let effective_gas_price = self.0.l1_gas_price_source.estimate_effective_gas_price(); - let current_l1_gas_price = - ((effective_gas_price as f64) * self.0.sender_config.gas_price_scale_factor) as u64; - - // In order for execution to pass smoothly, we need to ensure that block's required gasPerPubdata will be - // <= to the one in the transaction itself. - adjust_l1_gas_price_for_tx( - current_l1_gas_price, - self.0.sender_config.fair_l2_gas_price, + + let mut connection = self.acquire_replica_connection().await?; + let block_args = BlockArgs::pending(&mut connection).await?; + let protocol_version = block_args + .resolve_block_info(&mut connection) + .await + .with_context(|| format!("failed resolving block info for {block_args:?}"))? + .protocol_version; + drop(connection); + + let fee_input = { + // For now, both L1 gas price and pubdata price are scaled with the same coefficient + let fee_input = self + .0 + .batch_fee_input_provider + .get_batch_fee_input_scaled( + self.0.sender_config.gas_price_scale_factor, + self.0.sender_config.gas_price_scale_factor, + ) + .await; + adjust_pubdata_price_for_tx( + fee_input, tx.gas_per_pubdata_byte_limit(), + protocol_version.into(), ) }; - let (base_fee, gas_per_pubdata_byte) = derive_base_fee_and_gas_per_pubdata( - l1_gas_price, - self.0.sender_config.fair_l2_gas_price, - ); + let (base_fee, gas_per_pubdata_byte) = + derive_base_fee_and_gas_per_pubdata(fee_input, protocol_version.into()); match &mut tx.common_data { ExecuteTransactionCommon::L2(common_data) => { common_data.fee.max_fee_per_gas = base_fee.into(); @@ -684,23 +705,25 @@ impl TxSender { } let hashed_key = get_code_key(&tx.initiator_account()); - // if the default account does not have enough funds - // for transferring tx.value, without taking into account the fee, - // there is no sense to estimate the fee + // If the default account does not have enough funds for transferring `tx.value`, without taking into account the fee, + // there is no sense to estimate the fee. let account_code_hash = self - .0 - .replica_connection_pool - .access_storage_tagged("api") - .await - .unwrap() + .acquire_replica_connection() + .await? .storage_dal() .get_by_key(&hashed_key) .await + .with_context(|| { + format!( + "failed getting code hash for account {:?}", + tx.initiator_account() + ) + })? .unwrap_or_default(); if !tx.is_l1() && account_code_hash == H256::zero() - && tx.execute.value > self.get_balance(&tx.initiator_account()).await + && tx.execute.value > self.get_balance(&tx.initiator_account()).await? { tracing::info!( "fee estimation failed on validation step. @@ -717,7 +740,8 @@ impl TxSender { l2_common_data.signature = PackedEthSignature::default().serialize_packed().into(); } - l2_common_data.fee.gas_per_pubdata_limit = MAX_GAS_PER_PUBDATA_BYTE.into(); + l2_common_data.fee.gas_per_pubdata_limit = + U256::from(DEFAULT_L2_TX_GAS_PER_PUBDATA_BYTE); } // Acquire the vm token for the whole duration of the binary search. @@ -736,7 +760,7 @@ impl TxSender { tx.execute.factory_deps.as_deref().unwrap_or_default(), self.storage_caches(), ) - .await; + .await?; if pubdata_for_factory_deps > MAX_PUBDATA_PER_BLOCK { return Err(SubmitTxError::Unexecutable( @@ -747,7 +771,7 @@ impl TxSender { }; // We are using binary search to find the minimal values of gas_limit under which - // the transaction succeedes + // the transaction succeeds let mut lower_bound = 0; let mut upper_bound = MAX_L2_TX_GAS_LIMIT as u32; let tx_id = format!( @@ -765,20 +789,23 @@ impl TxSender { while lower_bound + acceptable_overestimation < upper_bound { let mid = (lower_bound + upper_bound) / 2; // There is no way to distinct between errors due to out of gas - // or normal exeuction errors, so we just hope that increasing the + // or normal execution errors, so we just hope that increasing the // gas limit will make the transaction successful let iteration_started_at = Instant::now(); let try_gas_limit = gas_for_bytecodes_pubdata + mid; - let (result, _execution_metrics) = self + let (result, _) = self .estimate_gas_step( vm_permit.clone(), tx.clone(), - gas_per_pubdata_byte, try_gas_limit, - l1_gas_price, + gas_per_pubdata_byte as u32, + fee_input, + block_args, base_fee, + protocol_version.into(), ) - .await; + .await + .context("estimate_gas step failed")?; if result.result.is_failed() { lower_bound = mid + 1; @@ -810,22 +837,42 @@ impl TxSender { .estimate_gas_step( vm_permit, tx.clone(), - gas_per_pubdata_byte, suggested_gas_limit, - l1_gas_price, + gas_per_pubdata_byte as u32, + fee_input, + block_args, base_fee, + protocol_version.into(), ) - .await; + .await + .context("final estimate_gas step failed")?; result.into_api_call_result()?; self.ensure_tx_executable(tx.clone(), &tx_metrics, false)?; - let overhead = derive_overhead( - suggested_gas_limit, - gas_per_pubdata_byte as u32, - tx.encoding_len(), - OverheadCoefficients::from_tx_type(tx.tx_format() as u8), - ); + // Now, we need to calculate the final overhead for the transaction. We need to take into account the fact + // that the migration of 1.4.1 may be still going on. + let overhead = if self + .0 + .sender_config + .l1_to_l2_transactions_compatibility_mode + { + derive_pessimistic_overhead( + suggested_gas_limit, + gas_per_pubdata_byte as u32, + tx.encoding_len(), + tx.tx_format() as u8, + protocol_version.into(), + ) + } else { + derive_overhead( + suggested_gas_limit, + gas_per_pubdata_byte as u32, + tx.encoding_len(), + tx.tx_format() as u8, + protocol_version.into(), + ) + }; let full_gas_limit = match tx_body_gas_limit.overflowing_add(gas_for_bytecodes_pubdata + overhead) { @@ -855,27 +902,43 @@ impl TxSender { let vm_permit = vm_permit.ok_or(SubmitTxError::ServerShuttingDown)?; let vm_execution_cache_misses_limit = self.0.sender_config.vm_execution_cache_misses_limit; - execute_tx_eth_call( - vm_permit, - self.shared_args(), - self.0.replica_connection_pool.clone(), - tx, - block_args, - vm_execution_cache_misses_limit, - vec![], - ) - .await - .into_api_call_result() + self.0 + .executor + .execute_tx_eth_call( + vm_permit, + self.shared_args().await, + self.0.replica_connection_pool.clone(), + tx, + block_args, + vm_execution_cache_misses_limit, + vec![], + ) + .await? + .into_api_call_result() } - pub fn gas_price(&self) -> u64 { - let gas_price = self.0.l1_gas_price_source.estimate_effective_gas_price(); - let l1_gas_price = (gas_price as f64 * self.0.sender_config.gas_price_scale_factor).round(); + pub async fn gas_price(&self) -> anyhow::Result { + let mut connection = self.acquire_replica_connection().await?; + let block_args = BlockArgs::pending(&mut connection).await?; + let protocol_version = block_args + .resolve_block_info(&mut connection) + .await + .with_context(|| format!("failed resolving block info for {block_args:?}"))? + .protocol_version; + drop(connection); + let (base_fee, _) = derive_base_fee_and_gas_per_pubdata( - l1_gas_price as u64, - self.0.sender_config.fair_l2_gas_price, + // For now, both the L1 gas price and the L1 pubdata price are scaled with the same coefficient + self.0 + .batch_fee_input_provider + .get_batch_fee_input_scaled( + self.0.sender_config.gas_price_scale_factor, + self.0.sender_config.gas_price_scale_factor, + ) + .await, + protocol_version.into(), ); - base_fee + Ok(base_fee) } fn ensure_tx_executable( @@ -884,13 +947,6 @@ impl TxSender { tx_metrics: &TransactionExecutionMetrics, log_message: bool, ) -> Result<(), SubmitTxError> { - let Some(sk_config) = &self.0.state_keeper_config else { - // No config provided, so we can't check if transaction satisfies the seal criteria. - // We assume that it's executable, and if it's not, it will be caught by the main server - // (where this check is always performed). - return Ok(()); - }; - // Hash is not computable for the provided `transaction` during gas estimation (it doesn't have // its input data set). Since we don't log a hash in this case anyway, we just use a dummy value. let tx_hash = if log_message { @@ -904,8 +960,10 @@ impl TxSender { // still reject them as it's not. let protocol_version = ProtocolVersionId::latest(); let seal_data = SealData::for_transaction(transaction, tx_metrics, protocol_version); - if let Some(reason) = - ConditionalSealer::find_unexecutable_reason(sk_config, &seal_data, protocol_version) + if let Some(reason) = self + .0 + .sealer + .find_unexecutable_reason(&seal_data, protocol_version) { let message = format!( "Tx is Unexecutable because of {reason}; inputs for decision: {seal_data:?}" @@ -918,3 +976,40 @@ impl TxSender { Ok(()) } } + +/// During switch to the 1.4.1 protocol version, there will be a moment of discrepancy, when while +/// the L2 has already upgraded to 1.4.1 (and thus suggests smaller overhead), the L1 is still on the previous version. +/// +/// This might lead to situations when L1->L2 transactions estimated with the new versions would work on the state keeper side, +/// but they won't even make it there, but the protection mechanisms for L1->L2 transactions will reject them on L1. +/// TODO(X): remove this function after the upgrade is complete +fn derive_pessimistic_overhead( + gas_limit: u32, + gas_price_per_pubdata: u32, + encoded_len: usize, + tx_type: u8, + vm_version: VmVersion, +) -> u32 { + let current_overhead = derive_overhead( + gas_limit, + gas_price_per_pubdata, + encoded_len, + tx_type, + vm_version, + ); + + if is_l1_tx_type(tx_type) { + // We are in the L1->L2 transaction, so we need to account for the fact that the L1 is still on the previous version. + // We assume that the overhead will be the same as for the previous version. + let previous_overhead = derive_overhead( + gas_limit, + gas_price_per_pubdata, + encoded_len, + tx_type, + VmVersion::VmBoojumIntegration, + ); + current_overhead.max(previous_overhead) + } else { + current_overhead + } +} diff --git a/core/lib/zksync_core/src/api_server/tx_sender/result.rs b/core/lib/zksync_core/src/api_server/tx_sender/result.rs index 2749e2a13c35..6224ac849a43 100644 --- a/core/lib/zksync_core/src/api_server/tx_sender/result.rs +++ b/core/lib/zksync_core/src/api_server/tx_sender/result.rs @@ -1,12 +1,10 @@ -use multivm::{ - interface::{ExecutionResult, VmExecutionResultAndLogs}, - tracers::validator::ValidationError, -}; +use multivm::interface::{ExecutionResult, VmExecutionResultAndLogs}; use thiserror::Error; use zksync_types::{l2::error::TxCheckError, U256}; -use crate::api_server::execution_sandbox::SandboxExecutionError; +use crate::api_server::execution_sandbox::{SandboxExecutionError, ValidationError}; +/// Errors that con occur submitting a transaction or estimating gas for its execution. #[derive(Debug, Error)] pub enum SubmitTxError { #[error("nonce too high. allowed nonce range: {0} - {1}, actual: {2}")] @@ -69,6 +67,11 @@ pub enum SubmitTxError { /// Error returned from main node #[error("{0}")] ProxyError(#[from] zksync_web3_decl::jsonrpsee::core::ClientError), + #[error("not enough gas to publish compressed bytecodes")] + FailedToPublishCompressedBytecodes, + /// Catch-all internal error (e.g., database error) that should not be exposed to the caller. + #[error("internal error")] + Internal(#[from] anyhow::Error), } impl SubmitTxError { @@ -99,6 +102,8 @@ impl SubmitTxError { Self::InsufficientFundsForTransfer => "insufficient-funds-for-transfer", Self::IntrinsicGas => "intrinsic-gas", Self::ProxyError(_) => "proxy-error", + Self::FailedToPublishCompressedBytecodes => "failed-to-publish-compressed-bytecodes", + Self::Internal(_) => "internal", } } @@ -142,7 +147,10 @@ impl From for SubmitTxError { impl From for SubmitTxError { fn from(err: ValidationError) -> Self { - Self::ValidationFailed(err.to_string()) + match err { + ValidationError::Internal(err) => Self::Internal(err), + ValidationError::Vm(err) => Self::ValidationFailed(err.to_string()), + } } } diff --git a/core/lib/zksync_core/src/api_server/tx_sender/tests.rs b/core/lib/zksync_core/src/api_server/tx_sender/tests.rs new file mode 100644 index 000000000000..55c6852cd4ab --- /dev/null +++ b/core/lib/zksync_core/src/api_server/tx_sender/tests.rs @@ -0,0 +1,139 @@ +//! Tests for the transaction sender. + +use zksync_types::{get_nonce_key, StorageLog}; + +use super::*; +use crate::{ + api_server::execution_sandbox::{testonly::MockTransactionExecutor, VmConcurrencyBarrier}, + genesis::{ensure_genesis_state, GenesisParams}, + utils::testonly::{create_miniblock, prepare_recovery_snapshot, MockL1GasPriceProvider}, +}; + +pub(crate) async fn create_test_tx_sender( + pool: ConnectionPool, + l2_chain_id: L2ChainId, + tx_executor: TransactionExecutor, +) -> (TxSender, VmConcurrencyBarrier) { + let web3_config = Web3JsonRpcConfig::for_tests(); + let state_keeper_config = StateKeeperConfig::for_tests(); + let tx_sender_config = TxSenderConfig::new(&state_keeper_config, &web3_config, l2_chain_id); + + let mut storage_caches = PostgresStorageCaches::new(1, 1); + let cache_update_task = storage_caches.configure_storage_values_cache( + 1, + pool.clone(), + tokio::runtime::Handle::current(), + ); + tokio::task::spawn_blocking(cache_update_task); + + let gas_adjuster = Arc::new(MockL1GasPriceProvider(1)); + let (mut tx_sender, vm_barrier) = crate::build_tx_sender( + &tx_sender_config, + &web3_config, + &state_keeper_config, + pool.clone(), + pool, + gas_adjuster, + storage_caches, + ) + .await; + + Arc::get_mut(&mut tx_sender.0).unwrap().executor = tx_executor; + (tx_sender, vm_barrier) +} + +#[tokio::test] +async fn getting_nonce_for_account() { + let l2_chain_id = L2ChainId::default(); + let test_address = Address::repeat_byte(1); + let pool = ConnectionPool::test_pool().await; + let mut storage = pool.access_storage().await.unwrap(); + ensure_genesis_state(&mut storage, l2_chain_id, &GenesisParams::mock()) + .await + .unwrap(); + // Manually insert a nonce for the address. + let nonce_key = get_nonce_key(&test_address); + let nonce_log = StorageLog::new_write_log(nonce_key, H256::from_low_u64_be(123)); + storage + .storage_logs_dal() + .append_storage_logs(MiniblockNumber(0), &[(H256::default(), vec![nonce_log])]) + .await; + + let tx_executor = MockTransactionExecutor::default().into(); + let (tx_sender, _) = create_test_tx_sender(pool.clone(), l2_chain_id, tx_executor).await; + + let nonce = tx_sender.get_expected_nonce(test_address).await.unwrap(); + assert_eq!(nonce, Nonce(123)); + + // Insert another miniblock with a new nonce log. + storage + .blocks_dal() + .insert_miniblock(&create_miniblock(1)) + .await + .unwrap(); + let nonce_log = StorageLog { + value: H256::from_low_u64_be(321), + ..nonce_log + }; + storage + .storage_logs_dal() + .insert_storage_logs(MiniblockNumber(1), &[(H256::default(), vec![nonce_log])]) + .await; + + let nonce = tx_sender.get_expected_nonce(test_address).await.unwrap(); + assert_eq!(nonce, Nonce(321)); + let missing_address = Address::repeat_byte(0xff); + let nonce = tx_sender.get_expected_nonce(missing_address).await.unwrap(); + assert_eq!(nonce, Nonce(0)); +} + +#[tokio::test] +async fn getting_nonce_for_account_after_snapshot_recovery() { + const SNAPSHOT_MINIBLOCK_NUMBER: u32 = 42; + + let pool = ConnectionPool::test_pool().await; + let mut storage = pool.access_storage().await.unwrap(); + let test_address = Address::repeat_byte(1); + let other_address = Address::repeat_byte(2); + let nonce_logs = [ + StorageLog::new_write_log(get_nonce_key(&test_address), H256::from_low_u64_be(123)), + StorageLog::new_write_log(get_nonce_key(&other_address), H256::from_low_u64_be(25)), + ]; + prepare_recovery_snapshot(&mut storage, SNAPSHOT_MINIBLOCK_NUMBER, &nonce_logs).await; + + let l2_chain_id = L2ChainId::default(); + let tx_executor = MockTransactionExecutor::default().into(); + let (tx_sender, _) = create_test_tx_sender(pool.clone(), l2_chain_id, tx_executor).await; + + let nonce = tx_sender.get_expected_nonce(test_address).await.unwrap(); + assert_eq!(nonce, Nonce(123)); + let nonce = tx_sender.get_expected_nonce(other_address).await.unwrap(); + assert_eq!(nonce, Nonce(25)); + let missing_address = Address::repeat_byte(0xff); + let nonce = tx_sender.get_expected_nonce(missing_address).await.unwrap(); + assert_eq!(nonce, Nonce(0)); + + storage + .blocks_dal() + .insert_miniblock(&create_miniblock(SNAPSHOT_MINIBLOCK_NUMBER + 1)) + .await + .unwrap(); + let new_nonce_logs = vec![StorageLog::new_write_log( + get_nonce_key(&test_address), + H256::from_low_u64_be(321), + )]; + storage + .storage_logs_dal() + .insert_storage_logs( + MiniblockNumber(SNAPSHOT_MINIBLOCK_NUMBER + 1), + &[(H256::default(), new_nonce_logs)], + ) + .await; + + let nonce = tx_sender.get_expected_nonce(test_address).await.unwrap(); + assert_eq!(nonce, Nonce(321)); + let nonce = tx_sender.get_expected_nonce(other_address).await.unwrap(); + assert_eq!(nonce, Nonce(25)); + let nonce = tx_sender.get_expected_nonce(missing_address).await.unwrap(); + assert_eq!(nonce, Nonce(0)); +} diff --git a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/mod.rs b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/mod.rs index 51f06345da19..b810c9fb5a2b 100644 --- a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/mod.rs +++ b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/mod.rs @@ -2,27 +2,29 @@ //! Consists mostly of boilerplate code implementing the `jsonrpsee` server traits for the corresponding //! namespace structures defined in `zksync_core`. -use std::{error::Error, fmt}; +use std::fmt; use zksync_web3_decl::{ error::Web3Error, jsonrpsee::types::{error::ErrorCode, ErrorObjectOwned}, }; -use crate::api_server::web3::metrics::API_METRICS; +use crate::api_server::{tx_sender::SubmitTxError, web3::metrics::API_METRICS}; pub mod batch_limiter_middleware; pub mod namespaces; -pub fn from_std_error(e: impl Error) -> ErrorObjectOwned { - ErrorObjectOwned::owned(ErrorCode::InternalError.code(), e.to_string(), Some(())) -} - -pub fn into_jsrpc_error(err: Web3Error) -> ErrorObjectOwned { +pub(crate) fn into_jsrpc_error(err: Web3Error) -> ErrorObjectOwned { + let data = match &err { + Web3Error::SubmitTransactionError(_, data) => Some(format!("0x{}", hex::encode(data))), + _ => None, + }; ErrorObjectOwned::owned( match err { Web3Error::InternalError | Web3Error::NotImplemented => ErrorCode::InternalError.code(), Web3Error::NoBlock + | Web3Error::PrunedBlock(_) + | Web3Error::PrunedL1Batch(_) | Web3Error::NoSuchFunction | Web3Error::RLPError(_) | Web3Error::InvalidTransactionData(_) @@ -37,17 +39,25 @@ pub fn into_jsrpc_error(err: Web3Error) -> ErrorObjectOwned { Web3Error::TreeApiUnavailable => 6, }, match err { - Web3Error::SubmitTransactionError(ref message, _) => message.clone(), + Web3Error::SubmitTransactionError(message, _) => message, _ => err.to_string(), }, - match err { - Web3Error::SubmitTransactionError(_, data) => Some(format!("0x{}", hex::encode(data))), - _ => None, - }, + data, ) } -pub fn internal_error(method_name: &'static str, error: impl fmt::Display) -> Web3Error { +impl SubmitTxError { + /// Maps this error into [`Web3Error`]. If this is an internal error, error details are logged, but are not returned + /// to the client. + pub(crate) fn into_web3_error(self, method_name: &'static str) -> Web3Error { + match self { + Self::Internal(err) => internal_error(method_name, err), + _ => Web3Error::SubmitTransactionError(self.to_string(), self.data()), + } + } +} + +pub(crate) fn internal_error(method_name: &'static str, error: impl fmt::Display) -> Web3Error { tracing::error!("Internal error in method {method_name}: {error}"); API_METRICS.web3_internal_errors[&method_name].inc(); Web3Error::InternalError diff --git a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/debug.rs b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/debug.rs index 0bd61bbbc3d2..9f1e00a6c80a 100644 --- a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/debug.rs +++ b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/debug.rs @@ -21,6 +21,7 @@ impl DebugNamespaceServer for DebugNamespace { .await .map_err(into_jsrpc_error) } + async fn trace_block_by_hash( &self, hash: H256, @@ -30,6 +31,7 @@ impl DebugNamespaceServer for DebugNamespace { .await .map_err(into_jsrpc_error) } + async fn trace_call( &self, request: CallRequest, @@ -40,11 +42,14 @@ impl DebugNamespaceServer for DebugNamespace { .await .map_err(into_jsrpc_error) } + async fn trace_transaction( &self, tx_hash: H256, options: Option, ) -> RpcResult> { - Ok(self.debug_trace_transaction_impl(tx_hash, options).await) + self.debug_trace_transaction_impl(tx_hash, options) + .await + .map_err(into_jsrpc_error) } } diff --git a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/en.rs b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/en.rs index 69dce6f6dae4..3480c6ec76f0 100644 --- a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/en.rs +++ b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/en.rs @@ -4,13 +4,10 @@ use zksync_web3_decl::{ namespaces::en::EnNamespaceServer, }; -use crate::{ - api_server::web3::{backend_jsonrpsee::into_jsrpc_error, namespaces::EnNamespace}, - l1_gas_price::L1GasPriceProvider, -}; +use crate::api_server::web3::{backend_jsonrpsee::into_jsrpc_error, namespaces::EnNamespace}; #[async_trait] -impl EnNamespaceServer for EnNamespace { +impl EnNamespaceServer for EnNamespace { async fn sync_l2_block( &self, block_number: MiniblockNumber, diff --git a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/eth.rs b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/eth.rs index 4766b1e8878a..17256c50fe48 100644 --- a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/eth.rs +++ b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/eth.rs @@ -13,13 +13,10 @@ use zksync_web3_decl::{ types::{Filter, FilterChanges}, }; -use crate::{ - api_server::web3::{backend_jsonrpsee::into_jsrpc_error, EthNamespace}, - l1_gas_price::L1GasPriceProvider, -}; +use crate::api_server::web3::{backend_jsonrpsee::into_jsrpc_error, EthNamespace}; #[async_trait] -impl EthNamespaceServer for EthNamespace { +impl EthNamespaceServer for EthNamespace { async fn get_block_number(&self) -> RpcResult { self.get_block_number_impl().await.map_err(into_jsrpc_error) } @@ -41,7 +38,7 @@ impl EthNamespaceServer for EthNa } async fn gas_price(&self) -> RpcResult { - self.gas_price_impl().map_err(into_jsrpc_error) + self.gas_price_impl().await.map_err(into_jsrpc_error) } async fn new_filter(&self, filter: Filter) -> RpcResult { @@ -115,6 +112,12 @@ impl EthNamespaceServer for EthNa .map_err(into_jsrpc_error) } + async fn get_block_receipts(&self, block_id: BlockId) -> RpcResult> { + self.get_block_receipts_impl(block_id) + .await + .map_err(into_jsrpc_error) + } + async fn get_block_transaction_count_by_hash( &self, block_hash: H256, diff --git a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/snapshots.rs b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/snapshots.rs index 5a60fafa9dc5..6596e29e4f2c 100644 --- a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/snapshots.rs +++ b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/snapshots.rs @@ -5,15 +5,12 @@ use zksync_types::{ }; use zksync_web3_decl::{jsonrpsee::core::RpcResult, namespaces::SnapshotsNamespaceServer}; -use crate::{ - api_server::web3::{backend_jsonrpsee::into_jsrpc_error, namespaces::SnapshotsNamespace}, - l1_gas_price::L1GasPriceProvider, +use crate::api_server::web3::{ + backend_jsonrpsee::into_jsrpc_error, namespaces::SnapshotsNamespace, }; #[async_trait] -impl SnapshotsNamespaceServer - for SnapshotsNamespace -{ +impl SnapshotsNamespaceServer for SnapshotsNamespace { async fn get_all_snapshots(&self) -> RpcResult { self.get_all_snapshots_impl() .await diff --git a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/zks.rs b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/zks.rs index 01afdd5a357f..db0760a66c76 100644 --- a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/zks.rs +++ b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/zks.rs @@ -7,6 +7,7 @@ use zksync_types::{ TransactionDetails, }, fee::Fee, + fee_model::FeeParams, transaction_request::CallRequest, Address, L1BatchNumber, MiniblockNumber, H256, U256, U64, }; @@ -16,13 +17,10 @@ use zksync_web3_decl::{ types::Token, }; -use crate::{ - api_server::web3::{backend_jsonrpsee::into_jsrpc_error, ZksNamespace}, - l1_gas_price::L1GasPriceProvider, -}; +use crate::api_server::web3::{backend_jsonrpsee::into_jsrpc_error, ZksNamespace}; #[async_trait] -impl ZksNamespaceServer for ZksNamespace { +impl ZksNamespaceServer for ZksNamespace { async fn estimate_fee(&self, req: CallRequest) -> RpcResult { self.estimate_fee_impl(req).await.map_err(into_jsrpc_error) } @@ -138,18 +136,26 @@ impl ZksNamespaceServer for ZksNa } async fn get_bytecode_by_hash(&self, hash: H256) -> RpcResult>> { - Ok(self.get_bytecode_by_hash_impl(hash).await) + self.get_bytecode_by_hash_impl(hash) + .await + .map_err(into_jsrpc_error) } async fn get_l1_gas_price(&self) -> RpcResult { - Ok(self.get_l1_gas_price_impl()) + Ok(self.get_l1_gas_price_impl().await) + } + + async fn get_fee_params(&self) -> RpcResult { + Ok(self.get_fee_params_impl()) } async fn get_protocol_version( &self, version_id: Option, ) -> RpcResult> { - Ok(self.get_protocol_version_impl(version_id).await) + self.get_protocol_version_impl(version_id) + .await + .map_err(into_jsrpc_error) } async fn get_proof( diff --git a/core/lib/zksync_core/src/api_server/web3/mod.rs b/core/lib/zksync_core/src/api_server/web3/mod.rs index 7776cd91b43d..0f88382a1d18 100644 --- a/core/lib/zksync_core/src/api_server/web3/mod.rs +++ b/core/lib/zksync_core/src/api_server/web3/mod.rs @@ -9,11 +9,10 @@ use tokio::{ task::JoinHandle, }; use tower_http::{cors::CorsLayer, metrics::InFlightRequestsLayer}; -use zksync_dal::{ConnectionPool, StorageProcessor}; +use zksync_dal::ConnectionPool; use zksync_health_check::{HealthStatus, HealthUpdater, ReactiveHealthCheck}; -use zksync_types::{api, MiniblockNumber}; +use zksync_types::MiniblockNumber; use zksync_web3_decl::{ - error::Web3Error, jsonrpsee::{ server::{BatchRequestConfig, RpcServiceBuilder, ServerBuilder}, RpcModule, @@ -26,7 +25,6 @@ use zksync_web3_decl::{ }; use self::{ - backend_jsonrpsee::internal_error, metrics::API_METRICS, namespaces::{ DebugNamespace, EnNamespace, EthNamespace, NetNamespace, SnapshotsNamespace, Web3Namespace, @@ -37,10 +35,11 @@ use self::{ }; use crate::{ api_server::{ - execution_sandbox::VmConcurrencyBarrier, tree::TreeApiHttpClient, tx_sender::TxSender, + execution_sandbox::{BlockStartInfo, VmConcurrencyBarrier}, + tree::TreeApiHttpClient, + tx_sender::TxSender, web3::backend_jsonrpsee::batch_limiter_middleware::LimitMiddleware, }, - l1_gas_price::L1GasPriceProvider, sync_layer::SyncState, }; @@ -119,37 +118,35 @@ struct OptionalApiParams { /// Full API server parameters. #[derive(Debug)] -struct FullApiParams { +struct FullApiParams { pool: ConnectionPool, last_miniblock_pool: ConnectionPool, config: InternalApiConfig, transport: ApiTransport, - tx_sender: TxSender, + tx_sender: TxSender, vm_barrier: VmConcurrencyBarrier, - threads: usize, polling_interval: Duration, namespaces: Vec, optional: OptionalApiParams, } #[derive(Debug)] -pub struct ApiBuilder { +pub struct ApiBuilder { pool: ConnectionPool, last_miniblock_pool: ConnectionPool, config: InternalApiConfig, polling_interval: Duration, // Mandatory params that must be set using builder methods. transport: Option, - tx_sender: Option>, + tx_sender: Option, vm_barrier: Option, - threads: Option, // Optional params that may or may not be set using builder methods. We treat `namespaces` // specially because we want to output a warning if they are not set. namespaces: Option>, optional: OptionalApiParams, } -impl ApiBuilder { +impl ApiBuilder { const DEFAULT_POLLING_INTERVAL: Duration = Duration::from_millis(200); pub fn jsonrpsee_backend(config: InternalApiConfig, pool: ConnectionPool) -> Self { @@ -161,7 +158,6 @@ impl ApiBuilder { transport: None, tx_sender: None, vm_barrier: None, - threads: None, namespaces: None, optional: OptionalApiParams::default(), } @@ -185,11 +181,7 @@ impl ApiBuilder { self } - pub fn with_tx_sender( - mut self, - tx_sender: TxSender, - vm_barrier: VmConcurrencyBarrier, - ) -> Self { + pub fn with_tx_sender(mut self, tx_sender: TxSender, vm_barrier: VmConcurrencyBarrier) -> Self { self.tx_sender = Some(tx_sender); self.vm_barrier = Some(vm_barrier); self @@ -229,11 +221,6 @@ impl ApiBuilder { self } - pub fn with_threads(mut self, threads: usize) -> Self { - self.threads = Some(threads); - self - } - pub fn with_polling_interval(mut self, polling_interval: Duration) -> Self { self.polling_interval = polling_interval; self @@ -255,7 +242,7 @@ impl ApiBuilder { self } - fn into_full_params(self) -> anyhow::Result> { + fn into_full_params(self) -> anyhow::Result { Ok(FullApiParams { pool: self.pool, last_miniblock_pool: self.last_miniblock_pool, @@ -263,7 +250,6 @@ impl ApiBuilder { transport: self.transport.context("API transport not set")?, tx_sender: self.tx_sender.context("Transaction sender not set")?, vm_barrier: self.vm_barrier.context("VM barrier not set")?, - threads: self.threads.context("Number of server threads not set")?, polling_interval: self.polling_interval, namespaces: self.namespaces.unwrap_or_else(|| { tracing::warn!( @@ -276,7 +262,7 @@ impl ApiBuilder { } } -impl ApiBuilder { +impl ApiBuilder { pub async fn build( self, stop_receiver: watch::Receiver, @@ -285,42 +271,46 @@ impl ApiBuilder { } } -impl FullApiParams { - fn build_rpc_state(self) -> RpcState { - // Chosen to be significantly smaller than the interval between miniblocks, but larger than - // the latency of getting the latest sealed miniblock number from Postgres. If the API server - // processes enough requests, information about the latest sealed miniblock will be updated - // by reporting block difference metrics, so the actual update lag would be much smaller than this value. - const SEALED_MINIBLOCK_UPDATE_INTERVAL: Duration = Duration::from_millis(25); - - let (last_sealed_miniblock, update_task) = - SealedMiniblockNumber::new(self.last_miniblock_pool, SEALED_MINIBLOCK_UPDATE_INTERVAL); - // The update tasks takes care of its termination, so we don't need to retain its handle. - tokio::spawn(update_task); - - RpcState { +impl FullApiParams { + async fn build_rpc_state( + self, + last_sealed_miniblock: SealedMiniblockNumber, + ) -> anyhow::Result { + let mut storage = self + .last_miniblock_pool + .access_storage_tagged("api") + .await?; + let start_info = BlockStartInfo::new(&mut storage).await?; + drop(storage); + + Ok(RpcState { installed_filters: Arc::new(Mutex::new(Filters::new(self.optional.filters_limit))), connection_pool: self.pool, tx_sender: self.tx_sender, sync_state: self.optional.sync_state, api_config: self.config, + start_info, last_sealed_miniblock, tree_api: self .optional .tree_api_url .map(|url| TreeApiHttpClient::new(url.as_str())), - } + }) } - async fn build_rpc_module(self, pubsub: Option) -> RpcModule<()> { + async fn build_rpc_module( + self, + pub_sub: Option, + last_sealed_miniblock: SealedMiniblockNumber, + ) -> anyhow::Result> { let namespaces = self.namespaces.clone(); let zksync_network_id = self.config.l2_chain_id; - let rpc_state = self.build_rpc_state(); + let rpc_state = self.build_rpc_state(last_sealed_miniblock).await?; // Collect all the methods into a single RPC module. let mut rpc = RpcModule::new(()); - if let Some(pubsub) = pubsub { - rpc.merge(pubsub.into_rpc()) + if let Some(pub_sub) = pub_sub { + rpc.merge(pub_sub.into_rpc()) .expect("Can't merge eth pubsub namespace"); } @@ -352,7 +342,7 @@ impl FullApiParams { rpc.merge(SnapshotsNamespace::new(rpc_state).into_rpc()) .expect("Can't merge snapshots namespace"); } - rpc + Ok(rpc) } async fn spawn_server( @@ -403,39 +393,27 @@ impl FullApiParams { self, stop_receiver: watch::Receiver, ) -> anyhow::Result { + // Chosen to be significantly smaller than the interval between miniblocks, but larger than + // the latency of getting the latest sealed miniblock number from Postgres. If the API server + // processes enough requests, information about the latest sealed miniblock will be updated + // by reporting block difference metrics, so the actual update lag would be much smaller than this value. + const SEALED_MINIBLOCK_UPDATE_INTERVAL: Duration = Duration::from_millis(25); + let transport = self.transport; - let (runtime_thread_name, health_check_name) = match transport { - ApiTransport::Http(_) => ("jsonrpsee-http-worker", "http_api"), - ApiTransport::WebSocket(_) => ("jsonrpsee-ws-worker", "ws_api"), + let health_check_name = match transport { + ApiTransport::Http(_) => "http_api", + ApiTransport::WebSocket(_) => "ws_api", }; let (health_check, health_updater) = ReactiveHealthCheck::new(health_check_name); - let vm_barrier = self.vm_barrier.clone(); - let batch_request_config = self - .optional - .batch_request_size_limit - .map_or(BatchRequestConfig::Unlimited, |limit| { - BatchRequestConfig::Limit(limit as u32) - }); - let response_body_size_limit = self - .optional - .response_body_size_limit - .map_or(u32::MAX, |limit| limit as u32); - let websocket_requests_per_minute_limit = self.optional.websocket_requests_per_minute_limit; - let subscriptions_limit = self.optional.subscriptions_limit; + let (last_sealed_miniblock, update_task) = SealedMiniblockNumber::new( + self.last_miniblock_pool.clone(), + SEALED_MINIBLOCK_UPDATE_INTERVAL, + stop_receiver.clone(), + ); + let mut tasks = vec![tokio::spawn(update_task)]; - let runtime = tokio::runtime::Builder::new_multi_thread() - .enable_all() - .thread_name(runtime_thread_name) - .worker_threads(self.threads) - .build() - .with_context(|| { - format!("Failed creating Tokio runtime for {health_check_name} jsonrpsee server") - })?; - - let mut tasks = vec![]; - let mut pubsub = None; - if matches!(transport, ApiTransport::WebSocket(_)) + let pub_sub = if matches!(transport, ApiTransport::WebSocket(_)) && self.namespaces.contains(&Namespace::Pubsub) { let mut pub_sub = EthSubscribe::new(); @@ -448,28 +426,20 @@ impl FullApiParams { self.polling_interval, stop_receiver.clone(), )); - pubsub = Some(pub_sub); - } + Some(pub_sub) + } else { + None + }; - let rpc = self.build_rpc_module(pubsub).await; // Start the server in a separate tokio runtime from a dedicated thread. let (local_addr_sender, local_addr) = oneshot::channel(); - let server_task = tokio::task::spawn_blocking(move || { - let res = runtime.block_on(Self::run_jsonrpsee_server( - rpc, - transport, - stop_receiver, - local_addr_sender, - health_updater, - vm_barrier, - batch_request_config, - response_body_size_limit, - subscriptions_limit, - websocket_requests_per_minute_limit, - )); - runtime.shutdown_timeout(GRACEFUL_SHUTDOWN_TIMEOUT); - res - }); + let server_task = tokio::spawn(self.run_jsonrpsee_server( + stop_receiver, + pub_sub, + last_sealed_miniblock, + local_addr_sender, + health_updater, + )); let local_addr = match local_addr.await { Ok(addr) => addr, @@ -490,19 +460,33 @@ impl FullApiParams { }) } - #[allow(clippy::too_many_arguments)] async fn run_jsonrpsee_server( - rpc: RpcModule<()>, - transport: ApiTransport, + self, mut stop_receiver: watch::Receiver, + pub_sub: Option, + last_sealed_miniblock: SealedMiniblockNumber, local_addr_sender: oneshot::Sender, health_updater: HealthUpdater, - vm_barrier: VmConcurrencyBarrier, - batch_request_config: BatchRequestConfig, - response_body_size_limit: u32, - subscriptions_limit: Option, - websocket_requests_per_minute_limit: Option, ) -> anyhow::Result<()> { + let transport = self.transport; + let batch_request_config = self + .optional + .batch_request_size_limit + .map_or(BatchRequestConfig::Unlimited, |limit| { + BatchRequestConfig::Limit(limit as u32) + }); + let response_body_size_limit = self + .optional + .response_body_size_limit + .map_or(u32::MAX, |limit| limit as u32); + let websocket_requests_per_minute_limit = self.optional.websocket_requests_per_minute_limit; + let subscriptions_limit = self.optional.subscriptions_limit; + let vm_barrier = self.vm_barrier.clone(); + + let rpc = self + .build_rpc_module(pub_sub, last_sealed_miniblock) + .await?; + let (transport_str, is_http, addr) = match transport { ApiTransport::Http(addr) => ("HTTP", true, addr), ApiTransport::WebSocket(addr) => ("WS", false, addr), @@ -591,14 +575,3 @@ impl FullApiParams { Ok(()) } } - -async fn resolve_block( - connection: &mut StorageProcessor<'_>, - block: api::BlockId, - method_name: &'static str, -) -> Result { - let result = connection.blocks_web3_dal().resolve_block_id(block).await; - result - .map_err(|err| internal_error(method_name, err))? - .ok_or(Web3Error::NoBlock) -} diff --git a/core/lib/zksync_core/src/api_server/web3/namespaces/debug.rs b/core/lib/zksync_core/src/api_server/web3/namespaces/debug.rs index d65c065392f7..351ebf3dbd80 100644 --- a/core/lib/zksync_core/src/api_server/web3/namespaces/debug.rs +++ b/core/lib/zksync_core/src/api_server/web3/namespaces/debug.rs @@ -2,62 +2,53 @@ use std::sync::Arc; use multivm::{interface::ExecutionResult, vm_latest::constants::BLOCK_GAS_LIMIT}; use once_cell::sync::OnceCell; -use zksync_dal::ConnectionPool; -use zksync_state::PostgresStorageCaches; +use zksync_system_constants::MAX_ENCODED_TX_SIZE; use zksync_types::{ api::{BlockId, BlockNumber, DebugCall, ResultDebugCall, TracerConfig}, + fee_model::BatchFeeInput, l2::L2Tx, transaction_request::CallRequest, vm_trace::Call, - AccountTreeId, L2ChainId, H256, USED_BOOTLOADER_MEMORY_BYTES, + AccountTreeId, H256, }; use zksync_web3_decl::error::Web3Error; -use crate::{ - api_server::{ - execution_sandbox::{ - execute_tx_eth_call, ApiTracer, BlockArgs, TxSharedArgs, VmConcurrencyLimiter, - }, - tx_sender::ApiContracts, - web3::{ - backend_jsonrpsee::internal_error, - metrics::API_METRICS, - resolve_block, - state::{RpcState, SealedMiniblockNumber}, - }, - }, - l1_gas_price::L1GasPriceProvider, +use crate::api_server::{ + execution_sandbox::{ApiTracer, TxSharedArgs}, + tx_sender::{ApiContracts, TxSenderConfig}, + web3::{backend_jsonrpsee::internal_error, metrics::API_METRICS, state::RpcState}, }; #[derive(Debug, Clone)] pub struct DebugNamespace { - connection_pool: ConnectionPool, - fair_l2_gas_price: u64, + batch_fee_input: BatchFeeInput, + state: RpcState, api_contracts: ApiContracts, - vm_execution_cache_misses_limit: Option, - vm_concurrency_limiter: Arc, - storage_caches: PostgresStorageCaches, - last_sealed_miniblock: SealedMiniblockNumber, - chain_id: L2ChainId, } impl DebugNamespace { - pub async fn new(state: RpcState) -> Self { - let sender_config = &state.tx_sender.0.sender_config; - + pub async fn new(state: RpcState) -> Self { let api_contracts = ApiContracts::load_from_disk(); Self { - connection_pool: state.connection_pool, - fair_l2_gas_price: sender_config.fair_l2_gas_price, + // For now, the same scaling is used for both the L1 gas price and the pubdata price + batch_fee_input: state + .tx_sender + .0 + .batch_fee_input_provider + .get_batch_fee_input_scaled( + state.api_config.estimate_gas_scale_factor, + state.api_config.estimate_gas_scale_factor, + ) + .await, + state, api_contracts, - vm_execution_cache_misses_limit: sender_config.vm_execution_cache_misses_limit, - vm_concurrency_limiter: state.tx_sender.vm_concurrency_limiter(), - storage_caches: state.tx_sender.storage_caches(), - last_sealed_miniblock: state.last_sealed_miniblock, - chain_id: sender_config.chain_id, } } + fn sender_config(&self) -> &TxSenderConfig { + &self.state.tx_sender.0.sender_config + } + #[tracing::instrument(skip(self))] pub async fn debug_trace_block_impl( &self, @@ -71,17 +62,21 @@ impl DebugNamespace { .map(|options| options.tracer_config.only_top_call) .unwrap_or(false); let mut connection = self + .state .connection_pool .access_storage_tagged("api") .await - .unwrap(); - let block_number = resolve_block(&mut connection, block_id, METHOD_NAME).await?; - let call_trace = connection + .map_err(|err| internal_error(METHOD_NAME, err))?; + let block_number = self + .state + .resolve_block(&mut connection, block_id, METHOD_NAME) + .await?; + let call_traces = connection .blocks_web3_dal() - .get_trace_for_miniblock(block_number) + .get_traces_for_miniblock(block_number) .await - .unwrap(); - let call_trace = call_trace + .map_err(|err| internal_error(METHOD_NAME, err))?; + let call_trace = call_traces .into_iter() .map(|call_trace| { let mut result: DebugCall = call_trace.into(); @@ -92,7 +87,7 @@ impl DebugNamespace { }) .collect(); - let block_diff = self.last_sealed_miniblock.diff(block_number); + let block_diff = self.state.last_sealed_miniblock.diff(block_number); method_latency.observe(block_diff); Ok(call_trace) } @@ -102,25 +97,30 @@ impl DebugNamespace { &self, tx_hash: H256, options: Option, - ) -> Option { + ) -> Result, Web3Error> { + const METHOD_NAME: &str = "debug_trace_transaction"; + let only_top_call = options .map(|options| options.tracer_config.only_top_call) .unwrap_or(false); - let call_trace = self + let mut connection = self + .state .connection_pool .access_storage_tagged("api") .await - .unwrap() + .map_err(|err| internal_error(METHOD_NAME, err))?; + let call_trace = connection .transactions_dal() .get_call_trace(tx_hash) - .await; - call_trace.map(|call_trace| { + .await + .map_err(|err| internal_error(METHOD_NAME, err))?; + Ok(call_trace.map(|call_trace| { let mut result: DebugCall = call_trace.into(); if only_top_call { result.calls = vec![]; } result - }) + })) } #[tracing::instrument(skip(self, request, block_id))] @@ -139,20 +139,26 @@ impl DebugNamespace { .unwrap_or(false); let mut connection = self + .state .connection_pool .access_storage_tagged("api") .await - .unwrap(); - let block_args = BlockArgs::new(&mut connection, block_id) - .await - .map_err(|err| internal_error("debug_trace_call", err))? - .ok_or(Web3Error::NoBlock)?; + .map_err(|err| internal_error(METHOD_NAME, err))?; + let block_args = self + .state + .resolve_block_args(&mut connection, block_id, METHOD_NAME) + .await?; drop(connection); - let tx = L2Tx::from_request(request.into(), USED_BOOTLOADER_MEMORY_BYTES)?; + let tx = L2Tx::from_request(request.into(), MAX_ENCODED_TX_SIZE)?; let shared_args = self.shared_args(); - let vm_permit = self.vm_concurrency_limiter.acquire().await; + let vm_permit = self + .state + .tx_sender + .vm_concurrency_limiter() + .acquire() + .await; let vm_permit = vm_permit.ok_or(Web3Error::InternalError)?; // We don't need properly trace if we only need top call @@ -163,16 +169,19 @@ impl DebugNamespace { vec![ApiTracer::CallTracer(call_tracer_result.clone())] }; - let result = execute_tx_eth_call( - vm_permit, - shared_args, - self.connection_pool.clone(), - tx.clone(), - block_args, - self.vm_execution_cache_misses_limit, - custom_tracers, - ) - .await; + let executor = &self.state.tx_sender.0.executor; + let result = executor + .execute_tx_eth_call( + vm_permit, + shared_args, + self.state.connection_pool.clone(), + tx.clone(), + block_args, + self.sender_config().vm_execution_cache_misses_limit, + custom_tracers, + ) + .await + .map_err(|err| internal_error(METHOD_NAME, err))?; let (output, revert_reason) = match result.result { ExecutionResult::Success { output, .. } => (output, None), @@ -200,20 +209,23 @@ impl DebugNamespace { trace, ); - let block_diff = self.last_sealed_miniblock.diff_with_block_args(&block_args); + let block_diff = self + .state + .last_sealed_miniblock + .diff_with_block_args(&block_args); method_latency.observe(block_diff); Ok(call.into()) } fn shared_args(&self) -> TxSharedArgs { + let sender_config = self.sender_config(); TxSharedArgs { operator_account: AccountTreeId::default(), - l1_gas_price: 100_000, - fair_l2_gas_price: self.fair_l2_gas_price, + fee_input: self.batch_fee_input, base_system_contracts: self.api_contracts.eth_call.clone(), - caches: self.storage_caches.clone(), + caches: self.state.tx_sender.storage_caches().clone(), validation_computational_gas_limit: BLOCK_GAS_LIMIT, - chain_id: self.chain_id, + chain_id: sender_config.chain_id, } } } diff --git a/core/lib/zksync_core/src/api_server/web3/namespaces/en.rs b/core/lib/zksync_core/src/api_server/web3/namespaces/en.rs index ada181c39636..fdef4f4a36ad 100644 --- a/core/lib/zksync_core/src/api_server/web3/namespaces/en.rs +++ b/core/lib/zksync_core/src/api_server/web3/namespaces/en.rs @@ -1,28 +1,17 @@ use zksync_types::{api::en::SyncBlock, MiniblockNumber}; use zksync_web3_decl::error::Web3Error; -use crate::{ - api_server::web3::{backend_jsonrpsee::internal_error, state::RpcState}, - l1_gas_price::L1GasPriceProvider, -}; +use crate::api_server::web3::{backend_jsonrpsee::internal_error, state::RpcState}; /// Namespace for External Node unique methods. /// Main use case for it is the EN synchronization. #[derive(Debug)] -pub struct EnNamespace { - pub state: RpcState, +pub struct EnNamespace { + state: RpcState, } -impl Clone for EnNamespace { - fn clone(&self) -> Self { - Self { - state: self.state.clone(), - } - } -} - -impl EnNamespace { - pub fn new(state: RpcState) -> Self { +impl EnNamespace { + pub fn new(state: RpcState) -> Self { Self { state } } @@ -32,20 +21,18 @@ impl EnNamespace { block_number: MiniblockNumber, include_transactions: bool, ) -> Result, Web3Error> { + const METHOD_NAME: &str = "en_syncL2Block"; + let mut storage = self .state .connection_pool .access_storage_tagged("api") .await - .unwrap(); + .map_err(|err| internal_error(METHOD_NAME, err))?; storage .sync_dal() - .sync_block( - block_number, - self.state.tx_sender.0.sender_config.fee_account_addr, - include_transactions, - ) + .sync_block(block_number, include_transactions) .await - .map_err(|err| internal_error("en_syncL2Block", err)) + .map_err(|err| internal_error(METHOD_NAME, err)) } } diff --git a/core/lib/zksync_core/src/api_server/web3/namespaces/eth.rs b/core/lib/zksync_core/src/api_server/web3/namespaces/eth.rs index f01683a16f3e..0098eacdbf03 100644 --- a/core/lib/zksync_core/src/api_server/web3/namespaces/eth.rs +++ b/core/lib/zksync_core/src/api_server/web3/namespaces/eth.rs @@ -1,3 +1,4 @@ +use zksync_system_constants::DEFAULT_L2_TX_GAS_PER_PUBDATA_BYTE; use zksync_types::{ api::{ BlockId, BlockNumber, GetLogsFilter, Transaction, TransactionId, TransactionReceipt, @@ -8,8 +9,7 @@ use zksync_types::{ utils::decompose_full_nonce, web3, web3::types::{FeeHistory, SyncInfo, SyncState}, - AccountTreeId, Bytes, MiniblockNumber, StorageKey, H256, L2_ETH_TOKEN_ADDRESS, - MAX_GAS_PER_PUBDATA_BYTE, U256, + AccountTreeId, Bytes, MiniblockNumber, StorageKey, H256, L2_ETH_TOKEN_ADDRESS, U256, }; use zksync_utils::u256_to_h256; use zksync_web3_decl::{ @@ -17,38 +17,23 @@ use zksync_web3_decl::{ types::{Address, Block, Filter, FilterChanges, Log, U64}, }; -use crate::{ - api_server::{ - execution_sandbox::BlockArgs, - web3::{ - backend_jsonrpsee::internal_error, - metrics::{BlockCallObserver, API_METRICS}, - resolve_block, - state::RpcState, - TypedFilter, - }, - }, - l1_gas_price::L1GasPriceProvider, +use crate::api_server::web3::{ + backend_jsonrpsee::internal_error, + metrics::{BlockCallObserver, API_METRICS}, + state::RpcState, + TypedFilter, }; pub const EVENT_TOPIC_NUMBER_LIMIT: usize = 4; pub const PROTOCOL_VERSION: &str = "zks/1"; #[derive(Debug)] -pub struct EthNamespace { - state: RpcState, -} - -impl Clone for EthNamespace { - fn clone(&self) -> Self { - Self { - state: self.state.clone(), - } - } +pub struct EthNamespace { + state: RpcState, } -impl EthNamespace { - pub fn new(state: RpcState) -> Self { +impl EthNamespace { + pub fn new(state: RpcState) -> Self { Self { state } } @@ -57,20 +42,21 @@ impl EthNamespace { const METHOD_NAME: &str = "get_block_number"; let method_latency = API_METRICS.start_call(METHOD_NAME); - let block_number = self + let mut storage = self .state .connection_pool .access_storage_tagged("api") .await - .unwrap() - .blocks_web3_dal() + .map_err(|err| internal_error(METHOD_NAME, err))?; + let block_number = storage + .blocks_dal() .get_sealed_miniblock_number() .await - .map(|n| U64::from(n.0)) - .map_err(|err| internal_error(METHOD_NAME, err)); + .map_err(|err| internal_error(METHOD_NAME, err))? + .ok_or(Web3Error::NoBlock)?; method_latency.observe(); - block_number + Ok(block_number.0.into()) } #[tracing::instrument(skip(self, request, block_id))] @@ -88,18 +74,18 @@ impl EthNamespace { .connection_pool .access_storage_tagged("api") .await - .unwrap(); - let block_args = BlockArgs::new(&mut connection, block_id) - .await - .map_err(|err| internal_error("eth_call", err))? - .ok_or(Web3Error::NoBlock)?; + .map_err(|err| internal_error(METHOD_NAME, err))?; + let block_args = self + .state + .resolve_block_args(&mut connection, block_id, METHOD_NAME) + .await?; + drop(connection); let tx = L2Tx::from_request(request.into(), self.state.api_config.max_tx_size)?; let call_result = self.state.tx_sender.eth_call(block_args, tx).await; - let res_bytes = call_result - .map_err(|err| Web3Error::SubmitTransactionError(err.to_string(), err.data()))?; + let res_bytes = call_result.map_err(|err| err.into_web3_error(METHOD_NAME))?; let block_diff = self .state @@ -125,7 +111,7 @@ impl EthNamespace { if let Some(ref mut eip712_meta) = request_with_gas_per_pubdata_overridden.eip712_meta { if eip712_meta.gas_per_pubdata == U256::zero() { - eip712_meta.gas_per_pubdata = MAX_GAS_PER_PUBDATA_BYTE.into(); + eip712_meta.gas_per_pubdata = DEFAULT_L2_TX_GAS_PER_PUBDATA_BYTE.into(); } } @@ -147,7 +133,9 @@ impl EthNamespace { // When we're estimating fee, we are trying to deduce values related to fee, so we should // not consider provided ones. - tx.common_data.fee.max_fee_per_gas = self.state.tx_sender.gas_price().into(); + let gas_price = self.state.tx_sender.gas_price().await; + let gas_price = gas_price.map_err(|err| internal_error(METHOD_NAME, err))?; + tx.common_data.fee.max_fee_per_gas = gas_price.into(); tx.common_data.fee.max_priority_fee_per_gas = tx.common_data.fee.max_fee_per_gas; // Modify the l1 gas price with the scale factor @@ -160,20 +148,20 @@ impl EthNamespace { .tx_sender .get_txs_fee_in_wei(tx.into(), scale_factor, acceptable_overestimation) .await - .map_err(|err| Web3Error::SubmitTransactionError(err.to_string(), err.data()))?; - + .map_err(|err| err.into_web3_error(METHOD_NAME))?; method_latency.observe(); Ok(fee.gas_limit) } #[tracing::instrument(skip(self))] - pub fn gas_price_impl(&self) -> Result { + pub async fn gas_price_impl(&self) -> Result { const METHOD_NAME: &str = "gas_price"; let method_latency = API_METRICS.start_call(METHOD_NAME); - let price = self.state.tx_sender.gas_price(); + let gas_price = self.state.tx_sender.gas_price().await; + let gas_price = gas_price.map_err(|err| internal_error(METHOD_NAME, err))?; method_latency.observe(); - Ok(price.into()) + Ok(gas_price.into()) } #[tracing::instrument(skip(self))] @@ -191,8 +179,11 @@ impl EthNamespace { .connection_pool .access_storage_tagged("api") .await - .unwrap(); - let block_number = resolve_block(&mut connection, block_id, METHOD_NAME).await?; + .map_err(|err| internal_error(METHOD_NAME, err))?; + let block_number = self + .state + .resolve_block(&mut connection, block_id, METHOD_NAME) + .await?; let balance = connection .storage_web3_dal() .standard_token_historical_balance( @@ -279,12 +270,13 @@ impl EthNamespace { }; let method_latency = API_METRICS.start_block_call(method_name, block_id); + self.state.start_info.ensure_not_pruned(block_id)?; let block = self .state .connection_pool .access_storage_tagged("api") .await - .unwrap() + .map_err(|err| internal_error(method_name, err))? .blocks_web3_dal() .get_block_by_web3_block_id( block_id, @@ -311,12 +303,13 @@ impl EthNamespace { const METHOD_NAME: &str = "get_block_transaction_count"; let method_latency = API_METRICS.start_block_call(METHOD_NAME, block_id); + self.state.start_info.ensure_not_pruned(block_id)?; let tx_count = self .state .connection_pool .access_storage_tagged("api") .await - .unwrap() + .map_err(|err| internal_error(METHOD_NAME, err))? .blocks_web3_dal() .get_block_tx_count(block_id) .await @@ -330,6 +323,60 @@ impl EthNamespace { Ok(tx_count?.map(|(_, count)| count)) } + #[tracing::instrument(skip(self))] + pub async fn get_block_receipts_impl( + &self, + block_id: BlockId, + ) -> Result, Web3Error> { + const METHOD_NAME: &str = "get_block_receipts"; + + let method_latency = API_METRICS.start_block_call(METHOD_NAME, block_id); + + self.state.start_info.ensure_not_pruned(block_id)?; + + let block = self + .state + .connection_pool + .access_storage_tagged("api") + .await + .map_err(|err| internal_error(METHOD_NAME, err))? + .blocks_web3_dal() + .get_block_by_web3_block_id(block_id, false, self.state.api_config.l2_chain_id) + .await + .map_err(|err| internal_error(METHOD_NAME, err))?; + + let transactions: &[TransactionVariant] = + block.as_ref().map_or(&[], |block| &block.transactions); + let hashes: Vec<_> = transactions + .iter() + .map(|tx| match tx { + TransactionVariant::Full(tx) => tx.hash, + TransactionVariant::Hash(hash) => *hash, + }) + .collect(); + + let mut receipts = self + .state + .connection_pool + .access_storage_tagged("api") + .await + .map_err(|err| internal_error(METHOD_NAME, err))? + .transactions_web3_dal() + .get_transaction_receipts(&hashes) + .await + .map_err(|err| internal_error(METHOD_NAME, err))?; + + receipts.sort_unstable_by_key(|receipt| receipt.transaction_index); + + if let Some(block) = block { + self.report_latency_with_block_id(method_latency, block.number.as_u32().into()); + } else { + method_latency.observe_without_diff(); + } + + Ok(receipts) + } + #[tracing::instrument(skip(self))] pub async fn get_code_impl( &self, @@ -346,7 +393,10 @@ impl EthNamespace { .access_storage_tagged("api") .await .unwrap(); - let block_number = resolve_block(&mut connection, block_id, METHOD_NAME).await?; + let block_number = self + .state + .resolve_block(&mut connection, block_id, METHOD_NAME) + .await?; let contract_code = connection .storage_web3_dal() .get_contract_code_unchecked(address, block_number) @@ -380,7 +430,10 @@ impl EthNamespace { .access_storage_tagged("api") .await .unwrap(); - let block_number = resolve_block(&mut connection, block_id, METHOD_NAME).await?; + let block_number = self + .state + .resolve_block(&mut connection, block_id, METHOD_NAME) + .await?; let value = connection .storage_web3_dal() .get_historical_value_unchecked(&storage_key, block_number) @@ -412,35 +465,34 @@ impl EthNamespace { .await .unwrap(); - let (full_nonce, block_number) = match block_id { - BlockId::Number(BlockNumber::Pending) => { - let nonce = connection - .transactions_web3_dal() - .next_nonce_by_initiator_account(address) - .await - .map_err(|err| internal_error(method_name, err)); - (nonce, None) - } - _ => { - let block_number = resolve_block(&mut connection, block_id, method_name).await?; - let nonce = connection - .storage_web3_dal() - .get_address_historical_nonce(address, block_number) - .await - .map_err(|err| internal_error(method_name, err)); - (nonce, Some(block_number)) - } - }; + let block_number = self + .state + .resolve_block(&mut connection, block_id, method_name) + .await?; + let full_nonce = connection + .storage_web3_dal() + .get_address_historical_nonce(address, block_number) + .await + .map_err(|err| internal_error(method_name, err))?; // TODO (SMA-1612): currently account nonce is returning always, but later we will // return account nonce for account abstraction and deployment nonce for non account abstraction. // Strip off deployer nonce part. - let account_nonce = full_nonce.map(|nonce| decompose_full_nonce(nonce).0); + let (mut account_nonce, _) = decompose_full_nonce(full_nonce); + + if matches!(block_id, BlockId::Number(BlockNumber::Pending)) { + let account_nonce_u64 = u64::try_from(account_nonce) + .map_err(|err| internal_error(method_name, anyhow::anyhow!(err)))?; + account_nonce = connection + .transactions_web3_dal() + .next_nonce_by_initiator_account(address, account_nonce_u64) + .await + .map_err(|err| internal_error(method_name, err))?; + } - let block_diff = - block_number.map_or(0, |number| self.state.last_sealed_miniblock.diff(number)); + let block_diff = self.state.last_sealed_miniblock.diff(block_number); method_latency.observe(block_diff); - account_nonce + Ok(account_nonce) } #[tracing::instrument(skip(self))] @@ -497,19 +549,20 @@ impl EthNamespace { const METHOD_NAME: &str = "get_transaction_receipt"; let method_latency = API_METRICS.start_call(METHOD_NAME); - let receipt = self + let receipts = self .state .connection_pool .access_storage_tagged("api") .await .unwrap() .transactions_web3_dal() - .get_transaction_receipt(hash) + .get_transaction_receipts(&[hash]) .await - .map_err(|err| internal_error(METHOD_NAME, err)); + .map_err(|err| internal_error(METHOD_NAME, err))?; method_latency.observe(); - receipt + + Ok(receipts.into_iter().next()) } #[tracing::instrument(skip(self))] @@ -517,25 +570,30 @@ impl EthNamespace { const METHOD_NAME: &str = "new_block_filter"; let method_latency = API_METRICS.start_call(METHOD_NAME); - let mut conn = self + let mut storage = self .state .connection_pool .access_storage_tagged("api") .await .map_err(|err| internal_error(METHOD_NAME, err))?; - let last_block_number = conn - .blocks_web3_dal() + let last_block_number = storage + .blocks_dal() .get_sealed_miniblock_number() .await .map_err(|err| internal_error(METHOD_NAME, err))?; - drop(conn); + let next_block_number = match last_block_number { + Some(number) => number + 1, + // If we don't have miniblocks in the storage, use the first projected miniblock number as the cursor + None => self.state.start_info.first_miniblock, + }; + drop(storage); let idx = self .state .installed_filters .lock() .await - .add(TypedFilter::Blocks(last_block_number + 1)); + .add(TypedFilter::Blocks(next_block_number)); method_latency.observe(); Ok(idx) } @@ -641,7 +699,7 @@ impl EthNamespace { let submit_result = submit_result.map(|_| hash).map_err(|err| { tracing::debug!("Send raw transaction error: {err}"); API_METRICS.submit_tx_error[&err.prom_error_code()].inc(); - Web3Error::SubmitTransactionError(err.to_string(), err.data()) + err.into_web3_error(METHOD_NAME) }); method_latency.observe(); @@ -695,8 +753,10 @@ impl EthNamespace { .access_storage_tagged("api") .await .unwrap(); - let newest_miniblock = - resolve_block(&mut connection, BlockId::Number(newest_block), METHOD_NAME).await?; + let newest_miniblock = self + .state + .resolve_block(&mut connection, BlockId::Number(newest_block), METHOD_NAME) + .await?; let mut base_fee_per_gas = connection .blocks_web3_dal() @@ -860,7 +920,7 @@ impl EthNamespace { // They are moved into a separate `impl` block so they don't make the actual implementation noisy. // This `impl` block contains methods that we *have* to implement for compliance, but don't really // make sense in terms of L2. -impl EthNamespace { +impl EthNamespace { pub fn coinbase_impl(&self) -> Address { // There is no coinbase account. Address::default() diff --git a/core/lib/zksync_core/src/api_server/web3/namespaces/snapshots.rs b/core/lib/zksync_core/src/api_server/web3/namespaces/snapshots.rs index 2f742f48abbe..b45fe9a472ee 100644 --- a/core/lib/zksync_core/src/api_server/web3/namespaces/snapshots.rs +++ b/core/lib/zksync_core/src/api_server/web3/namespaces/snapshots.rs @@ -4,25 +4,17 @@ use zksync_types::{ }; use zksync_web3_decl::error::Web3Error; -use crate::{ - api_server::web3::{backend_jsonrpsee::internal_error, metrics::API_METRICS, state::RpcState}, - l1_gas_price::L1GasPriceProvider, +use crate::api_server::web3::{ + backend_jsonrpsee::internal_error, metrics::API_METRICS, state::RpcState, }; -#[derive(Debug)] -pub struct SnapshotsNamespace { - state: RpcState, +#[derive(Debug, Clone)] +pub struct SnapshotsNamespace { + state: RpcState, } -impl Clone for SnapshotsNamespace { - fn clone(&self) -> Self { - Self { - state: self.state.clone(), - } - } -} -impl SnapshotsNamespace { - pub fn new(state: RpcState) -> Self { +impl SnapshotsNamespace { + pub fn new(state: RpcState) -> Self { Self { state } } @@ -37,7 +29,7 @@ impl SnapshotsNamespace { .map_err(|err| internal_error(method_name, err))?; let mut snapshots_dal = storage_processor.snapshots_dal(); let response = snapshots_dal - .get_all_snapshots() + .get_all_complete_snapshots() .await .map_err(|err| internal_error(method_name, err)); method_latency.observe(); @@ -56,45 +48,61 @@ impl SnapshotsNamespace { .access_storage_tagged("api") .await .map_err(|err| internal_error(method_name, err))?; - let mut snapshots_dal = storage_processor.snapshots_dal(); - let snapshot_metadata = snapshots_dal + let snapshot_metadata = storage_processor + .snapshots_dal() .get_snapshot_metadata(l1_batch_number) .await .map_err(|err| internal_error(method_name, err))?; - if let Some(snapshot_metadata) = snapshot_metadata { - let snapshot_files = snapshot_metadata.storage_logs_filepaths.clone(); - let chunks = snapshot_files - .iter() - .enumerate() - .map(|(chunk_id, filepath)| SnapshotStorageLogsChunkMetadata { - chunk_id: chunk_id as u64, - filepath: filepath.clone(), - }) - .collect(); - let l1_batch_with_metadata = storage_processor - .blocks_dal() - .get_l1_batch_metadata(l1_batch_number) - .await - .map_err(|err| internal_error(method_name, err))? - .unwrap(); - let miniblock_number = storage_processor - .blocks_dal() - .get_miniblock_range_of_l1_batch(l1_batch_number) - .await - .map_err(|err| internal_error(method_name, err))? - .unwrap() - .1; + + let Some(snapshot_metadata) = snapshot_metadata else { method_latency.observe(); - Ok(Some(SnapshotHeader { - l1_batch_number: snapshot_metadata.l1_batch_number, - miniblock_number, - last_l1_batch_with_metadata: l1_batch_with_metadata, - storage_logs_chunks: chunks, - factory_deps_filepath: snapshot_metadata.factory_deps_filepath, - })) - } else { + return Ok(None); + }; + + let snapshot_files = snapshot_metadata.storage_logs_filepaths; + let is_complete = snapshot_files.iter().all(Option::is_some); + if !is_complete { + // We don't return incomplete snapshots via API. method_latency.observe(); - Ok(None) + return Ok(None); } + + let chunks = snapshot_files + .into_iter() + .enumerate() + .filter_map(|(chunk_id, filepath)| { + Some(SnapshotStorageLogsChunkMetadata { + chunk_id: chunk_id as u64, + filepath: filepath?, + }) + }) + .collect(); + let l1_batch_with_metadata = storage_processor + .blocks_dal() + .get_l1_batch_metadata(l1_batch_number) + .await + .map_err(|err| internal_error(method_name, err))? + .ok_or_else(|| { + let err = format!("missing metadata for L1 batch #{l1_batch_number}"); + internal_error(method_name, err) + })?; + let (_, miniblock_number) = storage_processor + .blocks_dal() + .get_miniblock_range_of_l1_batch(l1_batch_number) + .await + .map_err(|err| internal_error(method_name, err))? + .ok_or_else(|| { + let err = format!("missing miniblocks for L1 batch #{l1_batch_number}"); + internal_error(method_name, err) + })?; + + method_latency.observe(); + Ok(Some(SnapshotHeader { + l1_batch_number: snapshot_metadata.l1_batch_number, + miniblock_number, + last_l1_batch_with_metadata: l1_batch_with_metadata, + storage_logs_chunks: chunks, + factory_deps_filepath: snapshot_metadata.factory_deps_filepath, + })) } } diff --git a/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs b/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs index f8f13e96af23..269250c295df 100644 --- a/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs +++ b/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs @@ -3,20 +3,21 @@ use std::{collections::HashMap, convert::TryInto}; use bigdecimal::{BigDecimal, Zero}; use zksync_dal::StorageProcessor; use zksync_mini_merkle_tree::MiniMerkleTree; +use zksync_system_constants::DEFAULT_L2_TX_GAS_PER_PUBDATA_BYTE; use zksync_types::{ api::{ BlockDetails, BridgeAddresses, GetLogsFilter, L1BatchDetails, L2ToL1LogProof, Proof, ProtocolVersion, StorageProof, TransactionDetails, }, fee::Fee, + fee_model::FeeParams, l1::L1Tx, l2::L2Tx, l2_to_l1_log::L2ToL1Log, tokens::ETHEREUM_ADDRESS, transaction_request::CallRequest, AccountTreeId, L1BatchNumber, MiniblockNumber, StorageKey, Transaction, L1_MESSENGER_ADDRESS, - L2_ETH_TOKEN_ADDRESS, MAX_GAS_PER_PUBDATA_BYTE, REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE, U256, - U64, + L2_ETH_TOKEN_ADDRESS, REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE, U256, U64, }; use zksync_utils::{address_to_h256, ratio_to_big_decimal_normalized}; use zksync_web3_decl::{ @@ -24,30 +25,30 @@ use zksync_web3_decl::{ types::{Address, Token, H256}, }; -use crate::{ - api_server::{ - tree::TreeApiClient, - web3::{backend_jsonrpsee::internal_error, metrics::API_METRICS, RpcState}, - }, - l1_gas_price::L1GasPriceProvider, +use crate::api_server::{ + tree::TreeApiClient, + web3::{backend_jsonrpsee::internal_error, metrics::API_METRICS, RpcState}, }; #[derive(Debug)] -pub struct ZksNamespace { - pub state: RpcState, +pub struct ZksNamespace { + pub state: RpcState, } -impl Clone for ZksNamespace { - fn clone(&self) -> Self { - Self { - state: self.state.clone(), - } +impl ZksNamespace { + pub fn new(state: RpcState) -> Self { + Self { state } } -} -impl ZksNamespace { - pub fn new(state: RpcState) -> Self { - Self { state } + async fn access_storage( + &self, + method_name: &'static str, + ) -> Result, Web3Error> { + self.state + .connection_pool + .access_storage_tagged("api") + .await + .map_err(|err| internal_error(method_name, err)) } #[tracing::instrument(skip(self, request))] @@ -62,7 +63,7 @@ impl ZksNamespace { .await?; if let Some(ref mut eip712_meta) = request_with_gas_per_pubdata_overridden.eip712_meta { - eip712_meta.gas_per_pubdata = MAX_GAS_PER_PUBDATA_BYTE.into(); + eip712_meta.gas_per_pubdata = U256::from(DEFAULT_L2_TX_GAS_PER_PUBDATA_BYTE); } let mut tx = L2Tx::from_request( @@ -73,9 +74,9 @@ impl ZksNamespace { // When we're estimating fee, we are trying to deduce values related to fee, so we should // not consider provided ones. tx.common_data.fee.max_priority_fee_per_gas = 0u64.into(); - tx.common_data.fee.gas_per_pubdata_limit = MAX_GAS_PER_PUBDATA_BYTE.into(); + tx.common_data.fee.gas_per_pubdata_limit = U256::from(DEFAULT_L2_TX_GAS_PER_PUBDATA_BYTE); - let fee = self.estimate_fee(tx.into()).await?; + let fee = self.estimate_fee(tx.into(), METHOD_NAME).await?; method_latency.observe(); Ok(fee) } @@ -101,24 +102,25 @@ impl ZksNamespace { .try_into() .map_err(Web3Error::SerializationError)?; - let fee = self.estimate_fee(tx.into()).await?; + let fee = self.estimate_fee(tx.into(), METHOD_NAME).await?; method_latency.observe(); Ok(fee.gas_limit) } - async fn estimate_fee(&self, tx: Transaction) -> Result { + async fn estimate_fee( + &self, + tx: Transaction, + method_name: &'static str, + ) -> Result { let scale_factor = self.state.api_config.estimate_gas_scale_factor; let acceptable_overestimation = self.state.api_config.estimate_gas_acceptable_overestimation; - let fee = self - .state + self.state .tx_sender .get_txs_fee_in_wei(tx, scale_factor, acceptable_overestimation) .await - .map_err(|err| Web3Error::SubmitTransactionError(err.to_string(), err.data()))?; - - Ok(fee) + .map_err(|err| err.into_web3_error(method_name)) } #[tracing::instrument(skip(self))] @@ -150,16 +152,14 @@ impl ZksNamespace { const METHOD_NAME: &str = "get_confirmed_tokens"; let method_latency = API_METRICS.start_call(METHOD_NAME); - let tokens = self - .state - .connection_pool - .access_storage_tagged("api") - .await - .unwrap() + let mut storage = self.access_storage(METHOD_NAME).await?; + let tokens = storage .tokens_web3_dal() .get_well_known_tokens() .await - .map_err(|err| internal_error(METHOD_NAME, err))? + .map_err(|err| internal_error(METHOD_NAME, err))?; + + let tokens = tokens .into_iter() .skip(from as usize) .take(limit.into()) @@ -171,7 +171,6 @@ impl ZksNamespace { decimals: token_info.metadata.decimals, }) .collect(); - method_latency.observe(); Ok(tokens) } @@ -189,12 +188,7 @@ impl ZksNamespace { let method_latency = API_METRICS.start_call(METHOD_NAME); let token_price_result = { - let mut storage = self - .state - .connection_pool - .access_storage_tagged("api") - .await - .unwrap(); + let mut storage = self.access_storage(METHOD_NAME).await?; storage.tokens_web3_dal().get_token_price(&l2_token).await }; @@ -220,16 +214,14 @@ impl ZksNamespace { const METHOD_NAME: &str = "get_all_balances"; let method_latency = API_METRICS.start_call(METHOD_NAME); - let balances = self - .state - .connection_pool - .access_storage_tagged("api") - .await - .unwrap() + let mut storage = self.access_storage(METHOD_NAME).await?; + let balances = storage .accounts_dal() .get_balances_for_address(address) .await - .map_err(|err| internal_error(METHOD_NAME, err))? + .map_err(|err| internal_error(METHOD_NAME, err))?; + + let balances = balances .into_iter() .map(|(address, balance)| { if address == L2_ETH_TOKEN_ADDRESS { @@ -239,7 +231,6 @@ impl ZksNamespace { } }) .collect(); - method_latency.observe(); Ok(balances) } @@ -255,20 +246,15 @@ impl ZksNamespace { const METHOD_NAME: &str = "get_l2_to_l1_msg_proof"; let method_latency = API_METRICS.start_call(METHOD_NAME); - let mut storage = self - .state - .connection_pool - .access_storage_tagged("api") - .await - .unwrap(); - let l1_batch_number = match storage + self.state.start_info.ensure_not_pruned(block_number)?; + let mut storage = self.access_storage(METHOD_NAME).await?; + let Some(l1_batch_number) = storage .blocks_web3_dal() .get_l1_batch_number_of_miniblock(block_number) .await .map_err(|err| internal_error(METHOD_NAME, err))? - { - Some(number) => number, - None => return Ok(None), + else { + return Ok(None); }; let (first_miniblock_of_l1_batch, _) = storage .blocks_web3_dal() @@ -384,12 +370,7 @@ impl ZksNamespace { const METHOD_NAME: &str = "get_l2_to_l1_msg_proof"; let method_latency = API_METRICS.start_call(METHOD_NAME); - let mut storage = self - .state - .connection_pool - .access_storage_tagged("api") - .await - .unwrap(); + let mut storage = self.access_storage(METHOD_NAME).await?; let Some((l1_batch_number, l1_batch_tx_index)) = storage .blocks_web3_dal() .get_l1_batch_info_for_tx(tx_hash) @@ -418,20 +399,16 @@ impl ZksNamespace { const METHOD_NAME: &str = "get_l1_batch_number"; let method_latency = API_METRICS.start_call(METHOD_NAME); - let l1_batch_number = self - .state - .connection_pool - .access_storage_tagged("api") - .await - .unwrap() - .blocks_web3_dal() + let mut storage = self.access_storage(METHOD_NAME).await?; + let l1_batch_number = storage + .blocks_dal() .get_sealed_l1_batch_number() .await - .map(|n| U64::from(n.0)) - .map_err(|err| internal_error(METHOD_NAME, err)); + .map_err(|err| internal_error(METHOD_NAME, err))? + .ok_or(Web3Error::NoBlock)?; method_latency.observe(); - l1_batch_number + Ok(l1_batch_number.0.into()) } #[tracing::instrument(skip(self))] @@ -442,12 +419,9 @@ impl ZksNamespace { const METHOD_NAME: &str = "get_miniblock_range"; let method_latency = API_METRICS.start_call(METHOD_NAME); - let minmax = self - .state - .connection_pool - .access_storage_tagged("api") - .await - .unwrap() + self.state.start_info.ensure_not_pruned(batch)?; + let mut storage = self.access_storage(METHOD_NAME).await?; + let minmax = storage .blocks_web3_dal() .get_miniblock_range_of_l1_batch(batch) .await @@ -466,17 +440,11 @@ impl ZksNamespace { const METHOD_NAME: &str = "get_block_details"; let method_latency = API_METRICS.start_call(METHOD_NAME); - let block_details = self - .state - .connection_pool - .access_storage_tagged("api") - .await - .unwrap() + self.state.start_info.ensure_not_pruned(block_number)?; + let mut storage = self.access_storage(METHOD_NAME).await?; + let block_details = storage .blocks_web3_dal() - .get_block_details( - block_number, - self.state.tx_sender.0.sender_config.fee_account_addr, - ) + .get_block_details(block_number) .await .map_err(|err| internal_error(METHOD_NAME, err)); @@ -492,12 +460,9 @@ impl ZksNamespace { const METHOD_NAME: &str = "get_raw_block_transactions"; let method_latency = API_METRICS.start_call(METHOD_NAME); - let transactions = self - .state - .connection_pool - .access_storage_tagged("api") - .await - .unwrap() + self.state.start_info.ensure_not_pruned(block_number)?; + let mut storage = self.access_storage(METHOD_NAME).await?; + let transactions = storage .transactions_web3_dal() .get_raw_miniblock_transactions(block_number) .await @@ -515,16 +480,13 @@ impl ZksNamespace { const METHOD_NAME: &str = "get_transaction_details"; let method_latency = API_METRICS.start_call(METHOD_NAME); - let mut tx_details = self - .state - .connection_pool - .access_storage_tagged("api") - .await - .unwrap() + let mut storage = self.access_storage(METHOD_NAME).await?; + let mut tx_details = storage .transactions_web3_dal() .get_transaction_details(hash) .await .map_err(|err| internal_error(METHOD_NAME, err)); + drop(storage); if let Some(proxy) = &self.state.tx_sender.0.proxy { // We're running an external node - we should query the main node directly @@ -550,12 +512,9 @@ impl ZksNamespace { const METHOD_NAME: &str = "get_l1_batch"; let method_latency = API_METRICS.start_call(METHOD_NAME); - let l1_batch = self - .state - .connection_pool - .access_storage_tagged("api") - .await - .unwrap() + self.state.start_info.ensure_not_pruned(batch_number)?; + let mut storage = self.access_storage(METHOD_NAME).await?; + let l1_batch = storage .blocks_web3_dal() .get_l1_batch_details(batch_number) .await @@ -566,26 +525,22 @@ impl ZksNamespace { } #[tracing::instrument(skip(self))] - pub async fn get_bytecode_by_hash_impl(&self, hash: H256) -> Option> { + pub async fn get_bytecode_by_hash_impl( + &self, + hash: H256, + ) -> Result>, Web3Error> { const METHOD_NAME: &str = "get_bytecode_by_hash"; let method_latency = API_METRICS.start_call(METHOD_NAME); - let bytecode = self - .state - .connection_pool - .access_storage_tagged("api") - .await - .unwrap() - .storage_dal() - .get_factory_dep(hash) - .await; + let mut storage = self.access_storage(METHOD_NAME).await?; + let bytecode = storage.storage_dal().get_factory_dep(hash).await; method_latency.observe(); - bytecode + Ok(bytecode) } #[tracing::instrument(skip(self))] - pub fn get_l1_gas_price_impl(&self) -> U64 { + pub async fn get_l1_gas_price_impl(&self) -> U64 { const METHOD_NAME: &str = "get_l1_gas_price"; let method_latency = API_METRICS.start_call(METHOD_NAME); @@ -593,38 +548,50 @@ impl ZksNamespace { .state .tx_sender .0 - .l1_gas_price_source - .estimate_effective_gas_price(); + .batch_fee_input_provider + .get_batch_fee_input() + .await + .l1_gas_price(); method_latency.observe(); gas_price.into() } + #[tracing::instrument(skip(self))] + pub fn get_fee_params_impl(&self) -> FeeParams { + const METHOD_NAME: &str = "get_fee_params"; + + let method_latency = API_METRICS.start_call(METHOD_NAME); + let fee_model_params = self + .state + .tx_sender + .0 + .batch_fee_input_provider + .get_fee_model_params(); + + method_latency.observe(); + + fee_model_params + } + #[tracing::instrument(skip(self))] pub async fn get_protocol_version_impl( &self, version_id: Option, - ) -> Option { + ) -> Result, Web3Error> { const METHOD_NAME: &str = "get_protocol_version"; let method_latency = API_METRICS.start_call(METHOD_NAME); + let mut storage = self.access_storage(METHOD_NAME).await?; let protocol_version = match version_id { Some(id) => { - self.state - .connection_pool - .access_storage() - .await - .unwrap() + storage .protocol_versions_web3_dal() .get_protocol_version_by_id(id) .await } None => Some( - self.state - .connection_pool - .access_storage() - .await - .unwrap() + storage .protocol_versions_web3_dal() .get_latest_protocol_version() .await, @@ -632,7 +599,7 @@ impl ZksNamespace { }; method_latency.observe(); - protocol_version + Ok(protocol_version) } #[tracing::instrument(skip_all)] @@ -644,11 +611,11 @@ impl ZksNamespace { ) -> Result { const METHOD_NAME: &str = "get_proofs"; + self.state.start_info.ensure_not_pruned(l1_batch_number)?; let hashed_keys = keys .iter() .map(|key| StorageKey::new(AccountTreeId::new(address), *key).hashed_key_u256()) .collect(); - let storage_proof = self .state .tree_api diff --git a/core/lib/zksync_core/src/api_server/web3/pubsub.rs b/core/lib/zksync_core/src/api_server/web3/pubsub.rs index 07a5eeb64af2..abbb35ae227c 100644 --- a/core/lib/zksync_core/src/api_server/web3/pubsub.rs +++ b/core/lib/zksync_core/src/api_server/web3/pubsub.rs @@ -24,6 +24,7 @@ use super::{ metrics::{SubscriptionType, PUB_SUB_METRICS}, namespaces::eth::EVENT_TOPIC_NUMBER_LIMIT, }; +use crate::api_server::execution_sandbox::BlockStartInfo; const BROADCAST_CHANNEL_CAPACITY: usize = 1024; const SUBSCRIPTION_SINK_SEND_TIMEOUT: Duration = Duration::from_secs(1); @@ -43,6 +44,7 @@ impl IdProvider for EthSubscriptionIdProvider { pub(super) enum PubSubEvent { Subscribed(SubscriptionType), NotifyIterationFinished(SubscriptionType), + MiniblockAdvanced(SubscriptionType, MiniblockNumber), } /// Manager of notifications for a certain type of subscriptions. @@ -55,15 +57,25 @@ struct PubSubNotifier { } impl PubSubNotifier { - async fn sealed_miniblock_number(&self) -> anyhow::Result { - self.connection_pool + async fn get_starting_miniblock_number(&self) -> anyhow::Result { + let mut storage = self + .connection_pool .access_storage_tagged("api") .await - .context("access_storage_tagged")? - .blocks_web3_dal() + .context("access_storage_tagged")?; + let sealed_miniblock_number = storage + .blocks_dal() .get_sealed_miniblock_number() .await - .context("get_sealed_miniblock_number()") + .context("get_sealed_miniblock_number()")?; + Ok(match sealed_miniblock_number { + Some(number) => number, + None => { + // We don't have miniblocks in the storage yet. Use the snapshot miniblock number instead. + let start_info = BlockStartInfo::new(&mut storage).await?; + MiniblockNumber(start_info.first_miniblock.saturating_sub(1)) + } + }) } fn emit_event(&self, event: PubSubEvent) { @@ -75,7 +87,7 @@ impl PubSubNotifier { impl PubSubNotifier { async fn notify_blocks(self, stop_receiver: watch::Receiver) -> anyhow::Result<()> { - let mut last_block_number = self.sealed_miniblock_number().await?; + let mut last_block_number = self.get_starting_miniblock_number().await?; let mut timer = interval(self.polling_interval); loop { if *stop_receiver.borrow() { @@ -92,6 +104,10 @@ impl PubSubNotifier { last_block_number = MiniblockNumber(last_block.number.unwrap().as_u32()); let new_blocks = new_blocks.into_iter().map(PubSubResult::Header).collect(); self.send_pub_sub_results(new_blocks, SubscriptionType::Blocks); + self.emit_event(PubSubEvent::MiniblockAdvanced( + SubscriptionType::Blocks, + last_block_number, + )); } self.emit_event(PubSubEvent::NotifyIterationFinished( SubscriptionType::Blocks, @@ -159,7 +175,8 @@ impl PubSubNotifier { } async fn notify_logs(self, stop_receiver: watch::Receiver) -> anyhow::Result<()> { - let mut last_block_number = self.sealed_miniblock_number().await?; + let mut last_block_number = self.get_starting_miniblock_number().await?; + let mut timer = interval(self.polling_interval); loop { if *stop_receiver.borrow() { @@ -176,6 +193,10 @@ impl PubSubNotifier { last_block_number = MiniblockNumber(last_log.block_number.unwrap().as_u32()); let new_logs = new_logs.into_iter().map(PubSubResult::Log).collect(); self.send_pub_sub_results(new_logs, SubscriptionType::Logs); + self.emit_event(PubSubEvent::MiniblockAdvanced( + SubscriptionType::Logs, + last_block_number, + )); } self.emit_event(PubSubEvent::NotifyIterationFinished(SubscriptionType::Logs)); } diff --git a/core/lib/zksync_core/src/api_server/web3/state.rs b/core/lib/zksync_core/src/api_server/web3/state.rs index bbb072ab2015..180e2de7211f 100644 --- a/core/lib/zksync_core/src/api_server/web3/state.rs +++ b/core/lib/zksync_core/src/api_server/web3/state.rs @@ -8,12 +8,12 @@ use std::{ }; use lru::LruCache; -use tokio::sync::Mutex; +use tokio::sync::{watch, Mutex}; use vise::GaugeGuard; use zksync_config::configs::{api::Web3JsonRpcConfig, chain::NetworkConfig, ContractsConfig}; -use zksync_dal::ConnectionPool; +use zksync_dal::{ConnectionPool, StorageProcessor}; use zksync_types::{ - api, l2::L2Tx, transaction_request::CallRequest, Address, L1ChainId, L2ChainId, + api, l2::L2Tx, transaction_request::CallRequest, Address, L1BatchNumber, L1ChainId, L2ChainId, MiniblockNumber, H256, U256, U64, }; use zksync_web3_decl::{error::Web3Error, types::Filter}; @@ -21,14 +21,54 @@ use zksync_web3_decl::{error::Web3Error, types::Filter}; use super::metrics::{FilterType, FILTER_METRICS}; use crate::{ api_server::{ - execution_sandbox::BlockArgs, + execution_sandbox::{BlockArgs, BlockArgsError, BlockStartInfo}, tree::TreeApiHttpClient, tx_sender::TxSender, - web3::{backend_jsonrpsee::internal_error, resolve_block, TypedFilter}, + web3::{backend_jsonrpsee::internal_error, TypedFilter}, }, sync_layer::SyncState, }; +#[derive(Debug)] +pub(super) enum PruneQuery { + BlockId(api::BlockId), + L1Batch(L1BatchNumber), +} + +impl From for PruneQuery { + fn from(id: api::BlockId) -> Self { + Self::BlockId(id) + } +} + +impl From for PruneQuery { + fn from(number: MiniblockNumber) -> Self { + Self::BlockId(api::BlockId::Number(number.0.into())) + } +} + +impl From for PruneQuery { + fn from(number: L1BatchNumber) -> Self { + Self::L1Batch(number) + } +} + +impl BlockStartInfo { + pub(super) fn ensure_not_pruned(&self, query: impl Into) -> Result<(), Web3Error> { + match query.into() { + PruneQuery::BlockId(id) => self + .ensure_not_pruned_block(id) + .map_err(Web3Error::PrunedBlock), + PruneQuery::L1Batch(number) => { + if number < self.first_l1_batch { + return Err(Web3Error::PrunedL1Batch(self.first_l1_batch)); + } + Ok(()) + } + } + } +} + /// Configuration values for the API. /// This structure is detached from `ZkSyncConfig`, since different node types (main, external, etc) /// may require different configuration layouts. @@ -88,32 +128,30 @@ impl SealedMiniblockNumber { pub fn new( connection_pool: ConnectionPool, update_interval: Duration, - ) -> (Self, impl Future + Send) { + stop_receiver: watch::Receiver, + ) -> (Self, impl Future>) { let this = Self(Arc::default()); let number_updater = this.clone(); + let update_task = async move { loop { - if Arc::strong_count(&number_updater.0) == 1 { - // The `sealed_miniblock_number` was dropped; there's no sense continuing updates. + if *stop_receiver.borrow() { tracing::debug!("Stopping latest sealed miniblock updates"); - break; + return Ok(()); } let mut connection = connection_pool.access_storage_tagged("api").await.unwrap(); - let last_sealed_miniblock = connection - .blocks_web3_dal() + let Some(last_sealed_miniblock) = connection + .blocks_dal() .get_sealed_miniblock_number() - .await; + .await? + else { + tokio::time::sleep(update_interval).await; + continue; + }; drop(connection); - match last_sealed_miniblock { - Ok(number) => { - number_updater.update(number); - } - Err(err) => tracing::warn!( - "Failed fetching latest sealed miniblock to update the watch channel: {err}" - ), - } + number_updater.update(last_sealed_miniblock); tokio::time::sleep(update_interval).await; } }; @@ -152,35 +190,21 @@ impl SealedMiniblockNumber { } /// Holder for the data required for the API to be functional. -#[derive(Debug)] -pub struct RpcState { +#[derive(Debug, Clone)] +pub struct RpcState { pub(crate) installed_filters: Arc>, pub connection_pool: ConnectionPool, pub tree_api: Option, - pub tx_sender: TxSender, + pub tx_sender: TxSender, pub sync_state: Option, pub(super) api_config: InternalApiConfig, + /// Number of the first locally available miniblock / L1 batch. May differ from 0 if the node state was recovered + /// from a snapshot. + pub(super) start_info: BlockStartInfo, pub(super) last_sealed_miniblock: SealedMiniblockNumber, } -// Custom implementation is required due to generic param: -// Even though it's under `Arc`, compiler doesn't generate the `Clone` implementation unless -// an unnecessary bound is added. -impl Clone for RpcState { - fn clone(&self) -> Self { - Self { - installed_filters: self.installed_filters.clone(), - connection_pool: self.connection_pool.clone(), - tx_sender: self.tx_sender.clone(), - tree_api: self.tree_api.clone(), - sync_state: self.sync_state.clone(), - api_config: self.api_config.clone(), - last_sealed_miniblock: self.last_sealed_miniblock.clone(), - } - } -} - -impl RpcState { +impl RpcState { pub fn parse_transaction_bytes(&self, bytes: &[u8]) -> Result<(L2Tx, H256), Web3Error> { let chain_id = self.api_config.l2_chain_id; let (tx_request, hash) = api::TransactionRequest::from_bytes(bytes, chain_id)?; @@ -199,6 +223,34 @@ impl RpcState { } } + pub(crate) async fn resolve_block( + &self, + connection: &mut StorageProcessor<'_>, + block: api::BlockId, + method_name: &'static str, + ) -> Result { + self.start_info.ensure_not_pruned(block)?; + let result = connection.blocks_web3_dal().resolve_block_id(block).await; + result + .map_err(|err| internal_error(method_name, err))? + .ok_or(Web3Error::NoBlock) + } + + pub(crate) async fn resolve_block_args( + &self, + connection: &mut StorageProcessor<'_>, + block: api::BlockId, + method_name: &'static str, + ) -> Result { + BlockArgs::new(connection, block, self.start_info) + .await + .map_err(|err| match err { + BlockArgsError::Pruned(number) => Web3Error::PrunedBlock(number), + BlockArgsError::Missing => Web3Error::NoBlock, + BlockArgsError::Database(err) => internal_error(method_name, err), + }) + } + pub async fn resolve_filter_block_number( &self, block_number: Option, @@ -215,12 +267,10 @@ impl RpcState { .connection_pool .access_storage_tagged("api") .await - .unwrap(); - Ok(conn - .blocks_web3_dal() - .resolve_block_id(block_id) + .map_err(|err| internal_error(METHOD_NAME, err))?; + Ok(self + .resolve_block(&mut conn, block_id, METHOD_NAME) .await - .map_err(|err| internal_error(METHOD_NAME, err))? .unwrap()) // ^ `unwrap()` is safe: `resolve_block_id(api::BlockId::Number(_))` can only return `None` // if called with an explicit number, and we've handled this case earlier. @@ -301,7 +351,9 @@ impl RpcState { .access_storage_tagged("api") .await .unwrap(); - let block_number = resolve_block(&mut connection, block_id, METHOD_NAME).await?; + let block_number = self + .resolve_block(&mut connection, block_id, METHOD_NAME) + .await?; let address_historical_nonce = connection .storage_web3_dal() .get_address_historical_nonce(from, block_number) diff --git a/core/lib/zksync_core/src/api_server/web3/tests/debug.rs b/core/lib/zksync_core/src/api_server/web3/tests/debug.rs new file mode 100644 index 000000000000..bf929469b441 --- /dev/null +++ b/core/lib/zksync_core/src/api_server/web3/tests/debug.rs @@ -0,0 +1,166 @@ +//! Tests for the `debug` Web3 namespace. + +use zksync_types::{tx::TransactionExecutionResult, vm_trace::Call, BOOTLOADER_ADDRESS}; +use zksync_web3_decl::namespaces::DebugNamespaceClient; + +use super::*; + +fn execute_l2_transaction_with_traces(index_in_block: u8) -> TransactionExecutionResult { + let first_call_trace = Call { + from: Address::repeat_byte(index_in_block), + to: Address::repeat_byte(index_in_block + 1), + gas: 100, + gas_used: 42, + ..Call::default() + }; + let second_call_trace = Call { + from: Address::repeat_byte(0xff - index_in_block), + to: Address::repeat_byte(0xab - index_in_block), + value: 123.into(), + gas: 58, + gas_used: 10, + input: b"input".to_vec(), + output: b"output".to_vec(), + ..Call::default() + }; + TransactionExecutionResult { + call_traces: vec![first_call_trace, second_call_trace], + ..execute_l2_transaction(create_l2_transaction(1, 2)) + } +} + +#[derive(Debug)] +struct TraceBlockTest(MiniblockNumber); + +#[async_trait] +impl HttpTest for TraceBlockTest { + async fn test(&self, client: &HttpClient, pool: &ConnectionPool) -> anyhow::Result<()> { + let tx_results = [0, 1, 2].map(execute_l2_transaction_with_traces); + let mut storage = pool.access_storage().await?; + let new_miniblock = store_miniblock(&mut storage, self.0, &tx_results).await?; + drop(storage); + + let block_ids = [ + api::BlockId::Number((*self.0).into()), + api::BlockId::Number(api::BlockNumber::Latest), + api::BlockId::Hash(new_miniblock.hash), + ]; + + for block_id in block_ids { + let block_traces = match block_id { + api::BlockId::Number(number) => client.trace_block_by_number(number, None).await?, + api::BlockId::Hash(hash) => client.trace_block_by_hash(hash, None).await?, + }; + + assert_eq!(block_traces.len(), tx_results.len()); // equals to the number of transactions in the block + for (trace, tx_result) in block_traces.iter().zip(&tx_results) { + let api::ResultDebugCall { result } = trace; + assert_eq!(result.from, Address::zero()); + assert_eq!(result.to, BOOTLOADER_ADDRESS); + assert_eq!(result.gas, tx_result.transaction.gas_limit()); + let expected_calls: Vec<_> = tx_result + .call_traces + .iter() + .map(|call| api::DebugCall::from(call.clone())) + .collect(); + assert_eq!(result.calls, expected_calls); + } + } + + let missing_block_number = api::BlockNumber::from(*self.0 + 100); + let error = client + .trace_block_by_number(missing_block_number, None) + .await + .unwrap_err(); + if let ClientError::Call(error) = error { + assert_eq!(error.code(), ErrorCode::InvalidParams.code()); + assert!( + error.message().contains("Block") && error.message().contains("doesn't exist"), + "{error:?}" + ); + assert!(error.data().is_none(), "{error:?}"); + } else { + panic!("Unexpected error: {error:?}"); + } + + Ok(()) + } +} + +#[tokio::test] +async fn tracing_block() { + test_http_server(TraceBlockTest(MiniblockNumber(1))).await; +} + +#[derive(Debug)] +struct TraceTransactionTest; + +#[async_trait] +impl HttpTest for TraceTransactionTest { + async fn test(&self, client: &HttpClient, pool: &ConnectionPool) -> anyhow::Result<()> { + let tx_results = [execute_l2_transaction_with_traces(0)]; + let mut storage = pool.access_storage().await?; + store_miniblock(&mut storage, MiniblockNumber(1), &tx_results).await?; + drop(storage); + + let expected_calls: Vec<_> = tx_results[0] + .call_traces + .iter() + .map(|call| api::DebugCall::from(call.clone())) + .collect(); + + let result = client + .trace_transaction(tx_results[0].hash, None) + .await? + .context("no transaction traces")?; + assert_eq!(result.from, Address::zero()); + assert_eq!(result.to, BOOTLOADER_ADDRESS); + assert_eq!(result.gas, tx_results[0].transaction.gas_limit()); + assert_eq!(result.calls, expected_calls); + + Ok(()) + } +} + +#[tokio::test] +async fn tracing_transaction() { + test_http_server(TraceTransactionTest).await; +} + +#[derive(Debug)] +struct TraceBlockTestWithSnapshotRecovery; + +#[async_trait] +impl HttpTest for TraceBlockTestWithSnapshotRecovery { + fn storage_initialization(&self) -> StorageInitialization { + StorageInitialization::empty_recovery() + } + + async fn test(&self, client: &HttpClient, pool: &ConnectionPool) -> anyhow::Result<()> { + let snapshot_miniblock_number = + MiniblockNumber(StorageInitialization::SNAPSHOT_RECOVERY_BLOCK); + let missing_miniblock_numbers = [ + MiniblockNumber(0), + snapshot_miniblock_number - 1, + snapshot_miniblock_number, + ]; + + for number in missing_miniblock_numbers { + let error = client + .trace_block_by_number(number.0.into(), None) + .await + .unwrap_err(); + assert_pruned_block_error(&error, 24); + } + + TraceBlockTest(snapshot_miniblock_number + 1) + .test(client, pool) + .await?; + Ok(()) + } +} + +#[tokio::test] +async fn tracing_block_after_snapshot_recovery() { + test_http_server(TraceBlockTestWithSnapshotRecovery).await; +} diff --git a/core/lib/zksync_core/src/api_server/web3/tests/filters.rs b/core/lib/zksync_core/src/api_server/web3/tests/filters.rs new file mode 100644 index 000000000000..913437b5e199 --- /dev/null +++ b/core/lib/zksync_core/src/api_server/web3/tests/filters.rs @@ -0,0 +1,265 @@ +//! Tests for filter-related methods in the `eth` namespace. + +use zksync_web3_decl::{jsonrpsee::core::ClientError as RpcError, types::FilterChanges}; + +use super::*; + +#[derive(Debug)] +struct BasicFilterChangesTest { + snapshot_recovery: bool, +} + +#[async_trait] +impl HttpTest for BasicFilterChangesTest { + fn storage_initialization(&self) -> StorageInitialization { + if self.snapshot_recovery { + StorageInitialization::empty_recovery() + } else { + StorageInitialization::Genesis + } + } + + async fn test(&self, client: &HttpClient, pool: &ConnectionPool) -> anyhow::Result<()> { + let block_filter_id = client.new_block_filter().await?; + let tx_filter_id = client.new_pending_transaction_filter().await?; + + // Sleep a little so that the filter timestamp is strictly lesser than the transaction "received at" timestamp. + tokio::time::sleep(POLL_INTERVAL).await; + + let tx_result = execute_l2_transaction(create_l2_transaction(1, 2)); + let new_tx_hash = tx_result.hash; + let new_miniblock = store_miniblock( + &mut pool.access_storage().await?, + MiniblockNumber(if self.snapshot_recovery { + StorageInitialization::SNAPSHOT_RECOVERY_BLOCK + 1 + } else { + 1 + }), + &[tx_result], + ) + .await?; + + let block_filter_changes = client.get_filter_changes(block_filter_id).await?; + assert_matches!( + block_filter_changes, + FilterChanges::Hashes(hashes) if hashes == [new_miniblock.hash] + ); + let block_filter_changes = client.get_filter_changes(block_filter_id).await?; + assert_matches!(block_filter_changes, FilterChanges::Hashes(hashes) if hashes.is_empty()); + + let tx_filter_changes = client.get_filter_changes(tx_filter_id).await?; + assert_matches!( + tx_filter_changes, + FilterChanges::Hashes(hashes) if hashes == [new_tx_hash] + ); + let tx_filter_changes = client.get_filter_changes(tx_filter_id).await?; + assert_matches!(tx_filter_changes, FilterChanges::Hashes(hashes) if hashes.is_empty()); + + // Check uninstalling the filter. + let removed = client.uninstall_filter(block_filter_id).await?; + assert!(removed); + let removed = client.uninstall_filter(block_filter_id).await?; + assert!(!removed); + + let err = client + .get_filter_changes(block_filter_id) + .await + .unwrap_err(); + assert_matches!(err, RpcError::Call(err) if err.code() == ErrorCode::InvalidParams.code()); + Ok(()) + } +} + +#[tokio::test] +async fn basic_filter_changes() { + test_http_server(BasicFilterChangesTest { + snapshot_recovery: false, + }) + .await; +} + +#[tokio::test] +async fn basic_filter_changes_after_snapshot_recovery() { + test_http_server(BasicFilterChangesTest { + snapshot_recovery: true, + }) + .await; +} + +#[derive(Debug)] +struct LogFilterChangesTest { + snapshot_recovery: bool, +} + +#[async_trait] +impl HttpTest for LogFilterChangesTest { + fn storage_initialization(&self) -> StorageInitialization { + if self.snapshot_recovery { + StorageInitialization::empty_recovery() + } else { + StorageInitialization::Genesis + } + } + + async fn test(&self, client: &HttpClient, pool: &ConnectionPool) -> anyhow::Result<()> { + let all_logs_filter_id = client.new_filter(Filter::default()).await?; + let address_filter = Filter { + address: Some(Address::repeat_byte(23).into()), + ..Filter::default() + }; + let address_filter_id = client.new_filter(address_filter).await?; + let topics_filter = Filter { + topics: Some(vec![Some(H256::repeat_byte(42).into())]), + ..Filter::default() + }; + let topics_filter_id = client.new_filter(topics_filter).await?; + + let mut storage = pool.access_storage().await?; + let first_local_miniblock = if self.snapshot_recovery { + StorageInitialization::SNAPSHOT_RECOVERY_BLOCK + 1 + } else { + 1 + }; + let (_, events) = store_events(&mut storage, first_local_miniblock, 0).await?; + drop(storage); + let events: Vec<_> = events.iter().collect(); + + let all_logs = client.get_filter_changes(all_logs_filter_id).await?; + let FilterChanges::Logs(all_logs) = all_logs else { + panic!("Unexpected getFilterChanges output: {:?}", all_logs); + }; + assert_logs_match(&all_logs, &events); + + let address_logs = client.get_filter_changes(address_filter_id).await?; + let FilterChanges::Logs(address_logs) = address_logs else { + panic!("Unexpected getFilterChanges output: {:?}", address_logs); + }; + assert_logs_match(&address_logs, &[events[0], events[3]]); + + let topics_logs = client.get_filter_changes(topics_filter_id).await?; + let FilterChanges::Logs(topics_logs) = topics_logs else { + panic!("Unexpected getFilterChanges output: {:?}", topics_logs); + }; + assert_logs_match(&topics_logs, &[events[1], events[3]]); + + let new_all_logs = client.get_filter_changes(all_logs_filter_id).await?; + let FilterChanges::Hashes(new_all_logs) = new_all_logs else { + panic!("Unexpected getFilterChanges output: {:?}", new_all_logs); + }; + assert!(new_all_logs.is_empty()); + Ok(()) + } +} + +#[tokio::test] +async fn log_filter_changes() { + test_http_server(LogFilterChangesTest { + snapshot_recovery: false, + }) + .await; +} + +#[tokio::test] +async fn log_filter_changes_after_snapshot_recovery() { + test_http_server(LogFilterChangesTest { + snapshot_recovery: true, + }) + .await; +} + +#[derive(Debug)] +struct LogFilterChangesWithBlockBoundariesTest; + +#[async_trait] +impl HttpTest for LogFilterChangesWithBlockBoundariesTest { + async fn test(&self, client: &HttpClient, pool: &ConnectionPool) -> anyhow::Result<()> { + let lower_bound_filter = Filter { + from_block: Some(api::BlockNumber::Number(2.into())), + ..Filter::default() + }; + let lower_bound_filter_id = client.new_filter(lower_bound_filter).await?; + let upper_bound_filter = Filter { + to_block: Some(api::BlockNumber::Number(1.into())), + ..Filter::default() + }; + let upper_bound_filter_id = client.new_filter(upper_bound_filter).await?; + let bounded_filter = Filter { + from_block: Some(api::BlockNumber::Number(1.into())), + to_block: Some(api::BlockNumber::Number(1.into())), + ..Filter::default() + }; + let bounded_filter_id = client.new_filter(bounded_filter).await?; + + let mut storage = pool.access_storage().await?; + let (_, events) = store_events(&mut storage, 1, 0).await?; + drop(storage); + let events: Vec<_> = events.iter().collect(); + + let lower_bound_logs = client.get_filter_changes(lower_bound_filter_id).await?; + assert_matches!( + lower_bound_logs, + FilterChanges::Hashes(hashes) if hashes.is_empty() + ); + // ^ Since `FilterChanges` is serialized w/o a tag, an empty array will be deserialized + // as `Hashes(_)` (the first declared variant). + + let upper_bound_logs = client.get_filter_changes(upper_bound_filter_id).await?; + let FilterChanges::Logs(upper_bound_logs) = upper_bound_logs else { + panic!("Unexpected getFilterChanges output: {:?}", upper_bound_logs); + }; + assert_logs_match(&upper_bound_logs, &events); + let bounded_logs = client.get_filter_changes(bounded_filter_id).await?; + let FilterChanges::Logs(bounded_logs) = bounded_logs else { + panic!("Unexpected getFilterChanges output: {:?}", bounded_logs); + }; + assert_eq!(bounded_logs, upper_bound_logs); + + // Add another miniblock with events to the storage. + let mut storage = pool.access_storage().await?; + let (_, new_events) = store_events(&mut storage, 2, 4).await?; + drop(storage); + let new_events: Vec<_> = new_events.iter().collect(); + + let lower_bound_logs = client.get_filter_changes(lower_bound_filter_id).await?; + let FilterChanges::Logs(lower_bound_logs) = lower_bound_logs else { + panic!("Unexpected getFilterChanges output: {:?}", lower_bound_logs); + }; + assert_logs_match(&lower_bound_logs, &new_events); + + let new_upper_bound_logs = client.get_filter_changes(upper_bound_filter_id).await?; + assert_matches!(new_upper_bound_logs, FilterChanges::Hashes(hashes) if hashes.is_empty()); + let new_bounded_logs = client.get_filter_changes(bounded_filter_id).await?; + assert_matches!(new_bounded_logs, FilterChanges::Hashes(hashes) if hashes.is_empty()); + + // Add miniblock #3. It should not be picked up by the bounded and upper bound filters, + // and should be picked up by the lower bound filter. + let mut storage = pool.access_storage().await?; + let (_, new_events) = store_events(&mut storage, 3, 8).await?; + drop(storage); + let new_events: Vec<_> = new_events.iter().collect(); + + let bounded_logs = client.get_filter_changes(bounded_filter_id).await?; + let FilterChanges::Hashes(bounded_logs) = bounded_logs else { + panic!("Unexpected getFilterChanges output: {:?}", bounded_logs); + }; + assert!(bounded_logs.is_empty()); + + let upper_bound_logs = client.get_filter_changes(upper_bound_filter_id).await?; + let FilterChanges::Hashes(upper_bound_logs) = upper_bound_logs else { + panic!("Unexpected getFilterChanges output: {:?}", upper_bound_logs); + }; + assert!(upper_bound_logs.is_empty()); + + let lower_bound_logs = client.get_filter_changes(lower_bound_filter_id).await?; + let FilterChanges::Logs(lower_bound_logs) = lower_bound_logs else { + panic!("Unexpected getFilterChanges output: {:?}", lower_bound_logs); + }; + assert_logs_match(&lower_bound_logs, &new_events); + Ok(()) + } +} + +#[tokio::test] +async fn log_filter_changes_with_block_boundaries() { + test_http_server(LogFilterChangesWithBlockBoundariesTest).await; +} diff --git a/core/lib/zksync_core/src/api_server/web3/tests/mod.rs b/core/lib/zksync_core/src/api_server/web3/tests/mod.rs index 96b0312ff3d6..6b5f8a2fa1b7 100644 --- a/core/lib/zksync_core/src/api_server/web3/tests/mod.rs +++ b/core/lib/zksync_core/src/api_server/web3/tests/mod.rs @@ -1,48 +1,58 @@ -use std::{sync::Arc, time::Instant}; +use std::{collections::HashMap, time::Instant}; use assert_matches::assert_matches; use async_trait::async_trait; +use jsonrpsee::core::ClientError; use tokio::sync::watch; use zksync_config::configs::{ api::Web3JsonRpcConfig, chain::{NetworkConfig, StateKeeperConfig}, ContractsConfig, }; -use zksync_contracts::BaseSystemContractsHashes; -use zksync_dal::{transactions_dal::L2TxSubmissionResult, ConnectionPool}; +use zksync_dal::{transactions_dal::L2TxSubmissionResult, ConnectionPool, StorageProcessor}; use zksync_health_check::CheckHealth; -use zksync_state::PostgresStorageCaches; use zksync_types::{ - block::MiniblockHeader, fee::TransactionExecutionMetrics, tx::IncludedTxLocation, Address, - L1BatchNumber, ProtocolVersionId, VmEvent, H256, U64, + api, + api::BlockId, + block::MiniblockHeader, + fee::TransactionExecutionMetrics, + get_nonce_key, + l2::L2Tx, + storage::get_code_key, + tx::{ + tx_execution_info::TxExecutionStatus, ExecutionMetrics, IncludedTxLocation, + TransactionExecutionResult, + }, + utils::storage_key_for_eth_balance, + AccountTreeId, Address, L1BatchNumber, Nonce, StorageKey, StorageLog, VmEvent, H256, U64, }; use zksync_web3_decl::{ - jsonrpsee::{core::ClientError as RpcError, http_client::HttpClient, types::error::ErrorCode}, + jsonrpsee::{http_client::HttpClient, types::error::ErrorCode}, namespaces::{EthNamespaceClient, ZksNamespaceClient}, - types::FilterChanges, }; use super::{metrics::ApiTransportLabel, *}; use crate::{ - api_server::tx_sender::TxSenderConfig, + api_server::{ + execution_sandbox::testonly::MockTransactionExecutor, + tx_sender::tests::create_test_tx_sender, + }, genesis::{ensure_genesis_state, GenesisParams}, - state_keeper::tests::create_l2_transaction, + utils::testonly::{ + create_l1_batch, create_l1_batch_metadata, create_l2_transaction, create_miniblock, + prepare_empty_recovery_snapshot, prepare_recovery_snapshot, + }, }; +mod debug; +mod filters; +mod snapshots; +mod vm; mod ws; const TEST_TIMEOUT: Duration = Duration::from_secs(10); const POLL_INTERVAL: Duration = Duration::from_millis(50); -/// Mock [`L1GasPriceProvider`] that returns a constant value. -struct MockL1GasPriceProvider(u64); - -impl L1GasPriceProvider for MockL1GasPriceProvider { - fn estimate_effective_gas_price(&self) -> u64 { - self.0 - } -} - impl ApiServerHandles { /// Waits until the server health check reports the ready state. pub(crate) async fn wait_until_ready(&self) { @@ -63,30 +73,36 @@ impl ApiServerHandles { pub(crate) async fn shutdown(self) { let stop_server = async { for task in self.tasks { - // FIXME(PLA-481): avoid these errors (by spawning notifier tasks on server runtime?) - if let Err(err) = task.await.expect("Server panicked") { - let err = err.root_cause().to_string(); - assert!(err.contains("Tokio 1.x context was found")); + match task.await { + Ok(Ok(())) => { /* Task successfully completed */ } + Err(err) if err.is_cancelled() => { + // Task was canceled since the server runtime which runs the task was dropped. + // This is fine. + } + Err(err) => panic!("Server task panicked: {err:?}"), + Ok(Err(err)) => panic!("Server task failed: {err:?}"), } } }; tokio::time::timeout(TEST_TIMEOUT, stop_server) .await - .unwrap(); + .expect(format!("panicking at {}", chrono::Utc::now()).as_str()); } } pub(crate) async fn spawn_http_server( network_config: &NetworkConfig, pool: ConnectionPool, + tx_executor: MockTransactionExecutor, stop_receiver: watch::Receiver, ) -> ApiServerHandles { spawn_server( ApiTransportLabel::Http, network_config, pool, - stop_receiver, None, + tx_executor, + stop_receiver, ) .await .0 @@ -102,8 +118,9 @@ async fn spawn_ws_server( ApiTransportLabel::Ws, network_config, pool, - stop_receiver, websocket_requests_per_minute_limit, + MockTransactionExecutor::default(), + stop_receiver, ) .await } @@ -112,30 +129,20 @@ async fn spawn_server( transport: ApiTransportLabel, network_config: &NetworkConfig, pool: ConnectionPool, - stop_receiver: watch::Receiver, websocket_requests_per_minute_limit: Option, + tx_executor: MockTransactionExecutor, + stop_receiver: watch::Receiver, ) -> (ApiServerHandles, mpsc::UnboundedReceiver) { let contracts_config = ContractsConfig::for_tests(); let web3_config = Web3JsonRpcConfig::for_tests(); - let state_keeper_config = StateKeeperConfig::for_tests(); let api_config = InternalApiConfig::new(network_config, &web3_config, &contracts_config); - let tx_sender_config = - TxSenderConfig::new(&state_keeper_config, &web3_config, api_config.l2_chain_id); - - let storage_caches = PostgresStorageCaches::new(1, 1); - let gas_adjuster = Arc::new(MockL1GasPriceProvider(1)); - let (tx_sender, vm_barrier) = crate::build_tx_sender( - &tx_sender_config, - &web3_config, - &state_keeper_config, - pool.clone(), - pool.clone(), - gas_adjuster, - storage_caches, - ) - .await; + let (tx_sender, vm_barrier) = + create_test_tx_sender(pool.clone(), api_config.l2_chain_id, tx_executor.into()).await; let (pub_sub_events_sender, pub_sub_events_receiver) = mpsc::unbounded_channel(); + let mut namespaces = Namespace::DEFAULT.to_vec(); + namespaces.extend([Namespace::Debug, Namespace::Snapshots]); + let server_builder = match transport { ApiTransportLabel::Http => ApiBuilder::jsonrpsee_backend(api_config, pool).http(0), ApiTransportLabel::Ws => { @@ -150,11 +157,10 @@ async fn spawn_server( } }; let server_handles = server_builder - .with_threads(1) .with_polling_interval(POLL_INTERVAL) .with_tx_sender(tx_sender, vm_barrier) .with_pub_sub_events(pub_sub_events_sender) - .enable_api_namespaces(Namespace::DEFAULT.to_vec()) + .enable_api_namespaces(namespaces) .build(stop_receiver) .await .expect("Failed spawning JSON-RPC server"); @@ -162,27 +168,91 @@ async fn spawn_server( } #[async_trait] -trait HttpTest { +trait HttpTest: Send + Sync { + /// Prepares the storage before the server is started. The default implementation performs genesis. + fn storage_initialization(&self) -> StorageInitialization { + StorageInitialization::Genesis + } + + fn transaction_executor(&self) -> MockTransactionExecutor { + MockTransactionExecutor::default() + } + async fn test(&self, client: &HttpClient, pool: &ConnectionPool) -> anyhow::Result<()>; } +/// Storage initialization strategy. +#[derive(Debug)] +enum StorageInitialization { + Genesis, + Recovery { + logs: Vec, + factory_deps: HashMap>, + }, +} + +impl StorageInitialization { + const SNAPSHOT_RECOVERY_BLOCK: u32 = 23; + + fn empty_recovery() -> Self { + Self::Recovery { + logs: vec![], + factory_deps: HashMap::new(), + } + } + + async fn prepare_storage( + &self, + network_config: &NetworkConfig, + storage: &mut StorageProcessor<'_>, + ) -> anyhow::Result<()> { + match self { + Self::Genesis => { + if storage.blocks_dal().is_genesis_needed().await? { + ensure_genesis_state( + storage, + network_config.zksync_network_id, + &GenesisParams::mock(), + ) + .await?; + } + } + Self::Recovery { logs, factory_deps } if logs.is_empty() && factory_deps.is_empty() => { + prepare_empty_recovery_snapshot(storage, Self::SNAPSHOT_RECOVERY_BLOCK).await; + } + Self::Recovery { logs, factory_deps } => { + prepare_recovery_snapshot(storage, Self::SNAPSHOT_RECOVERY_BLOCK, logs).await; + storage + .storage_dal() + .insert_factory_deps( + MiniblockNumber(Self::SNAPSHOT_RECOVERY_BLOCK), + factory_deps, + ) + .await?; + } + } + Ok(()) + } +} + async fn test_http_server(test: impl HttpTest) { let pool = ConnectionPool::test_pool().await; let network_config = NetworkConfig::for_tests(); let mut storage = pool.access_storage().await.unwrap(); - if storage.blocks_dal().is_genesis_needed().await.unwrap() { - ensure_genesis_state( - &mut storage, - network_config.zksync_network_id, - &GenesisParams::mock(), - ) + test.storage_initialization() + .prepare_storage(&network_config, &mut storage) .await - .unwrap(); - } + .expect("Failed preparing storage for test"); drop(storage); let (stop_sender, stop_receiver) = watch::channel(false); - let server_handles = spawn_http_server(&network_config, pool.clone(), stop_receiver).await; + let server_handles = spawn_http_server( + &network_config, + pool.clone(), + test.transaction_executor(), + stop_receiver, + ) + .await; server_handles.wait_until_ready().await; let client = ::builder() @@ -195,46 +265,84 @@ async fn test_http_server(test: impl HttpTest) { } fn assert_logs_match(actual_logs: &[api::Log], expected_logs: &[&VmEvent]) { - assert_eq!(actual_logs.len(), expected_logs.len()); + assert_eq!( + actual_logs.len(), + expected_logs.len(), + "expected: {expected_logs:?}, actual: {actual_logs:?}" + ); for (actual_log, &expected_log) in actual_logs.iter().zip(expected_logs) { - assert_eq!(actual_log.address, expected_log.address); - assert_eq!(actual_log.topics, expected_log.indexed_topics); - assert_eq!(actual_log.data.0, expected_log.value); + assert_eq!( + actual_log.address, expected_log.address, + "expected: {expected_logs:?}, actual: {actual_logs:?}" + ); + assert_eq!( + actual_log.topics, expected_log.indexed_topics, + "expected: {expected_logs:?}, actual: {actual_logs:?}" + ); + assert_eq!( + actual_log.data.0, expected_log.value, + "expected: {expected_logs:?}, actual: {actual_logs:?}" + ); } } -fn create_miniblock(number: u32) -> MiniblockHeader { - MiniblockHeader { - number: MiniblockNumber(number), - timestamp: number.into(), - hash: H256::from_low_u64_be(number.into()), - l1_tx_count: 0, - l2_tx_count: 0, - base_fee_per_gas: 100, - l1_gas_price: 100, - l2_fair_gas_price: 100, - base_system_contracts_hashes: BaseSystemContractsHashes::default(), - protocol_version: Some(ProtocolVersionId::latest()), - virtual_blocks: 1, +fn execute_l2_transaction(transaction: L2Tx) -> TransactionExecutionResult { + TransactionExecutionResult { + hash: transaction.hash(), + transaction: transaction.into(), + execution_info: ExecutionMetrics::default(), + execution_status: TxExecutionStatus::Success, + refunded_gas: 0, + operator_suggested_refund: 0, + compressed_bytecodes: vec![], + call_traces: vec![], + revert_reason: None, } } -async fn store_block(pool: &ConnectionPool) -> anyhow::Result<(MiniblockHeader, H256)> { - let mut storage = pool.access_storage().await?; - let new_tx = create_l2_transaction(1, 2); - let new_tx_hash = new_tx.hash(); - let tx_submission_result = storage +/// Stores miniblock #1 with a single transaction and returns the miniblock header + transaction hash. +async fn store_miniblock( + storage: &mut StorageProcessor<'_>, + number: MiniblockNumber, + transaction_results: &[TransactionExecutionResult], +) -> anyhow::Result { + for result in transaction_results { + let l2_tx = result.transaction.clone().try_into().unwrap(); + let tx_submission_result = storage + .transactions_dal() + .insert_transaction_l2(l2_tx, TransactionExecutionMetrics::default()) + .await; + assert_matches!(tx_submission_result, L2TxSubmissionResult::Added); + } + + let new_miniblock = create_miniblock(number.0); + storage + .blocks_dal() + .insert_miniblock(&new_miniblock) + .await?; + storage .transactions_dal() - .insert_transaction_l2(new_tx, TransactionExecutionMetrics::default()) + .mark_txs_as_executed_in_miniblock(new_miniblock.number, transaction_results, 1.into()) .await; - assert_matches!(tx_submission_result, L2TxSubmissionResult::Added); + Ok(new_miniblock) +} - let new_miniblock = create_miniblock(1); +async fn seal_l1_batch( + storage: &mut StorageProcessor<'_>, + number: L1BatchNumber, +) -> anyhow::Result<()> { + let header = create_l1_batch(number.0); + storage.blocks_dal().insert_mock_l1_batch(&header).await?; storage .blocks_dal() - .insert_miniblock(&new_miniblock) + .mark_miniblocks_as_executed_in_l1_batch(number) + .await?; + let metadata = create_l1_batch_metadata(number.0); + storage + .blocks_dal() + .save_l1_batch_metadata(number, &metadata, H256::zero(), false) .await?; - Ok((new_miniblock, new_tx_hash)) + Ok(()) } async fn store_events( @@ -243,6 +351,7 @@ async fn store_events( start_idx: u32, ) -> anyhow::Result<(IncludedTxLocation, Vec)> { let new_miniblock = create_miniblock(miniblock_number); + let l1_batch_number = L1BatchNumber(miniblock_number); storage .blocks_dal() .insert_miniblock(&new_miniblock) @@ -255,28 +364,28 @@ async fn store_events( let events = vec![ // Matches address, doesn't match topics VmEvent { - location: (L1BatchNumber(1), start_idx), + location: (l1_batch_number, start_idx), address: Address::repeat_byte(23), indexed_topics: vec![], value: start_idx.to_le_bytes().to_vec(), }, // Doesn't match address, matches topics VmEvent { - location: (L1BatchNumber(1), start_idx + 1), + location: (l1_batch_number, start_idx + 1), address: Address::zero(), indexed_topics: vec![H256::repeat_byte(42)], value: (start_idx + 1).to_le_bytes().to_vec(), }, // Doesn't match address or topics VmEvent { - location: (L1BatchNumber(1), start_idx + 2), + location: (l1_batch_number, start_idx + 2), address: Address::zero(), indexed_topics: vec![H256::repeat_byte(1), H256::repeat_byte(42)], value: (start_idx + 2).to_le_bytes().to_vec(), }, // Matches both address and topics VmEvent { - location: (L1BatchNumber(1), start_idx + 3), + location: (l1_batch_number, start_idx + 3), address: Address::repeat_byte(23), indexed_topics: vec![H256::repeat_byte(42), H256::repeat_byte(111)], value: (start_idx + 3).to_le_bytes().to_vec(), @@ -293,10 +402,10 @@ async fn store_events( } #[derive(Debug)] -struct HttpServerBasics; +struct HttpServerBasicsTest; #[async_trait] -impl HttpTest for HttpServerBasics { +impl HttpTest for HttpServerBasicsTest { async fn test(&self, client: &HttpClient, _pool: &ConnectionPool) -> anyhow::Result<()> { let block_number = client.get_block_number().await?; assert_eq!(block_number, U64::from(0)); @@ -315,204 +424,449 @@ impl HttpTest for HttpServerBasics { #[tokio::test] async fn http_server_basics() { - test_http_server(HttpServerBasics).await; + test_http_server(HttpServerBasicsTest).await; } #[derive(Debug)] -struct BasicFilterChanges; +struct BlockMethodsWithSnapshotRecovery; #[async_trait] -impl HttpTest for BasicFilterChanges { +impl HttpTest for BlockMethodsWithSnapshotRecovery { + fn storage_initialization(&self) -> StorageInitialization { + StorageInitialization::empty_recovery() + } + async fn test(&self, client: &HttpClient, pool: &ConnectionPool) -> anyhow::Result<()> { - let block_filter_id = client.new_block_filter().await?; - let tx_filter_id = client.new_pending_transaction_filter().await?; + let error = client.get_block_number().await.unwrap_err(); + if let ClientError::Call(error) = error { + assert_eq!(error.code(), ErrorCode::InvalidParams.code()); + } else { + panic!("Unexpected error: {error:?}"); + } - let (new_miniblock, new_tx_hash) = store_block(pool).await?; + let block = client + .get_block_by_number(api::BlockNumber::Latest, false) + .await?; + assert!(block.is_none()); + let block = client.get_block_by_number(1_000.into(), false).await?; + assert!(block.is_none()); - let block_filter_changes = client.get_filter_changes(block_filter_id).await?; - assert_matches!( - block_filter_changes, - FilterChanges::Hashes(hashes) if hashes == [new_miniblock.hash] - ); - let block_filter_changes = client.get_filter_changes(block_filter_id).await?; - assert_matches!(block_filter_changes, FilterChanges::Hashes(hashes) if hashes.is_empty()); + let mut storage = pool.access_storage().await?; + store_miniblock(&mut storage, MiniblockNumber(24), &[]).await?; + drop(storage); - let tx_filter_changes = client.get_filter_changes(tx_filter_id).await?; - assert_matches!( - tx_filter_changes, - FilterChanges::Hashes(hashes) if hashes == [new_tx_hash] + let block_number = client.get_block_number().await?; + let expected_block_number = StorageInitialization::SNAPSHOT_RECOVERY_BLOCK + 1; + assert_eq!(block_number, expected_block_number.into()); + + for block_number in [api::BlockNumber::Latest, expected_block_number.into()] { + let block = client + .get_block_by_number(block_number, false) + .await? + .context("no latest block")?; + assert_eq!(block.number, expected_block_number.into()); + } + + for number in [0, 1, expected_block_number - 1] { + let error = client + .get_block_details(MiniblockNumber(number)) + .await + .unwrap_err(); + assert_pruned_block_error(&error, expected_block_number); + let error = client + .get_raw_block_transactions(MiniblockNumber(number)) + .await + .unwrap_err(); + assert_pruned_block_error(&error, expected_block_number); + + let error = client + .get_block_transaction_count_by_number(number.into()) + .await + .unwrap_err(); + assert_pruned_block_error(&error, expected_block_number); + let error = client + .get_block_by_number(number.into(), false) + .await + .unwrap_err(); + assert_pruned_block_error(&error, expected_block_number); + } + + Ok(()) + } +} + +fn assert_pruned_block_error(error: &ClientError, first_retained_block: u32) { + if let ClientError::Call(error) = error { + assert_eq!(error.code(), ErrorCode::InvalidParams.code()); + assert!( + error + .message() + .contains(&format!("first retained block is {first_retained_block}")), + "{error:?}" ); - let tx_filter_changes = client.get_filter_changes(tx_filter_id).await?; - assert_matches!(tx_filter_changes, FilterChanges::Hashes(hashes) if hashes.is_empty()); + assert!(error.data().is_none(), "{error:?}"); + } else { + panic!("Unexpected error: {error:?}"); + } +} + +#[tokio::test] +async fn block_methods_with_snapshot_recovery() { + test_http_server(BlockMethodsWithSnapshotRecovery).await; +} + +#[derive(Debug)] +struct L1BatchMethodsWithSnapshotRecovery; + +#[async_trait] +impl HttpTest for L1BatchMethodsWithSnapshotRecovery { + fn storage_initialization(&self) -> StorageInitialization { + StorageInitialization::empty_recovery() + } + + async fn test(&self, client: &HttpClient, pool: &ConnectionPool) -> anyhow::Result<()> { + let error = client.get_l1_batch_number().await.unwrap_err(); + if let ClientError::Call(error) = error { + assert_eq!(error.code(), ErrorCode::InvalidParams.code()); + } else { + panic!("Unexpected error: {error:?}"); + } + + let mut storage = pool.access_storage().await?; + let miniblock_number = StorageInitialization::SNAPSHOT_RECOVERY_BLOCK + 1; + store_miniblock(&mut storage, MiniblockNumber(miniblock_number), &[]).await?; + seal_l1_batch(&mut storage, L1BatchNumber(miniblock_number)).await?; + drop(storage); + + let l1_batch_number = client.get_l1_batch_number().await?; + assert_eq!(l1_batch_number, miniblock_number.into()); + + // `get_miniblock_range` method + let miniblock_range = client + .get_miniblock_range(L1BatchNumber(miniblock_number)) + .await? + .context("no range for sealed L1 batch")?; + assert_eq!(miniblock_range.0, miniblock_number.into()); + assert_eq!(miniblock_range.1, miniblock_number.into()); + + let miniblock_range_for_future_batch = client + .get_miniblock_range(L1BatchNumber(miniblock_number) + 1) + .await?; + assert_eq!(miniblock_range_for_future_batch, None); + + let error = client + .get_miniblock_range(L1BatchNumber(miniblock_number) - 1) + .await + .unwrap_err(); + assert_pruned_l1_batch_error(&error, miniblock_number); - // Check uninstalling the filter. - let removed = client.uninstall_filter(block_filter_id).await?; - assert!(removed); - let removed = client.uninstall_filter(block_filter_id).await?; - assert!(!removed); + // `get_l1_batch_details` method + let details = client + .get_l1_batch_details(L1BatchNumber(miniblock_number)) + .await? + .context("no details for sealed L1 batch")?; + assert_eq!(details.number, L1BatchNumber(miniblock_number)); + + let details_for_future_batch = client + .get_l1_batch_details(L1BatchNumber(miniblock_number) + 1) + .await?; + assert!( + details_for_future_batch.is_none(), + "{details_for_future_batch:?}" + ); - let err = client - .get_filter_changes(block_filter_id) + let error = client + .get_l1_batch_details(L1BatchNumber(miniblock_number) - 1) .await .unwrap_err(); - assert_matches!(err, RpcError::Call(err) if err.code() == ErrorCode::InvalidParams.code()); + assert_pruned_l1_batch_error(&error, miniblock_number); + Ok(()) } } +fn assert_pruned_l1_batch_error(error: &ClientError, first_retained_l1_batch: u32) { + if let ClientError::Call(error) = error { + assert_eq!(error.code(), ErrorCode::InvalidParams.code()); + assert!( + error.message().contains(&format!( + "first retained L1 batch is {first_retained_l1_batch}" + )), + "{error:?}" + ); + assert!(error.data().is_none(), "{error:?}"); + } else { + panic!("Unexpected error: {error:?}"); + } +} + #[tokio::test] -async fn basic_filter_changes() { - test_http_server(BasicFilterChanges).await; +async fn l1_batch_methods_with_snapshot_recovery() { + test_http_server(L1BatchMethodsWithSnapshotRecovery).await; } #[derive(Debug)] -struct LogFilterChanges; +struct StorageAccessWithSnapshotRecovery; #[async_trait] -impl HttpTest for LogFilterChanges { - async fn test(&self, client: &HttpClient, pool: &ConnectionPool) -> anyhow::Result<()> { - let all_logs_filter_id = client.new_filter(Filter::default()).await?; - let address_filter = Filter { - address: Some(Address::repeat_byte(23).into()), - ..Filter::default() - }; - let address_filter_id = client.new_filter(address_filter).await?; - let topics_filter = Filter { - topics: Some(vec![Some(H256::repeat_byte(42).into())]), - ..Filter::default() - }; - let topics_filter_id = client.new_filter(topics_filter).await?; +impl HttpTest for StorageAccessWithSnapshotRecovery { + fn storage_initialization(&self) -> StorageInitialization { + let address = Address::repeat_byte(1); + let code_key = get_code_key(&address); + let code_hash = H256::repeat_byte(2); + let balance_key = storage_key_for_eth_balance(&address); + let logs = vec![ + StorageLog::new_write_log(code_key, code_hash), + StorageLog::new_write_log(balance_key, H256::from_low_u64_be(123)), + StorageLog::new_write_log( + StorageKey::new(AccountTreeId::new(address), H256::zero()), + H256::repeat_byte(0xff), + ), + ]; + let factory_deps = [(code_hash, b"code".to_vec())].into(); + StorageInitialization::Recovery { logs, factory_deps } + } + async fn test(&self, client: &HttpClient, pool: &ConnectionPool) -> anyhow::Result<()> { let mut storage = pool.access_storage().await?; - let (_, events) = store_events(&mut storage, 1, 0).await?; + + let address = Address::repeat_byte(1); + let first_local_miniblock = StorageInitialization::SNAPSHOT_RECOVERY_BLOCK + 1; + for number in [0, 1, first_local_miniblock - 1] { + let number = api::BlockIdVariant::BlockNumber(number.into()); + let error = client.get_code(address, Some(number)).await.unwrap_err(); + assert_pruned_block_error(&error, first_local_miniblock); + let error = client.get_balance(address, Some(number)).await.unwrap_err(); + assert_pruned_block_error(&error, first_local_miniblock); + let error = client + .get_storage_at(address, 0.into(), Some(number)) + .await + .unwrap_err(); + assert_pruned_block_error(&error, 24); + } + + store_miniblock(&mut storage, MiniblockNumber(first_local_miniblock), &[]).await?; drop(storage); - let events: Vec<_> = events.iter().collect(); - let all_logs = client.get_filter_changes(all_logs_filter_id).await?; - let FilterChanges::Logs(all_logs) = all_logs else { - panic!("Unexpected getFilterChanges output: {:?}", all_logs); - }; - assert_logs_match(&all_logs, &events); + for number in [api::BlockNumber::Latest, first_local_miniblock.into()] { + let number = api::BlockIdVariant::BlockNumber(number); + let code = client.get_code(address, Some(number)).await?; + assert_eq!(code.0, b"code"); + let balance = client.get_balance(address, Some(number)).await?; + assert_eq!(balance, 123.into()); + let storage_value = client + .get_storage_at(address, 0.into(), Some(number)) + .await?; + assert_eq!(storage_value, H256::repeat_byte(0xff)); + } + Ok(()) + } +} - let address_logs = client.get_filter_changes(address_filter_id).await?; - let FilterChanges::Logs(address_logs) = address_logs else { - panic!("Unexpected getFilterChanges output: {:?}", address_logs); - }; - assert_logs_match(&address_logs, &[events[0], events[3]]); +#[tokio::test] +async fn storage_access_with_snapshot_recovery() { + test_http_server(StorageAccessWithSnapshotRecovery).await; +} - let topics_logs = client.get_filter_changes(topics_filter_id).await?; - let FilterChanges::Logs(topics_logs) = topics_logs else { - panic!("Unexpected getFilterChanges output: {:?}", topics_logs); - }; - assert_logs_match(&topics_logs, &[events[1], events[3]]); +#[derive(Debug)] +struct TransactionCountTest; - let new_all_logs = client.get_filter_changes(all_logs_filter_id).await?; - let FilterChanges::Hashes(new_all_logs) = new_all_logs else { - panic!("Unexpected getFilterChanges output: {:?}", new_all_logs); - }; - assert!(new_all_logs.is_empty()); +#[async_trait] +impl HttpTest for TransactionCountTest { + async fn test(&self, client: &HttpClient, pool: &ConnectionPool) -> anyhow::Result<()> { + let test_address = Address::repeat_byte(11); + let mut storage = pool.access_storage().await?; + let mut miniblock_number = MiniblockNumber(0); + for nonce in [0, 1] { + let mut committed_tx = create_l2_transaction(10, 200); + committed_tx.common_data.initiator_address = test_address; + committed_tx.common_data.nonce = Nonce(nonce); + miniblock_number += 1; + store_miniblock( + &mut storage, + miniblock_number, + &[execute_l2_transaction(committed_tx)], + ) + .await?; + let nonce_log = StorageLog::new_write_log( + get_nonce_key(&test_address), + H256::from_low_u64_be((nonce + 1).into()), + ); + storage + .storage_logs_dal() + .insert_storage_logs(miniblock_number, &[(H256::zero(), vec![nonce_log])]) + .await; + } + + let pending_count = client.get_transaction_count(test_address, None).await?; + assert_eq!(pending_count, 2.into()); + + let mut pending_tx = create_l2_transaction(10, 200); + pending_tx.common_data.initiator_address = test_address; + pending_tx.common_data.nonce = Nonce(2); + storage + .transactions_dal() + .insert_transaction_l2(pending_tx, TransactionExecutionMetrics::default()) + .await; + + let pending_count = client.get_transaction_count(test_address, None).await?; + assert_eq!(pending_count, 3.into()); + + let latest_block_numbers = [api::BlockNumber::Latest, miniblock_number.0.into()]; + for number in latest_block_numbers { + let number = api::BlockIdVariant::BlockNumber(number); + let latest_count = client + .get_transaction_count(test_address, Some(number)) + .await?; + assert_eq!(latest_count, 2.into()); + } + + let earliest_block_numbers = [api::BlockNumber::Earliest, 0.into()]; + for number in earliest_block_numbers { + let number = api::BlockIdVariant::BlockNumber(number); + let historic_count = client + .get_transaction_count(test_address, Some(number)) + .await?; + assert_eq!(historic_count, 0.into()); + } + + let number = api::BlockIdVariant::BlockNumber(1.into()); + let historic_count = client + .get_transaction_count(test_address, Some(number)) + .await?; + assert_eq!(historic_count, 1.into()); + + let number = api::BlockIdVariant::BlockNumber(100.into()); + let error = client + .get_transaction_count(test_address, Some(number)) + .await + .unwrap_err(); + if let ClientError::Call(error) = error { + assert_eq!(error.code(), ErrorCode::InvalidParams.code()); + } else { + panic!("Unexpected error: {error:?}"); + } Ok(()) } } #[tokio::test] -async fn log_filter_changes() { - test_http_server(LogFilterChanges).await; +async fn getting_transaction_count_for_account() { + test_http_server(TransactionCountTest).await; } #[derive(Debug)] -struct LogFilterChangesWithBlockBoundaries; +struct TransactionCountAfterSnapshotRecoveryTest; #[async_trait] -impl HttpTest for LogFilterChangesWithBlockBoundaries { +impl HttpTest for TransactionCountAfterSnapshotRecoveryTest { + fn storage_initialization(&self) -> StorageInitialization { + let test_address = Address::repeat_byte(11); + let nonce_log = + StorageLog::new_write_log(get_nonce_key(&test_address), H256::from_low_u64_be(3)); + StorageInitialization::Recovery { + logs: vec![nonce_log], + factory_deps: HashMap::new(), + } + } + async fn test(&self, client: &HttpClient, pool: &ConnectionPool) -> anyhow::Result<()> { - let lower_bound_filter = Filter { - from_block: Some(api::BlockNumber::Number(2.into())), - ..Filter::default() - }; - let lower_bound_filter_id = client.new_filter(lower_bound_filter).await?; - let upper_bound_filter = Filter { - to_block: Some(api::BlockNumber::Number(1.into())), - ..Filter::default() - }; - let upper_bound_filter_id = client.new_filter(upper_bound_filter).await?; - let bounded_filter = Filter { - from_block: Some(api::BlockNumber::Number(1.into())), - to_block: Some(api::BlockNumber::Number(1.into())), - ..Filter::default() - }; - let bounded_filter_id = client.new_filter(bounded_filter).await?; + let test_address = Address::repeat_byte(11); + let pending_count = client.get_transaction_count(test_address, None).await?; + assert_eq!(pending_count, 3.into()); + let mut pending_tx = create_l2_transaction(10, 200); + pending_tx.common_data.initiator_address = test_address; + pending_tx.common_data.nonce = Nonce(3); let mut storage = pool.access_storage().await?; - let (_, events) = store_events(&mut storage, 1, 0).await?; - drop(storage); - let events: Vec<_> = events.iter().collect(); + storage + .transactions_dal() + .insert_transaction_l2(pending_tx, TransactionExecutionMetrics::default()) + .await; + + let pending_count = client.get_transaction_count(test_address, None).await?; + assert_eq!(pending_count, 4.into()); + + let pruned_block_numbers = [ + api::BlockNumber::Earliest, + 0.into(), + StorageInitialization::SNAPSHOT_RECOVERY_BLOCK.into(), + ]; + for number in pruned_block_numbers { + let number = api::BlockIdVariant::BlockNumber(number); + let error = client + .get_transaction_count(test_address, Some(number)) + .await + .unwrap_err(); + assert_pruned_block_error(&error, StorageInitialization::SNAPSHOT_RECOVERY_BLOCK + 1); + } - let lower_bound_logs = client.get_filter_changes(lower_bound_filter_id).await?; - assert_matches!( - lower_bound_logs, - FilterChanges::Hashes(hashes) if hashes.is_empty() - ); - // ^ Since `FilterChanges` is serialized w/o a tag, an empty array will be deserialized - // as `Hashes(_)` (the first declared variant). + let latest_miniblock_number = StorageInitialization::SNAPSHOT_RECOVERY_BLOCK + 1; + store_miniblock(&mut storage, MiniblockNumber(latest_miniblock_number), &[]).await?; - let upper_bound_logs = client.get_filter_changes(upper_bound_filter_id).await?; - let FilterChanges::Logs(upper_bound_logs) = upper_bound_logs else { - panic!("Unexpected getFilterChanges output: {:?}", upper_bound_logs); - }; - assert_logs_match(&upper_bound_logs, &events); - let bounded_logs = client.get_filter_changes(bounded_filter_id).await?; - let FilterChanges::Logs(bounded_logs) = bounded_logs else { - panic!("Unexpected getFilterChanges output: {:?}", bounded_logs); - }; - assert_eq!(bounded_logs, upper_bound_logs); + let latest_block_numbers = [api::BlockNumber::Latest, latest_miniblock_number.into()]; + for number in latest_block_numbers { + let number = api::BlockIdVariant::BlockNumber(number); + let latest_count = client + .get_transaction_count(test_address, Some(number)) + .await?; + assert_eq!(latest_count, 3.into()); + } + Ok(()) + } +} + +#[tokio::test] +async fn getting_transaction_count_for_account_after_snapshot_recovery() { + test_http_server(TransactionCountAfterSnapshotRecoveryTest).await; +} - // Add another miniblock with events to the storage. +#[derive(Debug)] +struct TransactionReceiptsTest; + +#[async_trait] +impl HttpTest for TransactionReceiptsTest { + async fn test(&self, client: &HttpClient, pool: &ConnectionPool) -> anyhow::Result<()> { let mut storage = pool.access_storage().await?; - let (_, new_events) = store_events(&mut storage, 2, 4).await?; - drop(storage); - let new_events: Vec<_> = new_events.iter().collect(); + let miniblock_number = MiniblockNumber(1); - let lower_bound_logs = client.get_filter_changes(lower_bound_filter_id).await?; - let FilterChanges::Logs(lower_bound_logs) = lower_bound_logs else { - panic!("Unexpected getFilterChanges output: {:?}", lower_bound_logs); - }; - assert_logs_match(&lower_bound_logs, &new_events); + let tx1 = create_l2_transaction(10, 200); + let tx2 = create_l2_transaction(10, 200); - let new_upper_bound_logs = client.get_filter_changes(upper_bound_filter_id).await?; - assert_matches!(new_upper_bound_logs, FilterChanges::Hashes(hashes) if hashes.is_empty()); - let new_bounded_logs = client.get_filter_changes(bounded_filter_id).await?; - assert_matches!(new_bounded_logs, FilterChanges::Hashes(hashes) if hashes.is_empty()); + let tx_results = vec![ + execute_l2_transaction(tx1.clone()), + execute_l2_transaction(tx2.clone()), + ]; - // Add miniblock #3. It should not be picked up by the bounded and upper bound filters, - // and should be picked up by the lower bound filter. - let mut storage = pool.access_storage().await?; - let (_, new_events) = store_events(&mut storage, 3, 8).await?; - drop(storage); - let new_events: Vec<_> = new_events.iter().collect(); + store_miniblock(&mut storage, miniblock_number, &tx_results).await?; - let bounded_logs = client.get_filter_changes(bounded_filter_id).await?; - let FilterChanges::Hashes(bounded_logs) = bounded_logs else { - panic!("Unexpected getFilterChanges output: {:?}", bounded_logs); - }; - assert!(bounded_logs.is_empty()); + let mut expected_receipts = Vec::new(); - let upper_bound_logs = client.get_filter_changes(upper_bound_filter_id).await?; - let FilterChanges::Hashes(upper_bound_logs) = upper_bound_logs else { - panic!("Unexpected getFilterChanges output: {:?}", upper_bound_logs); - }; - assert!(upper_bound_logs.is_empty()); + for tx in &tx_results { + expected_receipts.push( + client + .get_transaction_receipt(tx.hash) + .await? + .expect("Receipt found"), + ); + } - let lower_bound_logs = client.get_filter_changes(lower_bound_filter_id).await?; - let FilterChanges::Logs(lower_bound_logs) = lower_bound_logs else { - panic!("Unexpected getFilterChanges output: {:?}", lower_bound_logs); - }; - assert_logs_match(&lower_bound_logs, &new_events); + for (tx_result, receipt) in tx_results.iter().zip(&expected_receipts) { + assert_eq!(tx_result.hash, receipt.transaction_hash); + } + + let receipts = client + .get_block_receipts(BlockId::Number(miniblock_number.0.into())) + .await?; + assert_eq!(receipts.len(), 2); + for (receipt, expected_receipt) in receipts.iter().zip(&expected_receipts) { + assert_eq!(receipt, expected_receipt); + } Ok(()) } } #[tokio::test] -async fn log_filter_changes_with_block_boundaries() { - test_http_server(LogFilterChangesWithBlockBoundaries).await; +async fn transaction_receipts() { + test_http_server(TransactionReceiptsTest).await; } diff --git a/core/lib/zksync_core/src/api_server/web3/tests/snapshots.rs b/core/lib/zksync_core/src/api_server/web3/tests/snapshots.rs new file mode 100644 index 000000000000..1765a7c2397d --- /dev/null +++ b/core/lib/zksync_core/src/api_server/web3/tests/snapshots.rs @@ -0,0 +1,101 @@ +//! Tests for the `snapshots` Web3 namespace. + +use std::collections::HashSet; + +use zksync_web3_decl::namespaces::SnapshotsNamespaceClient; + +use super::*; + +#[derive(Debug)] +struct SnapshotBasicsTest { + chunk_ids: HashSet, +} + +impl SnapshotBasicsTest { + const CHUNK_COUNT: u64 = 5; + + fn new(chunk_ids: impl IntoIterator) -> Self { + let chunk_ids: HashSet<_> = chunk_ids.into_iter().collect(); + assert!(chunk_ids.iter().all(|&id| id < Self::CHUNK_COUNT)); + Self { chunk_ids } + } + + fn is_complete_snapshot(&self) -> bool { + self.chunk_ids == HashSet::from_iter(0..Self::CHUNK_COUNT) + } +} + +#[async_trait] +impl HttpTest for SnapshotBasicsTest { + async fn test(&self, client: &HttpClient, pool: &ConnectionPool) -> anyhow::Result<()> { + let mut storage = pool.access_storage().await.unwrap(); + store_miniblock( + &mut storage, + MiniblockNumber(1), + &[execute_l2_transaction(create_l2_transaction(1, 2))], + ) + .await?; + seal_l1_batch(&mut storage, L1BatchNumber(1)).await?; + storage + .snapshots_dal() + .add_snapshot(L1BatchNumber(1), Self::CHUNK_COUNT, "file:///factory_deps") + .await?; + + for &chunk_id in &self.chunk_ids { + let path = format!("file:///storage_logs/chunk{chunk_id}"); + storage + .snapshots_dal() + .add_storage_logs_filepath_for_snapshot(L1BatchNumber(1), chunk_id, &path) + .await?; + } + + let all_snapshots = client.get_all_snapshots().await?; + if self.is_complete_snapshot() { + assert_eq!(all_snapshots.snapshots_l1_batch_numbers, [L1BatchNumber(1)]); + } else { + assert_eq!(all_snapshots.snapshots_l1_batch_numbers, []); + } + + let snapshot_header = client + .get_snapshot_by_l1_batch_number(L1BatchNumber(1)) + .await?; + let snapshot_header = if self.is_complete_snapshot() { + snapshot_header.context("no snapshot for L1 batch #1")? + } else { + assert!(snapshot_header.is_none()); + return Ok(()); + }; + + assert_eq!(snapshot_header.l1_batch_number, L1BatchNumber(1)); + assert_eq!(snapshot_header.miniblock_number, MiniblockNumber(1)); + assert_eq!( + snapshot_header.factory_deps_filepath, + "file:///factory_deps" + ); + + assert_eq!( + snapshot_header.storage_logs_chunks.len(), + self.chunk_ids.len() + ); + for chunk in &snapshot_header.storage_logs_chunks { + assert!(self.chunk_ids.contains(&chunk.chunk_id)); + assert!(chunk.filepath.starts_with("file:///storage_logs/")); + } + Ok(()) + } +} + +#[tokio::test] +async fn snapshot_without_chunks() { + test_http_server(SnapshotBasicsTest::new([])).await; +} + +#[tokio::test] +async fn snapshot_with_some_chunks() { + test_http_server(SnapshotBasicsTest::new([0, 2, 4])).await; +} + +#[tokio::test] +async fn snapshot_with_all_chunks() { + test_http_server(SnapshotBasicsTest::new(0..SnapshotBasicsTest::CHUNK_COUNT)).await; +} diff --git a/core/lib/zksync_core/src/api_server/web3/tests/vm.rs b/core/lib/zksync_core/src/api_server/web3/tests/vm.rs new file mode 100644 index 000000000000..ba5ca2ead005 --- /dev/null +++ b/core/lib/zksync_core/src/api_server/web3/tests/vm.rs @@ -0,0 +1,237 @@ +//! Tests for the VM-instantiating methods (e.g., `eth_call`). + +// TODO: Test other VM methods (`debug_traceCall`, `eth_estimateGas`) + +use multivm::interface::ExecutionResult; +use zksync_types::{ + get_intrinsic_constants, transaction_request::CallRequest, L2ChainId, PackedEthSignature, U256, +}; +use zksync_utils::u256_to_h256; + +use super::*; + +#[derive(Debug)] +struct CallTest; + +impl CallTest { + fn call_request() -> CallRequest { + CallRequest { + from: Some(Address::repeat_byte(1)), + to: Some(Address::repeat_byte(2)), + data: Some(b"call".to_vec().into()), + ..CallRequest::default() + } + } +} + +#[async_trait] +impl HttpTest for CallTest { + fn transaction_executor(&self) -> MockTransactionExecutor { + let mut tx_executor = MockTransactionExecutor::default(); + tx_executor.insert_call_response( + Self::call_request().data.unwrap().0, + ExecutionResult::Success { + output: b"output".to_vec(), + }, + ); + tx_executor + } + + async fn test(&self, client: &HttpClient, _pool: &ConnectionPool) -> anyhow::Result<()> { + let call_result = client.call(Self::call_request(), None).await?; + assert_eq!(call_result.0, b"output"); + + let valid_block_numbers = [ + api::BlockNumber::Pending, + api::BlockNumber::Latest, + 0.into(), + ]; + for number in valid_block_numbers { + let number = api::BlockIdVariant::BlockNumber(number); + let call_result = client.call(Self::call_request(), Some(number)).await?; + assert_eq!(call_result.0, b"output"); + } + + let invalid_block_number = api::BlockNumber::from(100); + let number = api::BlockIdVariant::BlockNumber(invalid_block_number); + let error = client + .call(Self::call_request(), Some(number)) + .await + .unwrap_err(); + if let ClientError::Call(error) = error { + assert_eq!(error.code(), ErrorCode::InvalidParams.code()); + } else { + panic!("Unexpected error: {error:?}"); + } + + Ok(()) + } +} + +#[tokio::test] +async fn call_method_basics() { + test_http_server(CallTest).await; +} + +#[derive(Debug)] +struct CallTestAfterSnapshotRecovery; + +#[async_trait] +impl HttpTest for CallTestAfterSnapshotRecovery { + fn storage_initialization(&self) -> StorageInitialization { + StorageInitialization::empty_recovery() + } + + fn transaction_executor(&self) -> MockTransactionExecutor { + CallTest.transaction_executor() + } + + async fn test(&self, client: &HttpClient, pool: &ConnectionPool) -> anyhow::Result<()> { + let call_result = client.call(CallTest::call_request(), None).await?; + assert_eq!(call_result.0, b"output"); + let pending_block_number = api::BlockIdVariant::BlockNumber(api::BlockNumber::Pending); + let call_result = client + .call(CallTest::call_request(), Some(pending_block_number)) + .await?; + assert_eq!(call_result.0, b"output"); + + let first_local_miniblock = StorageInitialization::SNAPSHOT_RECOVERY_BLOCK + 1; + let first_miniblock_numbers = [api::BlockNumber::Latest, first_local_miniblock.into()]; + for number in first_miniblock_numbers { + let number = api::BlockIdVariant::BlockNumber(number); + let error = client + .call(CallTest::call_request(), Some(number)) + .await + .unwrap_err(); + if let ClientError::Call(error) = error { + assert_eq!(error.code(), ErrorCode::InvalidParams.code()); + } else { + panic!("Unexpected error: {error:?}"); + } + } + + let pruned_block_numbers = [0, 1, StorageInitialization::SNAPSHOT_RECOVERY_BLOCK]; + for number in pruned_block_numbers { + let number = api::BlockIdVariant::BlockNumber(number.into()); + let error = client + .call(CallTest::call_request(), Some(number)) + .await + .unwrap_err(); + assert_pruned_block_error(&error, StorageInitialization::SNAPSHOT_RECOVERY_BLOCK + 1); + } + + let mut storage = pool.access_storage().await?; + store_miniblock(&mut storage, MiniblockNumber(first_local_miniblock), &[]).await?; + drop(storage); + + for number in first_miniblock_numbers { + let number = api::BlockIdVariant::BlockNumber(number); + let call_result = client.call(CallTest::call_request(), Some(number)).await?; + assert_eq!(call_result.0, b"output"); + } + Ok(()) + } +} + +#[tokio::test] +async fn call_method_after_snapshot_recovery() { + test_http_server(CallTestAfterSnapshotRecovery).await; +} + +#[derive(Debug)] +struct SendRawTransactionTest { + snapshot_recovery: bool, +} + +impl SendRawTransactionTest { + fn transaction_bytes_and_hash() -> (Vec, H256) { + let private_key = H256::repeat_byte(11); + let address = PackedEthSignature::address_from_private_key(&private_key).unwrap(); + + let tx_request = api::TransactionRequest { + chain_id: Some(L2ChainId::default().as_u64()), + from: Some(address), + to: Some(Address::repeat_byte(2)), + value: 123_456.into(), + gas: (get_intrinsic_constants().l2_tx_intrinsic_gas * 2).into(), + gas_price: StateKeeperConfig::for_tests().minimal_l2_gas_price.into(), + input: vec![1, 2, 3, 4].into(), + ..api::TransactionRequest::default() + }; + let mut rlp = Default::default(); + tx_request.rlp(&mut rlp, L2ChainId::default().as_u64(), None); + let data = rlp.out(); + let signed_message = PackedEthSignature::message_to_signed_bytes(&data); + let signature = PackedEthSignature::sign_raw(&private_key, &signed_message).unwrap(); + + let mut rlp = Default::default(); + tx_request.rlp(&mut rlp, L2ChainId::default().as_u64(), Some(&signature)); + let data = rlp.out(); + let (_, tx_hash) = + api::TransactionRequest::from_bytes(&data, L2ChainId::default()).unwrap(); + (data.into(), tx_hash) + } + + fn balance_storage_log() -> StorageLog { + let private_key = H256::repeat_byte(11); + let address = PackedEthSignature::address_from_private_key(&private_key).unwrap(); + let balance_key = storage_key_for_eth_balance(&address); + StorageLog::new_write_log(balance_key, u256_to_h256(U256::one() << 64)) + } +} + +#[async_trait] +impl HttpTest for SendRawTransactionTest { + fn storage_initialization(&self) -> StorageInitialization { + if self.snapshot_recovery { + let logs = vec![Self::balance_storage_log()]; + StorageInitialization::Recovery { + logs, + factory_deps: HashMap::default(), + } + } else { + StorageInitialization::Genesis + } + } + + fn transaction_executor(&self) -> MockTransactionExecutor { + let mut tx_executor = MockTransactionExecutor::default(); + tx_executor.insert_tx_response( + Self::transaction_bytes_and_hash().1, + ExecutionResult::Success { output: vec![] }, + ); + tx_executor + } + + async fn test(&self, client: &HttpClient, pool: &ConnectionPool) -> anyhow::Result<()> { + if !self.snapshot_recovery { + // Manually set sufficient balance for the transaction account. + let mut storage = pool.access_storage().await?; + storage + .storage_dal() + .apply_storage_logs(&[(H256::zero(), vec![Self::balance_storage_log()])]) + .await; + } + + let (tx_bytes, tx_hash) = Self::transaction_bytes_and_hash(); + let send_result = client.send_raw_transaction(tx_bytes.into()).await?; + assert_eq!(send_result, tx_hash); + Ok(()) + } +} + +#[tokio::test] +async fn send_raw_transaction_basics() { + test_http_server(SendRawTransactionTest { + snapshot_recovery: false, + }) + .await; +} + +#[tokio::test] +async fn send_raw_transaction_after_snapshot_recovery() { + test_http_server(SendRawTransactionTest { + snapshot_recovery: true, + }) + .await; +} diff --git a/core/lib/zksync_core/src/api_server/web3/tests/ws.rs b/core/lib/zksync_core/src/api_server/web3/tests/ws.rs index af062f8367b3..a368854f9e75 100644 --- a/core/lib/zksync_core/src/api_server/web3/tests/ws.rs +++ b/core/lib/zksync_core/src/api_server/web3/tests/ws.rs @@ -1,5 +1,7 @@ //! WS-related tests. +use std::collections::HashSet; + use async_trait::async_trait; use jsonrpsee::core::{client::ClientT, params::BatchRequestBuilder, ClientError}; use reqwest::StatusCode; @@ -44,9 +46,35 @@ async fn wait_for_subscription( } #[allow(clippy::needless_pass_by_ref_mut)] // false positive -async fn wait_for_notifier( +async fn wait_for_notifiers( + events: &mut mpsc::UnboundedReceiver, + sub_types: &[SubscriptionType], +) { + let mut sub_types: HashSet<_> = sub_types.iter().copied().collect(); + let wait_future = tokio::time::timeout(TEST_TIMEOUT, async { + loop { + let event = events + .recv() + .await + .expect("Events emitter unexpectedly dropped"); + if let PubSubEvent::NotifyIterationFinished(ty) = event { + sub_types.remove(&ty); + if sub_types.is_empty() { + break; + } + } else { + tracing::trace!(?event, "Skipping event"); + } + } + }); + wait_future.await.expect("Timed out waiting for notifier"); +} + +#[allow(clippy::needless_pass_by_ref_mut)] // false positive +async fn wait_for_notifier_miniblock( events: &mut mpsc::UnboundedReceiver, sub_type: SubscriptionType, + expected: MiniblockNumber, ) { let wait_future = tokio::time::timeout(TEST_TIMEOUT, async { loop { @@ -54,18 +82,68 @@ async fn wait_for_notifier( .recv() .await .expect("Events emitter unexpectedly dropped"); - if matches!(event, PubSubEvent::NotifyIterationFinished(ty) if ty == sub_type) { - break; + if let PubSubEvent::MiniblockAdvanced(ty, number) = event { + if ty == sub_type && number >= expected { + break; + } } else { tracing::trace!(?event, "Skipping event"); } } }); - wait_future.await.expect("Timed out waiting for notifier") + wait_future.await.expect("Timed out waiting for notifier"); +} + +#[tokio::test] +async fn notifiers_start_after_snapshot_recovery() { + let pool = ConnectionPool::test_pool().await; + let mut storage = pool.access_storage().await.unwrap(); + prepare_empty_recovery_snapshot(&mut storage, StorageInitialization::SNAPSHOT_RECOVERY_BLOCK) + .await; + + let (stop_sender, stop_receiver) = watch::channel(false); + let (events_sender, mut events_receiver) = mpsc::unbounded_channel(); + let mut subscribe_logic = EthSubscribe::new(); + subscribe_logic.set_events_sender(events_sender); + let notifier_handles = + subscribe_logic.spawn_notifiers(pool.clone(), POLL_INTERVAL, stop_receiver); + assert!(!notifier_handles.is_empty()); + + // Wait a little doing nothing and check that notifier tasks are still active (i.e., have not panicked). + tokio::time::sleep(POLL_INTERVAL).await; + for handle in ¬ifier_handles { + assert!(!handle.is_finished()); + } + + // Emulate creating the first miniblock; check that notifiers react to it. + let first_local_miniblock = MiniblockNumber(StorageInitialization::SNAPSHOT_RECOVERY_BLOCK + 1); + store_miniblock(&mut storage, first_local_miniblock, &[]) + .await + .unwrap(); + + wait_for_notifiers( + &mut events_receiver, + &[ + SubscriptionType::Blocks, + SubscriptionType::Txs, + SubscriptionType::Logs, + ], + ) + .await; + + stop_sender.send_replace(true); + for handle in notifier_handles { + handle.await.unwrap().expect("Notifier task failed"); + } } #[async_trait] -trait WsTest { +trait WsTest: Send + Sync { + /// Prepares the storage before the server is started. The default implementation performs genesis. + fn storage_initialization(&self) -> StorageInitialization { + StorageInitialization::Genesis + } + async fn test( &self, client: &WsClient, @@ -82,15 +160,10 @@ async fn test_ws_server(test: impl WsTest) { let pool = ConnectionPool::test_pool().await; let network_config = NetworkConfig::for_tests(); let mut storage = pool.access_storage().await.unwrap(); - if storage.blocks_dal().is_genesis_needed().await.unwrap() { - ensure_genesis_state( - &mut storage, - network_config.zksync_network_id, - &GenesisParams::mock(), - ) + test.storage_initialization() + .prepare_storage(&network_config, &mut storage) .await - .unwrap(); - } + .expect("Failed preparing storage for test"); drop(storage); let (stop_sender, stop_receiver) = watch::channel(false); @@ -114,10 +187,10 @@ async fn test_ws_server(test: impl WsTest) { } #[derive(Debug)] -struct WsServerCanStart; +struct WsServerCanStartTest; #[async_trait] -impl WsTest for WsServerCanStart { +impl WsTest for WsServerCanStartTest { async fn test( &self, client: &WsClient, @@ -141,14 +214,24 @@ impl WsTest for WsServerCanStart { #[tokio::test] async fn ws_server_can_start() { - test_ws_server(WsServerCanStart).await; + test_ws_server(WsServerCanStartTest).await; } #[derive(Debug)] -struct BasicSubscriptions; +struct BasicSubscriptionsTest { + snapshot_recovery: bool, +} #[async_trait] -impl WsTest for BasicSubscriptions { +impl WsTest for BasicSubscriptionsTest { + fn storage_initialization(&self) -> StorageInitialization { + if self.snapshot_recovery { + StorageInitialization::empty_recovery() + } else { + StorageInitialization::Genesis + } + } + async fn test( &self, client: &WsClient, @@ -157,8 +240,11 @@ impl WsTest for BasicSubscriptions { ) -> anyhow::Result<()> { // Wait for the notifiers to get initialized so that they don't skip notifications // for the created subscriptions. - wait_for_notifier(&mut pub_sub_events, SubscriptionType::Blocks).await; - wait_for_notifier(&mut pub_sub_events, SubscriptionType::Txs).await; + wait_for_notifiers( + &mut pub_sub_events, + &[SubscriptionType::Blocks, SubscriptionType::Txs], + ) + .await; let params = rpc_params!["newHeads"]; let mut blocks_subscription = client @@ -172,7 +258,16 @@ impl WsTest for BasicSubscriptions { .await?; wait_for_subscription(&mut pub_sub_events, SubscriptionType::Txs).await; - let (new_miniblock, new_tx_hash) = store_block(pool).await?; + let mut storage = pool.access_storage().await?; + let tx_result = execute_l2_transaction(create_l2_transaction(1, 2)); + let new_tx_hash = tx_result.hash; + let miniblock_number = MiniblockNumber(if self.snapshot_recovery { + StorageInitialization::SNAPSHOT_RECOVERY_BLOCK + 1 + } else { + 1 + }); + let new_miniblock = store_miniblock(&mut storage, miniblock_number, &[tx_result]).await?; + drop(storage); let received_tx_hash = tokio::time::timeout(TEST_TIMEOUT, txs_subscription.next()) .await @@ -181,11 +276,17 @@ impl WsTest for BasicSubscriptions { assert_eq!(received_tx_hash, new_tx_hash); let received_block_header = tokio::time::timeout(TEST_TIMEOUT, blocks_subscription.next()) .await - .context("Timed out waiting for new block hash")? + .context("Timed out waiting for new block header")? .context("New blocks subscription terminated")??; - assert_eq!(received_block_header.number, Some(1.into())); + assert_eq!( + received_block_header.number, + Some(new_miniblock.number.0.into()) + ); assert_eq!(received_block_header.hash, Some(new_miniblock.hash)); - assert_eq!(received_block_header.timestamp, 1.into()); + assert_eq!( + received_block_header.timestamp, + new_miniblock.timestamp.into() + ); blocks_subscription.unsubscribe().await?; Ok(()) } @@ -193,27 +294,40 @@ impl WsTest for BasicSubscriptions { #[tokio::test] async fn basic_subscriptions() { - test_ws_server(BasicSubscriptions).await; + test_ws_server(BasicSubscriptionsTest { + snapshot_recovery: false, + }) + .await; +} + +#[tokio::test] +async fn basic_subscriptions_after_snapshot_recovery() { + test_ws_server(BasicSubscriptionsTest { + snapshot_recovery: true, + }) + .await; } #[derive(Debug)] -struct LogSubscriptions; +struct LogSubscriptionsTest { + snapshot_recovery: bool, +} #[derive(Debug)] -struct Subscriptions { +struct LogSubscriptions { all_logs_subscription: Subscription, address_subscription: Subscription, topic_subscription: Subscription, } -impl Subscriptions { +impl LogSubscriptions { async fn new( client: &WsClient, pub_sub_events: &mut mpsc::UnboundedReceiver, ) -> anyhow::Result { // Wait for the notifier to get initialized so that it doesn't skip notifications // for the created subscriptions. - wait_for_notifier(pub_sub_events, SubscriptionType::Logs).await; + wait_for_notifiers(pub_sub_events, &[SubscriptionType::Logs]).await; let params = rpc_params!["logs"]; let all_logs_subscription = client @@ -248,21 +362,34 @@ impl Subscriptions { } #[async_trait] -impl WsTest for LogSubscriptions { +impl WsTest for LogSubscriptionsTest { + fn storage_initialization(&self) -> StorageInitialization { + if self.snapshot_recovery { + StorageInitialization::empty_recovery() + } else { + StorageInitialization::Genesis + } + } + async fn test( &self, client: &WsClient, pool: &ConnectionPool, mut pub_sub_events: mpsc::UnboundedReceiver, ) -> anyhow::Result<()> { - let Subscriptions { + let LogSubscriptions { mut all_logs_subscription, mut address_subscription, mut topic_subscription, - } = Subscriptions::new(client, &mut pub_sub_events).await?; + } = LogSubscriptions::new(client, &mut pub_sub_events).await?; let mut storage = pool.access_storage().await?; - let (tx_location, events) = store_events(&mut storage, 1, 0).await?; + let miniblock_number = if self.snapshot_recovery { + StorageInitialization::SNAPSHOT_RECOVERY_BLOCK + 1 + } else { + 1 + }; + let (tx_location, events) = store_events(&mut storage, miniblock_number, 0).await?; drop(storage); let events: Vec<_> = events.iter().collect(); @@ -271,7 +398,7 @@ impl WsTest for LogSubscriptions { assert_eq!(log.transaction_index, Some(0.into())); assert_eq!(log.log_index, Some(i.into())); assert_eq!(log.transaction_hash, Some(tx_location.tx_hash)); - assert_eq!(log.block_number, Some(1.into())); + assert_eq!(log.block_number, Some(miniblock_number.into())); } assert_logs_match(&all_logs, &events); @@ -281,7 +408,7 @@ impl WsTest for LogSubscriptions { let topic_logs = collect_logs(&mut topic_subscription, 2).await?; assert_logs_match(&topic_logs, &[events[1], events[3]]); - wait_for_notifier(&mut pub_sub_events, SubscriptionType::Logs).await; + wait_for_notifiers(&mut pub_sub_events, &[SubscriptionType::Logs]).await; // Check that no new notifications were sent to subscribers. tokio::time::timeout(POLL_INTERVAL, all_logs_subscription.next()) @@ -314,25 +441,36 @@ async fn collect_logs( #[tokio::test] async fn log_subscriptions() { - test_ws_server(LogSubscriptions).await; + test_ws_server(LogSubscriptionsTest { + snapshot_recovery: false, + }) + .await; +} + +#[tokio::test] +async fn log_subscriptions_after_snapshot_recovery() { + test_ws_server(LogSubscriptionsTest { + snapshot_recovery: true, + }) + .await; } #[derive(Debug)] -struct LogSubscriptionsWithNewBlock; +struct LogSubscriptionsWithNewBlockTest; #[async_trait] -impl WsTest for LogSubscriptionsWithNewBlock { +impl WsTest for LogSubscriptionsWithNewBlockTest { async fn test( &self, client: &WsClient, pool: &ConnectionPool, mut pub_sub_events: mpsc::UnboundedReceiver, ) -> anyhow::Result<()> { - let Subscriptions { + let LogSubscriptions { mut all_logs_subscription, mut address_subscription, .. - } = Subscriptions::new(client, &mut pub_sub_events).await?; + } = LogSubscriptions::new(client, &mut pub_sub_events).await?; let mut storage = pool.access_storage().await?; let (_, events) = store_events(&mut storage, 1, 0).await?; @@ -362,25 +500,25 @@ impl WsTest for LogSubscriptionsWithNewBlock { #[tokio::test] async fn log_subscriptions_with_new_block() { - test_ws_server(LogSubscriptionsWithNewBlock).await; + test_ws_server(LogSubscriptionsWithNewBlockTest).await; } #[derive(Debug)] -struct LogSubscriptionsWithManyBlocks; +struct LogSubscriptionsWithManyBlocksTest; #[async_trait] -impl WsTest for LogSubscriptionsWithManyBlocks { +impl WsTest for LogSubscriptionsWithManyBlocksTest { async fn test( &self, client: &WsClient, pool: &ConnectionPool, mut pub_sub_events: mpsc::UnboundedReceiver, ) -> anyhow::Result<()> { - let Subscriptions { + let LogSubscriptions { mut all_logs_subscription, mut address_subscription, .. - } = Subscriptions::new(client, &mut pub_sub_events).await?; + } = LogSubscriptions::new(client, &mut pub_sub_events).await?; // Add two blocks in the storage atomically. let mut storage = pool.access_storage().await?; @@ -408,29 +546,35 @@ impl WsTest for LogSubscriptionsWithManyBlocks { #[tokio::test] async fn log_subscriptions_with_many_new_blocks_at_once() { - test_ws_server(LogSubscriptionsWithManyBlocks).await; + test_ws_server(LogSubscriptionsWithManyBlocksTest).await; } #[derive(Debug)] -struct LogSubscriptionsWithDelay; +struct LogSubscriptionsWithDelayTest; #[async_trait] -impl WsTest for LogSubscriptionsWithDelay { +impl WsTest for LogSubscriptionsWithDelayTest { async fn test( &self, client: &WsClient, pool: &ConnectionPool, mut pub_sub_events: mpsc::UnboundedReceiver, ) -> anyhow::Result<()> { + // Wait until notifiers are initialized. + wait_for_notifiers(&mut pub_sub_events, &[SubscriptionType::Logs]).await; + // Store a miniblock w/o subscriptions being present. let mut storage = pool.access_storage().await?; store_events(&mut storage, 1, 0).await?; drop(storage); - while pub_sub_events.try_recv().is_ok() { - // Drain all existing pub-sub events. - } - wait_for_notifier(&mut pub_sub_events, SubscriptionType::Logs).await; + // Wait for the log notifier to process the new miniblock. + wait_for_notifier_miniblock( + &mut pub_sub_events, + SubscriptionType::Logs, + MiniblockNumber(1), + ) + .await; let params = rpc_params!["logs"]; let mut all_logs_subscription = client @@ -472,14 +616,14 @@ impl WsTest for LogSubscriptionsWithDelay { #[tokio::test] async fn log_subscriptions_with_delay() { - test_ws_server(LogSubscriptionsWithDelay).await; + test_ws_server(LogSubscriptionsWithDelayTest).await; } #[derive(Debug)] -struct RateLimiting; +struct RateLimitingTest; #[async_trait] -impl WsTest for RateLimiting { +impl WsTest for RateLimitingTest { async fn test( &self, client: &WsClient, @@ -509,14 +653,14 @@ impl WsTest for RateLimiting { #[tokio::test] async fn rate_limiting() { - test_ws_server(RateLimiting).await; + test_ws_server(RateLimitingTest).await; } #[derive(Debug)] -struct BatchGetsRateLimited; +struct BatchGetsRateLimitedTest; #[async_trait] -impl WsTest for BatchGetsRateLimited { +impl WsTest for BatchGetsRateLimitedTest { async fn test( &self, client: &WsClient, @@ -553,5 +697,5 @@ impl WsTest for BatchGetsRateLimited { #[tokio::test] async fn batch_rate_limiting() { - test_ws_server(BatchGetsRateLimited).await; + test_ws_server(BatchGetsRateLimitedTest).await; } diff --git a/core/lib/zksync_core/src/basic_witness_input_producer/mod.rs b/core/lib/zksync_core/src/basic_witness_input_producer/mod.rs index 0367830f9c6f..ed933c18d5b3 100644 --- a/core/lib/zksync_core/src/basic_witness_input_producer/mod.rs +++ b/core/lib/zksync_core/src/basic_witness_input_producer/mod.rs @@ -4,19 +4,15 @@ use anyhow::Context; use async_trait::async_trait; use multivm::interface::{L2BlockEnv, VmInterface}; use tokio::{runtime::Handle, task::JoinHandle}; +use vm_utils::{create_vm, execute_tx}; use zksync_dal::{basic_witness_input_producer_dal::JOB_MAX_ATTEMPT, ConnectionPool}; use zksync_object_store::{ObjectStore, ObjectStoreFactory}; use zksync_queued_job_processor::JobProcessor; use zksync_types::{witness_block_state::WitnessBlockState, L1BatchNumber, L2ChainId}; -use self::{ - metrics::METRICS, - vm_interactions::{create_vm, execute_tx}, -}; +use self::metrics::METRICS; mod metrics; -mod vm_interactions; - /// Component that extracts all data (from DB) necessary to run a Basic Witness Generator. /// Does this by rerunning an entire L1Batch and extracting information from both the VM run and DB. /// This component will upload Witness Inputs to the object store. @@ -37,7 +33,7 @@ impl BasicWitnessInputProducer { ) -> anyhow::Result { Ok(BasicWitnessInputProducer { connection_pool, - object_store: store_factory.create_store().await.into(), + object_store: store_factory.create_store().await, l2_chain_id, }) } diff --git a/core/lib/zksync_core/src/block_reverter/mod.rs b/core/lib/zksync_core/src/block_reverter/mod.rs index e45bef7eb216..9b3c23dfc844 100644 --- a/core/lib/zksync_core/src/block_reverter/mod.rs +++ b/core/lib/zksync_core/src/block_reverter/mod.rs @@ -189,7 +189,7 @@ impl BlockReverter { path: &Path, storage_root_hash: H256, ) { - let db = RocksDB::new(path); + let db = RocksDB::new(path).expect("Failed initializing RocksDB for Merkle tree"); let mut tree = ZkSyncTree::new_lightweight(db.into()); if tree.next_l1_batch_number() <= last_l1_batch_to_keep { @@ -207,14 +207,19 @@ impl BlockReverter { /// Reverts blocks in the state keeper cache. async fn rollback_state_keeper_cache(&self, last_l1_batch_to_keep: L1BatchNumber) { tracing::info!("opening DB with state keeper cache..."); - let mut sk_cache = RocksdbStorage::new(self.state_keeper_cache_path.as_ref()); + let sk_cache = RocksdbStorage::builder(self.state_keeper_cache_path.as_ref()) + .await + .expect("Failed initializing state keeper cache"); - if sk_cache.l1_batch_number() > last_l1_batch_to_keep + 1 { + if sk_cache.l1_batch_number().await > Some(last_l1_batch_to_keep + 1) { let mut storage = self.connection_pool.access_storage().await.unwrap(); - tracing::info!("rolling back state keeper cache..."); - sk_cache.rollback(&mut storage, last_l1_batch_to_keep).await; + tracing::info!("Rolling back state keeper cache..."); + sk_cache + .rollback(&mut storage, last_l1_batch_to_keep) + .await + .expect("Failed rolling back state keeper cache"); } else { - tracing::info!("nothing to revert in state keeper cache"); + tracing::info!("Nothing to revert in state keeper cache"); } } @@ -260,7 +265,8 @@ impl BlockReverter { transaction .storage_logs_dal() .rollback_storage(last_miniblock_to_keep) - .await; + .await + .expect("failed rolling back storage"); tracing::info!("rolling back storage logs..."); transaction .storage_logs_dal() @@ -272,6 +278,11 @@ impl BlockReverter { .delete_l1_batches(last_l1_batch_to_keep) .await .unwrap(); + transaction + .blocks_dal() + .delete_initial_writes(last_l1_batch_to_keep) + .await + .unwrap(); tracing::info!("rolling back miniblocks..."); transaction .blocks_dal() diff --git a/core/lib/zksync_core/src/consensus/config.rs b/core/lib/zksync_core/src/consensus/config.rs new file mode 100644 index 000000000000..649a90ebc767 --- /dev/null +++ b/core/lib/zksync_core/src/consensus/config.rs @@ -0,0 +1,149 @@ +//! Configuration utilities for the consensus component. +use std::collections::{BTreeMap, BTreeSet}; + +use anyhow::Context as _; +use zksync_consensus_crypto::{read_required_text, Text, TextFmt}; +use zksync_consensus_executor as executor; +use zksync_consensus_roles::{node, validator}; +use zksync_protobuf::{required, ProtoFmt}; + +use crate::consensus::proto; + +/// Decodes a proto message from json for arbitrary `ProtoFmt`. +pub fn decode_json(json: &str) -> anyhow::Result { + let mut d = serde_json::Deserializer::from_str(json); + let p: T = zksync_protobuf::serde::deserialize(&mut d)?; + d.end()?; + Ok(p) +} + +/// Decodes a secret of type T from an env var with name `var_name`. +/// It makes sure that the error message doesn't contain the secret. +pub fn read_secret(var_name: &str) -> anyhow::Result { + let raw = std::env::var(var_name).map_err(|_| anyhow::anyhow!("{var_name} not set"))?; + Text::new(&raw) + .decode() + .map_err(|_| anyhow::anyhow!("{var_name} has invalid format")) +} + +/// Config (shared between main node and external node). +#[derive(Clone, Debug, PartialEq)] +pub struct Config { + /// Local socket address to listen for the incoming connections. + pub server_addr: std::net::SocketAddr, + /// Public address of this node (should forward to `server_addr`) + /// that will be advertised to peers, so that they can connect to this + /// node. + pub public_addr: std::net::SocketAddr, + + /// Validators participating in consensus. + pub validators: validator::ValidatorSet, + + /// Maximal allowed size of the payload in bytes. + pub max_payload_size: usize, + + /// Limit on the number of inbound connections outside + /// of the `static_inbound` set. + pub gossip_dynamic_inbound_limit: usize, + /// Inbound gossip connections that should be unconditionally accepted. + pub gossip_static_inbound: BTreeSet, + /// Outbound gossip connections that the node should actively try to + /// establish and maintain. + pub gossip_static_outbound: BTreeMap, +} + +impl Config { + pub fn executor_config(&self, node_key: node::SecretKey) -> executor::Config { + executor::Config { + server_addr: self.server_addr, + validators: self.validators.clone(), + max_payload_size: self.max_payload_size, + node_key, + gossip_dynamic_inbound_limit: self.gossip_dynamic_inbound_limit, + gossip_static_inbound: self.gossip_static_inbound.clone().into_iter().collect(), + gossip_static_outbound: self.gossip_static_outbound.clone().into_iter().collect(), + } + } + + pub fn validator_config( + &self, + validator_key: validator::SecretKey, + ) -> executor::ValidatorConfig { + executor::ValidatorConfig { + public_addr: self.public_addr, + key: validator_key, + } + } +} + +impl ProtoFmt for Config { + type Proto = proto::ConsensusConfig; + fn read(r: &Self::Proto) -> anyhow::Result { + let validators = r + .validators + .iter() + .enumerate() + .map(|(i, v)| { + Text::new(v) + .decode() + .with_context(|| format!("validators[{i}]")) + }) + .collect::, _>>()?; + let validators = validator::ValidatorSet::new(validators).context("validators")?; + + let mut gossip_static_inbound = BTreeSet::new(); + for (i, v) in r.gossip_static_inbound.iter().enumerate() { + gossip_static_inbound.insert( + Text::new(v) + .decode() + .with_context(|| format!("gossip_static_inbound[{i}]"))?, + ); + } + let mut gossip_static_outbound = BTreeMap::new(); + for (i, e) in r.gossip_static_outbound.iter().enumerate() { + let key = read_required_text(&e.key) + .with_context(|| format!("gossip_static_outbound[{i}].key"))?; + let addr = read_required_text(&e.addr) + .with_context(|| format!("gossip_static_outbound[{i}].addr"))?; + gossip_static_outbound.insert(key, addr); + } + Ok(Self { + server_addr: read_required_text(&r.server_addr).context("server_addr")?, + public_addr: read_required_text(&r.public_addr).context("public_addr")?, + validators, + max_payload_size: required(&r.max_payload_size) + .and_then(|x| Ok((*x).try_into()?)) + .context("max_payload_size")?, + gossip_dynamic_inbound_limit: required(&r.gossip_dynamic_inbound_limit) + .and_then(|x| Ok((*x).try_into()?)) + .context("gossip_dynamic_inbound_limit")?, + gossip_static_inbound, + gossip_static_outbound, + }) + } + + fn build(&self) -> Self::Proto { + Self::Proto { + server_addr: Some(self.server_addr.encode()), + public_addr: Some(self.public_addr.encode()), + validators: self.validators.iter().map(TextFmt::encode).collect(), + max_payload_size: Some(self.max_payload_size.try_into().unwrap()), + gossip_static_inbound: self + .gossip_static_inbound + .iter() + .map(TextFmt::encode) + .collect(), + gossip_static_outbound: self + .gossip_static_outbound + .iter() + .map(|(key, addr)| proto::NodeAddr { + key: Some(TextFmt::encode(key)), + addr: Some(TextFmt::encode(addr)), + }) + .collect(), + gossip_dynamic_inbound_limit: Some( + self.gossip_dynamic_inbound_limit.try_into().unwrap(), + ), + } + } +} diff --git a/core/lib/zksync_core/src/consensus/mod.rs b/core/lib/zksync_core/src/consensus/mod.rs index 34c73274fb5a..e0681502503a 100644 --- a/core/lib/zksync_core/src/consensus/mod.rs +++ b/core/lib/zksync_core/src/consensus/mod.rs @@ -1,61 +1,119 @@ //! Consensus-related functionality. -use std::sync::Arc; -use anyhow::Context as _; -use zksync_concurrency::{ctx, scope}; -use zksync_consensus_executor::{ConsensusConfig, Executor, ExecutorConfig}; -use zksync_consensus_roles::{node, validator}; +#![allow(clippy::redundant_locals)] + +use zksync_concurrency::{ctx, error::Wrap as _, scope, time}; +use zksync_consensus_executor as executor; +use zksync_consensus_roles::validator; +use zksync_consensus_storage::BlockStore; use zksync_dal::ConnectionPool; -use zksync_types::Address; -mod payload; -mod proto; -mod storage; +use self::storage::Store; +use crate::sync_layer::{sync_action::ActionQueueSender, MainNodeClient, SyncState}; +pub mod config; +pub mod proto; +mod storage; #[cfg(test)] pub(crate) mod testonly; #[cfg(test)] mod tests; -pub(crate) use self::{payload::Payload, storage::sync_block_to_consensus_block}; - -#[derive(Debug)] -pub struct Config { - pub executor: ExecutorConfig, - pub consensus: ConsensusConfig, - pub node_key: node::SecretKey, - pub validator_key: validator::SecretKey, - pub operator_address: Address, +/// Main node consensus config. +#[derive(Debug, Clone)] +pub struct MainNodeConfig { + pub executor: executor::Config, + pub validator: executor::ValidatorConfig, } -impl Config { - #[allow(dead_code)] +impl MainNodeConfig { + /// Task generating consensus certificates for the miniblocks generated by `StateKeeper`. + /// Broadcasts the blocks with certificates to gossip network peers. pub async fn run(self, ctx: &ctx::Ctx, pool: ConnectionPool) -> anyhow::Result<()> { anyhow::ensure!( self.executor.validators - == validator::ValidatorSet::new(vec![self.validator_key.public()]).unwrap(), + == validator::ValidatorSet::new(vec![self.validator.key.public()]).unwrap(), "currently only consensus with just 1 validator is supported" ); - let store = Arc::new( - storage::SignedBlockStore::new( - ctx, - pool, - &self.executor.genesis_block, - self.operator_address, - ) - .await?, - ); - let mut executor = Executor::new(ctx, self.executor, self.node_key, store.clone()).await?; - executor - .set_validator( - self.consensus, - self.validator_key, - store.clone(), - store.clone(), - ) - .context("executor.set_validator()")?; scope::run!(&ctx, |ctx, s| async { - s.spawn_bg(store.run_background_tasks(ctx)); + let store = Store::new(pool); + let mut block_store = store.clone().into_block_store(); + block_store + .try_init_genesis(ctx, &self.validator.key) + .await + .wrap("block_store.try_init_genesis()")?; + let (block_store, runner) = BlockStore::new(ctx, Box::new(block_store)) + .await + .wrap("BlockStore::new()")?; + s.spawn_bg(runner.run(ctx)); + let executor = executor::Executor { + config: self.executor, + block_store, + validator: Some(executor::Validator { + config: self.validator, + replica_store: Box::new(store.clone()), + payload_manager: Box::new(store.clone()), + }), + }; + executor.run(ctx).await + }) + .await + } +} + +/// Periodically fetches the head of the main node +/// and updates `SyncState` accordingly. +pub async fn run_main_node_state_fetcher( + ctx: &ctx::Ctx, + client: &dyn MainNodeClient, + sync_state: &SyncState, +) -> ctx::OrCanceled<()> { + const DELAY_INTERVAL: time::Duration = time::Duration::milliseconds(500); + const RETRY_DELAY_INTERVAL: time::Duration = time::Duration::seconds(5); + loop { + match ctx.wait(client.fetch_l2_block_number()).await? { + Ok(head) => { + sync_state.set_main_node_block(head); + ctx.sleep(DELAY_INTERVAL).await?; + } + Err(err) => { + tracing::warn!("main_node_client.fetch_l2_block_number(): {err}"); + ctx.sleep(RETRY_DELAY_INTERVAL).await?; + } + } + } +} + +/// External node consensus config. +#[derive(Debug, Clone)] +pub struct FetcherConfig { + pub executor: executor::Config, +} + +impl FetcherConfig { + /// Task fetching L2 blocks using peer-to-peer gossip network. + pub async fn run( + self, + ctx: &ctx::Ctx, + pool: ConnectionPool, + actions: ActionQueueSender, + ) -> anyhow::Result<()> { + scope::run!(ctx, |ctx, s| async { + let store = Store::new(pool); + let mut block_store = store.clone().into_block_store(); + block_store + .set_actions_queue(ctx, actions) + .await + .wrap("block_store.set_actions_queue()")?; + let (block_store, runner) = BlockStore::new(ctx, Box::new(block_store)) + .await + .wrap("BlockStore::new()")?; + s.spawn_bg(runner.run(ctx)); + let executor = executor::Executor { + config: self.executor, + block_store, + validator: None, + }; executor.run(ctx).await }) .await diff --git a/core/lib/zksync_core/src/consensus/payload.rs b/core/lib/zksync_core/src/consensus/payload.rs deleted file mode 100644 index be7a839c8f83..000000000000 --- a/core/lib/zksync_core/src/consensus/payload.rs +++ /dev/null @@ -1,105 +0,0 @@ -use anyhow::Context as _; -use zksync_consensus_roles::validator; -use zksync_protobuf::{required, ProtoFmt}; -use zksync_types::{ - api::en::SyncBlock, Address, L1BatchNumber, ProtocolVersionId, Transaction, H256, -}; - -/// L2 block (= miniblock) payload. -#[derive(Debug, PartialEq)] -pub(crate) struct Payload { - pub protocol_version: ProtocolVersionId, - pub hash: H256, - pub l1_batch_number: L1BatchNumber, - pub timestamp: u64, - pub l1_gas_price: u64, - pub l2_fair_gas_price: u64, - pub virtual_blocks: u32, - pub operator_address: Address, - pub transactions: Vec, -} - -impl ProtoFmt for Payload { - type Proto = super::proto::Payload; - - fn read(message: &Self::Proto) -> anyhow::Result { - let mut transactions = Vec::with_capacity(message.transactions.len()); - for (i, tx) in message.transactions.iter().enumerate() { - transactions.push( - required(&tx.json) - .and_then(|json_str| Ok(serde_json::from_str(json_str)?)) - .with_context(|| format!("transaction[{i}]"))?, - ); - } - - Ok(Self { - protocol_version: required(&message.protocol_version) - .and_then(|x| Ok(ProtocolVersionId::try_from(u16::try_from(*x)?)?)) - .context("protocol_version")?, - hash: required(&message.hash) - .and_then(|bytes| Ok(<[u8; 32]>::try_from(bytes.as_slice())?.into())) - .context("hash")?, - l1_batch_number: L1BatchNumber( - *required(&message.l1_batch_number).context("l1_batch_number")?, - ), - timestamp: *required(&message.timestamp).context("timestamp")?, - l1_gas_price: *required(&message.l1_gas_price).context("l1_gas_price")?, - l2_fair_gas_price: *required(&message.l2_fair_gas_price) - .context("l2_fair_gas_price")?, - virtual_blocks: *required(&message.virtual_blocks).context("virtual_blocks")?, - operator_address: required(&message.operator_address) - .and_then(|bytes| Ok(<[u8; 20]>::try_from(bytes.as_slice())?.into())) - .context("operator_address")?, - transactions, - }) - } - fn build(&self) -> Self::Proto { - Self::Proto { - protocol_version: Some((self.protocol_version as u16).into()), - hash: Some(self.hash.as_bytes().into()), - l1_batch_number: Some(self.l1_batch_number.0), - timestamp: Some(self.timestamp), - l1_gas_price: Some(self.l1_gas_price), - l2_fair_gas_price: Some(self.l2_fair_gas_price), - virtual_blocks: Some(self.virtual_blocks), - operator_address: Some(self.operator_address.as_bytes().into()), - // Transactions are stored in execution order, therefore order is deterministic. - transactions: self - .transactions - .iter() - .map(|t| super::proto::Transaction { - // TODO: There is no guarantee that json encoding here will be deterministic. - json: Some(serde_json::to_string(t).unwrap()), - }) - .collect(), - } - } -} - -impl TryFrom for Payload { - type Error = anyhow::Error; - - fn try_from(block: SyncBlock) -> anyhow::Result { - Ok(Self { - protocol_version: block.protocol_version, - hash: block.hash.unwrap_or_default(), - l1_batch_number: block.l1_batch_number, - timestamp: block.timestamp, - l1_gas_price: block.l1_gas_price, - l2_fair_gas_price: block.l2_fair_gas_price, - virtual_blocks: block.virtual_blocks.unwrap_or(0), - operator_address: block.operator_address, - transactions: block.transactions.context("Transactions are required")?, - }) - } -} - -impl Payload { - pub fn decode(payload: &validator::Payload) -> anyhow::Result { - zksync_protobuf::decode(&payload.0) - } - - pub fn encode(&self) -> validator::Payload { - validator::Payload(zksync_protobuf::encode(self)) - } -} diff --git a/core/lib/zksync_core/src/consensus/proto/mod.proto b/core/lib/zksync_core/src/consensus/proto/mod.proto index c5f99582875a..a943f9470e95 100644 --- a/core/lib/zksync_core/src/consensus/proto/mod.proto +++ b/core/lib/zksync_core/src/consensus/proto/mod.proto @@ -1,23 +1,53 @@ +// For config readability and ease of use, some of the primitive types are +// encoded as strings. Fields of these types have a comment with the name of the type. +// Here is the list of string-encoded types and their corresponding string formats: +// +// IpAddr - TCP socket address, encoded as a string of the form "IP:port". +// Both IPv4 and IPv6 are supported +// (note that opening IPv6 ports may not work depending on the VM capabilities). +// examples: "203.0.113.7:3456", "[2001:DB8::1]:4567" +// +// ValidatorPublicKey - public key of the validator (consensus participant) of the form "validator:public::" +// Currently only bn254 signature scheme is supported for validators. +// example: "validator:public:bn254:4b0c4697f0a35eab30f63684ae4611f3c1d631eecfd97237e2345a9b3d0c472dbb16c49b793beceaab0cdd89cda6ff1099bd1aaf1ad6cabde9a15793cc09b407" +// +// NodePublicKey - public key of the node (gossip network participant) of the form "node:public::" +// Currently only ed25519 signature scheme is supported for nodes. +// example: "node:public:ed25519:d36607699a0a3fbe3de16947928cf299484219ff62ca20f387795b0859dbe501" syntax = "proto3"; package zksync.core.consensus; -message Transaction { - // Default derive(serde::Serialize) encoding of the zksync_types::Transaction. - // TODO(gprusak): it is neither efficient, unique, nor suitable for version control. - // replace with a more robust encoding. - optional string json = 1; // required +// (public key, ip address) of a gossip network node. +message NodeAddr { + optional string key = 1; // required; NodePublicKey + optional string addr = 2; // required; IpAddr } -message Payload { - // zksync-era ProtocolVersionId - optional uint32 protocol_version = 9; // required; u16 - optional bytes hash = 1; // required; H256 - optional uint32 l1_batch_number = 2; // required - optional uint64 timestamp = 3; // required; seconds since UNIX epoch - optional uint64 l1_gas_price = 4; // required; gwei - optional uint64 l2_fair_gas_price = 5; // required; gwei - optional uint32 virtual_blocks = 6; // required - optional bytes operator_address = 7; // required; H160 - repeated Transaction transactions = 8; +message ConsensusConfig { + // IP:port to listen on, for incoming TCP connections. + // Use `0.0.0.0:` to listen on all network interfaces (i.e. on all IPs exposed by this VM). + optional string server_addr = 1; // required; IpAddr + + // Public IP:port to advertise, should forward to server_addr. + // Can be `127.0.0.1:` for local tests. + optional string public_addr = 2; // required; IpAddr + + // Public keys of all validators. + // Currently it has to be a singleton with a public key corresponding to secret key in CONSENSUS_VALIDATOR_KEY env var. + repeated string validators = 3; // required; ValidatorPublicKey + + // Maximal allowed size of the payload. + optional uint64 max_payload_size = 4; // required; bytes + + // Inbound connections that should be unconditionally accepted on the gossip network. + repeated string gossip_static_inbound = 5; // required; NodePublicKey + + // Limit on the number of gossip network inbound connections outside + // of the `gossip_static_inbound` set. + optional uint64 gossip_dynamic_inbound_limit = 6; // required + + // Outbound gossip network connections that the node should actively try to + // establish and maintain. + repeated NodeAddr gossip_static_outbound = 7; } diff --git a/core/lib/zksync_core/src/consensus/proto/mod.rs b/core/lib/zksync_core/src/consensus/proto/mod.rs index e6ac37696c21..f5b556c455cf 100644 --- a/core/lib/zksync_core/src/consensus/proto/mod.rs +++ b/core/lib/zksync_core/src/consensus/proto/mod.rs @@ -1,2 +1,3 @@ #![allow(warnings)] + include!(concat!(env!("OUT_DIR"), "/src/consensus/proto/gen.rs")); diff --git a/core/lib/zksync_core/src/consensus/storage.rs b/core/lib/zksync_core/src/consensus/storage.rs deleted file mode 100644 index d0feecf77949..000000000000 --- a/core/lib/zksync_core/src/consensus/storage.rs +++ /dev/null @@ -1,419 +0,0 @@ -//! Storage implementation based on DAL. -use std::ops; - -use anyhow::Context as _; -use zksync_concurrency::{ctx, error::Wrap as _, sync, time}; -use zksync_consensus_bft::PayloadSource; -use zksync_consensus_roles::validator; -use zksync_consensus_storage::{BlockStore, ReplicaState, ReplicaStateStore, WriteBlockStore}; -use zksync_dal::{blocks_dal::ConsensusBlockFields, ConnectionPool}; -use zksync_types::{api::en::SyncBlock, Address, MiniblockNumber}; - -use crate::consensus; - -pub(crate) fn sync_block_to_consensus_block( - block: SyncBlock, -) -> anyhow::Result { - let number = validator::BlockNumber(block.number.0.into()); - let consensus = ConsensusBlockFields::decode( - block - .consensus - .as_ref() - .context("Missing consensus fields")?, - ) - .context("ConsensusBlockFields::decode()")?; - - let payload: consensus::Payload = block.try_into()?; - let payload = payload.encode(); - anyhow::ensure!(payload.hash() == consensus.justification.message.proposal.payload); - Ok(validator::FinalBlock { - header: validator::BlockHeader { - parent: consensus.parent, - number, - payload: payload.hash(), - }, - payload, - justification: consensus.justification, - }) -} - -/// Context-aware `zksync_dal::StorageProcessor` wrapper. -pub(super) struct StorageProcessor<'a>(zksync_dal::StorageProcessor<'a>); - -pub(super) async fn storage<'a>( - ctx: &ctx::Ctx, - pool: &'a ConnectionPool, -) -> ctx::Result> { - Ok(StorageProcessor( - ctx.wait(pool.access_storage_tagged("sync_layer")).await??, - )) -} - -impl<'a> StorageProcessor<'a> { - pub async fn start_transaction<'b, 'c: 'b>( - &'c mut self, - ctx: &ctx::Ctx, - ) -> ctx::Result> { - Ok(StorageProcessor( - ctx.wait(self.0.start_transaction()) - .await? - .context("sqlx")?, - )) - } - - pub async fn commit(self, ctx: &ctx::Ctx) -> ctx::Result<()> { - Ok(ctx.wait(self.0.commit()).await?.context("sqlx")?) - } - - async fn fetch_sync_block( - &mut self, - ctx: &ctx::Ctx, - number: validator::BlockNumber, - operator_address: Address, - ) -> ctx::Result> { - let number = MiniblockNumber(number.0.try_into().context("MiniblockNumber")?); - Ok(ctx - .wait(self.0.sync_dal().sync_block(number, operator_address, true)) - .await? - .context("sync_block()")?) - } - - pub async fn fetch_block( - &mut self, - ctx: &ctx::Ctx, - number: validator::BlockNumber, - operator_address: Address, - ) -> ctx::Result> { - let Some(block) = self.fetch_sync_block(ctx, number, operator_address).await? else { - return Ok(None); - }; - if block.consensus.is_none() { - return Ok(None); - } - Ok(Some( - sync_block_to_consensus_block(block).context("sync_block_to_consensus_block()")?, - )) - } - - pub async fn fetch_payload( - &mut self, - ctx: &ctx::Ctx, - block_number: validator::BlockNumber, - operator_address: Address, - ) -> ctx::Result> { - let Some(sync_block) = self - .fetch_sync_block(ctx, block_number, operator_address) - .await? - else { - return Ok(None); - }; - Ok(Some(sync_block.try_into()?)) - } - - pub async fn put_block( - &mut self, - ctx: &ctx::Ctx, - block: &validator::FinalBlock, - operator_address: Address, - ) -> ctx::Result<()> { - let n = MiniblockNumber( - block - .header - .number - .0 - .try_into() - .context("MiniblockNumber")?, - ); - let mut txn = self - .start_transaction(ctx) - .await - .wrap("start_transaction()")?; - - // We require the block to be already stored in Postgres when we set the consensus field. - let sync_block = txn - .fetch_sync_block(ctx, block.header.number, operator_address) - .await? - .context("unknown block")?; - let want = &ConsensusBlockFields { - parent: block.header.parent, - justification: block.justification.clone(), - }; - - // If consensus field is already set, just validate the stored value but don't override it. - if sync_block.consensus.is_some() { - sync_block_to_consensus_block(sync_block) - .context("an invalid block found in storage")?; - return Ok(()); - } - - // Verify that the payload matches the storage. - let want_payload: consensus::Payload = sync_block.try_into()?; - if want_payload.encode() != block.payload { - let got_payload = consensus::Payload::decode(&block.payload)?; - return Err(anyhow::anyhow!( - "payload mismatch: got {got_payload:?}, want {want_payload:?}" - ) - .into()); - } - - ctx.wait(txn.0.blocks_dal().set_miniblock_consensus_fields(n, want)) - .await? - .context("set_miniblock_consensus_fields()")?; - txn.commit(ctx).await.wrap("commit()")?; - Ok(()) - } - - pub async fn find_head_number( - &mut self, - ctx: &ctx::Ctx, - ) -> ctx::Result { - let head = ctx - .wait( - self.0 - .blocks_dal() - .get_last_miniblock_number_with_consensus_fields(), - ) - .await? - .context("get_last_miniblock_number_with_consensus_fields()")? - .context("head not found")?; - Ok(validator::BlockNumber(head.0.into())) - } - - pub async fn find_head_forward( - &mut self, - ctx: &ctx::Ctx, - start_at: validator::BlockNumber, - ) -> ctx::Result { - let mut head = MiniblockNumber(start_at.0.try_into().context("MiniblockNumber")?); - while ctx - .wait(self.0.blocks_dal().has_consensus_fields(head + 1)) - .await? - .context("has_consensus_fields()")? - { - head += 1; - } - Ok(validator::BlockNumber(head.0.into())) - } -} - -/// Postgres-based [`BlockStore`] implementation, which -/// considers blocks as stored <=> they have consensus field set. -#[derive(Debug)] -pub(super) struct SignedBlockStore { - genesis: validator::BlockNumber, - head: sync::watch::Sender, - pool: ConnectionPool, - operator_address: Address, -} - -impl SignedBlockStore { - /// Creates a new storage handle. `pool` should have multiple connections to work efficiently. - pub async fn new( - ctx: &ctx::Ctx, - pool: ConnectionPool, - genesis: &validator::FinalBlock, - operator_address: Address, - ) -> anyhow::Result { - // Ensure that genesis block has consensus field set in postgres. - let head = { - let mut storage = storage(ctx, &pool).await.wrap("storage()")?; - storage - .put_block(ctx, genesis, operator_address) - .await - .wrap("put_block()")?; - - // Find the last miniblock with consensus field set (aka head). - // We assume here that all blocks in range (genesis,head) also have consensus field set. - // WARNING: genesis should NEVER be moved to an earlier block. - storage - .find_head_number(ctx) - .await - .wrap("find_head_number()")? - }; - Ok(Self { - genesis: genesis.header.number, - head: sync::watch::channel(head).0, - pool, - operator_address, - }) - } -} - -#[async_trait::async_trait] -impl WriteBlockStore for SignedBlockStore { - /// Verify that `payload` is a correct proposal for the block `block_number`. - async fn verify_payload( - &self, - ctx: &ctx::Ctx, - block_number: validator::BlockNumber, - payload: &validator::Payload, - ) -> ctx::Result<()> { - let storage = &mut storage(ctx, &self.pool).await.wrap("storage()")?; - let want = storage - .fetch_payload(ctx, block_number, self.operator_address) - .await - .wrap("fetch_payload()")? - .context("unknown block")?; - let got = consensus::Payload::decode(payload).context("consensus::Payload::decode()")?; - if got != want { - return Err(anyhow::anyhow!("unexpected payload: got {got:?} want {want:?}").into()); - } - Ok(()) - } - - /// Puts a block into this storage. - async fn put_block(&self, ctx: &ctx::Ctx, block: &validator::FinalBlock) -> ctx::Result<()> { - let storage = &mut storage(ctx, &self.pool).await.wrap("storage()")?; - - // Currently main node is the only validator, so it should be the only one creating new - // blocks. To ensure that no gaps in the blocks are created we check here that we always - // insert the next block after the current head block. - let head = *self.head.borrow(); - let head = storage - .find_head_forward(ctx, head) - .await - .wrap("find_head_forward()")?; - if block.header.number != head.next() { - return Err(anyhow::anyhow!( - "expected block with number {}, got {}", - head.next(), - block.header.number - ) - .into()); - } - - storage - .put_block(ctx, block, self.operator_address) - .await - .wrap("put_block()") - } -} - -#[async_trait::async_trait] -impl BlockStore for SignedBlockStore { - async fn head_block(&self, ctx: &ctx::Ctx) -> ctx::Result { - let head = self.last_contiguous_block_number(ctx).await?; - Ok(self.block(ctx, head).await?.context("head block missing")?) - } - - async fn first_block(&self, ctx: &ctx::Ctx) -> ctx::Result { - Ok(self - .block(ctx, self.genesis) - .await? - .context("Genesis miniblock not present in Postgres")?) - } - - async fn last_contiguous_block_number( - &self, - ctx: &ctx::Ctx, - ) -> ctx::Result { - let storage = &mut storage(ctx, &self.pool).await.wrap("storage()")?; - let head = *self.head.borrow(); - storage - .find_head_forward(ctx, head) - .await - .wrap("find_head_forward()") - } - - async fn block( - &self, - ctx: &ctx::Ctx, - number: validator::BlockNumber, - ) -> ctx::Result> { - let storage = &mut storage(ctx, &self.pool).await.wrap("storage()")?; - storage - .fetch_block(ctx, number, self.operator_address) - .await - .wrap("fetch_block()") - } - - async fn missing_block_numbers( - &self, - ctx: &ctx::Ctx, - range: ops::Range, - ) -> ctx::Result> { - let last = self.last_contiguous_block_number(ctx).await?; - let mut output = vec![]; - output.extend((range.start.0..self.genesis.0).map(validator::BlockNumber)); - output.extend((last.next().0..range.end.0).map(validator::BlockNumber)); - Ok(output) - } - - fn subscribe_to_block_writes(&self) -> sync::watch::Receiver { - self.head.subscribe() - } -} - -#[async_trait::async_trait] -impl ReplicaStateStore for SignedBlockStore { - async fn replica_state(&self, ctx: &ctx::Ctx) -> ctx::Result> { - let storage = &mut storage(ctx, &self.pool).await.wrap("storage")?; - Ok(ctx - .wait(storage.0.consensus_dal().replica_state()) - .await? - .context("replica_state()")?) - } - - async fn put_replica_state( - &self, - ctx: &ctx::Ctx, - replica_state: &ReplicaState, - ) -> ctx::Result<()> { - let storage = &mut storage(ctx, &self.pool).await.wrap("storage")?; - Ok(ctx - .wait(storage.0.consensus_dal().put_replica_state(replica_state)) - .await? - .context("put_replica_state()")?) - } -} - -#[async_trait::async_trait] -impl PayloadSource for SignedBlockStore { - async fn propose( - &self, - ctx: &ctx::Ctx, - block_number: validator::BlockNumber, - ) -> ctx::Result { - const POLL_INTERVAL: time::Duration = time::Duration::milliseconds(50); - loop { - let storage = &mut storage(ctx, &self.pool).await.wrap("storage()")?; - if let Some(payload) = storage - .fetch_payload(ctx, block_number, self.operator_address) - .await - .wrap("fetch_payload()")? - { - return Ok(payload.encode()); - } - ctx.sleep(POLL_INTERVAL).await?; - } - } -} - -impl SignedBlockStore { - pub async fn run_background_tasks(&self, ctx: &ctx::Ctx) -> anyhow::Result<()> { - const POLL_INTERVAL: time::Duration = time::Duration::milliseconds(100); - let mut head = *self.head.borrow(); - let res: ctx::Result<()> = async { - loop { - let storage = &mut storage(ctx, &self.pool).await.wrap("storage()")?; - head = storage - .find_head_forward(ctx, head) - .await - .wrap("find_head_forward()")?; - self.head.send_if_modified(|x| { - if *x >= head { - return false; - } - *x = head; - true - }); - ctx.sleep(POLL_INTERVAL).await?; - } - } - .await; - match res.err().unwrap() { - ctx::Error::Canceled(_) => Ok(()), - ctx::Error::Internal(err) => Err(err), - } - } -} diff --git a/core/lib/zksync_core/src/consensus/storage/mod.rs b/core/lib/zksync_core/src/consensus/storage/mod.rs new file mode 100644 index 000000000000..bac1c54f3e65 --- /dev/null +++ b/core/lib/zksync_core/src/consensus/storage/mod.rs @@ -0,0 +1,429 @@ +//! Storage implementation based on DAL. + +use anyhow::Context as _; +use zksync_concurrency::{ctx, error::Wrap as _, sync, time}; +use zksync_consensus_bft::PayloadManager; +use zksync_consensus_roles::validator; +use zksync_consensus_storage::{BlockStoreState, PersistentBlockStore, ReplicaState, ReplicaStore}; +use zksync_dal::{consensus_dal::Payload, ConnectionPool}; +use zksync_types::MiniblockNumber; + +#[cfg(test)] +mod testonly; + +use crate::sync_layer::{ + fetcher::{FetchedBlock, FetcherCursor}, + sync_action::ActionQueueSender, +}; + +/// Context-aware `zksync_dal::StorageProcessor` wrapper. +pub(super) struct CtxStorage<'a>(zksync_dal::StorageProcessor<'a>); + +impl<'a> CtxStorage<'a> { + /// Wrapper for `access_storage_tagged()`. + pub async fn access(ctx: &ctx::Ctx, pool: &'a ConnectionPool) -> ctx::Result> { + Ok(Self( + ctx.wait(pool.access_storage_tagged("consensus")).await??, + )) + } + + /// Wrapper for `start_transaction()`. + pub async fn start_transaction<'b, 'c: 'b>( + &'c mut self, + ctx: &ctx::Ctx, + ) -> ctx::Result> { + Ok(CtxStorage( + ctx.wait(self.0.start_transaction()) + .await? + .context("sqlx")?, + )) + } + + /// Wrapper for `blocks_dal().get_sealed_miniblock_number()`. + pub async fn last_miniblock_number( + &mut self, + ctx: &ctx::Ctx, + ) -> ctx::Result { + let number = ctx + .wait(self.0.blocks_dal().get_sealed_miniblock_number()) + .await? + .context("sqlx")? + .context("no miniblocks in storage")?; // FIXME (PLA-703): handle empty storage + Ok(validator::BlockNumber(number.0.into())) + } + + /// Wrapper for `commit()`. + pub async fn commit(self, ctx: &ctx::Ctx) -> ctx::Result<()> { + Ok(ctx.wait(self.0.commit()).await?.context("sqlx")?) + } + + /// Wrapper for `consensus_dal().block_payload()`. + pub async fn payload( + &mut self, + ctx: &ctx::Ctx, + number: validator::BlockNumber, + ) -> ctx::Result> { + Ok(ctx + .wait(self.0.consensus_dal().block_payload(number)) + .await??) + } + + /// Wrapper for `consensus_dal().first_certificate()`. + pub async fn first_certificate( + &mut self, + ctx: &ctx::Ctx, + ) -> ctx::Result> { + Ok(ctx + .wait(self.0.consensus_dal().first_certificate()) + .await??) + } + + /// Wrapper for `consensus_dal().last_certificate()`. + pub async fn last_certificate( + &mut self, + ctx: &ctx::Ctx, + ) -> ctx::Result> { + Ok(ctx + .wait(self.0.consensus_dal().last_certificate()) + .await??) + } + + /// Wrapper for `consensus_dal().certificate()`. + pub async fn certificate( + &mut self, + ctx: &ctx::Ctx, + number: validator::BlockNumber, + ) -> ctx::Result> { + Ok(ctx + .wait(self.0.consensus_dal().certificate(number)) + .await??) + } + + /// Wrapper for `consensus_dal().insert_certificate()`. + pub async fn insert_certificate( + &mut self, + ctx: &ctx::Ctx, + cert: &validator::CommitQC, + ) -> ctx::Result<()> { + Ok(ctx + .wait(self.0.consensus_dal().insert_certificate(cert)) + .await??) + } + + /// Wrapper for `consensus_dal().replica_state()`. + pub async fn replica_state(&mut self, ctx: &ctx::Ctx) -> ctx::Result> { + Ok(ctx.wait(self.0.consensus_dal().replica_state()).await??) + } + + /// Wrapper for `consensus_dal().set_replica_state()`. + pub async fn set_replica_state( + &mut self, + ctx: &ctx::Ctx, + state: &ReplicaState, + ) -> ctx::Result<()> { + Ok(ctx + .wait(self.0.consensus_dal().set_replica_state(state)) + .await? + .context("sqlx")?) + } + + /// Wrapper for `FetcherCursor::new()`. + pub async fn new_fetcher_cursor(&mut self, ctx: &ctx::Ctx) -> ctx::Result { + Ok(ctx.wait(FetcherCursor::new(&mut self.0)).await??) + } +} + +#[derive(Debug)] +struct Cursor { + inner: FetcherCursor, + actions: ActionQueueSender, +} + +impl Cursor { + /// Advances the cursor by converting the block into actions and pushing them + /// to the actions queue. + /// Does nothing and returns Ok() if the block has been already processed. + /// Returns an error if a block with an earlier block number was expected. + async fn advance(&mut self, block: &validator::FinalBlock) -> anyhow::Result<()> { + let number = MiniblockNumber( + u32::try_from(block.header().number.0) + .context("Integer overflow converting block number")?, + ); + let payload = + Payload::decode(&block.payload).context("Failed deserializing block payload")?; + let want = self.inner.next_miniblock; + // Some blocks are missing. + if number > want { + return Err(anyhow::anyhow!("expected {want:?}, got {number:?}")); + } + // Block already processed. + if number < want { + return Ok(()); + } + let block = FetchedBlock { + number, + l1_batch_number: payload.l1_batch_number, + last_in_batch: payload.last_in_batch, + protocol_version: payload.protocol_version, + timestamp: payload.timestamp, + reference_hash: Some(payload.hash), + l1_gas_price: payload.l1_gas_price, + l2_fair_gas_price: payload.l2_fair_gas_price, + fair_pubdata_price: payload.fair_pubdata_price, + virtual_blocks: payload.virtual_blocks, + operator_address: payload.operator_address, + transactions: payload.transactions, + }; + self.actions.push_actions(self.inner.advance(block)).await; + Ok(()) + } +} + +/// Wrapper of `ConnectionPool` implementing `ReplicaStore` and `PayloadManager`. +#[derive(Clone, Debug)] +pub(super) struct Store { + pool: ConnectionPool, +} + +/// Wrapper of `ConnectionPool` implementing `PersistentBlockStore`. +#[derive(Debug)] +pub(super) struct BlockStore { + inner: Store, + /// Mutex preventing concurrent execution of `store_next_block` calls. + store_next_block_mutex: sync::Mutex>, +} + +impl Store { + /// Creates a `Store`. `pool` should have multiple connections to work efficiently. + pub fn new(pool: ConnectionPool) -> Self { + Self { pool } + } + + /// Converts `Store` into a `BlockStore`. + pub fn into_block_store(self) -> BlockStore { + BlockStore { + inner: self, + store_next_block_mutex: sync::Mutex::new(None), + } + } +} + +impl BlockStore { + /// Generates and stores the genesis cert (signed by `validator_key`) for the last sealed miniblock. + /// No-op if db already contains a genesis cert. + pub async fn try_init_genesis( + &mut self, + ctx: &ctx::Ctx, + validator_key: &validator::SecretKey, + ) -> ctx::Result<()> { + let mut storage = CtxStorage::access(ctx, &self.inner.pool) + .await + .wrap("access()")?; + // Fetch last miniblock number outside of the transaction to avoid taking a lock. + let number = storage + .last_miniblock_number(ctx) + .await + .wrap("last_miniblock_number()")?; + + let mut txn = storage + .start_transaction(ctx) + .await + .wrap("start_transaction()")?; + if txn + .first_certificate(ctx) + .await + .wrap("first_certificate()")? + .is_some() + { + return Ok(()); + } + let payload = txn + .payload(ctx, number) + .await + .wrap("payload()")? + .context("miniblock disappeared")?; + let mut genesis = validator::GenesisSetup { + keys: vec![validator_key.clone()], + blocks: vec![], + }; + genesis + .next_block() + .block_number(number) + .payload(payload.encode()) + .push(); + txn.insert_certificate(ctx, &genesis.blocks[0].justification) + .await + .wrap("insert_certificate()")?; + txn.commit(ctx).await.wrap("commit()") + } + + /// Sets an `ActionQueueSender` in the `BlockStore`. See `store_next_block()` for details. + pub async fn set_actions_queue( + &mut self, + ctx: &ctx::Ctx, + actions: ActionQueueSender, + ) -> ctx::Result<()> { + let mut storage = CtxStorage::access(ctx, &self.inner.pool) + .await + .wrap("access()")?; + let inner = storage + .new_fetcher_cursor(ctx) + .await + .wrap("new_fetcher_cursor()")?; + *sync::lock(ctx, &self.store_next_block_mutex).await? = Some(Cursor { inner, actions }); + Ok(()) + } +} + +#[async_trait::async_trait] +impl PersistentBlockStore for BlockStore { + async fn state(&self, ctx: &ctx::Ctx) -> ctx::Result { + let mut storage = CtxStorage::access(ctx, &self.inner.pool) + .await + .wrap("access()")?; + let first = storage + .first_certificate(ctx) + .await + .wrap("first_certificate()")? + .context("store is empty")?; + let last = storage + .last_certificate(ctx) + .await + .wrap("last_certificate()")? + .context("store is empty")?; + Ok(BlockStoreState { first, last }) + } + + async fn block( + &self, + ctx: &ctx::Ctx, + number: validator::BlockNumber, + ) -> ctx::Result { + let storage = &mut CtxStorage::access(ctx, &self.inner.pool) + .await + .wrap("access()")?; + let justification = storage + .certificate(ctx, number) + .await + .wrap("certificate()")? + .context("not found")?; + let payload = storage + .payload(ctx, number) + .await + .wrap("payload()")? + .context("miniblock disappeared from storage")?; + Ok(validator::FinalBlock { + payload: payload.encode(), + justification, + }) + } + + /// If actions queue is set (and the block has not been stored yet), + /// the block will be translated into a sequence of actions. + /// The received actions should be fed + /// to `ExternalIO`, so that `StateKeeper` will store the corresponding miniblock in the db. + /// + /// `store_next_block()` call will wait synchronously for the miniblock. + /// Once miniblock is observed in storage, `store_next_block()` will store a cert for this + /// miniblock. + async fn store_next_block( + &self, + ctx: &ctx::Ctx, + block: &validator::FinalBlock, + ) -> ctx::Result<()> { + // This mutex prevents concurrent `store_next_block` calls. + let mut guard = ctx.wait(self.store_next_block_mutex.lock()).await?; + if let Some(cursor) = &mut *guard { + cursor.advance(block).await.context("cursor.advance()")?; + } + const POLL_INTERVAL: time::Duration = time::Duration::milliseconds(50); + loop { + let mut storage = CtxStorage::access(ctx, &self.inner.pool) + .await + .wrap("access()")?; + let number = storage + .last_miniblock_number(ctx) + .await + .wrap("last_miniblock_number()")?; + if number >= block.header().number { + storage + .insert_certificate(ctx, &block.justification) + .await + .wrap("insert_certificate()")?; + return Ok(()); + } + drop(storage); + ctx.sleep(POLL_INTERVAL).await?; + } + } +} + +#[async_trait::async_trait] +impl ReplicaStore for Store { + async fn state(&self, ctx: &ctx::Ctx) -> ctx::Result> { + let storage = &mut CtxStorage::access(ctx, &self.pool).await.wrap("access()")?; + storage.replica_state(ctx).await.wrap("replica_state()") + } + + async fn set_state(&self, ctx: &ctx::Ctx, state: &ReplicaState) -> ctx::Result<()> { + let storage = &mut CtxStorage::access(ctx, &self.pool).await.wrap("access()")?; + storage + .set_replica_state(ctx, state) + .await + .wrap("set_replica_state()") + } +} + +#[async_trait::async_trait] +impl PayloadManager for Store { + /// Currently (for the main node) proposing is implemented as just converting a miniblock from db (without a cert) into a + /// payload. + async fn propose( + &self, + ctx: &ctx::Ctx, + block_number: validator::BlockNumber, + ) -> ctx::Result { + const POLL_INTERVAL: time::Duration = time::Duration::milliseconds(50); + let mut storage = CtxStorage::access(ctx, &self.pool).await.wrap("access()")?; + storage + .certificate(ctx, block_number.prev()) + .await + .wrap("certificate()")? + .with_context(|| format!("parent of {block_number:?} is missing"))?; + drop(storage); + loop { + let mut storage = CtxStorage::access(ctx, &self.pool).await.wrap("access()")?; + if let Some(payload) = storage.payload(ctx, block_number).await.wrap("payload()")? { + let encoded_payload = payload.encode(); + if encoded_payload.0.len() > 1 << 20 { + tracing::warn!( + "large payload ({}B) with {} transactions", + encoded_payload.0.len(), + payload.transactions.len() + ); + } + return Ok(encoded_payload); + } + drop(storage); + ctx.sleep(POLL_INTERVAL).await?; + } + } + + /// Verify that `payload` is a correct proposal for the block `block_number`. + /// Currently (for the main node) it is implemented as checking whether the received payload + /// matches the miniblock in the db. + async fn verify( + &self, + ctx: &ctx::Ctx, + block_number: validator::BlockNumber, + payload: &validator::Payload, + ) -> ctx::Result<()> { + let want = self.propose(ctx, block_number).await?; + let want = Payload::decode(&want).context("Payload::decode(want)")?; + let got = Payload::decode(payload).context("Payload::decode(got)")?; + if got != want { + return Err(anyhow::anyhow!("unexpected payload: got {got:?} want {want:?}").into()); + } + Ok(()) + } +} diff --git a/core/lib/zksync_core/src/consensus/storage/testonly.rs b/core/lib/zksync_core/src/consensus/storage/testonly.rs new file mode 100644 index 000000000000..a0c32c57a690 --- /dev/null +++ b/core/lib/zksync_core/src/consensus/storage/testonly.rs @@ -0,0 +1,47 @@ +//! Storage test helpers. +use anyhow::Context as _; +use zksync_concurrency::{ctx, error::Wrap as _, time}; +use zksync_consensus_roles::validator; +use zksync_consensus_storage as storage; + +use super::{BlockStore, CtxStorage}; + +impl BlockStore { + /// Waits for the `number` miniblock to have a certificate. + pub async fn wait_for_certificate( + &self, + ctx: &ctx::Ctx, + number: validator::BlockNumber, + ) -> ctx::Result<()> { + const POLL_INTERVAL: time::Duration = time::Duration::milliseconds(100); + loop { + let mut storage = CtxStorage::access(ctx, &self.inner.pool) + .await + .wrap("access()")?; + if storage.certificate(ctx, number).await?.is_some() { + return Ok(()); + } + ctx.sleep(POLL_INTERVAL).await?; + } + } + + /// Waits for `want_last` block to have certificate, then fetches all miniblocks with certificates + /// and verifies them. + pub async fn wait_for_blocks_and_verify( + &self, + ctx: &ctx::Ctx, + validators: &validator::ValidatorSet, + want_last: validator::BlockNumber, + ) -> ctx::Result> { + self.wait_for_certificate(ctx, want_last).await?; + let blocks = storage::testonly::dump(ctx, self).await; + let got_last = blocks.last().context("empty store")?.header().number; + assert_eq!(got_last, want_last); + for block in &blocks { + block + .validate(validators, 1) + .context(block.header().number)?; + } + Ok(blocks) + } +} diff --git a/core/lib/zksync_core/src/consensus/testonly.rs b/core/lib/zksync_core/src/consensus/testonly.rs index c2a7a4ec475b..88a23d17ba37 100644 --- a/core/lib/zksync_core/src/consensus/testonly.rs +++ b/core/lib/zksync_core/src/consensus/testonly.rs @@ -1,7 +1,11 @@ +//! Utilities for testing the consensus module. use anyhow::Context as _; -use rand::Rng; -use zksync_concurrency::{ctx, scope, sync, time}; -use zksync_consensus_roles::validator; +use rand::{ + distributions::{Distribution, Standard}, + Rng, +}; +use zksync_concurrency::{ctx, error::Wrap as _, scope, sync, time}; +use zksync_consensus_roles::{node, validator}; use zksync_contracts::{BaseSystemContractsHashes, SystemContractCode}; use zksync_dal::ConnectionPool; use zksync_types::{ @@ -10,17 +14,47 @@ use zksync_types::{ }; use crate::{ + consensus::{ + config::Config, + storage::{BlockStore, CtxStorage}, + Store, + }, genesis::{ensure_genesis_state, GenesisParams}, state_keeper::{ - tests::{create_l1_batch_metadata, create_l2_transaction, MockBatchExecutorBuilder}, - MiniblockSealer, ZkSyncStateKeeper, + seal_criteria::NoopSealer, tests::MockBatchExecutorBuilder, MiniblockSealer, + ZkSyncStateKeeper, }, sync_layer::{ sync_action::{ActionQueue, ActionQueueSender, SyncAction}, ExternalIO, MainNodeClient, SyncState, }, + utils::testonly::{create_l1_batch_metadata, create_l2_transaction}, }; +fn make_addr(rng: &mut R) -> std::net::SocketAddr { + std::net::SocketAddr::new(std::net::IpAddr::from(rng.gen::<[u8; 16]>()), rng.gen()) +} + +fn make_node_key(rng: &mut R) -> node::PublicKey { + rng.gen::().public() +} + +impl Distribution for Standard { + fn sample(&self, rng: &mut R) -> Config { + Config { + server_addr: make_addr(rng), + public_addr: make_addr(rng), + validators: rng.gen(), + max_payload_size: usize::MAX, + gossip_dynamic_inbound_limit: rng.gen(), + gossip_static_inbound: (0..3).map(|_| make_node_key(rng)).collect(), + gossip_static_outbound: (0..5) + .map(|_| (make_node_key(rng), make_addr(rng))) + .collect(), + } + } +} + #[derive(Debug, Default)] pub(crate) struct MockMainNodeClient { prev_miniblock_hash: H256, @@ -68,13 +102,13 @@ impl MockMainNodeClient { timestamp: number.into(), l1_gas_price: 2, l2_fair_gas_price: 3, + fair_pubdata_price: Some(24), base_system_contracts_hashes: BaseSystemContractsHashes::default(), operator_address: Address::repeat_byte(2), transactions: Some(transactions), virtual_blocks: Some(!is_fictive as u32), hash: Some(miniblock_hash), protocol_version: ProtocolVersionId::latest(), - consensus: None, } }); @@ -133,73 +167,110 @@ impl MainNodeClient for MockMainNodeClient { } } -pub(crate) struct StateKeeperHandle { - next_batch: L1BatchNumber, - next_block: MiniblockNumber, - next_timestamp: u64, +/// Fake StateKeeper for tests. +pub(super) struct StateKeeper { + // Batch of the `last_block`. + last_batch: L1BatchNumber, + last_block: MiniblockNumber, + // timestamp of the last block. + last_timestamp: u64, batch_sealed: bool, fee_per_gas: u64, gas_per_pubdata: u32, - operator_address: Address, - actions_sender: ActionQueueSender, + pub(super) actions_sender: ActionQueueSender, + pub(super) pool: ConnectionPool, } -pub(crate) struct StateKeeperRunner { +/// Fake StateKeeper task to be executed in the background. +pub(super) struct StateKeeperRunner { actions_queue: ActionQueue, - operator_address: Address, + pool: ConnectionPool, } -impl StateKeeperHandle { - pub fn new(operator_address: Address) -> (Self, StateKeeperRunner) { +impl StateKeeper { + /// Constructs and initializes a new `StateKeeper`. + /// Caller has to run `StateKeeperRunner.run()` task in the background. + pub async fn new(pool: ConnectionPool) -> anyhow::Result<(Self, StateKeeperRunner)> { + // ensure genesis + let mut storage = pool.access_storage().await.context("access_storage()")?; + if storage + .blocks_dal() + .is_genesis_needed() + .await + .context("is_genesis_needed()")? + { + ensure_genesis_state(&mut storage, L2ChainId::default(), &GenesisParams::mock()) + .await + .context("ensure_genesis_state()")?; + } + + let last_l1_batch_number = storage + .blocks_dal() + .get_sealed_l1_batch_number() + .await + .context("get_sealed_l1_batch_number()")? + .context("no L1 batches in storage")?; + let last_miniblock_header = storage + .blocks_dal() + .get_last_sealed_miniblock_header() + .await + .context("get_last_sealed_miniblock_header()")? + .context("no miniblocks in storage")?; + + let pending_batch = storage + .blocks_dal() + .pending_batch_exists() + .await + .context("pending_batch_exists()")?; let (actions_sender, actions_queue) = ActionQueue::new(); - ( + Ok(( Self { - next_batch: L1BatchNumber(1), - next_block: MiniblockNumber(1), - next_timestamp: 124356, - batch_sealed: true, + last_batch: last_l1_batch_number + if pending_batch { 1 } else { 0 }, + last_block: last_miniblock_header.number, + last_timestamp: last_miniblock_header.timestamp, + batch_sealed: !pending_batch, fee_per_gas: 10, gas_per_pubdata: 100, - operator_address, actions_sender, + pool: pool.clone(), }, StateKeeperRunner { - operator_address, actions_queue, + pool: pool.clone(), }, - ) + )) } fn open_block(&mut self) -> SyncAction { if self.batch_sealed { - let action = SyncAction::OpenBatch { - number: self.next_batch, - timestamp: self.next_timestamp, + self.last_batch += 1; + self.last_block += 1; + self.last_timestamp += 5; + self.batch_sealed = false; + SyncAction::OpenBatch { + number: self.last_batch, + timestamp: self.last_timestamp, l1_gas_price: 2, l2_fair_gas_price: 3, - operator_address: self.operator_address, + fair_pubdata_price: Some(24), + operator_address: GenesisParams::mock().first_validator, protocol_version: ProtocolVersionId::latest(), - first_miniblock_info: (self.next_block, 1), - }; - self.next_batch += 1; - self.next_block += 1; - self.next_timestamp += 5; - self.batch_sealed = false; - action + first_miniblock_info: (self.last_block, 1), + } } else { - let action = SyncAction::Miniblock { - number: self.next_block, - timestamp: self.next_timestamp, + self.last_block += 1; + self.last_timestamp += 2; + SyncAction::Miniblock { + number: self.last_block, + timestamp: self.last_timestamp, virtual_blocks: 0, - }; - self.next_block += 1; - self.next_timestamp += 2; - action + } } } + /// Pushes a new miniblock with `transactions` transactions to the `StateKeeper`. pub async fn push_block(&mut self, transactions: usize) { assert!(transactions > 0); let mut actions = vec![self.open_block()]; @@ -207,25 +278,24 @@ impl StateKeeperHandle { let tx = create_l2_transaction(self.fee_per_gas, self.gas_per_pubdata); actions.push(SyncAction::Tx(Box::new(tx.into()))); } - actions.push(SyncAction::SealMiniblock(None)); + actions.push(SyncAction::SealMiniblock); self.actions_sender.push_actions(actions).await; } + /// Pushes `SealBatch` command to the `StateKeeper`. pub async fn seal_batch(&mut self) { // Each batch ends with an empty block (aka fictive block). let mut actions = vec![self.open_block()]; - actions.push(SyncAction::SealBatch { - virtual_blocks: 0, - consensus: None, - }); + actions.push(SyncAction::SealBatch { virtual_blocks: 0 }); self.actions_sender.push_actions(actions).await; self.batch_sealed = true; } + /// Pushes `count` random miniblocks to the StateKeeper. pub async fn push_random_blocks(&mut self, rng: &mut impl Rng, count: usize) { for _ in 0..count { // 20% chance to seal an L1 batch. - // seal_batch() also produces a (fictive) block. + // `seal_batch()` also produces a (fictive) block. if rng.gen_range(0..100) < 20 { self.seal_batch().await; } else { @@ -234,130 +304,96 @@ impl StateKeeperHandle { } } - // Wait for all pushed miniblocks to be produced. - pub async fn sync(&self, ctx: &ctx::Ctx, pool: &ConnectionPool) -> anyhow::Result<()> { - const POLL_INTERVAL: time::Duration = time::Duration::milliseconds(100); - loop { - let mut storage = pool.access_storage().await.context("access_storage()")?; - let head = storage - .blocks_dal() - .get_sealed_miniblock_number() - .await - .context("get_sealed_miniblock_number()")?; - if head.0 >= self.next_block.0 - 1 { - return Ok(()); - } - ctx.sleep(POLL_INTERVAL).await?; - } + /// Last block that has been pushed to the `StateKeeper` via `ActionQueue`. + /// It might NOT be present in storage yet. + pub fn last_block(&self) -> validator::BlockNumber { + validator::BlockNumber(self.last_block.0 as u64) } - // Wait for all pushed miniblocks to have consensus certificate. - pub async fn sync_consensus( - &self, - ctx: &ctx::Ctx, - pool: &ConnectionPool, - ) -> anyhow::Result<()> { + /// Creates a new `BlockStore` for the underlying `ConnectionPool`. + pub fn store(&self) -> BlockStore { + Store::new(self.pool.clone()).into_block_store() + } + + // Wait for all pushed miniblocks to be produced. + pub async fn wait_for_miniblocks(&self, ctx: &ctx::Ctx) -> ctx::Result<()> { const POLL_INTERVAL: time::Duration = time::Duration::milliseconds(100); + loop { - let mut storage = pool.access_storage().await.context("access_storage()")?; - if let Some(head) = storage - .blocks_dal() - .get_last_miniblock_number_with_consensus_fields() + let mut storage = CtxStorage::access(ctx, &self.pool).await.wrap("access()")?; + if storage + .payload(ctx, self.last_block()) .await - .context("get_last_miniblock_number_with_consensus_fields()")? + .wrap("storage.payload()")? + .is_some() { - if head.0 >= self.next_block.0 - 1 { - return Ok(()); - } + return Ok(()); } ctx.sleep(POLL_INTERVAL).await?; } } - - /// Validate consensus certificates for all expected miniblocks. - pub async fn validate_consensus( - &self, - ctx: &ctx::Ctx, - pool: &ConnectionPool, - genesis: validator::BlockNumber, - validators: &validator::ValidatorSet, - ) -> anyhow::Result<()> { - let mut storage = super::storage::storage(ctx, pool) - .await - .context("storage()")?; - for i in genesis.0..self.next_block.0 as u64 { - let block = storage - .fetch_block(ctx, validator::BlockNumber(i), self.operator_address) - .await? - .with_context(|| format!("missing block {i}"))?; - block.validate(validators, 1).unwrap(); - } - Ok(()) - } } -// Waits for L1 batches to be sealed and then populates them with mock metadata. -async fn run_mock_metadata_calculator(ctx: &ctx::Ctx, pool: ConnectionPool) -> anyhow::Result<()> { +/// Waits for L1 batches to be sealed and then populates them with mock metadata. +async fn run_mock_metadata_calculator(ctx: &ctx::Ctx, pool: &ConnectionPool) -> anyhow::Result<()> { const POLL_INTERVAL: time::Duration = time::Duration::milliseconds(100); - let mut n = L1BatchNumber(1); + let mut n = { + let mut storage = pool.access_storage().await.context("access_storage()")?; + storage + .blocks_dal() + .get_last_l1_batch_number_with_metadata() + .await + .context("get_last_l1_batch_number_with_metadata()")? + .context("no L1 batches in Postgres")? + }; while let Ok(()) = ctx.sleep(POLL_INTERVAL).await { let mut storage = pool.access_storage().await.context("access_storage()")?; let last = storage .blocks_dal() .get_sealed_l1_batch_number() .await - .context("get_sealed_l1_batch_number()")?; + .context("get_sealed_l1_batch_number()")? + .context("no L1 batches in Postgres")?; - while n <= last { + while n < last { + n += 1; let metadata = create_l1_batch_metadata(n.0); storage .blocks_dal() .save_l1_batch_metadata(n, &metadata, H256::zero(), false) .await .context("save_l1_batch_metadata()")?; - n += 1; } } Ok(()) } impl StateKeeperRunner { - pub async fn run(self, ctx: &ctx::Ctx, pool: &ConnectionPool) -> anyhow::Result<()> { + /// Executes the StateKeeper task. + pub async fn run(self, ctx: &ctx::Ctx) -> anyhow::Result<()> { scope::run!(ctx, |ctx, s| async { - let mut storage = pool.access_storage().await.context("access_storage()")?; - // ensure genesis - if storage - .blocks_dal() - .is_genesis_needed() - .await - .context("is_genesis_needed()")? - { - let mut params = GenesisParams::mock(); - params.first_validator = self.operator_address; - ensure_genesis_state(&mut storage, L2ChainId::default(), ¶ms) - .await - .context("ensure_genesis_state()")?; - } let (stop_sender, stop_receiver) = sync::watch::channel(false); - let (miniblock_sealer, miniblock_sealer_handle) = MiniblockSealer::new(pool.clone(), 5); + let (miniblock_sealer, miniblock_sealer_handle) = + MiniblockSealer::new(self.pool.clone(), 5); let io = ExternalIO::new( miniblock_sealer_handle, - pool.clone(), + self.pool.clone(), self.actions_queue, SyncState::new(), Box::::default(), - self.operator_address, + Address::repeat_byte(11), u32::MAX, L2ChainId::default(), ) .await; s.spawn_bg(miniblock_sealer.run()); - s.spawn_bg(run_mock_metadata_calculator(ctx, pool.clone())); + s.spawn_bg(run_mock_metadata_calculator(ctx, &self.pool)); s.spawn_bg( - ZkSyncStateKeeper::without_sealer( + ZkSyncStateKeeper::new( stop_receiver, Box::new(io), Box::new(MockBatchExecutorBuilder), + Box::new(NoopSealer), ) .run(), ); diff --git a/core/lib/zksync_core/src/consensus/tests.rs b/core/lib/zksync_core/src/consensus/tests.rs index be8ff9bacb23..7d3ed8f0df80 100644 --- a/core/lib/zksync_core/src/consensus/tests.rs +++ b/core/lib/zksync_core/src/consensus/tests.rs @@ -1,81 +1,325 @@ +use std::ops::Range; + +use anyhow::Context as _; +use tracing::Instrument as _; use zksync_concurrency::{ctx, scope}; -use zksync_consensus_executor::testonly::FullValidatorConfig; -use zksync_consensus_roles::validator; -use zksync_dal::ConnectionPool; -use zksync_types::Address; +use zksync_consensus_executor::testonly::{connect_full_node, ValidatorNode}; +use zksync_consensus_storage as storage; +use zksync_consensus_storage::PersistentBlockStore as _; +use zksync_consensus_utils::no_copy::NoCopy; +use zksync_dal::{connection::TestTemplate, ConnectionPool}; +use zksync_protobuf::testonly::test_encode_random; use super::*; +use crate::consensus::storage::CtxStorage; -// In the current implementation, consensus certificates are created asynchronously -// for the miniblocks constructed by the StateKeeper. This means that consensus actor -// is effectively just backfilling the consensus certificates for the miniblocks in storage. -#[tokio::test(flavor = "multi_thread")] -async fn test_backfill() { - const OPERATOR_ADDRESS: Address = Address::repeat_byte(17); - const GENESIS_BLOCK: validator::BlockNumber = validator::BlockNumber(5); +async fn make_blocks( + ctx: &ctx::Ctx, + pool: &ConnectionPool, + mut range: Range, +) -> ctx::Result> { + let rng = &mut ctx.rng(); + let mut storage = CtxStorage::access(ctx, pool).await.wrap("access()")?; + let mut blocks: Vec = vec![]; + while !range.is_empty() { + let payload = storage + .payload(ctx, range.start) + .await + .wrap(range.start)? + .context("payload not found")? + .encode(); + let header = match blocks.last().as_ref() { + Some(parent) => validator::BlockHeader::new(parent.header(), payload.hash()), + None => validator::BlockHeader::genesis(payload.hash(), range.start), + }; + blocks.push(validator::FinalBlock { + payload, + justification: validator::testonly::make_justification( + rng, + &header, + validator::ProtocolVersion::EARLIEST, + ), + }); + range.start = range.start.next(); + } + Ok(blocks) +} +#[tokio::test(flavor = "multi_thread")] +async fn test_validator_block_store() { zksync_concurrency::testonly::abort_on_panic(); let ctx = &ctx::test_root(&ctx::RealClock); let rng = &mut ctx.rng(); let pool = ConnectionPool::test_pool().await; + // Fill storage with unsigned miniblocks. + // Fetch a suffix of blocks that we will generate (fake) certs for. + let want = scope::run!(ctx, |ctx, s| async { + // Start state keeper. + let (mut sk, runner) = testonly::StateKeeper::new(pool.clone()).await?; + s.spawn_bg(runner.run(ctx)); + sk.push_random_blocks(rng, 10).await; + sk.wait_for_miniblocks(ctx).await?; + let range = Range { + start: validator::BlockNumber(4), + end: sk.last_block(), + }; + make_blocks(ctx, &sk.pool, range) + .await + .context("make_blocks") + }) + .await + .unwrap(); + + // Insert blocks one by one and check the storage state. + for (i, block) in want.iter().enumerate() { + let store = Store::new(pool.clone()).into_block_store(); + store.store_next_block(ctx, block).await.unwrap(); + assert_eq!(want[..i + 1], storage::testonly::dump(ctx, &store).await); + } +} + +// In the current implementation, consensus certificates are created asynchronously +// for the miniblocks constructed by the StateKeeper. This means that consensus actor +// is effectively just back filling the consensus certificates for the miniblocks in storage. +#[tokio::test(flavor = "multi_thread")] +async fn test_validator() { + zksync_concurrency::testonly::abort_on_panic(); + let ctx = &ctx::test_root(&ctx::AffineClock::new(10.)); + let rng = &mut ctx.rng(); + scope::run!(ctx, |ctx, s| async { // Start state keeper. - let (mut sk, sk_runner) = testonly::StateKeeperHandle::new(OPERATOR_ADDRESS); - s.spawn_bg(sk_runner.run(ctx, &pool)); + let pool = ConnectionPool::test_pool().await; + let (mut sk, runner) = testonly::StateKeeper::new(pool).await?; + s.spawn_bg(runner.run(ctx)); // Populate storage with a bunch of blocks. - sk.push_random_blocks(rng, 10).await; - sk.sync(ctx, &pool).await.context("sk.sync(<1st phase>)")?; - - // Prepare genesis block for consensus. - let genesis_payload = { - let mut storage = storage::storage(ctx, &pool).await.context("storage()")?; - storage - .fetch_payload(ctx, GENESIS_BLOCK, OPERATOR_ADDRESS) - .await - .context("fetch_payload()")? - .context("genesis block missing")? - }; - let cfg = FullValidatorConfig::for_single_validator( - &mut ctx.rng(), - genesis_payload.encode(), - GENESIS_BLOCK, - ); - let validators = cfg.node_config.validators.clone(); - - // Start consensus actor and wait for it to catch up. - let cfg = Config { - executor: cfg.node_config, - consensus: cfg.consensus_config, - node_key: cfg.node_key, - validator_key: cfg.validator_key, - operator_address: OPERATOR_ADDRESS, - }; - s.spawn_bg(cfg.run(ctx, pool.clone())); - sk.sync_consensus(ctx, &pool) + sk.push_random_blocks(rng, 5).await; + sk.wait_for_miniblocks(ctx) .await - .context("sk.sync_consensus(<1st phase>)")?; + .context("sk.wait_for_miniblocks(<1st phase>)")?; - // Generate couple more blocks and wait for consensus to catch up. - sk.push_random_blocks(rng, 7).await; - sk.sync_consensus(ctx, &pool) + let cfg = ValidatorNode::new(&mut ctx.rng()); + let validators = cfg.node.validators.clone(); + + // Restart consensus actor a couple times, making it process a bunch of blocks each time. + for iteration in 0..3 { + scope::run!(ctx, |ctx, s| async { + // Start consensus actor (in the first iteration it will select a genesis block and + // store a cert for it). + let cfg = MainNodeConfig { + executor: cfg.node.clone(), + validator: cfg.validator.clone(), + }; + s.spawn_bg(cfg.run(ctx, sk.pool.clone())); + sk.store() + .wait_for_certificate(ctx, sk.last_block()) + .await + .context("wait_for_certificate(<1st phase>)")?; + + // Generate couple more blocks and wait for consensus to catch up. + sk.push_random_blocks(rng, 3).await; + sk.store() + .wait_for_certificate(ctx, sk.last_block()) + .await + .context("wait_for_certificate(<2nd phase>)")?; + + // Synchronously produce blocks one by one, and wait for consensus. + for _ in 0..2 { + sk.push_random_blocks(rng, 1).await; + sk.store() + .wait_for_certificate(ctx, sk.last_block()) + .await + .context("wait_for_certificate(<3rd phase>)")?; + } + + sk.store() + .wait_for_blocks_and_verify(ctx, &validators, sk.last_block()) + .await + .context("wait_for_blocks_and_verify()")?; + Ok(()) + }) .await - .context("sk.sync_consensus(<2nd phase>)")?; + .context(iteration)?; + } + Ok(()) + }) + .await + .unwrap(); +} + +// Test running a validator node and a couple of full nodes (aka fetchers). +// Validator is producing signed blocks and fetchers are expected to fetch +// them directly or indirectly. +#[tokio::test(flavor = "multi_thread")] +async fn test_fetcher() { + const FETCHERS: usize = 2; + + zksync_concurrency::testonly::abort_on_panic(); + let ctx = &ctx::test_root(&ctx::AffineClock::new(10.)); + let rng = &mut ctx.rng(); + + // topology: + // validator <-> fetcher <-> fetcher <-> ... + let cfg = ValidatorNode::new(rng); + let validators = cfg.node.validators.clone(); + let mut cfg = MainNodeConfig { + executor: cfg.node, + validator: cfg.validator, + }; + let mut fetcher_cfgs = vec![connect_full_node(rng, &mut cfg.executor)]; + while fetcher_cfgs.len() < FETCHERS { + let cfg = connect_full_node(rng, fetcher_cfgs.last_mut().unwrap()); + fetcher_cfgs.push(cfg); + } + let fetcher_cfgs: Vec<_> = fetcher_cfgs + .into_iter() + .map(|executor| FetcherConfig { executor }) + .collect(); - // Synchronously produce blocks one by one, and wait for consensus. - for _ in 0..5 { - sk.push_random_blocks(rng, 1).await; - sk.sync_consensus(ctx, &pool) + // Create an initial database snapshot, which contains a cert for genesis block. + let pool = scope::run!(ctx, |ctx, s| async { + let pool = ConnectionPool::test_pool().await; + let (mut sk, runner) = testonly::StateKeeper::new(pool).await?; + s.spawn_bg(runner.run(ctx)); + s.spawn_bg(cfg.clone().run(ctx, sk.pool.clone())); + sk.push_random_blocks(rng, 5).await; + sk.store() + .wait_for_certificate(ctx, sk.last_block()) + .await?; + Ok(sk.pool) + }) + .await + .unwrap(); + let template = TestTemplate::freeze(pool).await.unwrap(); + + // Run validator and fetchers in parallel. + scope::run!(ctx, |ctx, s| async { + // Run validator. + let pool = template.create_db().await?; + let (mut validator, runner) = testonly::StateKeeper::new(pool).await?; + s.spawn_bg(async { + runner + .run(ctx) + .instrument(tracing::info_span!("validator")) .await - .context("sk.sync_consensus(<3rd phase>)")?; + .context("validator") + }); + s.spawn_bg(cfg.run(ctx, validator.pool.clone())); + + // Run fetchers. + let mut fetchers = vec![]; + for (i, cfg) in fetcher_cfgs.into_iter().enumerate() { + let i = NoCopy::from(i); + let pool = template.create_db().await?; + let (fetcher, runner) = testonly::StateKeeper::new(pool).await?; + fetchers.push(fetcher.store()); + s.spawn_bg(async { + let i = i; + runner + .run(ctx) + .instrument(tracing::info_span!("fetcher", i = *i)) + .await + .with_context(|| format!("fetcher{}", *i)) + }); + s.spawn_bg(cfg.run(ctx, fetcher.pool, fetcher.actions_sender)); } - sk.validate_consensus(ctx, &pool, GENESIS_BLOCK, &validators) - .await - .context("sk.validate_consensus()")?; + // Make validator produce blocks and wait for fetchers to get them. + validator.push_random_blocks(rng, 5).await; + let want_last = validator.last_block(); + let want = validator + .store() + .wait_for_blocks_and_verify(ctx, &validators, want_last) + .await?; + for fetcher in &fetchers { + assert_eq!( + want, + fetcher + .wait_for_blocks_and_verify(ctx, &validators, want_last) + .await? + ); + } + Ok(()) + }) + .await + .unwrap(); +} + +// Test fetcher back filling missing certs. +#[tokio::test(flavor = "multi_thread")] +async fn test_fetcher_backfill_certs() { + zksync_concurrency::testonly::abort_on_panic(); + let ctx = &ctx::test_root(&ctx::AffineClock::new(10.)); + let rng = &mut ctx.rng(); + + let cfg = ValidatorNode::new(rng); + let mut cfg = MainNodeConfig { + executor: cfg.node, + validator: cfg.validator, + }; + let fetcher_cfg = FetcherConfig { + executor: connect_full_node(rng, &mut cfg.executor), + }; + + // Create an initial database snapshot, which contains some blocks: some with certs, some + // without. + let pool = scope::run!(ctx, |ctx, s| async { + let pool = ConnectionPool::test_pool().await; + let (mut sk, runner) = testonly::StateKeeper::new(pool).await?; + s.spawn_bg(runner.run(ctx)); + + // Some blocks with certs. + scope::run!(ctx, |ctx, s| async { + s.spawn_bg(cfg.clone().run(ctx, sk.pool.clone())); + sk.push_random_blocks(rng, 5).await; + sk.store() + .wait_for_certificate(ctx, sk.last_block()) + .await?; + Ok(()) + }) + .await?; + + // Some blocks without certs. + sk.push_random_blocks(rng, 5).await; + sk.wait_for_miniblocks(ctx).await?; + Ok(sk.pool) + }) + .await + .unwrap(); + let template = TestTemplate::freeze(pool).await.unwrap(); + + // Run validator and fetchers in parallel. + scope::run!(ctx, |ctx, s| async { + // Run validator. + let pool = template.create_db().await?; + let (mut validator, runner) = testonly::StateKeeper::new(pool).await?; + s.spawn_bg(runner.run(ctx)); + s.spawn_bg(cfg.run(ctx, validator.pool.clone())); + + // Run fetcher. + let pool = template.create_db().await?; + let (fetcher, runner) = testonly::StateKeeper::new(pool).await?; + let fetcher_store = fetcher.store(); + s.spawn_bg(runner.run(ctx)); + s.spawn_bg(fetcher_cfg.run(ctx, fetcher.pool, fetcher.actions_sender)); + + // Make validator produce new blocks and + // wait for the fetcher to get both the missing certs and the new blocks. + validator.push_random_blocks(rng, 5).await; + fetcher_store + .wait_for_certificate(ctx, validator.last_block()) + .await?; Ok(()) }) .await .unwrap(); } + +#[test] +fn test_schema_encoding() { + let ctx = ctx::test_root(&ctx::RealClock); + let rng = &mut ctx.rng(); + test_encode_random::(rng); +} diff --git a/core/lib/zksync_core/src/consistency_checker/mod.rs b/core/lib/zksync_core/src/consistency_checker/mod.rs index 4e3dc44a7fd9..8441f927f8f5 100644 --- a/core/lib/zksync_core/src/consistency_checker/mod.rs +++ b/core/lib/zksync_core/src/consistency_checker/mod.rs @@ -1,204 +1,321 @@ -use std::time::Duration; +use std::{fmt, time::Duration}; +use anyhow::Context as _; +use tokio::sync::watch; use zksync_contracts::PRE_BOOJUM_COMMIT_FUNCTION; -use zksync_dal::ConnectionPool; -use zksync_types::{ - web3::{error, ethabi, transports::Http, types::TransactionId, Web3}, - L1BatchNumber, +use zksync_dal::{ConnectionPool, StorageProcessor}; +use zksync_eth_client::{clients::QueryClient, Error as L1ClientError, EthInterface}; +use zksync_l1_contract_interface::{i_executor::structures::CommitBatchInfo, Tokenizable}; +use zksync_types::{web3::ethabi, L1BatchNumber, H256}; + +use crate::{ + metrics::{CheckerComponent, EN_METRICS}, + utils::wait_for_l1_batch_with_metadata, }; -use crate::metrics::{CheckerComponent, EN_METRICS}; +#[cfg(test)] +mod tests; -#[derive(Debug)] -pub struct ConsistencyChecker { - // ABI of the zkSync contract - contract: ethabi::Contract, - // How many past batches to check when starting - max_batches_to_recheck: u32, - web3: Web3, - db: ConnectionPool, +#[derive(Debug, thiserror::Error)] +enum CheckError { + #[error("Web3 error communicating with L1")] + Web3(#[from] L1ClientError), + #[error("Internal error")] + Internal(#[from] anyhow::Error), } -const SLEEP_DELAY: Duration = Duration::from_secs(5); +impl From for CheckError { + fn from(err: zksync_dal::SqlxError) -> Self { + Self::Internal(err.into()) + } +} -impl ConsistencyChecker { - pub fn new(web3_url: &str, max_batches_to_recheck: u32, db: ConnectionPool) -> Self { - let web3 = Web3::new(Http::new(web3_url).unwrap()); - let contract = zksync_contracts::zksync_contract(); - Self { - web3, - contract, - max_batches_to_recheck, - db, - } +trait UpdateCheckedBatch: fmt::Debug + Send + Sync { + fn update_checked_batch(&mut self, last_checked_batch: L1BatchNumber); +} + +/// Default [`UpdateCheckedBatch`] implementation that reports the batch number as a metric. +impl UpdateCheckedBatch for () { + fn update_checked_batch(&mut self, last_checked_batch: L1BatchNumber) { + EN_METRICS.last_correct_batch[&CheckerComponent::ConsistencyChecker] + .set(last_checked_batch.0.into()); } +} - async fn check_commitments(&self, batch_number: L1BatchNumber) -> Result { - let mut storage = self.db.access_storage().await.unwrap(); +/// Consistency checker behavior when L1 commit data divergence is detected. +// This is a temporary workaround for a bug that sometimes leads to incorrect L1 batch data returned by the server +// (and thus persisted by external nodes). Eventually, we want to go back to bailing on L1 data mismatch; +// for now, it's only enabled for the unit tests. +#[derive(Debug)] +enum L1DataMismatchBehavior { + #[cfg(test)] + Bail, + Log, +} + +/// L1 commit data loaded from Postgres. +#[derive(Debug)] +struct LocalL1BatchCommitData { + is_pre_boojum: bool, + l1_commit_data: ethabi::Token, + commit_tx_hash: H256, +} - let storage_l1_batch = storage +impl LocalL1BatchCommitData { + /// Returns `Ok(None)` if Postgres doesn't contain all data necessary to check L1 commitment + /// for the specified batch. + async fn new( + storage: &mut StorageProcessor<'_>, + batch_number: L1BatchNumber, + ) -> anyhow::Result> { + let Some(storage_l1_batch) = storage .blocks_dal() .get_storage_l1_batch(batch_number) - .await - .unwrap() - .unwrap_or_else(|| panic!("L1 batch #{} not found in the database", batch_number)); + .await? + else { + return Ok(None); + }; - let commit_tx_id = storage_l1_batch - .eth_commit_tx_id - .unwrap_or_else(|| panic!("Commit tx not found for L1 batch #{}", batch_number)) - as u32; + let Some(commit_tx_id) = storage_l1_batch.eth_commit_tx_id else { + return Ok(None); + }; + let commit_tx_hash = storage + .eth_sender_dal() + .get_confirmed_tx_hash_by_eth_tx_id(commit_tx_id as u32) + .await? + .with_context(|| { + format!("Commit tx hash not found in the database for tx id {commit_tx_id}") + })?; - let block_metadata = storage + let Some(l1_batch) = storage .blocks_dal() .get_l1_batch_with_metadata(storage_l1_batch) - .await - .unwrap() - .unwrap_or_else(|| { - panic!( - "Metadata for L1 batch #{} not found in the database", - batch_number - ) - }); + .await? + else { + return Ok(None); + }; - let commit_tx_hash = storage - .eth_sender_dal() - .get_confirmed_tx_hash_by_eth_tx_id(commit_tx_id) - .await - .unwrap() - .unwrap_or_else(|| { - panic!( - "Commit tx hash not found in the database. Commit tx id: {}", - commit_tx_id - ) - }); + let is_pre_boojum = l1_batch + .header + .protocol_version + .map_or(true, |version| version.is_pre_boojum()); + let metadata = &l1_batch.metadata; - tracing::info!( - "Checking commit tx {} for batch {}", + // For Boojum batches, `bootloader_initial_content_commitment` and `events_queue_commitment` + // are (temporarily) only computed by the metadata calculator if it runs with the full tree. + // I.e., for these batches, we may have partial metadata in Postgres, which would not be sufficient + // to compute local L1 commitment. + if !is_pre_boojum + && (metadata.bootloader_initial_content_commitment.is_none() + || metadata.events_queue_commitment.is_none()) + { + return Ok(None); + } + + Ok(Some(Self { + is_pre_boojum, + l1_commit_data: CommitBatchInfo(&l1_batch).into_token(), commit_tx_hash, - batch_number.0 - ); + })) + } +} - // we can't get tx calldata from db because it can be fake - let commit_tx = self - .web3 - .eth() - .transaction(TransactionId::Hash(commit_tx_hash)) - .await? - .expect("Commit tx not found on L1"); +#[derive(Debug)] +pub struct ConsistencyChecker { + /// ABI of the zkSync contract + contract: ethabi::Contract, + /// How many past batches to check when starting + max_batches_to_recheck: u32, + sleep_interval: Duration, + l1_client: Box, + l1_batch_updater: Box, + l1_data_mismatch_behavior: L1DataMismatchBehavior, + pool: ConnectionPool, +} + +impl ConsistencyChecker { + const DEFAULT_SLEEP_INTERVAL: Duration = Duration::from_secs(5); + + pub fn new(web3_url: &str, max_batches_to_recheck: u32, pool: ConnectionPool) -> Self { + let web3 = QueryClient::new(web3_url).unwrap(); + Self { + contract: zksync_contracts::zksync_contract(), + max_batches_to_recheck, + sleep_interval: Self::DEFAULT_SLEEP_INTERVAL, + l1_client: Box::new(web3), + l1_batch_updater: Box::new(()), + l1_data_mismatch_behavior: L1DataMismatchBehavior::Log, + pool, + } + } + + async fn check_commitments( + &self, + batch_number: L1BatchNumber, + local: &LocalL1BatchCommitData, + ) -> Result { + let commit_tx_hash = local.commit_tx_hash; + tracing::info!("Checking commit tx {commit_tx_hash} for L1 batch #{batch_number}"); let commit_tx_status = self - .web3 - .eth() - .transaction_receipt(commit_tx_hash) + .l1_client + .get_tx_status(commit_tx_hash, "consistency_checker") .await? - .expect("Commit tx receipt not found on L1") - .status; + .with_context(|| format!("Receipt for tx {commit_tx_hash:?} not found on L1"))?; + if !commit_tx_status.success { + let err = anyhow::anyhow!("Main node gave us a failed commit tx"); + return Err(err.into()); + } - assert_eq!( - commit_tx_status, - Some(1.into()), - "Main node gave us a failed commit tx" - ); + // We can't get tx calldata from db because it can be fake. + let commit_tx_input_data = self + .l1_client + .get_tx(commit_tx_hash, "consistency_checker") + .await? + .with_context(|| format!("Commit for tx {commit_tx_hash:?} not found on L1"))? + .input; + // TODO (PLA-721): Check receiving contract and selector - let commit_function = if block_metadata - .header - .protocol_version - .unwrap() - .is_pre_boojum() - { - PRE_BOOJUM_COMMIT_FUNCTION.clone() + let commit_function = if local.is_pre_boojum { + &*PRE_BOOJUM_COMMIT_FUNCTION } else { - self.contract.function("commitBatches").unwrap().clone() + self.contract + .function("commitBatches") + .context("L1 contract does not have `commitBatches` function")? }; + let commitment = + Self::extract_commit_data(&commit_tx_input_data.0, commit_function, batch_number) + .with_context(|| { + format!("Failed extracting commit data for transaction {commit_tx_hash:?}") + })?; + Ok(commitment == local.l1_commit_data) + } - let commitments = commit_function - .decode_input(&commit_tx.input.0[4..]) - .unwrap() + fn extract_commit_data( + commit_tx_input_data: &[u8], + commit_function: ðabi::Function, + batch_number: L1BatchNumber, + ) -> anyhow::Result { + let mut commit_input_tokens = commit_function + .decode_input(&commit_tx_input_data[4..]) + .with_context(|| format!("Failed decoding calldata for L1 commit function"))?; + let mut commitments = commit_input_tokens .pop() - .unwrap() + .context("Unexpected signature for L1 commit function")? .into_array() - .unwrap(); + .context("Unexpected signature for L1 commit function")?; // Commit transactions usually publish multiple commitments at once, so we need to find // the one that corresponds to the batch we're checking. - let first_batch_number = match &commitments[0] { - ethabi::Token::Tuple(tuple) => tuple[0].clone().into_uint().unwrap().as_usize(), - _ => panic!("ABI does not match the expected one"), + let first_batch_commitment = commitments + .first() + .with_context(|| format!("L1 batch commitment is empty"))?; + let ethabi::Token::Tuple(first_batch_commitment) = first_batch_commitment else { + anyhow::bail!("Unexpected signature for L1 commit function"); }; - let commitment = &commitments[batch_number.0 as usize - first_batch_number]; + let first_batch_number = first_batch_commitment + .first() + .context("Unexpected signature for L1 commit function")?; + let first_batch_number = first_batch_number + .clone() + .into_uint() + .context("Unexpected signature for L1 commit function")?; + let first_batch_number = usize::try_from(first_batch_number) + .map_err(|_| anyhow::anyhow!("Integer overflow for L1 batch number"))?; + // ^ `TryFrom` has `&str` error here, so we can't use `.context()`. - Ok(commitment == &block_metadata.l1_commit_data()) + let commitment = (batch_number.0 as usize) + .checked_sub(first_batch_number) + .and_then(|offset| { + (offset < commitments.len()).then(|| commitments.swap_remove(offset)) + }); + commitment.with_context(|| { + let actual_range = first_batch_number..(first_batch_number + commitments.len()); + format!( + "Malformed commitment data; it should prove L1 batch #{batch_number}, \ + but it actually proves batches #{actual_range:?}" + ) + }) } - async fn last_committed_batch(&self) -> L1BatchNumber { - self.db + async fn last_committed_batch(&self) -> anyhow::Result> { + Ok(self + .pool .access_storage() - .await - .unwrap() + .await? .blocks_dal() .get_number_of_last_l1_batch_committed_on_eth() - .await - .unwrap() - .unwrap_or(L1BatchNumber(0)) + .await?) } - pub async fn run( - self, - stop_receiver: tokio::sync::watch::Receiver, - ) -> anyhow::Result<()> { - let mut batch_number: L1BatchNumber = self + pub async fn run(mut self, mut stop_receiver: watch::Receiver) -> anyhow::Result<()> { + // It doesn't make sense to start the checker until we have at least one L1 batch with metadata. + let earliest_l1_batch_number = + wait_for_l1_batch_with_metadata(&self.pool, self.sleep_interval, &mut stop_receiver) + .await?; + + let Some(earliest_l1_batch_number) = earliest_l1_batch_number else { + return Ok(()); // Stop signal received + }; + + let last_committed_batch = self .last_committed_batch() - .await + .await? + .unwrap_or(earliest_l1_batch_number); + let first_batch_to_check: L1BatchNumber = last_committed_batch .0 .saturating_sub(self.max_batches_to_recheck) - .max(1) .into(); + // We shouldn't check batches not present in the storage, and skip the genesis batch since + // it's not committed on L1. + let first_batch_to_check = first_batch_to_check + .max(earliest_l1_batch_number) + .max(L1BatchNumber(1)); + tracing::info!( + "Last committed L1 batch is #{last_committed_batch}; starting checks from L1 batch #{first_batch_to_check}" + ); - tracing::info!("Starting consistency checker from batch {}", batch_number.0); - + let mut batch_number = first_batch_to_check; loop { if *stop_receiver.borrow() { tracing::info!("Stop signal received, consistency_checker is shutting down"); break; } - let metadata = self - .db - .access_storage() - .await - .unwrap() - .blocks_dal() - .get_l1_batch_metadata(batch_number) - .await - .unwrap(); - let batch_has_metadata = metadata - .map(|m| { - m.metadata.bootloader_initial_content_commitment.is_some() - && m.metadata.events_queue_commitment.is_some() - }) - .unwrap_or(false); - + let mut storage = self.pool.access_storage().await?; // The batch might be already committed but not yet processed by the external node's tree // OR the batch might be processed by the external node's tree but not yet committed. // We need both. - if !batch_has_metadata || self.last_committed_batch().await < batch_number { - tokio::time::sleep(SLEEP_DELAY).await; + let Some(local) = LocalL1BatchCommitData::new(&mut storage, batch_number).await? else { + tokio::time::sleep(self.sleep_interval).await; continue; - } + }; + drop(storage); - match self.check_commitments(batch_number).await { + match self.check_commitments(batch_number, &local).await { Ok(true) => { - tracing::info!("Batch {} is consistent with L1", batch_number.0); - EN_METRICS.last_correct_batch[&CheckerComponent::ConsistencyChecker] - .set(batch_number.0.into()); - batch_number.0 += 1; + tracing::info!("L1 batch #{batch_number} is consistent with L1"); + self.l1_batch_updater.update_checked_batch(batch_number); + batch_number += 1; } - Ok(false) => { - tracing::warn!("Batch {} is inconsistent with L1", batch_number.0); + Ok(false) => match &self.l1_data_mismatch_behavior { + #[cfg(test)] + L1DataMismatchBehavior::Bail => { + anyhow::bail!("L1 Batch #{batch_number} is inconsistent with L1"); + } + L1DataMismatchBehavior::Log => { + tracing::warn!("L1 Batch #{batch_number} is inconsistent with L1"); + batch_number += 1; // We don't want to infinitely loop failing the check on the same batch + } + }, + Err(CheckError::Web3(err)) => { + tracing::warn!("Error accessing L1; will retry after a delay: {err}"); + tokio::time::sleep(self.sleep_interval).await; } - Err(e) => { - tracing::warn!("Consistency checker error: {}", e); - tokio::time::sleep(SLEEP_DELAY).await; + Err(CheckError::Internal(err)) => { + let context = + format!("Failed verifying consistency of L1 batch #{batch_number}"); + return Err(err.context(context)); } } } diff --git a/core/lib/zksync_core/src/consistency_checker/tests/commit_l1_batch_200000_testnet_goerli.calldata b/core/lib/zksync_core/src/consistency_checker/tests/commit_l1_batch_200000_testnet_goerli.calldata new file mode 100644 index 000000000000..8018825804e4 Binary files /dev/null and b/core/lib/zksync_core/src/consistency_checker/tests/commit_l1_batch_200000_testnet_goerli.calldata differ diff --git a/core/lib/zksync_core/src/consistency_checker/tests/commit_l1_batch_351000-351004_mainnet.calldata b/core/lib/zksync_core/src/consistency_checker/tests/commit_l1_batch_351000-351004_mainnet.calldata new file mode 100644 index 000000000000..f7983ec06bef Binary files /dev/null and b/core/lib/zksync_core/src/consistency_checker/tests/commit_l1_batch_351000-351004_mainnet.calldata differ diff --git a/core/lib/zksync_core/src/consistency_checker/tests/commit_l1_batch_4470_testnet_sepolia.calldata b/core/lib/zksync_core/src/consistency_checker/tests/commit_l1_batch_4470_testnet_sepolia.calldata new file mode 100644 index 000000000000..d1ecde78199a Binary files /dev/null and b/core/lib/zksync_core/src/consistency_checker/tests/commit_l1_batch_4470_testnet_sepolia.calldata differ diff --git a/core/lib/zksync_core/src/consistency_checker/tests/mod.rs b/core/lib/zksync_core/src/consistency_checker/tests/mod.rs new file mode 100644 index 000000000000..0803b25d4a95 --- /dev/null +++ b/core/lib/zksync_core/src/consistency_checker/tests/mod.rs @@ -0,0 +1,607 @@ +//! Tests for the consistency checker component. + +use std::{collections::HashMap, slice}; + +use assert_matches::assert_matches; +use test_casing::{test_casing, Product}; +use tokio::sync::mpsc; +use zksync_dal::StorageProcessor; +use zksync_eth_client::clients::MockEthereum; +use zksync_l1_contract_interface::i_executor::structures::StoredBatchInfo; +use zksync_types::{ + aggregated_operations::AggregatedActionType, commitment::L1BatchWithMetadata, + web3::contract::Options, L2ChainId, ProtocolVersion, ProtocolVersionId, H256, +}; + +use super::*; +use crate::{ + genesis::{ensure_genesis_state, GenesisParams}, + utils::testonly::{create_l1_batch, create_l1_batch_metadata}, +}; + +/// **NB.** For tests to run correctly, the returned value must be deterministic (i.e., depend only on `number`). +fn create_l1_batch_with_metadata(number: u32) -> L1BatchWithMetadata { + L1BatchWithMetadata { + header: create_l1_batch(number), + metadata: create_l1_batch_metadata(number), + factory_deps: vec![], + } +} + +const PRE_BOOJUM_PROTOCOL_VERSION: ProtocolVersionId = ProtocolVersionId::Version10; + +fn create_pre_boojum_l1_batch_with_metadata(number: u32) -> L1BatchWithMetadata { + let mut l1_batch = L1BatchWithMetadata { + header: create_l1_batch(number), + metadata: create_l1_batch_metadata(number), + factory_deps: vec![], + }; + l1_batch.header.protocol_version = Some(PRE_BOOJUM_PROTOCOL_VERSION); + l1_batch.metadata.bootloader_initial_content_commitment = None; + l1_batch.metadata.events_queue_commitment = None; + l1_batch +} + +fn build_commit_tx_input_data(batches: &[L1BatchWithMetadata]) -> Vec { + let commit_tokens = batches + .iter() + .map(|batch| CommitBatchInfo(batch).into_token()); + let commit_tokens = ethabi::Token::Array(commit_tokens.collect()); + + let mut encoded = vec![]; + // Fake Solidity function selector (not checked for now) + encoded.extend_from_slice(b"fake"); + // Mock an additional argument used in real `commitBlocks` / `commitBatches`. In real transactions, + // it's taken from the L1 batch previous to `batches[0]`, but since this argument is not checked, + // it's OK to use `batches[0]`. + let prev_header_tokens = StoredBatchInfo(&batches[0]).into_token(); + encoded.extend_from_slice(ðabi::encode(&[prev_header_tokens, commit_tokens])); + encoded +} + +fn create_mock_checker(client: MockEthereum, pool: ConnectionPool) -> ConsistencyChecker { + ConsistencyChecker { + contract: zksync_contracts::zksync_contract(), + max_batches_to_recheck: 100, + sleep_interval: Duration::from_millis(10), + l1_client: Box::new(client), + l1_batch_updater: Box::new(()), + l1_data_mismatch_behavior: L1DataMismatchBehavior::Bail, + pool, + } +} + +impl UpdateCheckedBatch for mpsc::UnboundedSender { + fn update_checked_batch(&mut self, last_checked_batch: L1BatchNumber) { + self.send(last_checked_batch).ok(); + } +} + +#[test] +fn build_commit_tx_input_data_is_correct() { + let contract = zksync_contracts::zksync_contract(); + let commit_function = contract.function("commitBatches").unwrap(); + let batches = vec![ + create_l1_batch_with_metadata(1), + create_l1_batch_with_metadata(2), + ]; + + let commit_tx_input_data = build_commit_tx_input_data(&batches); + + for batch in &batches { + let commit_data = ConsistencyChecker::extract_commit_data( + &commit_tx_input_data, + commit_function, + batch.header.number, + ) + .unwrap(); + assert_eq!(commit_data, CommitBatchInfo(batch).into_token()); + } +} + +#[test] +fn extracting_commit_data_for_boojum_batch() { + let contract = zksync_contracts::zksync_contract(); + let commit_function = contract.function("commitBatches").unwrap(); + // Calldata taken from the commit transaction for `https://sepolia.explorer.zksync.io/batch/4470`; + // `https://sepolia.etherscan.io/tx/0x300b9115037028b1f8aa2177abf98148c3df95c9b04f95a4e25baf4dfee7711f` + let commit_tx_input_data = include_bytes!("commit_l1_batch_4470_testnet_sepolia.calldata"); + + let commit_data = ConsistencyChecker::extract_commit_data( + commit_tx_input_data, + commit_function, + L1BatchNumber(4_470), + ) + .unwrap(); + + assert_matches!( + commit_data, + ethabi::Token::Tuple(tuple) if tuple[0] == ethabi::Token::Uint(4_470.into()) + ); + + for bogus_l1_batch in [0, 1, 1_000, 4_469, 4_471, 100_000] { + ConsistencyChecker::extract_commit_data( + commit_tx_input_data, + commit_function, + L1BatchNumber(bogus_l1_batch), + ) + .unwrap_err(); + } +} + +#[test] +fn extracting_commit_data_for_multiple_batches() { + let contract = zksync_contracts::zksync_contract(); + let commit_function = contract.function("commitBatches").unwrap(); + // Calldata taken from the commit transaction for `https://explorer.zksync.io/batch/351000`; + // `https://etherscan.io/tx/0xbd8dfe0812df0da534eb95a2d2a4382d65a8172c0b648a147d60c1c2921227fd` + let commit_tx_input_data = include_bytes!("commit_l1_batch_351000-351004_mainnet.calldata"); + + for l1_batch in 351_000..=351_004 { + let commit_data = ConsistencyChecker::extract_commit_data( + commit_tx_input_data, + commit_function, + L1BatchNumber(l1_batch), + ) + .unwrap(); + + assert_matches!( + commit_data, + ethabi::Token::Tuple(tuple) if tuple[0] == ethabi::Token::Uint(l1_batch.into()) + ); + } + + for bogus_l1_batch in [350_000, 350_999, 351_005, 352_000] { + ConsistencyChecker::extract_commit_data( + commit_tx_input_data, + commit_function, + L1BatchNumber(bogus_l1_batch), + ) + .unwrap_err(); + } +} + +#[test] +fn extracting_commit_data_for_pre_boojum_batch() { + // Calldata taken from the commit transaction for `https://goerli.explorer.zksync.io/batch/200000`; + // `https://goerli.etherscan.io/tx/0xfd2ef4ccd1223f502cc4a4e0f76c6905feafabc32ba616e5f70257eb968f20a3` + let commit_tx_input_data = include_bytes!("commit_l1_batch_200000_testnet_goerli.calldata"); + + let commit_data = ConsistencyChecker::extract_commit_data( + commit_tx_input_data, + &PRE_BOOJUM_COMMIT_FUNCTION, + L1BatchNumber(200_000), + ) + .unwrap(); + + assert_matches!( + commit_data, + ethabi::Token::Tuple(tuple) if tuple[0] == ethabi::Token::Uint(200_000.into()) + ); +} + +#[derive(Debug, Clone, Copy)] +enum SaveAction<'a> { + InsertBatch(&'a L1BatchWithMetadata), + SaveMetadata(&'a L1BatchWithMetadata), + InsertCommitTx(L1BatchNumber), +} + +impl SaveAction<'_> { + async fn apply( + self, + storage: &mut StorageProcessor<'_>, + commit_tx_hash_by_l1_batch: &HashMap, + ) { + match self { + Self::InsertBatch(l1_batch) => { + storage + .blocks_dal() + .insert_mock_l1_batch(&l1_batch.header) + .await + .unwrap(); + } + Self::SaveMetadata(l1_batch) => { + storage + .blocks_dal() + .save_l1_batch_metadata( + l1_batch.header.number, + &l1_batch.metadata, + H256::default(), + l1_batch.header.protocol_version.unwrap().is_pre_boojum(), + ) + .await + .unwrap(); + } + Self::InsertCommitTx(l1_batch_number) => { + let commit_tx_hash = commit_tx_hash_by_l1_batch[&l1_batch_number]; + storage + .eth_sender_dal() + .insert_bogus_confirmed_eth_tx( + l1_batch_number, + AggregatedActionType::Commit, + commit_tx_hash, + chrono::Utc::now(), + ) + .await + .unwrap(); + } + } + } +} + +type SaveActionMapper = fn(&[L1BatchWithMetadata]) -> Vec>; + +/// Various strategies to persist L1 batches in the DB. Strings are added for debugging failed test cases. +const SAVE_ACTION_MAPPERS: [(&str, SaveActionMapper); 4] = [ + ("sequential_metadata_first", |l1_batches| { + l1_batches + .iter() + .flat_map(|batch| { + [ + SaveAction::InsertBatch(batch), + SaveAction::SaveMetadata(batch), + SaveAction::InsertCommitTx(batch.header.number), + ] + }) + .collect() + }), + ("sequential_commit_txs_first", |l1_batches| { + l1_batches + .iter() + .flat_map(|batch| { + [ + SaveAction::InsertBatch(batch), + SaveAction::InsertCommitTx(batch.header.number), + SaveAction::SaveMetadata(batch), + ] + }) + .collect() + }), + ("all_metadata_first", |l1_batches| { + let commit_tx_actions = l1_batches + .iter() + .map(|batch| SaveAction::InsertCommitTx(batch.header.number)); + l1_batches + .iter() + .map(SaveAction::InsertBatch) + .chain(l1_batches.iter().map(SaveAction::SaveMetadata)) + .chain(commit_tx_actions) + .collect() + }), + ("all_commit_txs_first", |l1_batches| { + let commit_tx_actions = l1_batches + .iter() + .map(|batch| SaveAction::InsertCommitTx(batch.header.number)); + l1_batches + .iter() + .map(SaveAction::InsertBatch) + .chain(commit_tx_actions) + .chain(l1_batches.iter().map(SaveAction::SaveMetadata)) + .collect() + }), +]; + +#[test_casing(12, Product(([10, 3, 1], SAVE_ACTION_MAPPERS)))] +#[tokio::test] +async fn normal_checker_function( + batches_per_transaction: usize, + (mapper_name, save_actions_mapper): (&'static str, SaveActionMapper), +) { + println!("Using save_actions_mapper={mapper_name}"); + + let pool = ConnectionPool::test_pool().await; + let mut storage = pool.access_storage().await.unwrap(); + ensure_genesis_state(&mut storage, L2ChainId::default(), &GenesisParams::mock()) + .await + .unwrap(); + + let l1_batches: Vec<_> = (1..=10).map(create_l1_batch_with_metadata).collect(); + let mut commit_tx_hash_by_l1_batch = HashMap::with_capacity(l1_batches.len()); + let client = MockEthereum::default(); + + for (i, l1_batches) in l1_batches.chunks(batches_per_transaction).enumerate() { + let input_data = build_commit_tx_input_data(l1_batches); + let signed_tx = client.sign_prepared_tx( + input_data.clone(), + Options { + nonce: Some(i.into()), + ..Options::default() + }, + ); + let signed_tx = signed_tx.unwrap(); + client.send_raw_tx(signed_tx.raw_tx).await.unwrap(); + client.execute_tx(signed_tx.hash, true, 1); + + commit_tx_hash_by_l1_batch.extend( + l1_batches + .iter() + .map(|batch| (batch.header.number, signed_tx.hash)), + ); + } + + let (l1_batch_updates_sender, mut l1_batch_updates_receiver) = mpsc::unbounded_channel(); + let checker = ConsistencyChecker { + l1_batch_updater: Box::new(l1_batch_updates_sender), + ..create_mock_checker(client, pool.clone()) + }; + + let (stop_sender, stop_receiver) = watch::channel(false); + let checker_task = tokio::spawn(checker.run(stop_receiver)); + + // Add new batches to the storage. + for save_action in save_actions_mapper(&l1_batches) { + save_action + .apply(&mut storage, &commit_tx_hash_by_l1_batch) + .await; + tokio::time::sleep(Duration::from_millis(7)).await; + } + + // Wait until all batches are checked. + loop { + let checked_batch = l1_batch_updates_receiver.recv().await.unwrap(); + if checked_batch == l1_batches.last().unwrap().header.number { + break; + } + } + + // Send the stop signal to the checker and wait for it to stop. + stop_sender.send_replace(true); + checker_task.await.unwrap().unwrap(); +} + +#[test_casing(4, SAVE_ACTION_MAPPERS)] +#[tokio::test] +async fn checker_processes_pre_boojum_batches( + (mapper_name, save_actions_mapper): (&'static str, SaveActionMapper), +) { + println!("Using save_actions_mapper={mapper_name}"); + + let pool = ConnectionPool::test_pool().await; + let mut storage = pool.access_storage().await.unwrap(); + let genesis_params = GenesisParams { + protocol_version: PRE_BOOJUM_PROTOCOL_VERSION, + ..GenesisParams::mock() + }; + ensure_genesis_state(&mut storage, L2ChainId::default(), &genesis_params) + .await + .unwrap(); + storage + .protocol_versions_dal() + .save_protocol_version_with_tx(ProtocolVersion::default()) + .await; + + let l1_batches: Vec<_> = (1..=5) + .map(create_pre_boojum_l1_batch_with_metadata) + .chain((6..=10).map(create_l1_batch_with_metadata)) + .collect(); + let mut commit_tx_hash_by_l1_batch = HashMap::with_capacity(l1_batches.len()); + let client = MockEthereum::default(); + + for (i, l1_batch) in l1_batches.iter().enumerate() { + let input_data = build_commit_tx_input_data(slice::from_ref(l1_batch)); + let signed_tx = client.sign_prepared_tx( + input_data.clone(), + Options { + nonce: Some(i.into()), + ..Options::default() + }, + ); + let signed_tx = signed_tx.unwrap(); + client.send_raw_tx(signed_tx.raw_tx).await.unwrap(); + client.execute_tx(signed_tx.hash, true, 1); + + commit_tx_hash_by_l1_batch.insert(l1_batch.header.number, signed_tx.hash); + } + + let (l1_batch_updates_sender, mut l1_batch_updates_receiver) = mpsc::unbounded_channel(); + let checker = ConsistencyChecker { + l1_batch_updater: Box::new(l1_batch_updates_sender), + ..create_mock_checker(client, pool.clone()) + }; + + let (stop_sender, stop_receiver) = watch::channel(false); + let checker_task = tokio::spawn(checker.run(stop_receiver)); + + // Add new batches to the storage. + for save_action in save_actions_mapper(&l1_batches) { + save_action + .apply(&mut storage, &commit_tx_hash_by_l1_batch) + .await; + tokio::time::sleep(Duration::from_millis(7)).await; + } + + // Wait until all batches are checked. + loop { + let checked_batch = l1_batch_updates_receiver.recv().await.unwrap(); + if checked_batch == l1_batches.last().unwrap().header.number { + break; + } + } + + // Send the stop signal to the checker and wait for it to stop. + stop_sender.send_replace(true); + checker_task.await.unwrap().unwrap(); +} + +#[test_casing(2, [false, true])] +#[tokio::test] +async fn checker_functions_after_snapshot_recovery(delay_batch_insertion: bool) { + let pool = ConnectionPool::test_pool().await; + let mut storage = pool.access_storage().await.unwrap(); + storage + .protocol_versions_dal() + .save_protocol_version_with_tx(ProtocolVersion::default()) + .await; + + let l1_batch = create_l1_batch_with_metadata(99); + + let commit_tx_input_data = build_commit_tx_input_data(slice::from_ref(&l1_batch)); + let client = MockEthereum::default(); + let signed_tx = client.sign_prepared_tx( + commit_tx_input_data.clone(), + Options { + nonce: Some(0.into()), + ..Options::default() + }, + ); + let signed_tx = signed_tx.unwrap(); + let commit_tx_hash = signed_tx.hash; + client.send_raw_tx(signed_tx.raw_tx).await.unwrap(); + client.execute_tx(commit_tx_hash, true, 1); + + let save_actions = [ + SaveAction::InsertBatch(&l1_batch), + SaveAction::SaveMetadata(&l1_batch), + SaveAction::InsertCommitTx(l1_batch.header.number), + ]; + let commit_tx_hash_by_l1_batch = HashMap::from([(l1_batch.header.number, commit_tx_hash)]); + + if !delay_batch_insertion { + for &save_action in &save_actions { + save_action + .apply(&mut storage, &commit_tx_hash_by_l1_batch) + .await; + } + } + + let (l1_batch_updates_sender, mut l1_batch_updates_receiver) = mpsc::unbounded_channel(); + let checker = ConsistencyChecker { + l1_batch_updater: Box::new(l1_batch_updates_sender), + ..create_mock_checker(client, pool.clone()) + }; + let (stop_sender, stop_receiver) = watch::channel(false); + let checker_task = tokio::spawn(checker.run(stop_receiver)); + + if delay_batch_insertion { + tokio::time::sleep(Duration::from_millis(10)).await; + for &save_action in &save_actions { + save_action + .apply(&mut storage, &commit_tx_hash_by_l1_batch) + .await; + } + } + + // Wait until the batch is checked. + let checked_batch = l1_batch_updates_receiver.recv().await.unwrap(); + assert_eq!(checked_batch, l1_batch.header.number); + + stop_sender.send_replace(true); + checker_task.await.unwrap().unwrap(); +} + +#[derive(Debug, Clone, Copy)] +enum IncorrectDataKind { + MissingStatus, + MismatchedStatus, + BogusCommitDataFormat, + MismatchedCommitDataTimestamp, + CommitDataForAnotherBatch, + CommitDataForPreBoojum, +} + +impl IncorrectDataKind { + const ALL: [Self; 6] = [ + Self::MissingStatus, + Self::MismatchedStatus, + Self::BogusCommitDataFormat, + Self::MismatchedCommitDataTimestamp, + Self::CommitDataForAnotherBatch, + Self::CommitDataForPreBoojum, + ]; + + async fn apply(self, client: &MockEthereum, l1_batch: &L1BatchWithMetadata) -> H256 { + let (commit_tx_input_data, successful_status) = match self { + Self::MissingStatus => { + return H256::zero(); // Do not execute the transaction + } + Self::MismatchedStatus => { + let commit_tx_input_data = build_commit_tx_input_data(slice::from_ref(l1_batch)); + (commit_tx_input_data, false) + } + Self::BogusCommitDataFormat => { + let mut bogus_tx_input_data = b"test".to_vec(); // Preserve the function selector + bogus_tx_input_data + .extend_from_slice(ðabi::encode(&[ethabi::Token::Bool(true)])); + (bogus_tx_input_data, true) + } + Self::MismatchedCommitDataTimestamp => { + let mut l1_batch = create_l1_batch_with_metadata(1); + l1_batch.header.timestamp += 1; + let bogus_tx_input_data = build_commit_tx_input_data(slice::from_ref(&l1_batch)); + (bogus_tx_input_data, true) + } + Self::CommitDataForAnotherBatch => { + let l1_batch = create_l1_batch_with_metadata(100); + let bogus_tx_input_data = build_commit_tx_input_data(slice::from_ref(&l1_batch)); + (bogus_tx_input_data, true) + } + Self::CommitDataForPreBoojum => { + let mut l1_batch = create_l1_batch_with_metadata(1); + l1_batch.header.protocol_version = Some(ProtocolVersionId::Version0); + let bogus_tx_input_data = build_commit_tx_input_data(slice::from_ref(&l1_batch)); + (bogus_tx_input_data, true) + } + }; + + let signed_tx = client.sign_prepared_tx( + commit_tx_input_data, + Options { + nonce: Some(0.into()), + ..Options::default() + }, + ); + let signed_tx = signed_tx.unwrap(); + client.send_raw_tx(signed_tx.raw_tx).await.unwrap(); + client.execute_tx(signed_tx.hash, successful_status, 1); + signed_tx.hash + } +} + +#[test_casing(6, Product((IncorrectDataKind::ALL, [false])))] +// ^ `snapshot_recovery = true` is tested below; we don't want to run it with all incorrect data kinds +#[tokio::test] +async fn checker_detects_incorrect_tx_data(kind: IncorrectDataKind, snapshot_recovery: bool) { + let pool = ConnectionPool::test_pool().await; + let mut storage = pool.access_storage().await.unwrap(); + if snapshot_recovery { + storage + .protocol_versions_dal() + .save_protocol_version_with_tx(ProtocolVersion::default()) + .await; + } else { + ensure_genesis_state(&mut storage, L2ChainId::default(), &GenesisParams::mock()) + .await + .unwrap(); + } + + let l1_batch = create_l1_batch_with_metadata(if snapshot_recovery { 99 } else { 1 }); + let client = MockEthereum::default(); + let commit_tx_hash = kind.apply(&client, &l1_batch).await; + let commit_tx_hash_by_l1_batch = HashMap::from([(l1_batch.header.number, commit_tx_hash)]); + + let save_actions = [ + SaveAction::InsertBatch(&l1_batch), + SaveAction::SaveMetadata(&l1_batch), + SaveAction::InsertCommitTx(l1_batch.header.number), + ]; + for save_action in save_actions { + save_action + .apply(&mut storage, &commit_tx_hash_by_l1_batch) + .await; + } + drop(storage); + + let checker = create_mock_checker(client, pool); + let (_stop_sender, stop_receiver) = watch::channel(false); + // The checker must stop with an error. + tokio::time::timeout(Duration::from_secs(30), checker.run(stop_receiver)) + .await + .expect("Timed out waiting for checker to stop") + .unwrap_err(); +} + +#[tokio::test] +async fn checker_detects_incorrect_tx_data_after_snapshot_recovery() { + checker_detects_incorrect_tx_data(IncorrectDataKind::CommitDataForAnotherBatch, true).await; +} diff --git a/core/lib/zksync_core/src/eth_sender/aggregated_operations.rs b/core/lib/zksync_core/src/eth_sender/aggregated_operations.rs new file mode 100644 index 000000000000..bb7cf75e50d4 --- /dev/null +++ b/core/lib/zksync_core/src/eth_sender/aggregated_operations.rs @@ -0,0 +1,55 @@ +use std::ops; + +use zksync_l1_contract_interface::i_executor::methods::{ + CommitBatches, ExecuteBatches, ProveBatches, +}; +use zksync_types::{aggregated_operations::AggregatedActionType, L1BatchNumber, ProtocolVersionId}; + +#[allow(clippy::large_enum_variant)] +#[derive(Debug, Clone)] +pub enum AggregatedOperation { + Commit(CommitBatches), + PublishProofOnchain(ProveBatches), + Execute(ExecuteBatches), +} + +impl AggregatedOperation { + pub fn get_action_type(&self) -> AggregatedActionType { + match self { + Self::Commit(_) => AggregatedActionType::Commit, + Self::PublishProofOnchain(_) => AggregatedActionType::PublishProofOnchain, + Self::Execute(_) => AggregatedActionType::Execute, + } + } + + pub fn l1_batch_range(&self) -> ops::RangeInclusive { + let batches = match self { + Self::Commit(op) => &op.l1_batches, + Self::PublishProofOnchain(op) => &op.l1_batches, + Self::Execute(op) => &op.l1_batches, + }; + + if batches.is_empty() { + return L1BatchNumber(0)..=L1BatchNumber(0); + } + let first_batch = &batches[0]; + let last_batch = &batches[batches.len() - 1]; + first_batch.header.number..=last_batch.header.number + } + + pub fn get_action_caption(&self) -> &'static str { + match self { + Self::Commit(_) => "commit", + Self::PublishProofOnchain(_) => "proof", + Self::Execute(_) => "execute", + } + } + + pub fn protocol_version(&self) -> ProtocolVersionId { + match self { + Self::Commit(op) => op.l1_batches[0].header.protocol_version.unwrap(), + Self::PublishProofOnchain(op) => op.l1_batches[0].header.protocol_version.unwrap(), + Self::Execute(op) => op.l1_batches[0].header.protocol_version.unwrap(), + } + } +} diff --git a/core/lib/zksync_core/src/eth_sender/aggregator.rs b/core/lib/zksync_core/src/eth_sender/aggregator.rs index 549d0a5acf90..fe887db6469e 100644 --- a/core/lib/zksync_core/src/eth_sender/aggregator.rs +++ b/core/lib/zksync_core/src/eth_sender/aggregator.rs @@ -1,22 +1,25 @@ +use std::sync::Arc; + use zksync_config::configs::eth_sender::{ProofLoadingMode, ProofSendingMode, SenderConfig}; use zksync_contracts::BaseSystemContractsHashes; use zksync_dal::StorageProcessor; -use zksync_object_store::ObjectStore; -use zksync_prover_utils::gcs_proof_fetcher::load_wrapped_fri_proofs_for_range; +use zksync_l1_contract_interface::i_executor::methods::{ + CommitBatches, ExecuteBatches, ProveBatches, +}; +use zksync_object_store::{ObjectStore, ObjectStoreError}; +use zksync_prover_interface::outputs::L1BatchProofForL1; use zksync_types::{ - aggregated_operations::{ - AggregatedActionType, AggregatedOperation, L1BatchCommitOperation, L1BatchExecuteOperation, - L1BatchProofOperation, - }, - commitment::L1BatchWithMetadata, - helpers::unix_timestamp_ms, - protocol_version::L1VerifierConfig, - L1BatchNumber, ProtocolVersionId, + aggregated_operations::AggregatedActionType, commitment::L1BatchWithMetadata, + helpers::unix_timestamp_ms, protocol_version::L1VerifierConfig, L1BatchNumber, + ProtocolVersionId, }; -use super::publish_criterion::{ - DataSizeCriterion, GasCriterion, L1BatchPublishCriterion, NumberCriterion, - TimestampDeadlineCriterion, +use super::{ + aggregated_operations::AggregatedOperation, + publish_criterion::{ + DataSizeCriterion, GasCriterion, L1BatchPublishCriterion, NumberCriterion, + TimestampDeadlineCriterion, + }, }; #[derive(Debug)] @@ -25,11 +28,11 @@ pub struct Aggregator { proof_criteria: Vec>, execute_criteria: Vec>, config: SenderConfig, - blob_store: Box, + blob_store: Arc, } impl Aggregator { - pub fn new(config: SenderConfig, blob_store: Box) -> Self { + pub fn new(config: SenderConfig, blob_store: Arc) -> Self { Self { commit_criteria: vec![ Box::from(NumberCriterion { @@ -95,11 +98,15 @@ impl Aggregator { protocol_version_id: ProtocolVersionId, l1_verifier_config: L1VerifierConfig, ) -> Option { - let last_sealed_l1_batch_number = storage + let Some(last_sealed_l1_batch_number) = storage .blocks_dal() .get_sealed_l1_batch_number() .await - .unwrap(); + .unwrap() + else { + return None; // No L1 batches in Postgres; no operations are ready yet + }; + if let Some(op) = self .get_execute_operations( storage, @@ -137,7 +144,7 @@ impl Aggregator { storage: &mut StorageProcessor<'_>, limit: usize, last_sealed_l1_batch: L1BatchNumber, - ) -> Option { + ) -> Option { let max_l1_batch_timestamp_millis = self .config .l1_batch_min_age_before_execute_seconds @@ -155,7 +162,7 @@ impl Aggregator { ) .await; - l1_batches.map(|l1_batches| L1BatchExecuteOperation { l1_batches }) + l1_batches.map(|l1_batches| ExecuteBatches { l1_batches }) } async fn get_commit_operation( @@ -165,7 +172,7 @@ impl Aggregator { last_sealed_batch: L1BatchNumber, base_system_contracts_hashes: BaseSystemContractsHashes, protocol_version_id: ProtocolVersionId, - ) -> Option { + ) -> Option { let mut blocks_dal = storage.blocks_dal(); let last_committed_l1_batch = blocks_dal .get_last_committed_to_eth_l1_batch() @@ -213,7 +220,7 @@ impl Aggregator { ) .await; - batches.map(|batches| L1BatchCommitOperation { + batches.map(|batches| CommitBatches { last_committed_l1_batch, l1_batches: batches, }) @@ -224,7 +231,7 @@ impl Aggregator { l1_verifier_config: L1VerifierConfig, proof_loading_mode: &ProofLoadingMode, blob_store: &dyn ObjectStore, - ) -> Option { + ) -> Option { let previous_proven_batch_number = storage .blocks_dal() .get_last_l1_batch_with_prove_tx() @@ -292,7 +299,7 @@ impl Aggregator { ); }); - Some(L1BatchProofOperation { + Some(ProveBatches { prev_l1_batch: previous_proven_batch_metadata, l1_batches: vec![metadata_for_batch_being_proved], proofs, @@ -305,7 +312,7 @@ impl Aggregator { storage: &mut StorageProcessor<'_>, ready_for_proof_l1_batches: Vec, last_sealed_l1_batch: L1BatchNumber, - ) -> Option { + ) -> Option { let batches = extract_ready_subrange( storage, &mut self.proof_criteria, @@ -321,7 +328,7 @@ impl Aggregator { .await .unwrap()?; - Some(L1BatchProofOperation { + Some(ProveBatches { prev_l1_batch: prev_batch, l1_batches: batches, proofs: vec![], @@ -335,7 +342,7 @@ impl Aggregator { limit: usize, last_sealed_l1_batch: L1BatchNumber, l1_verifier_config: L1VerifierConfig, - ) -> Option { + ) -> Option { match self.config.proof_sending_mode { ProofSendingMode::OnlyRealProofs => { Self::load_real_proof_operation( @@ -414,3 +421,23 @@ async fn extract_ready_subrange( .collect(), ) } + +pub async fn load_wrapped_fri_proofs_for_range( + from: L1BatchNumber, + to: L1BatchNumber, + blob_store: &dyn ObjectStore, +) -> Vec { + let mut proofs = Vec::new(); + for l1_batch_number in from.0..=to.0 { + let l1_batch_number = L1BatchNumber(l1_batch_number); + match blob_store.get(l1_batch_number).await { + Ok(proof) => proofs.push(proof), + Err(ObjectStoreError::KeyNotFound(_)) => (), // do nothing, proof is not ready yet + Err(err) => panic!( + "Failed to load proof for batch {}: {}", + l1_batch_number.0, err + ), + } + } + proofs +} diff --git a/core/lib/zksync_core/src/eth_sender/error.rs b/core/lib/zksync_core/src/eth_sender/error.rs index 080e252c92c2..206bbf2d583a 100644 --- a/core/lib/zksync_core/src/eth_sender/error.rs +++ b/core/lib/zksync_core/src/eth_sender/error.rs @@ -1,10 +1,9 @@ -use zksync_eth_client::types; use zksync_types::web3::contract; #[derive(Debug, thiserror::Error)] pub enum ETHSenderError { #[error("Ethereum gateway Error {0}")] - EthereumGateWayError(#[from] types::Error), + EthereumGateWayError(#[from] zksync_eth_client::Error), #[error("Token parsing Error: {0}")] ParseError(#[from] contract::Error), } diff --git a/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs b/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs index 49ba4129dfc5..70a8b3d8ae41 100644 --- a/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs +++ b/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs @@ -1,21 +1,24 @@ -use std::convert::TryInto; +use std::{convert::TryInto, sync::Arc}; use tokio::sync::watch; use zksync_config::configs::eth_sender::SenderConfig; use zksync_contracts::BaseSystemContractsHashes; use zksync_dal::{ConnectionPool, StorageProcessor}; -use zksync_eth_client::BoundEthInterface; +use zksync_eth_client::{BoundEthInterface, CallFunctionArgs}; +use zksync_l1_contract_interface::{ + multicall3::{Multicall3Call, Multicall3Result}, + pre_boojum_verifier::old_l1_vk_commitment, + Detokenize, Tokenizable, Tokenize, +}; use zksync_types::{ - aggregated_operations::AggregatedOperation, - contracts::{Multicall3Call, Multicall3Result}, eth_sender::EthTx, ethabi::{Contract, Token}, protocol_version::{L1VerifierConfig, VerifierParams}, - vk_transform::l1_vk_commitment, - web3::contract::{tokens::Tokenizable, Error, Options}, + web3::contract::Error as Web3ContractError, Address, ProtocolVersionId, H256, U256, }; +use super::aggregated_operations::AggregatedOperation; use crate::{ eth_sender::{ metrics::{PubdataKind, METRICS}, @@ -41,6 +44,7 @@ pub struct MulticallData { #[derive(Debug)] pub struct EthTxAggregator { aggregator: Aggregator, + eth_client: Arc, config: SenderConfig, timelock_contract_address: Address, l1_multicall3_address: Address, @@ -53,6 +57,7 @@ impl EthTxAggregator { pub fn new( config: SenderConfig, aggregator: Aggregator, + eth_client: Arc, timelock_contract_address: Address, l1_multicall3_address: Address, main_zksync_contract_address: Address, @@ -62,6 +67,7 @@ impl EthTxAggregator { Self { config, aggregator, + eth_client, timelock_contract_address, l1_multicall3_address, main_zksync_contract_address, @@ -70,10 +76,9 @@ impl EthTxAggregator { } } - pub async fn run( + pub async fn run( mut self, pool: ConnectionPool, - eth_client: E, stop_receiver: watch::Receiver, ) -> anyhow::Result<()> { loop { @@ -84,7 +89,7 @@ impl EthTxAggregator { break; } - if let Err(err) = self.loop_iteration(&mut storage, ð_client).await { + if let Err(err) = self.loop_iteration(&mut storage).await { // Web3 API request failures can cause this, // and anything more important is already properly reported. tracing::warn!("eth_sender error {err:?}"); @@ -95,24 +100,14 @@ impl EthTxAggregator { Ok(()) } - pub(super) async fn get_multicall_data( - &mut self, - eth_client: &E, - ) -> Result { + pub(super) async fn get_multicall_data(&mut self) -> Result { let calldata = self.generate_calldata_for_multicall(); - let aggregate3_result = eth_client - .call_contract_function( - &self.functions.aggregate3.name, - calldata, - None, - Options::default(), - None, - self.l1_multicall3_address, - self.functions.multicall_contract.clone(), - ) - .await?; - - self.parse_multicall_data(aggregate3_result) + let args = CallFunctionArgs::new(&self.functions.aggregate3.name, calldata).for_contract( + self.l1_multicall3_address, + self.functions.multicall_contract.clone(), + ); + let aggregate3_result = self.eth_client.call_contract_function(args).await?; + self.parse_multicall_data(Token::from_tokens(aggregate3_result)?) } // Multicall's aggregate function accepts 1 argument - arrays of different contract calls. @@ -187,16 +182,19 @@ impl EthTxAggregator { ] } - // The role of the method below is to detokenize multicall call's result, which is actually a token. - // This token is an array of tuples like (bool, bytes), that contain the status and result for each contract call. + // The role of the method below is to de-tokenize multicall call's result, which is actually a token. + // This token is an array of tuples like `(bool, bytes)`, that contain the status and result for each contract call. pub(super) fn parse_multicall_data( &self, token: Token, ) -> Result { let parse_error = |tokens: &[Token]| { - Err(ETHSenderError::ParseError(Error::InvalidOutputType( - format!("Failed to parse multicall token: {:?}", tokens), - ))) + Err(ETHSenderError::ParseError( + Web3ContractError::InvalidOutputType(format!( + "Failed to parse multicall token: {:?}", + tokens + )), + )) }; if let Token::Array(call_results) = token { @@ -210,24 +208,24 @@ impl EthTxAggregator { Multicall3Result::from_token(call_results_iterator.next().unwrap())?.return_data; if multicall3_bootloader.len() != 32 { - return Err(ETHSenderError::ParseError(Error::InvalidOutputType( - format!( + return Err(ETHSenderError::ParseError( + Web3ContractError::InvalidOutputType(format!( "multicall3 bootloader hash data is not of the len of 32: {:?}", multicall3_bootloader - ), - ))); + )), + )); } let bootloader = H256::from_slice(&multicall3_bootloader); let multicall3_default_aa = Multicall3Result::from_token(call_results_iterator.next().unwrap())?.return_data; if multicall3_default_aa.len() != 32 { - return Err(ETHSenderError::ParseError(Error::InvalidOutputType( - format!( + return Err(ETHSenderError::ParseError( + Web3ContractError::InvalidOutputType(format!( "multicall3 default aa hash data is not of the len of 32: {:?}", multicall3_default_aa - ), - ))); + )), + )); } let default_aa = H256::from_slice(&multicall3_default_aa); let base_system_contracts_hashes = BaseSystemContractsHashes { @@ -238,12 +236,12 @@ impl EthTxAggregator { let multicall3_verifier_params = Multicall3Result::from_token(call_results_iterator.next().unwrap())?.return_data; if multicall3_verifier_params.len() != 96 { - return Err(ETHSenderError::ParseError(Error::InvalidOutputType( - format!( + return Err(ETHSenderError::ParseError( + Web3ContractError::InvalidOutputType(format!( "multicall3 verifier params data is not of the len of 96: {:?}", multicall3_default_aa - ), - ))); + )), + )); } let recursion_node_level_vk_hash = H256::from_slice(&multicall3_verifier_params[..32]); let recursion_leaf_level_vk_hash = @@ -259,24 +257,24 @@ impl EthTxAggregator { let multicall3_verifier_address = Multicall3Result::from_token(call_results_iterator.next().unwrap())?.return_data; if multicall3_verifier_address.len() != 32 { - return Err(ETHSenderError::ParseError(Error::InvalidOutputType( - format!( + return Err(ETHSenderError::ParseError( + Web3ContractError::InvalidOutputType(format!( "multicall3 verifier address data is not of the len of 32: {:?}", multicall3_verifier_address - ), - ))); + )), + )); } let verifier_address = Address::from_slice(&multicall3_verifier_address[12..]); let multicall3_protocol_version = Multicall3Result::from_token(call_results_iterator.next().unwrap())?.return_data; if multicall3_protocol_version.len() != 32 { - return Err(ETHSenderError::ParseError(Error::InvalidOutputType( - format!( + return Err(ETHSenderError::ParseError( + Web3ContractError::InvalidOutputType(format!( "multicall3 protocol version data is not of the len of 32: {:?}", multicall3_protocol_version - ), - ))); + )), + )); } let protocol_version_id = U256::from_big_endian(&multicall3_protocol_version) .try_into() @@ -293,9 +291,8 @@ impl EthTxAggregator { } /// Loads current verifier config on L1 - async fn get_recursion_scheduler_level_vk_hash( + async fn get_recursion_scheduler_level_vk_hash( &mut self, - eth_client: &E, verifier_address: Address, contracts_are_pre_boojum: bool, ) -> Result { @@ -305,67 +302,46 @@ impl EthTxAggregator { tracing::debug!("Calling get_verification_key"); if contracts_are_pre_boojum { let abi = Contract { - functions: vec![( + functions: [( self.functions.get_verification_key.name.clone(), vec![self.functions.get_verification_key.clone()], )] - .into_iter() - .collect(), + .into(), ..Default::default() }; - let vk = eth_client - .call_contract_function( - &self.functions.get_verification_key.name, - (), - None, - Default::default(), - None, - verifier_address, - abi, - ) - .await?; - Ok(l1_vk_commitment(vk)) + let args = CallFunctionArgs::new(&self.functions.get_verification_key.name, ()) + .for_contract(verifier_address, abi); + + let vk = self.eth_client.call_contract_function(args).await?; + Ok(old_l1_vk_commitment(Token::from_tokens(vk)?)) } else { let get_vk_hash = self.functions.verification_key_hash.as_ref(); tracing::debug!("Calling verificationKeyHash"); - let vk_hash = eth_client - .call_contract_function( - &get_vk_hash.unwrap().name, - (), - None, - Default::default(), - None, - verifier_address, - self.functions.verifier_contract.clone(), - ) - .await?; - Ok(vk_hash) + let args = CallFunctionArgs::new(&get_vk_hash.unwrap().name, ()) + .for_contract(verifier_address, self.functions.verifier_contract.clone()); + let vk_hash = self.eth_client.call_contract_function(args).await?; + Ok(H256::from_tokens(vk_hash)?) } } - #[tracing::instrument(skip(self, storage, eth_client))] - async fn loop_iteration( + #[tracing::instrument(skip(self, storage))] + async fn loop_iteration( &mut self, storage: &mut StorageProcessor<'_>, - eth_client: &E, ) -> Result<(), ETHSenderError> { let MulticallData { base_system_contracts_hashes, verifier_params, verifier_address, protocol_version_id, - } = self.get_multicall_data(eth_client).await.map_err(|err| { + } = self.get_multicall_data().await.map_err(|err| { tracing::error!("Failed to get multicall data {err:?}"); err })?; let contracts_are_pre_boojum = protocol_version_id.is_pre_boojum(); let recursion_scheduler_level_vk_hash = self - .get_recursion_scheduler_level_vk_hash( - eth_client, - verifier_address, - contracts_are_pre_boojum, - ) + .get_recursion_scheduler_level_vk_hash(verifier_address, contracts_are_pre_boojum) .await .map_err(|err| { tracing::error!("Failed to get VK hash from the Verifier {err:?}"); @@ -433,7 +409,7 @@ impl EthTxAggregator { // For "commit" and "prove" operations it's necessary that the contracts are of the same version as L1 batches are. // For "execute" it's not required, i.e. we can "execute" pre-boojum batches with post-boojum contracts. - match &op { + match op.clone() { AggregatedOperation::Commit(op) => { assert_eq!(contracts_are_pre_boojum, operation_is_pre_boojum); let f = if contracts_are_pre_boojum { @@ -444,7 +420,8 @@ impl EthTxAggregator { .as_ref() .expect("Missing ABI for commitBatches") }; - f.encode_input(&op.get_eth_tx_args()) + f.encode_input(&op.into_tokens()) + .expect("Failed to encode commit transaction data") } AggregatedOperation::PublishProofOnchain(op) => { assert_eq!(contracts_are_pre_boojum, operation_is_pre_boojum); @@ -456,7 +433,8 @@ impl EthTxAggregator { .as_ref() .expect("Missing ABI for proveBatches") }; - f.encode_input(&op.get_eth_tx_args()) + f.encode_input(&op.into_tokens()) + .expect("Failed to encode prove transaction data") } AggregatedOperation::Execute(op) => { let f = if contracts_are_pre_boojum { @@ -467,10 +445,10 @@ impl EthTxAggregator { .as_ref() .expect("Missing ABI for executeBatches") }; - f.encode_input(&op.get_eth_tx_args()) + f.encode_input(&op.into_tokens()) + .expect("Failed to encode execute transaction data") } } - .expect("Failed to encode transaction data") } pub(super) async fn save_eth_tx( diff --git a/core/lib/zksync_core/src/eth_sender/eth_tx_manager.rs b/core/lib/zksync_core/src/eth_sender/eth_tx_manager.rs index 2ef9ea87a7c7..be0c8b3ba097 100644 --- a/core/lib/zksync_core/src/eth_sender/eth_tx_manager.rs +++ b/core/lib/zksync_core/src/eth_sender/eth_tx_manager.rs @@ -5,8 +5,7 @@ use tokio::sync::watch; use zksync_config::configs::eth_sender::SenderConfig; use zksync_dal::{ConnectionPool, StorageProcessor}; use zksync_eth_client::{ - types::{Error, ExecutedTxStatus, SignedCallResult}, - BoundEthInterface, + BoundEthInterface, Error, EthInterface, ExecutedTxStatus, RawTransactionBytes, SignedCallResult, }; use zksync_types::{ eth_sender::EthTx, @@ -38,6 +37,7 @@ struct OperatorNonce { #[derive(Debug, Clone, Copy)] pub(super) struct L1BlockNumbers { + pub safe: L1BlockNumber, pub finalized: L1BlockNumber, pub latest: L1BlockNumber, } @@ -48,18 +48,18 @@ pub(super) struct L1BlockNumbers { /// Based on eth_tx_history queue the component can mark txs as stuck and create the new attempt /// with higher gas price #[derive(Debug)] -pub struct EthTxManager { - ethereum_gateway: E, +pub struct EthTxManager { + ethereum_gateway: Arc, config: SenderConfig, - gas_adjuster: Arc, + gas_adjuster: Arc, } -impl EthTxManager -where - E: BoundEthInterface + Sync, - G: L1TxParamsProvider, -{ - pub fn new(config: SenderConfig, gas_adjuster: Arc, ethereum_gateway: E) -> Self { +impl EthTxManager { + pub fn new( + config: SenderConfig, + gas_adjuster: Arc, + ethereum_gateway: Arc, + ) -> Self { Self { ethereum_gateway, config, @@ -175,7 +175,7 @@ where return Err(ETHSenderError::from(Error::from(Web3Error::Internal))); } - // Increase `priority_fee_per_gas` by at least 20% to prevent "replacement transaction underpriced" error. + // Increase `priority_fee_per_gas` by at least 20% to prevent "replacement transaction under-priced" error. Ok((previous_priority_fee + (previous_priority_fee / 5) + 1) .max(self.gas_adjuster.get_priority_fee())) } @@ -208,7 +208,7 @@ where base_fee_per_gas, priority_fee_per_gas, signed_tx.hash, - signed_tx.raw_tx.clone(), + signed_tx.raw_tx.as_ref(), ) .await .unwrap() @@ -233,7 +233,7 @@ where &self, storage: &mut StorageProcessor<'_>, tx_history_id: u32, - raw_tx: Vec, + raw_tx: RawTransactionBytes, current_block: L1BlockNumber, ) -> Result { match self.ethereum_gateway.send_raw_tx(raw_tx).await { @@ -301,19 +301,32 @@ where .await? .as_u32() .into(); - Ok(L1BlockNumbers { finalized, latest }) + + let safe = self + .ethereum_gateway + .block(BlockId::Number(BlockNumber::Safe), "eth_tx_manager") + .await? + .expect("Safe block must be present on L1") + .number + .expect("Safe block must contain number") + .as_u32() + .into(); + + Ok(L1BlockNumbers { + finalized, + latest, + safe, + }) } - // Monitors the inflight transactions, marks mined ones as confirmed, + // Monitors the in-flight transactions, marks mined ones as confirmed, // returns the one that has to be resent (if there is one). pub(super) async fn monitor_inflight_transactions( &mut self, storage: &mut StorageProcessor<'_>, l1_block_numbers: L1BlockNumbers, ) -> Result, ETHSenderError> { - METRICS - .last_known_l1_block - .set(l1_block_numbers.latest.0.into()); + METRICS.track_block_numbers(&l1_block_numbers); let operator_nonce = self.get_operator_nonce(l1_block_numbers).await?; let inflight_txs = storage.eth_sender_dal().get_inflight_txs().await.unwrap(); METRICS.number_of_inflight_txs.set(inflight_txs.len()); @@ -334,7 +347,7 @@ where // If the `operator_nonce.latest` <= `tx.nonce`, this means // that `tx` is not mined and we should resend it. - // We only resend the first unmined transaction. + // We only resend the first un-mined transaction. if operator_nonce.latest <= tx.nonce { // None means txs hasn't been sent yet let first_sent_at_block = storage @@ -368,9 +381,9 @@ where } None => { // The nonce has increased but we did not find the receipt. - // This is an error because such a big reorg may cause transactions that were + // This is an error because such a big re-org may cause transactions that were // previously recorded as confirmed to become pending again and we have to - // make sure it's not the case - otherwise eth_sender may not work properly. + // make sure it's not the case - otherwise `eth_sender` may not work properly. tracing::error!( "Possible block reorgs: finalized nonce increase detected, but no tx receipt found for tx {:?}", &tx @@ -411,7 +424,7 @@ where ) { for tx in storage.eth_sender_dal().get_unsent_txs().await.unwrap() { // Check already sent txs not marked as sent and mark them as sent. - // The common reason for this behaviour is that we sent tx and stop the server + // The common reason for this behavior is that we sent tx and stop the server // before updating the database let tx_status = self.get_tx_status(tx.tx_hash).await; @@ -436,12 +449,12 @@ where .send_raw_transaction( storage, tx.id, - tx.signed_raw_tx.clone(), + RawTransactionBytes::new_unchecked(tx.signed_raw_tx.clone()), l1_block_numbers.latest, ) .await { - tracing::warn!("Error {:?} in sending tx {:?}", error, &tx); + tracing::warn!("Error sending transaction {tx:?}: {error}"); } } } @@ -562,8 +575,8 @@ where self.send_unsent_txs(&mut storage, l1_block_numbers).await; } - // It's mandatory to set last_known_l1_block to zero, otherwise the first iteration - // will never check inflight txs status + // It's mandatory to set `last_known_l1_block` to zero, otherwise the first iteration + // will never check in-flight txs status let mut last_known_l1_block = L1BlockNumber(0); loop { let mut storage = pool.access_storage_tagged("eth_sender").await.unwrap(); diff --git a/core/lib/zksync_core/src/eth_sender/grafana_metrics.rs b/core/lib/zksync_core/src/eth_sender/grafana_metrics.rs deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/core/lib/zksync_core/src/eth_sender/metrics.rs b/core/lib/zksync_core/src/eth_sender/metrics.rs index 4bce1bf1a1f4..255eca2f8d74 100644 --- a/core/lib/zksync_core/src/eth_sender/metrics.rs +++ b/core/lib/zksync_core/src/eth_sender/metrics.rs @@ -7,7 +7,10 @@ use zksync_dal::StorageProcessor; use zksync_types::{aggregated_operations::AggregatedActionType, eth_sender::EthTx}; use zksync_utils::time::seconds_since_epoch; -use crate::metrics::{BlockL1Stage, BlockStage, APP_METRICS}; +use crate::{ + eth_sender::eth_tx_manager::L1BlockNumbers, + metrics::{BlockL1Stage, BlockStage, APP_METRICS}, +}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelSet, EncodeLabelValue)] #[metrics(label = "kind", rename_all = "snake_case")] @@ -18,6 +21,15 @@ pub(super) enum PubdataKind { RepeatedWritesCompressed, } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelSet, EncodeLabelValue)] +#[metrics(label = "block_number_variant", rename_all = "snake_case")] +#[allow(clippy::enum_variant_names)] +pub(super) enum BlockNumberVariant { + Latest, + Finalized, + Safe, +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelSet, EncodeLabelValue)] #[metrics(label = "type")] pub(super) struct ActionTypeLabel(AggregatedActionType); @@ -76,20 +88,28 @@ pub(super) struct EthSenderMetrics { #[metrics(buckets = FEE_BUCKETS)] pub used_priority_fee_per_gas: Histogram, /// Last L1 block observed by the Ethereum sender. - pub last_known_l1_block: Gauge, + pub last_known_l1_block: Family>, /// Number of in-flight txs produced by the Ethereum sender. pub number_of_inflight_txs: Gauge, #[metrics(buckets = GAS_BUCKETS)] pub l1_gas_used: Family>, #[metrics(buckets = Buckets::LATENCIES)] pub l1_tx_mined_latency: Family>, - #[metrics(buckets = &[1.0, 2.0, 3.0, 5.0, 7.0, 10.0, 20.0, 30.0, 50.0])] + #[metrics(buckets = & [1.0, 2.0, 3.0, 5.0, 7.0, 10.0, 20.0, 30.0, 50.0])] pub l1_blocks_waited_in_mempool: Family>, /// Number of L1 batches aggregated for publishing with a specific reason. pub block_aggregation_reason: Family, } impl EthSenderMetrics { + pub fn track_block_numbers(&self, l1_block_numbers: &L1BlockNumbers) { + self.last_known_l1_block[&BlockNumberVariant::Latest] + .set(l1_block_numbers.latest.0 as usize); + self.last_known_l1_block[&BlockNumberVariant::Finalized] + .set(l1_block_numbers.finalized.0 as usize); + self.last_known_l1_block[&BlockNumberVariant::Safe].set(l1_block_numbers.safe.0 as usize); + } + pub async fn track_eth_tx_metrics( &self, connection: &mut StorageProcessor<'_>, diff --git a/core/lib/zksync_core/src/eth_sender/mod.rs b/core/lib/zksync_core/src/eth_sender/mod.rs index e5a47d3f62f8..010441dc0d1a 100644 --- a/core/lib/zksync_core/src/eth_sender/mod.rs +++ b/core/lib/zksync_core/src/eth_sender/mod.rs @@ -1,3 +1,4 @@ +mod aggregated_operations; mod aggregator; mod error; mod eth_tx_aggregator; diff --git a/core/lib/zksync_core/src/eth_sender/publish_criterion.rs b/core/lib/zksync_core/src/eth_sender/publish_criterion.rs index 85f6a46c960b..bc931a119490 100644 --- a/core/lib/zksync_core/src/eth_sender/publish_criterion.rs +++ b/core/lib/zksync_core/src/eth_sender/publish_criterion.rs @@ -3,8 +3,10 @@ use std::fmt; use async_trait::async_trait; use chrono::Utc; use zksync_dal::StorageProcessor; +use zksync_l1_contract_interface::{i_executor::structures::CommitBatchInfo, Tokenizable}; use zksync_types::{ - aggregated_operations::AggregatedActionType, commitment::L1BatchWithMetadata, L1BatchNumber, + aggregated_operations::AggregatedActionType, commitment::L1BatchWithMetadata, ethabi, + L1BatchNumber, }; use super::metrics::METRICS; @@ -215,13 +217,16 @@ impl L1BatchPublishCriterion for DataSizeCriterion { let mut data_size_left = self.data_limit - STORED_BLOCK_INFO_SIZE; for (index, l1_batch) in consecutive_l1_batches.iter().enumerate() { - if data_size_left < l1_batch.l1_commit_data_size() { + // TODO (PLA-771): Make sure that this estimation is correct. + let l1_commit_data_size = ethabi::encode(&[ethabi::Token::Array(vec![ + CommitBatchInfo(l1_batch).into_token(), + ])]) + .len(); + if data_size_left < l1_commit_data_size { if index == 0 { panic!( "L1 batch #{} requires {} data, which is more than the range limit of {}", - l1_batch.header.number, - l1_batch.l1_commit_data_size(), - self.data_limit + l1_batch.header.number, l1_commit_data_size, self.data_limit ); } @@ -236,7 +241,7 @@ impl L1BatchPublishCriterion for DataSizeCriterion { METRICS.block_aggregation_reason[&(self.op, "data_size").into()].inc(); return Some(output); } - data_size_left -= l1_batch.l1_commit_data_size(); + data_size_left -= l1_commit_data_size; } None diff --git a/core/lib/zksync_core/src/eth_sender/tests.rs b/core/lib/zksync_core/src/eth_sender/tests.rs index 01781a424f5c..723c765f3954 100644 --- a/core/lib/zksync_core/src/eth_sender/tests.rs +++ b/core/lib/zksync_core/src/eth_sender/tests.rs @@ -1,4 +1,4 @@ -use std::sync::{atomic::Ordering, Arc}; +use std::sync::Arc; use assert_matches::assert_matches; use once_cell::sync::Lazy; @@ -6,14 +6,13 @@ use zksync_config::{ configs::eth_sender::{ProofSendingMode, SenderConfig}, ContractsConfig, ETHSenderConfig, GasAdjusterConfig, }; -use zksync_contracts::BaseSystemContractsHashes; use zksync_dal::{ConnectionPool, StorageProcessor}; -use zksync_eth_client::{clients::mock::MockEthereum, EthInterface}; +use zksync_eth_client::{clients::MockEthereum, EthInterface}; +use zksync_l1_contract_interface::i_executor::methods::{ + CommitBatches, ExecuteBatches, ProveBatches, +}; use zksync_object_store::ObjectStoreFactory; use zksync_types::{ - aggregated_operations::{ - AggregatedOperation, L1BatchCommitOperation, L1BatchExecuteOperation, L1BatchProofOperation, - }, block::L1BatchHeader, commitment::{L1BatchMetaParameters, L1BatchMetadata, L1BatchWithMetadata}, ethabi::Token, @@ -24,24 +23,20 @@ use zksync_types::{ use crate::{ eth_sender::{ - eth_tx_manager::L1BlockNumbers, Aggregator, ETHSenderError, EthTxAggregator, EthTxManager, + aggregated_operations::AggregatedOperation, eth_tx_manager::L1BlockNumbers, Aggregator, + ETHSenderError, EthTxAggregator, EthTxManager, }, l1_gas_price::GasAdjuster, + utils::testonly::create_l1_batch, }; -// Alias to conveniently call static methods of ETHSender. -type MockEthTxManager = EthTxManager, GasAdjuster>>; +// Alias to conveniently call static methods of `ETHSender`. +type MockEthTxManager = EthTxManager; static DUMMY_OPERATION: Lazy = Lazy::new(|| { - AggregatedOperation::Execute(L1BatchExecuteOperation { + AggregatedOperation::Execute(ExecuteBatches { l1_batches: vec![L1BatchWithMetadata { - header: L1BatchHeader::new( - L1BatchNumber(1), - 1, - Address::default(), - BaseSystemContractsHashes::default(), - ProtocolVersionId::latest(), - ), + header: create_l1_batch(1), metadata: default_l1_batch_metadata(), factory_deps: Vec::new(), }], @@ -84,9 +79,7 @@ impl EthSenderTester { .with_non_ordering_confirmation(non_ordering_confirmations) .with_multicall_address(contracts_config.l1_multicall3_addr), ); - gateway - .block_number - .fetch_add(Self::WAIT_CONFIRMATIONS, Ordering::Relaxed); + gateway.advance_block_number(Self::WAIT_CONFIRMATIONS); let gas_adjuster = Arc::new( GasAdjuster::new( @@ -113,6 +106,7 @@ impl EthSenderTester { aggregator_config.clone(), store_factory.create_store().await, ), + gateway.clone(), // zkSync contract address Address::random(), contracts_config.l1_multicall3_addr, @@ -141,7 +135,11 @@ impl EthSenderTester { async fn get_block_numbers(&self) -> L1BlockNumbers { let latest = self.gateway.block_number("").await.unwrap().as_u32().into(); let finalized = latest - Self::WAIT_CONFIRMATIONS as u32; - L1BlockNumbers { finalized, latest } + L1BlockNumbers { + finalized, + latest, + safe: finalized, + } } } @@ -175,7 +173,7 @@ async fn confirm_many() -> anyhow::Result<()> { } // check that we sent something - assert_eq!(tester.gateway.sent_txs.read().unwrap().len(), 5); + assert_eq!(tester.gateway.sent_tx_count(), 5); assert_eq!( tester .storage() @@ -191,7 +189,7 @@ async fn confirm_many() -> anyhow::Result<()> { for hash in hashes { tester .gateway - .execute_tx(hash, true, EthSenderTester::WAIT_CONFIRMATIONS)?; + .execute_tx(hash, true, EthSenderTester::WAIT_CONFIRMATIONS); } let to_resend = tester @@ -221,7 +219,7 @@ async fn confirm_many() -> anyhow::Result<()> { Ok(()) } -// Tests that we resend first unmined transaction every block with an increased gas price. +// Tests that we resend first un-mined transaction every block with an increased gas price. #[tokio::test] async fn resend_each_block() -> anyhow::Result<()> { let connection_pool = ConnectionPool::test_pool().await; @@ -252,7 +250,7 @@ async fn resend_each_block() -> anyhow::Result<()> { .await?; // check that we sent something and stored it in the db - assert_eq!(tester.gateway.sent_txs.read().unwrap().len(), 1); + assert_eq!(tester.gateway.sent_tx_count(), 1); assert_eq!( tester .storage() @@ -265,10 +263,18 @@ async fn resend_each_block() -> anyhow::Result<()> { 1 ); - let sent_tx = tester.gateway.sent_txs.read().unwrap()[&hash]; + let sent_tx = tester + .gateway + .get_tx(hash, "") + .await + .unwrap() + .expect("no transaction"); assert_eq!(sent_tx.hash, hash); - assert_eq!(sent_tx.nonce, 0); - assert_eq!(sent_tx.base_fee.as_usize(), 18); // 6 * 3 * 2^0 + assert_eq!(sent_tx.nonce, 0.into()); + assert_eq!( + sent_tx.max_fee_per_gas.unwrap() - sent_tx.max_priority_fee_per_gas.unwrap(), + 18.into() // `6 * 3 * 2^0` + ); // now, median is 5 tester.gateway.advance_block_number(2); @@ -295,7 +301,7 @@ async fn resend_each_block() -> anyhow::Result<()> { .await?; // check that transaction has been resent - assert_eq!(tester.gateway.sent_txs.read().unwrap().len(), 2); + assert_eq!(tester.gateway.sent_tx_count(), 2); assert_eq!( tester .storage() @@ -308,9 +314,17 @@ async fn resend_each_block() -> anyhow::Result<()> { 1 ); - let resent_tx = tester.gateway.sent_txs.read().unwrap()[&resent_hash]; - assert_eq!(resent_tx.nonce, 0); - assert_eq!(resent_tx.base_fee.as_usize(), 30); // 5 * 3 * 2^1 + let resent_tx = tester + .gateway + .get_tx(resent_hash, "") + .await + .unwrap() + .expect("no transaction"); + assert_eq!(resent_tx.nonce, 0.into()); + assert_eq!( + resent_tx.max_fee_per_gas.unwrap() - resent_tx.max_priority_fee_per_gas.unwrap(), + 30.into() // `5 * 3 * 2^1` + ); Ok(()) } @@ -343,7 +357,7 @@ async fn dont_resend_already_mined() -> anyhow::Result<()> { .unwrap(); // check that we sent something and stored it in the db - assert_eq!(tester.gateway.sent_txs.read().unwrap().len(), 1); + assert_eq!(tester.gateway.sent_tx_count(), 1); assert_eq!( tester .storage() @@ -359,7 +373,7 @@ async fn dont_resend_already_mined() -> anyhow::Result<()> { // mine the transaction but don't have enough confirmations yet tester .gateway - .execute_tx(hash, true, EthSenderTester::WAIT_CONFIRMATIONS - 1)?; + .execute_tx(hash, true, EthSenderTester::WAIT_CONFIRMATIONS - 1); let to_resend = tester .manager @@ -369,7 +383,7 @@ async fn dont_resend_already_mined() -> anyhow::Result<()> { ) .await?; - // check that transaction is still considered inflight + // check that transaction is still considered in-flight assert_eq!( tester .storage() @@ -420,17 +434,16 @@ async fn three_scenarios() -> anyhow::Result<()> { } // check that we sent something - assert_eq!(tester.gateway.sent_txs.read().unwrap().len(), 3); + assert_eq!(tester.gateway.sent_tx_count(), 3); // mined & confirmed tester .gateway - .execute_tx(hashes[0], true, EthSenderTester::WAIT_CONFIRMATIONS)?; - + .execute_tx(hashes[0], true, EthSenderTester::WAIT_CONFIRMATIONS); // mined but not confirmed tester .gateway - .execute_tx(hashes[1], true, EthSenderTester::WAIT_CONFIRMATIONS - 1)?; + .execute_tx(hashes[1], true, EthSenderTester::WAIT_CONFIRMATIONS - 1); let (to_resend, _) = tester .manager @@ -441,7 +454,7 @@ async fn three_scenarios() -> anyhow::Result<()> { .await? .expect("we should be trying to resend the last tx"); - // check that last 2 transactions are still considered inflight + // check that last 2 transactions are still considered in-flight assert_eq!( tester .storage() @@ -490,8 +503,7 @@ async fn failed_eth_tx() { // fail this tx tester .gateway - .execute_tx(hash, false, EthSenderTester::WAIT_CONFIRMATIONS) - .unwrap(); + .execute_tx(hash, false, EthSenderTester::WAIT_CONFIRMATIONS); tester .manager .monitor_inflight_transactions( @@ -859,7 +871,7 @@ async fn test_parse_multicall_data() { async fn get_multicall_data() { let connection_pool = ConnectionPool::test_pool().await; let mut tester = EthSenderTester::new(connection_pool, vec![100; 100], false).await; - let multicall_data = tester.aggregator.get_multicall_data(&tester.gateway).await; + let multicall_data = tester.aggregator.get_multicall_data().await; assert!(multicall_data.is_ok()); } @@ -873,21 +885,14 @@ async fn insert_genesis_protocol_version(tester: &EthSenderTester) { } async fn insert_l1_batch(tester: &EthSenderTester, number: L1BatchNumber) -> L1BatchHeader { - let mut header = L1BatchHeader::new( - number, - 0, - Address::zero(), - BaseSystemContractsHashes::default(), - Default::default(), - ); - header.is_finished = true; + let header = create_l1_batch(number.0); // Save L1 batch to the database tester .storage() .await .blocks_dal() - .insert_l1_batch(&header, &[], Default::default(), &[], &[]) + .insert_mock_l1_batch(&header) .await .unwrap(); tester @@ -910,7 +915,7 @@ async fn execute_l1_batches( l1_batches: Vec, confirm: bool, ) -> H256 { - let operation = AggregatedOperation::Execute(L1BatchExecuteOperation { + let operation = AggregatedOperation::Execute(ExecuteBatches { l1_batches: l1_batches.into_iter().map(l1_batch_with_metadata).collect(), }); send_operation(tester, operation, confirm).await @@ -922,7 +927,7 @@ async fn prove_l1_batch( l1_batch: L1BatchHeader, confirm: bool, ) -> H256 { - let operation = AggregatedOperation::PublishProofOnchain(L1BatchProofOperation { + let operation = AggregatedOperation::PublishProofOnchain(ProveBatches { prev_l1_batch: l1_batch_with_metadata(last_committed_l1_batch), l1_batches: vec![l1_batch_with_metadata(l1_batch)], proofs: vec![], @@ -937,7 +942,7 @@ async fn commit_l1_batch( l1_batch: L1BatchHeader, confirm: bool, ) -> H256 { - let operation = AggregatedOperation::Commit(L1BatchCommitOperation { + let operation = AggregatedOperation::Commit(CommitBatches { last_committed_l1_batch: l1_batch_with_metadata(last_committed_l1_batch), l1_batches: vec![l1_batch_with_metadata(l1_batch)], }); @@ -979,9 +984,7 @@ async fn send_operation( async fn confirm_tx(tester: &mut EthSenderTester, hash: H256) { tester .gateway - .execute_tx(hash, true, EthSenderTester::WAIT_CONFIRMATIONS) - .unwrap(); - + .execute_tx(hash, true, EthSenderTester::WAIT_CONFIRMATIONS); tester .manager .monitor_inflight_transactions( diff --git a/core/lib/zksync_core/src/eth_watch/client.rs b/core/lib/zksync_core/src/eth_watch/client.rs index cbd3785640e2..28707ce4a4c5 100644 --- a/core/lib/zksync_core/src/eth_watch/client.rs +++ b/core/lib/zksync_core/src/eth_watch/client.rs @@ -1,10 +1,13 @@ +use std::fmt; + use zksync_contracts::verifier_contract; -use zksync_eth_client::{types::Error as EthClientError, EthInterface}; +use zksync_eth_client::{CallFunctionArgs, Error as EthClientError, EthInterface}; +use zksync_l1_contract_interface::pre_boojum_verifier::old_l1_vk_commitment; use zksync_types::{ ethabi::{Contract, Token}, - vk_transform::l1_vk_commitment, web3::{ self, + contract::tokens::Detokenize, types::{BlockId, BlockNumber, FilterBuilder, Log}, }, Address, H256, @@ -22,8 +25,14 @@ pub enum Error { InfiniteRecursion, } +impl From for Error { + fn from(err: web3::contract::Error) -> Self { + Self::EthClient(err.into()) + } +} + #[async_trait::async_trait] -pub trait EthClient { +pub trait EthClient: 'static + fmt::Debug + Send + Sync { /// Returns events in a given block range. async fn get_events( &self, @@ -44,8 +53,8 @@ const TOO_MANY_RESULTS_INFURA: &str = "query returned more than"; const TOO_MANY_RESULTS_ALCHEMY: &str = "response size exceeded"; #[derive(Debug)] -pub struct EthHttpQueryClient { - client: E, +pub struct EthHttpQueryClient { + client: Box, topics: Vec, zksync_contract_addr: Address, /// Address of the `Governance` contract. It's optional because it is present only for post-boojum chains. @@ -55,9 +64,9 @@ pub struct EthHttpQueryClient { confirmations_for_eth_event: Option, } -impl EthHttpQueryClient { +impl EthHttpQueryClient { pub fn new( - client: E, + client: Box, zksync_contract_addr: Address, governance_address: Option

, confirmations_for_eth_event: Option, @@ -101,41 +110,23 @@ impl EthHttpQueryClient { } #[async_trait::async_trait] -impl EthClient for EthHttpQueryClient { +impl EthClient for EthHttpQueryClient { async fn scheduler_vk_hash(&self, verifier_address: Address) -> Result { // This is here for backward compatibility with the old verifier: // Legacy verifier returns the full verification key; // New verifier returns the hash of the verification key. - let vk_hash = self - .client - .call_contract_function( - "verificationKeyHash", - (), - None, - Default::default(), - None, - verifier_address, - self.verifier_contract_abi.clone(), - ) - .await; + let args = CallFunctionArgs::new("verificationKeyHash", ()) + .for_contract(verifier_address, self.verifier_contract_abi.clone()); + let vk_hash_tokens = self.client.call_contract_function(args).await; - if let Ok(Token::FixedBytes(vk_hash)) = vk_hash { - Ok(H256::from_slice(&vk_hash)) + if let Ok(tokens) = vk_hash_tokens { + Ok(H256::from_tokens(tokens)?) } else { - let vk = self - .client - .call_contract_function( - "get_verification_key", - (), - None, - Default::default(), - None, - verifier_address, - self.verifier_contract_abi.clone(), - ) - .await?; - Ok(l1_vk_commitment(vk)) + let args = CallFunctionArgs::new("get_verification_key", ()) + .for_contract(verifier_address, self.verifier_contract_abi.clone()); + let vk = self.client.call_contract_function(args).await?; + Ok(old_l1_vk_commitment(Token::from_tokens(vk)?)) } } diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/governance_upgrades.rs b/core/lib/zksync_core/src/eth_watch/event_processors/governance_upgrades.rs index 2f7e2e86b2c7..6008f4a05e96 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/governance_upgrades.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/governance_upgrades.rs @@ -38,11 +38,11 @@ impl GovernanceUpgradesEventProcessor { } #[async_trait::async_trait] -impl EventProcessor for GovernanceUpgradesEventProcessor { +impl EventProcessor for GovernanceUpgradesEventProcessor { async fn process_events( &mut self, storage: &mut StorageProcessor<'_>, - client: &W, + client: &dyn EthClient, events: Vec, ) -> Result<(), Error> { let mut upgrades = Vec::new(); @@ -66,7 +66,7 @@ impl EventProcessor for GovernanceUpgradesEventProcessor ); continue; }; - // Scheduler VK is not present in proposal event. It is hardcoded in verifier contract. + // Scheduler VK is not present in proposal event. It is hard coded in verifier contract. let scheduler_vk_hash = if let Some(address) = upgrade.verifier_address { Some(client.scheduler_vk_hash(address).await?) } else { diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/mod.rs b/core/lib/zksync_core/src/eth_watch/event_processors/mod.rs index 202b7efb586a..0a068033f2bd 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/mod.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/mod.rs @@ -1,3 +1,5 @@ +use std::fmt; + use zksync_dal::StorageProcessor; use zksync_types::{web3::types::Log, H256}; @@ -8,12 +10,12 @@ pub mod priority_ops; pub mod upgrades; #[async_trait::async_trait] -pub trait EventProcessor: Send + std::fmt::Debug { +pub trait EventProcessor: 'static + fmt::Debug + Send + Sync { /// Processes given events async fn process_events( &mut self, storage: &mut StorageProcessor<'_>, - client: &W, + client: &dyn EthClient, events: Vec, ) -> Result<(), Error>; diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/priority_ops.rs b/core/lib/zksync_core/src/eth_watch/event_processors/priority_ops.rs index 9c2d34bf589e..ad24eba1791b 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/priority_ops.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/priority_ops.rs @@ -33,11 +33,11 @@ impl PriorityOpsEventProcessor { } #[async_trait::async_trait] -impl EventProcessor for PriorityOpsEventProcessor { +impl EventProcessor for PriorityOpsEventProcessor { async fn process_events( &mut self, storage: &mut StorageProcessor<'_>, - _client: &W, + _client: &dyn EthClient, events: Vec, ) -> Result<(), Error> { let mut priority_ops = Vec::new(); diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs b/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs index 497cb705ee1c..e7f906cdf070 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs @@ -29,11 +29,11 @@ impl UpgradesEventProcessor { } #[async_trait::async_trait] -impl EventProcessor for UpgradesEventProcessor { +impl EventProcessor for UpgradesEventProcessor { async fn process_events( &mut self, storage: &mut StorageProcessor<'_>, - client: &W, + client: &dyn EthClient, events: Vec, ) -> Result<(), Error> { let mut upgrades = Vec::new(); @@ -43,7 +43,7 @@ impl EventProcessor for UpgradesEventProcessor { { let upgrade = ProtocolUpgrade::try_from(event) .map_err(|err| Error::LogParse(format!("{:?}", err)))?; - // Scheduler VK is not present in proposal event. It is hardcoded in verifier contract. + // Scheduler VK is not present in proposal event. It is hard coded in verifier contract. let scheduler_vk_hash = if let Some(address) = upgrade.verifier_address { Some(client.scheduler_vk_hash(address).await?) } else { diff --git a/core/lib/zksync_core/src/eth_watch/mod.rs b/core/lib/zksync_core/src/eth_watch/mod.rs index 69f447e7fba9..5aac8624d474 100644 --- a/core/lib/zksync_core/src/eth_watch/mod.rs +++ b/core/lib/zksync_core/src/eth_watch/mod.rs @@ -39,32 +39,32 @@ struct EthWatchState { } #[derive(Debug)] -pub struct EthWatch { - client: W, +pub struct EthWatch { + client: Box, poll_interval: Duration, - event_processors: Vec>>, + event_processors: Vec>, last_processed_ethereum_block: u64, } -impl EthWatch { +impl EthWatch { pub async fn new( diamond_proxy_address: Address, governance_contract: Option, - mut client: W, + mut client: Box, pool: &ConnectionPool, poll_interval: Duration, ) -> Self { let mut storage = pool.access_storage_tagged("eth_watch").await.unwrap(); - let state = Self::initialize_state(&client, &mut storage).await; + let state = Self::initialize_state(&*client, &mut storage).await; tracing::info!("initialized state: {:?}", state); let priority_ops_processor = PriorityOpsEventProcessor::new(state.next_expected_priority_id); let upgrades_processor = UpgradesEventProcessor::new(state.last_seen_version_id); - let mut event_processors: Vec>> = vec![ + let mut event_processors: Vec> = vec![ Box::new(priority_ops_processor), Box::new(upgrades_processor), ]; @@ -92,7 +92,10 @@ impl EthWatch { } } - async fn initialize_state(client: &W, storage: &mut StorageProcessor<'_>) -> EthWatchState { + async fn initialize_state( + client: &dyn EthClient, + storage: &mut StorageProcessor<'_>, + ) -> EthWatchState { let next_expected_priority_id: PriorityOpId = storage .transactions_dal() .last_priority_id() @@ -149,7 +152,7 @@ impl EthWatch { // thus entering priority mode, which is not desired. tracing::error!("Failed to process new blocks {}", error); self.last_processed_ethereum_block = - Self::initialize_state(&self.client, &mut storage) + Self::initialize_state(&*self.client, &mut storage) .await .last_processed_ethereum_block; } @@ -177,7 +180,7 @@ impl EthWatch { for processor in self.event_processors.iter_mut() { processor - .process_events(storage, &self.client, events.clone()) + .process_events(storage, &*self.client, events.clone()) .await?; } self.last_processed_ethereum_block = to_block; @@ -185,10 +188,10 @@ impl EthWatch { } } -pub async fn start_eth_watch( +pub async fn start_eth_watch( config: ETHWatchConfig, pool: ConnectionPool, - eth_gateway: E, + eth_gateway: Box, diamond_proxy_addr: Address, governance: (Contract, Address), stop_receiver: watch::Receiver, @@ -203,7 +206,7 @@ pub async fn start_eth_watch( let mut eth_watch = EthWatch::new( diamond_proxy_addr, Some(governance.0), - eth_client, + Box::new(eth_client), &pool, config.poll_interval(), ) diff --git a/core/lib/zksync_core/src/eth_watch/tests.rs b/core/lib/zksync_core/src/eth_watch/tests.rs index 31c467419294..76b170ba365e 100644 --- a/core/lib/zksync_core/src/eth_watch/tests.rs +++ b/core/lib/zksync_core/src/eth_watch/tests.rs @@ -17,6 +17,7 @@ use crate::eth_watch::{ client::EthClient, event_processors::upgrades::UPGRADE_PROPOSAL_SIGNATURE, EthWatch, }; +#[derive(Debug)] struct FakeEthClientData { transactions: HashMap>, diamond_upgrades: HashMap>, @@ -67,7 +68,7 @@ impl FakeEthClientData { } } -#[derive(Clone)] +#[derive(Debug, Clone)] struct FakeEthClient { inner: Arc>, } @@ -208,7 +209,7 @@ async fn test_normal_operation_l1_txs() { let mut watcher = EthWatch::new( Address::default(), None, - client.clone(), + Box::new(client.clone()), &connection_pool, std::time::Duration::from_nanos(1), ) @@ -256,7 +257,7 @@ async fn test_normal_operation_upgrades() { let mut watcher = EthWatch::new( Address::default(), None, - client.clone(), + Box::new(client.clone()), &connection_pool, std::time::Duration::from_nanos(1), ) @@ -317,7 +318,7 @@ async fn test_gap_in_upgrades() { let mut watcher = EthWatch::new( Address::default(), None, - client.clone(), + Box::new(client.clone()), &connection_pool, std::time::Duration::from_nanos(1), ) @@ -356,7 +357,7 @@ async fn test_normal_operation_governance_upgrades() { let mut watcher = EthWatch::new( Address::default(), Some(governance_contract()), - client.clone(), + Box::new(client.clone()), &connection_pool, std::time::Duration::from_nanos(1), ) @@ -418,7 +419,7 @@ async fn test_gap_in_single_batch() { let mut watcher = EthWatch::new( Address::default(), None, - client.clone(), + Box::new(client.clone()), &connection_pool, std::time::Duration::from_nanos(1), ) @@ -448,7 +449,7 @@ async fn test_gap_between_batches() { let mut watcher = EthWatch::new( Address::default(), None, - client.clone(), + Box::new(client.clone()), &connection_pool, std::time::Duration::from_nanos(1), ) @@ -483,7 +484,7 @@ async fn test_overlapping_batches() { let mut watcher = EthWatch::new( Address::default(), None, - client.clone(), + Box::new(client.clone()), &connection_pool, std::time::Duration::from_nanos(1), ) @@ -523,12 +524,13 @@ async fn test_overlapping_batches() { } async fn get_all_db_txs(storage: &mut StorageProcessor<'_>) -> Vec { - storage.transactions_dal().reset_mempool().await; - storage + storage.transactions_dal().reset_mempool().await.unwrap(); + let (txs, _) = storage .transactions_dal() - .sync_mempool(vec![], vec![], 0, 0, 1000) + .sync_mempool(&[], &[], 0, 0, 1000) .await - .0 + .unwrap(); + txs } fn tx_into_log(tx: L1Tx) -> Log { diff --git a/core/lib/zksync_core/src/fee_model.rs b/core/lib/zksync_core/src/fee_model.rs new file mode 100644 index 000000000000..8d43cdc99a7a --- /dev/null +++ b/core/lib/zksync_core/src/fee_model.rs @@ -0,0 +1,441 @@ +use std::{fmt, sync::Arc}; + +use zksync_dal::ConnectionPool; +use zksync_types::{ + fee_model::{ + BatchFeeInput, FeeModelConfig, FeeModelConfigV2, FeeParams, FeeParamsV1, FeeParamsV2, + L1PeggedBatchFeeModelInput, PubdataIndependentBatchFeeModelInput, + }, + U256, +}; +use zksync_utils::ceil_div_u256; + +use crate::l1_gas_price::L1GasPriceProvider; + +/// Trait responsible for providing fee info for a batch +#[async_trait::async_trait] +pub trait BatchFeeModelInputProvider: fmt::Debug + 'static + Send + Sync { + /// Returns the batch fee with scaling applied. This may be used to account for the fact that the L1 gas and pubdata prices may fluctuate, esp. + /// in API methods that should return values that are valid for some period of time after the estimation was done. + async fn get_batch_fee_input_scaled( + &self, + l1_gas_price_scale_factor: f64, + l1_pubdata_price_scale_factor: f64, + ) -> BatchFeeInput { + let params = self.get_fee_model_params(); + + match params { + FeeParams::V1(params) => BatchFeeInput::L1Pegged(compute_batch_fee_model_input_v1( + params, + l1_gas_price_scale_factor, + )), + FeeParams::V2(params) => { + BatchFeeInput::PubdataIndependent(compute_batch_fee_model_input_v2( + params, + l1_gas_price_scale_factor, + l1_pubdata_price_scale_factor, + )) + } + } + } + + /// Returns the batch fee input as-is, i.e. without any scaling for the L1 gas and pubdata prices. + async fn get_batch_fee_input(&self) -> BatchFeeInput { + self.get_batch_fee_input_scaled(1.0, 1.0).await + } + + /// Returns the fee model parameters. + fn get_fee_model_params(&self) -> FeeParams; +} + +/// The struct that represents the batch fee input provider to be used in the main node of the server, i.e. +/// it explicitly gets the L1 gas price from the provider and uses it to calculate the batch fee input instead of getting +/// it from other node. +#[derive(Debug)] +pub(crate) struct MainNodeFeeInputProvider { + provider: Arc, + config: FeeModelConfig, +} + +impl BatchFeeModelInputProvider for MainNodeFeeInputProvider { + fn get_fee_model_params(&self) -> FeeParams { + match self.config { + FeeModelConfig::V1(config) => FeeParams::V1(FeeParamsV1 { + config, + l1_gas_price: self.provider.estimate_effective_gas_price(), + }), + FeeModelConfig::V2(config) => FeeParams::V2(FeeParamsV2 { + config, + l1_gas_price: self.provider.estimate_effective_gas_price(), + l1_pubdata_price: self.provider.estimate_effective_pubdata_price(), + }), + } + } +} + +impl MainNodeFeeInputProvider { + pub(crate) fn new(provider: Arc, config: FeeModelConfig) -> Self { + Self { provider, config } + } +} + +/// The fee model provider to be used in the API. It returns the maximal batch fee input between the projected main node one and +/// the one from the last sealed miniblock. +#[derive(Debug)] +pub(crate) struct ApiFeeInputProvider { + inner: MainNodeFeeInputProvider, + connection_pool: ConnectionPool, +} + +impl ApiFeeInputProvider { + pub fn new( + provider: Arc, + config: FeeModelConfig, + connection_pool: ConnectionPool, + ) -> Self { + Self { + inner: MainNodeFeeInputProvider::new(provider, config), + connection_pool, + } + } +} + +#[async_trait::async_trait] +impl BatchFeeModelInputProvider for ApiFeeInputProvider { + async fn get_batch_fee_input_scaled( + &self, + l1_gas_price_scale_factor: f64, + l1_pubdata_price_scale_factor: f64, + ) -> BatchFeeInput { + let inner_input = self + .inner + .get_batch_fee_input_scaled(l1_gas_price_scale_factor, l1_pubdata_price_scale_factor) + .await; + let last_miniblock_params = self + .connection_pool + .access_storage_tagged("api_fee_input_provider") + .await + .unwrap() + .blocks_dal() + .get_last_sealed_miniblock_header() + .await + .unwrap(); + + last_miniblock_params + .map(|header| inner_input.stricter(header.batch_fee_input)) + .unwrap_or(inner_input) + } + + /// Returns the fee model parameters. + fn get_fee_model_params(&self) -> FeeParams { + self.inner.get_fee_model_params() + } +} + +/// Calculates the batch fee input based on the main node parameters. +/// This function uses the `V1` fee model, i.e. where the pubdata price does not include the proving costs. +fn compute_batch_fee_model_input_v1( + params: FeeParamsV1, + l1_gas_price_scale_factor: f64, +) -> L1PeggedBatchFeeModelInput { + let l1_gas_price = (params.l1_gas_price as f64 * l1_gas_price_scale_factor) as u64; + + L1PeggedBatchFeeModelInput { + l1_gas_price, + fair_l2_gas_price: params.config.minimal_l2_gas_price, + } +} + +/// Calculates the batch fee input based on the main node parameters. +/// This function uses the `V2` fee model, i.e. where the pubdata price does not include the proving costs. +fn compute_batch_fee_model_input_v2( + params: FeeParamsV2, + l1_gas_price_scale_factor: f64, + l1_pubdata_price_scale_factor: f64, +) -> PubdataIndependentBatchFeeModelInput { + let FeeParamsV2 { + config, + l1_gas_price, + l1_pubdata_price, + } = params; + + let FeeModelConfigV2 { + minimal_l2_gas_price, + compute_overhead_part, + pubdata_overhead_part, + batch_overhead_l1_gas, + max_gas_per_batch, + max_pubdata_per_batch, + } = config; + + // Firstly, we scale the gas price and pubdata price in case it is needed. + let l1_gas_price = (l1_gas_price as f64 * l1_gas_price_scale_factor) as u64; + let l1_pubdata_price = (l1_pubdata_price as f64 * l1_pubdata_price_scale_factor) as u64; + + // While the final results of the calculations are not expected to have any overflows, the intermediate computations + // might, so we use U256 for them. + let l1_batch_overhead_wei = U256::from(l1_gas_price) * U256::from(batch_overhead_l1_gas); + + let fair_l2_gas_price = { + // Firstly, we calculate which part of the overall overhead overhead each unit of L2 gas should cover. + let l1_batch_overhead_per_gas = + ceil_div_u256(l1_batch_overhead_wei, U256::from(max_gas_per_batch)); + + // Then, we multiply by the `compute_overhead_part` to get the overhead for the computation for each gas. + // Also, this means that if we almost never close batches because of compute, the `compute_overhead_part` should be zero and so + // it is possible that the computation costs include for no overhead. + let gas_overhead_wei = + (l1_batch_overhead_per_gas.as_u64() as f64 * compute_overhead_part) as u64; + + // We sum up the minimal L2 gas price (i.e. the raw prover/compute cost of a single L2 gas) and the overhead for batch being closed. + minimal_l2_gas_price + gas_overhead_wei + }; + + let fair_pubdata_price = { + // Firstly, we calculate which part of the overall overhead overhead each pubdata byte should cover. + let l1_batch_overhead_per_pubdata = + ceil_div_u256(l1_batch_overhead_wei, U256::from(max_pubdata_per_batch)); + + // Then, we multiply by the `pubdata_overhead_part` to get the overhead for each pubdata byte. + // Also, this means that if we almost never close batches because of pubdata, the `pubdata_overhead_part` should be zero and so + // it is possible that the pubdata costs include no overhead. + let pubdata_overhead_wei = + (l1_batch_overhead_per_pubdata.as_u64() as f64 * pubdata_overhead_part) as u64; + + // We sum up the raw L1 pubdata price (i.e. the expected price of publishing a single pubdata byte) and the overhead for batch being closed. + l1_pubdata_price + pubdata_overhead_wei + }; + + PubdataIndependentBatchFeeModelInput { + l1_gas_price, + fair_l2_gas_price, + fair_pubdata_price, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // To test that overflow never happens, we'll use giant L1 gas price, i.e. + // almost realistic very large value of 100k gwei. Since it is so large, we'll also + // use it for the L1 pubdata price. + const GIANT_L1_GAS_PRICE: u64 = 100_000_000_000_000; + + // As a small small L2 gas price we'll use the value of 1 wei. + const SMALL_L1_GAS_PRICE: u64 = 1; + + #[test] + fn test_compute_batch_fee_model_input_v2_giant_numbers() { + let config = FeeModelConfigV2 { + minimal_l2_gas_price: GIANT_L1_GAS_PRICE, + // We generally don't expect those values to be larger than 1. Still, in theory the operator + // may need to set higher values in extreme cases. + compute_overhead_part: 5.0, + pubdata_overhead_part: 5.0, + // The batch overhead would likely never grow beyond that + batch_overhead_l1_gas: 1_000_000, + // Let's imagine that for some reason the limit is relatively small + max_gas_per_batch: 50_000_000, + // The pubdata will likely never go below that + max_pubdata_per_batch: 100_000, + }; + + let params = FeeParamsV2 { + config, + l1_gas_price: GIANT_L1_GAS_PRICE, + l1_pubdata_price: GIANT_L1_GAS_PRICE, + }; + + // We'll use scale factor of 3.0 + let input = compute_batch_fee_model_input_v2(params, 3.0, 3.0); + + assert_eq!(input.l1_gas_price, GIANT_L1_GAS_PRICE * 3); + assert_eq!(input.fair_l2_gas_price, 130_000_000_000_000); + assert_eq!(input.fair_pubdata_price, 15_300_000_000_000_000); + } + + #[test] + fn test_compute_batch_fee_model_input_v2_small_numbers() { + // Here we assume that the operator wants to make the lives of users as cheap as possible. + let config = FeeModelConfigV2 { + minimal_l2_gas_price: SMALL_L1_GAS_PRICE, + compute_overhead_part: 0.0, + pubdata_overhead_part: 0.0, + batch_overhead_l1_gas: 0, + max_gas_per_batch: 50_000_000, + max_pubdata_per_batch: 100_000, + }; + + let params = FeeParamsV2 { + config, + l1_gas_price: SMALL_L1_GAS_PRICE, + l1_pubdata_price: SMALL_L1_GAS_PRICE, + }; + + let input = compute_batch_fee_model_input_v2(params, 1.0, 1.0); + + assert_eq!(input.l1_gas_price, SMALL_L1_GAS_PRICE); + assert_eq!(input.fair_l2_gas_price, SMALL_L1_GAS_PRICE); + assert_eq!(input.fair_pubdata_price, SMALL_L1_GAS_PRICE); + } + + #[test] + fn test_compute_batch_fee_model_input_v2_only_pubdata_overhead() { + // Here we use sensible config, but when only pubdata is used to close the batch + let config = FeeModelConfigV2 { + minimal_l2_gas_price: 100_000_000_000, + compute_overhead_part: 0.0, + pubdata_overhead_part: 1.0, + batch_overhead_l1_gas: 700_000, + max_gas_per_batch: 500_000_000, + max_pubdata_per_batch: 100_000, + }; + + let params = FeeParamsV2 { + config, + l1_gas_price: GIANT_L1_GAS_PRICE, + l1_pubdata_price: GIANT_L1_GAS_PRICE, + }; + + let input = compute_batch_fee_model_input_v2(params, 1.0, 1.0); + assert_eq!(input.l1_gas_price, GIANT_L1_GAS_PRICE); + // The fair L2 gas price is identical to the minimal one. + assert_eq!(input.fair_l2_gas_price, 100_000_000_000); + // The fair pubdata price is the minimal one plus the overhead. + assert_eq!(input.fair_pubdata_price, 800_000_000_000_000); + } + + #[test] + fn test_compute_batch_fee_model_input_v2_only_compute_overhead() { + // Here we use sensible config, but when only compute is used to close the batch + let config = FeeModelConfigV2 { + minimal_l2_gas_price: 100_000_000_000, + compute_overhead_part: 1.0, + pubdata_overhead_part: 0.0, + batch_overhead_l1_gas: 700_000, + max_gas_per_batch: 500_000_000, + max_pubdata_per_batch: 100_000, + }; + + let params = FeeParamsV2 { + config, + l1_gas_price: GIANT_L1_GAS_PRICE, + l1_pubdata_price: GIANT_L1_GAS_PRICE, + }; + + let input = compute_batch_fee_model_input_v2(params, 1.0, 1.0); + assert_eq!(input.l1_gas_price, GIANT_L1_GAS_PRICE); + // The fair L2 gas price is identical to the minimal one, plus the overhead + assert_eq!(input.fair_l2_gas_price, 240_000_000_000); + // The fair pubdata price is equal to the original one. + assert_eq!(input.fair_pubdata_price, GIANT_L1_GAS_PRICE); + } + + #[test] + fn test_compute_batch_fee_model_input_v2_param_tweaking() { + // In this test we generally checking that each param behaves as expected + let base_config = FeeModelConfigV2 { + minimal_l2_gas_price: 100_000_000_000, + compute_overhead_part: 0.5, + pubdata_overhead_part: 0.5, + batch_overhead_l1_gas: 700_000, + max_gas_per_batch: 500_000_000, + max_pubdata_per_batch: 100_000, + }; + + let base_params = FeeParamsV2 { + config: base_config, + l1_gas_price: 1_000_000_000, + l1_pubdata_price: 1_000_000_000, + }; + + let base_input = compute_batch_fee_model_input_v2(base_params, 1.0, 1.0); + + let base_input_larger_l1_gas_price = compute_batch_fee_model_input_v2( + FeeParamsV2 { + l1_gas_price: base_params.l1_gas_price * 2, + ..base_params + }, + 1.0, + 1.0, + ); + let base_input_scaled_l1_gas_price = + compute_batch_fee_model_input_v2(base_params, 2.0, 1.0); + assert_eq!( + base_input_larger_l1_gas_price, base_input_scaled_l1_gas_price, + "Scaling has the correct effect for the L1 gas price" + ); + assert!( + base_input.fair_l2_gas_price < base_input_larger_l1_gas_price.fair_l2_gas_price, + "L1 gas price increase raises L2 gas price" + ); + assert!( + base_input.fair_pubdata_price < base_input_larger_l1_gas_price.fair_pubdata_price, + "L1 gas price increase raises pubdata price" + ); + + let base_input_larger_pubdata_price = compute_batch_fee_model_input_v2( + FeeParamsV2 { + l1_pubdata_price: base_params.l1_pubdata_price * 2, + ..base_params + }, + 1.0, + 1.0, + ); + let base_input_scaled_pubdata_price = + compute_batch_fee_model_input_v2(base_params, 1.0, 2.0); + assert_eq!( + base_input_larger_pubdata_price, base_input_scaled_pubdata_price, + "Scaling has the correct effect for the pubdata price" + ); + assert_eq!( + base_input.fair_l2_gas_price, base_input_larger_pubdata_price.fair_l2_gas_price, + "L1 pubdata increase has no effect on L2 gas price" + ); + assert!( + base_input.fair_pubdata_price < base_input_larger_pubdata_price.fair_pubdata_price, + "Pubdata price increase raises pubdata price" + ); + + let base_input_larger_max_gas = compute_batch_fee_model_input_v2( + FeeParamsV2 { + config: FeeModelConfigV2 { + max_gas_per_batch: base_config.max_gas_per_batch * 2, + ..base_config + }, + ..base_params + }, + 1.0, + 1.0, + ); + assert!( + base_input.fair_l2_gas_price > base_input_larger_max_gas.fair_l2_gas_price, + "Max gas increase lowers L2 gas price" + ); + assert_eq!( + base_input.fair_pubdata_price, base_input_larger_max_gas.fair_pubdata_price, + "Max gas increase has no effect on pubdata price" + ); + + let base_input_larger_max_pubdata = compute_batch_fee_model_input_v2( + FeeParamsV2 { + config: FeeModelConfigV2 { + max_pubdata_per_batch: base_config.max_pubdata_per_batch * 2, + ..base_config + }, + ..base_params + }, + 1.0, + 1.0, + ); + assert_eq!( + base_input.fair_l2_gas_price, base_input_larger_max_pubdata.fair_l2_gas_price, + "Max pubdata increase has no effect on L2 gas price" + ); + assert!( + base_input.fair_pubdata_price > base_input_larger_max_pubdata.fair_pubdata_price, + "Max pubdata increase lowers pubdata price" + ); + } +} diff --git a/core/lib/zksync_core/src/gas_tracker/constants.rs b/core/lib/zksync_core/src/gas_tracker/constants.rs index 4eb9475cb0f5..00c96486a72e 100644 --- a/core/lib/zksync_core/src/gas_tracker/constants.rs +++ b/core/lib/zksync_core/src/gas_tracker/constants.rs @@ -1,5 +1,5 @@ -// Currently, every AGGR_* cost is overestimated, -// so there are safety margins around 100_000 -- 200_000 +// Currently, every `AGGR_* cost` is overestimated, +// so there are safety margins around `100_000 -- 200_000` pub(super) const AGGR_L1_BATCH_COMMIT_BASE_COST: u32 = 242_000; pub(super) const AGGR_L1_BATCH_PROVE_BASE_COST: u32 = 1_000_000; diff --git a/core/lib/zksync_core/src/genesis.rs b/core/lib/zksync_core/src/genesis.rs index bba6a2d6744a..9d9021c7c151 100644 --- a/core/lib/zksync_core/src/genesis.rs +++ b/core/lib/zksync_core/src/genesis.rs @@ -3,18 +3,24 @@ //! setups the required databases, and outputs the data required to initialize a smart contract. use anyhow::Context as _; +use multivm::{ + utils::get_max_gas_per_pubdata_byte, + zk_evm_latest::aux_structures::{LogQuery as MultiVmLogQuery, Timestamp as MultiVMTimestamp}, + zkevm_test_harness_latest::witness::sort_storage_access::sort_storage_access_queries, +}; use zksync_contracts::BaseSystemContracts; use zksync_dal::StorageProcessor; use zksync_merkle_tree::domain::ZkSyncTree; use zksync_types::{ block::{BlockGasCount, DeployedContract, L1BatchHeader, MiniblockHasher, MiniblockHeader}, commitment::{L1BatchCommitment, L1BatchMetadata}, + fee_model::BatchFeeInput, get_code_key, get_system_context_init_logs, protocol_version::{L1VerifierConfig, ProtocolVersion}, tokens::{TokenInfo, TokenMetadata, ETHEREUM_ADDRESS}, - zkevm_test_harness::witness::sort_storage_access::sort_storage_access_queries, - AccountTreeId, Address, L1BatchNumber, L2ChainId, LogQuery, MiniblockNumber, ProtocolVersionId, - StorageKey, StorageLog, StorageLogKind, Timestamp, H256, + zk_evm_types::{LogQuery, Timestamp}, + AccountTreeId, Address, L1BatchNumber, L2ChainId, MiniblockNumber, ProtocolVersionId, + StorageKey, StorageLog, StorageLogKind, H256, }; use zksync_utils::{be_words_to_bytes, bytecode::hash_bytecode, h256_to_u256, u256_to_h256}; @@ -107,7 +113,7 @@ pub async fn ensure_genesis_state( vec![], H256::zero(), H256::zero(), - protocol_version.is_pre_boojum(), + *protocol_version, ); save_genesis_l1_batch_metadata( @@ -161,7 +167,8 @@ async fn insert_base_system_contracts_to_factory_deps( storage .storage_dal() .insert_factory_deps(MiniblockNumber(0), &factory_deps) - .await; + .await + .unwrap(); } async fn insert_system_contracts( @@ -195,7 +202,7 @@ async fn insert_system_contracts( // we don't produce proof for the genesis block, // but we still need to populate the table // to have the correct initial state of the merkle tree - let log_queries: Vec = storage_logs + let log_queries: Vec = storage_logs .iter() .enumerate() .flat_map(|(tx_index, (_, storage_logs))| { @@ -203,9 +210,9 @@ async fn insert_system_contracts( .iter() .enumerate() .map(move |(log_index, storage_log)| { - LogQuery { + MultiVmLogQuery { // Monotonically increasing Timestamp. Normally it's generated by the VM, but we don't have a VM in the genesis block. - timestamp: Timestamp(((tx_index << 16) + log_index) as u32), + timestamp: MultiVMTimestamp(((tx_index << 16) + log_index) as u32), tx_number_in_block: tx_index as u16, aux_byte: 0, shard_id: 0, @@ -218,11 +225,27 @@ async fn insert_system_contracts( is_service: false, } }) - .collect::>() + .collect::>() }) .collect(); - let (_, deduped_log_queries) = sort_storage_access_queries(&log_queries); + let deduped_log_queries: Vec = sort_storage_access_queries(&log_queries) + .1 + .into_iter() + .map(|log_query| LogQuery { + timestamp: Timestamp(log_query.timestamp.0), + tx_number_in_block: log_query.tx_number_in_block, + aux_byte: log_query.aux_byte, + shard_id: log_query.shard_id, + address: log_query.address, + key: log_query.key, + read_value: log_query.read_value, + written_value: log_query.written_value, + rw_flag: log_query.rw_flag, + rollback: log_query.rollback, + is_service: log_query.is_service, + }) + .collect(); let (deduplicated_writes, protective_reads): (Vec<_>, Vec<_>) = deduped_log_queries .into_iter() @@ -253,7 +276,8 @@ async fn insert_system_contracts( transaction .storage_dal() .insert_factory_deps(MiniblockNumber(0), &factory_deps) - .await; + .await + .unwrap(); transaction.commit().await.unwrap(); } @@ -278,14 +302,12 @@ pub(crate) async fn create_genesis_l1_batch( tx: None, }; - let mut genesis_l1_batch_header = L1BatchHeader::new( + let genesis_l1_batch_header = L1BatchHeader::new( L1BatchNumber(0), 0, - first_validator_address, base_system_contracts.hashes(), - ProtocolVersionId::latest(), + protocol_version, ); - genesis_l1_batch_header.is_finished = true; let genesis_miniblock_header = MiniblockHeader { number: MiniblockNumber(0), @@ -293,11 +315,12 @@ pub(crate) async fn create_genesis_l1_batch( hash: MiniblockHasher::legacy_hash(MiniblockNumber(0)), l1_tx_count: 0, l2_tx_count: 0, + fee_account_address: first_validator_address, base_fee_per_gas: 0, - l1_gas_price: 0, - l2_fair_gas_price: 0, + gas_per_pubdata_limit: get_max_gas_per_pubdata_byte(protocol_version.into()), + batch_fee_input: BatchFeeInput::l1_pegged(0, 0), base_system_contracts_hashes: base_system_contracts.hashes(), - protocol_version: Some(ProtocolVersionId::latest()), + protocol_version: Some(protocol_version), virtual_blocks: 0, }; @@ -315,6 +338,7 @@ pub(crate) async fn create_genesis_l1_batch( BlockGasCount::default(), &[], &[], + Default::default(), ) .await .unwrap(); @@ -437,7 +461,7 @@ mod tests { #[tokio::test] async fn running_genesis_with_big_chain_id() { let pool = ConnectionPool::test_pool().await; - let mut conn: StorageProcessor<'_> = pool.access_storage().await.unwrap(); + let mut conn = pool.access_storage().await.unwrap(); conn.blocks_dal().delete_genesis().await.unwrap(); let params = GenesisParams { @@ -460,4 +484,19 @@ mod tests { let root_hash = metadata.unwrap().unwrap().metadata.root_hash; assert_ne!(root_hash, H256::zero()); } + + #[tokio::test] + async fn running_genesis_with_non_latest_protocol_version() { + let pool = ConnectionPool::test_pool().await; + let mut conn = pool.access_storage().await.unwrap(); + let params = GenesisParams { + protocol_version: ProtocolVersionId::Version10, + ..GenesisParams::mock() + }; + + ensure_genesis_state(&mut conn, L2ChainId::max(), ¶ms) + .await + .unwrap(); + assert!(!conn.blocks_dal().is_genesis_needed().await.unwrap()); + } } diff --git a/core/lib/zksync_core/src/house_keeper/blocks_state_reporter.rs b/core/lib/zksync_core/src/house_keeper/blocks_state_reporter.rs index 2ed1f97fee71..695c2008e134 100644 --- a/core/lib/zksync_core/src/house_keeper/blocks_state_reporter.rs +++ b/core/lib/zksync_core/src/house_keeper/blocks_state_reporter.rs @@ -1,9 +1,11 @@ use async_trait::async_trait; use zksync_dal::ConnectionPool; -use zksync_prover_utils::periodic_job::PeriodicJob; use zksync_utils::time::seconds_since_epoch; -use crate::metrics::{BlockL1Stage, BlockStage, L1StageLatencyLabel, APP_METRICS}; +use crate::{ + house_keeper::periodic_job::PeriodicJob, + metrics::{BlockL1Stage, BlockStage, L1StageLatencyLabel, APP_METRICS}, +}; #[derive(Debug)] pub struct L1BatchMetricsReporter { @@ -20,14 +22,16 @@ impl L1BatchMetricsReporter { } async fn report_metrics(&self) { + let mut block_metrics = vec![]; let mut conn = self.connection_pool.access_storage().await.unwrap(); - let mut block_metrics = vec![( - conn.blocks_dal() - .get_sealed_l1_batch_number() - .await - .unwrap(), - BlockStage::Sealed, - )]; + let last_l1_batch = conn + .blocks_dal() + .get_sealed_l1_batch_number() + .await + .unwrap(); + if let Some(number) = last_l1_batch { + block_metrics.push((number, BlockStage::Sealed)); + } let last_l1_batch_with_metadata = conn .blocks_dal() diff --git a/core/lib/zksync_core/src/house_keeper/fri_proof_compressor_job_retry_manager.rs b/core/lib/zksync_core/src/house_keeper/fri_proof_compressor_job_retry_manager.rs index fc26524e992e..7cf2c231b67a 100644 --- a/core/lib/zksync_core/src/house_keeper/fri_proof_compressor_job_retry_manager.rs +++ b/core/lib/zksync_core/src/house_keeper/fri_proof_compressor_job_retry_manager.rs @@ -2,7 +2,8 @@ use std::time::Duration; use async_trait::async_trait; use zksync_dal::ConnectionPool; -use zksync_prover_utils::periodic_job::PeriodicJob; + +use crate::house_keeper::periodic_job::PeriodicJob; #[derive(Debug)] pub struct FriProofCompressorJobRetryManager { diff --git a/core/lib/zksync_core/src/house_keeper/fri_proof_compressor_queue_monitor.rs b/core/lib/zksync_core/src/house_keeper/fri_proof_compressor_queue_monitor.rs index 73c752b69558..0039b32bc77c 100644 --- a/core/lib/zksync_core/src/house_keeper/fri_proof_compressor_queue_monitor.rs +++ b/core/lib/zksync_core/src/house_keeper/fri_proof_compressor_queue_monitor.rs @@ -1,7 +1,7 @@ use async_trait::async_trait; -use zksync_dal::ConnectionPool; -use zksync_prover_utils::periodic_job::PeriodicJob; -use zksync_types::proofs::JobCountStatistics; +use zksync_dal::{fri_prover_dal::types::JobCountStatistics, ConnectionPool}; + +use crate::house_keeper::periodic_job::PeriodicJob; const PROOF_COMPRESSOR_SERVICE_NAME: &str = "proof_compressor"; diff --git a/core/lib/zksync_core/src/house_keeper/fri_prover_job_retry_manager.rs b/core/lib/zksync_core/src/house_keeper/fri_prover_job_retry_manager.rs index fefb7333a675..8ff847a5ca92 100644 --- a/core/lib/zksync_core/src/house_keeper/fri_prover_job_retry_manager.rs +++ b/core/lib/zksync_core/src/house_keeper/fri_prover_job_retry_manager.rs @@ -2,7 +2,8 @@ use std::time::Duration; use async_trait::async_trait; use zksync_dal::ConnectionPool; -use zksync_prover_utils::periodic_job::PeriodicJob; + +use crate::house_keeper::periodic_job::PeriodicJob; #[derive(Debug)] pub struct FriProverJobRetryManager { diff --git a/core/lib/zksync_core/src/house_keeper/fri_prover_queue_monitor.rs b/core/lib/zksync_core/src/house_keeper/fri_prover_queue_monitor.rs index f0ccf0be7333..90f90759b323 100644 --- a/core/lib/zksync_core/src/house_keeper/fri_prover_queue_monitor.rs +++ b/core/lib/zksync_core/src/house_keeper/fri_prover_queue_monitor.rs @@ -1,7 +1,8 @@ use async_trait::async_trait; use zksync_config::configs::fri_prover_group::FriProverGroupConfig; use zksync_dal::ConnectionPool; -use zksync_prover_utils::periodic_job::PeriodicJob; + +use crate::house_keeper::periodic_job::PeriodicJob; #[derive(Debug)] pub struct FriProverStatsReporter { @@ -38,11 +39,11 @@ impl PeriodicJob for FriProverStatsReporter { for ((circuit_id, aggregation_round), stats) in stats.into_iter() { // BEWARE, HERE BE DRAGONS. - // In database, the circuit_id stored is the circuit for which the aggregation is done, + // In database, the `circuit_id` stored is the circuit for which the aggregation is done, // not the circuit which is running. // There is a single node level aggregation circuit, which is circuit 2. // This can aggregate multiple leaf nodes (which may belong to different circuits). - // This reporting is a hacky forced way to use circuit_id 2 which will solve autoscalers. + // This reporting is a hacky forced way to use `circuit_id` 2 which will solve auto scalers. // A proper fix will be later provided to solve this at database level. let circuit_id = if aggregation_round == 2 { 2 @@ -90,13 +91,24 @@ impl PeriodicJob for FriProverStatsReporter { let mut db_conn = self.db_connection_pool.access_storage().await.unwrap(); - if let Some(l1_batch_number) = db_conn + let oldest_unpicked_batch = match db_conn .proof_generation_dal() .get_oldest_unpicked_batch() .await { - metrics::gauge!("fri_prover.oldest_unpicked_batch", l1_batch_number.0 as f64) - } + Some(l1_batch_number) => l1_batch_number.0 as f64, + // if there is no unpicked batch in database, we use sealed batch number as a result + None => { + db_conn + .blocks_dal() + .get_sealed_l1_batch_number() + .await + .unwrap() + .unwrap() + .0 as f64 + } + }; + metrics::gauge!("fri_prover.oldest_unpicked_batch", oldest_unpicked_batch); if let Some(l1_batch_number) = db_conn .proof_generation_dal() diff --git a/core/lib/zksync_core/src/house_keeper/fri_scheduler_circuit_queuer.rs b/core/lib/zksync_core/src/house_keeper/fri_scheduler_circuit_queuer.rs index 0adfdb470551..70911339a8fd 100644 --- a/core/lib/zksync_core/src/house_keeper/fri_scheduler_circuit_queuer.rs +++ b/core/lib/zksync_core/src/house_keeper/fri_scheduler_circuit_queuer.rs @@ -1,6 +1,7 @@ use async_trait::async_trait; use zksync_dal::ConnectionPool; -use zksync_prover_utils::periodic_job::PeriodicJob; + +use crate::house_keeper::periodic_job::PeriodicJob; #[derive(Debug)] pub struct SchedulerCircuitQueuer { diff --git a/core/lib/zksync_core/src/house_keeper/fri_witness_generator_jobs_retry_manager.rs b/core/lib/zksync_core/src/house_keeper/fri_witness_generator_jobs_retry_manager.rs index f81cb03dc379..3aa21bdd534d 100644 --- a/core/lib/zksync_core/src/house_keeper/fri_witness_generator_jobs_retry_manager.rs +++ b/core/lib/zksync_core/src/house_keeper/fri_witness_generator_jobs_retry_manager.rs @@ -2,7 +2,8 @@ use std::time::Duration; use async_trait::async_trait; use zksync_dal::ConnectionPool; -use zksync_prover_utils::periodic_job::PeriodicJob; + +use crate::house_keeper::periodic_job::PeriodicJob; #[derive(Debug)] pub struct FriWitnessGeneratorJobRetryManager { diff --git a/core/lib/zksync_core/src/house_keeper/fri_witness_generator_queue_monitor.rs b/core/lib/zksync_core/src/house_keeper/fri_witness_generator_queue_monitor.rs index 67f81295b44f..cf1cdc90314e 100644 --- a/core/lib/zksync_core/src/house_keeper/fri_witness_generator_queue_monitor.rs +++ b/core/lib/zksync_core/src/house_keeper/fri_witness_generator_queue_monitor.rs @@ -1,9 +1,10 @@ use std::collections::HashMap; use async_trait::async_trait; -use zksync_dal::ConnectionPool; -use zksync_prover_utils::periodic_job::PeriodicJob; -use zksync_types::proofs::{AggregationRound, JobCountStatistics}; +use zksync_dal::{fri_prover_dal::types::JobCountStatistics, ConnectionPool}; +use zksync_types::basic_fri_types::AggregationRound; + +use crate::house_keeper::periodic_job::PeriodicJob; const FRI_WITNESS_GENERATOR_SERVICE_NAME: &str = "fri_witness_generator"; diff --git a/core/lib/zksync_core/src/house_keeper/gpu_prover_queue_monitor.rs b/core/lib/zksync_core/src/house_keeper/gpu_prover_queue_monitor.rs deleted file mode 100644 index ab96b52bedc9..000000000000 --- a/core/lib/zksync_core/src/house_keeper/gpu_prover_queue_monitor.rs +++ /dev/null @@ -1,66 +0,0 @@ -use async_trait::async_trait; -use zksync_dal::ConnectionPool; -use zksync_prover_utils::periodic_job::PeriodicJob; - -#[derive(Debug)] -pub struct GpuProverQueueMonitor { - synthesizer_per_gpu: u16, - reporting_interval_ms: u64, - prover_connection_pool: ConnectionPool, -} - -impl GpuProverQueueMonitor { - pub fn new( - synthesizer_per_gpu: u16, - reporting_interval_ms: u64, - prover_connection_pool: ConnectionPool, - ) -> Self { - Self { - synthesizer_per_gpu, - reporting_interval_ms, - prover_connection_pool, - } - } -} - -/// Invoked periodically to push prover job statistics to Prometheus -/// Note: these values will be used for auto-scaling circuit-synthesizer -#[async_trait] -impl PeriodicJob for GpuProverQueueMonitor { - const SERVICE_NAME: &'static str = "GpuProverQueueMonitor"; - - async fn run_routine_task(&mut self) -> anyhow::Result<()> { - let prover_gpu_count_per_region_zone = self - .prover_connection_pool - .access_storage() - .await - .unwrap() - .gpu_prover_queue_dal() - .get_prover_gpu_count_per_region_zone() - .await; - - for ((region, zone), num_gpu) in prover_gpu_count_per_region_zone { - let synthesizers = self.synthesizer_per_gpu as u64 * num_gpu; - if synthesizers > 0 { - tracing::info!( - "Would be spawning {} circuit synthesizers in region {} zone {}", - synthesizers, - region, - zone - ); - } - metrics::gauge!( - "server.circuit_synthesizer.jobs", - synthesizers as f64, - "region" => region, - "zone" => zone, - "type" => "queued" - ); - } - Ok(()) - } - - fn polling_interval_ms(&self) -> u64 { - self.reporting_interval_ms - } -} diff --git a/core/lib/zksync_core/src/house_keeper/mod.rs b/core/lib/zksync_core/src/house_keeper/mod.rs index b4a5a3047321..2c029d42e779 100644 --- a/core/lib/zksync_core/src/house_keeper/mod.rs +++ b/core/lib/zksync_core/src/house_keeper/mod.rs @@ -6,7 +6,5 @@ pub mod fri_prover_queue_monitor; pub mod fri_scheduler_circuit_queuer; pub mod fri_witness_generator_jobs_retry_manager; pub mod fri_witness_generator_queue_monitor; -pub mod gpu_prover_queue_monitor; -pub mod prover_job_retry_manager; -pub mod prover_queue_monitor; +pub mod periodic_job; pub mod waiting_to_queued_fri_witness_job_mover; diff --git a/core/lib/prover_utils/src/periodic_job.rs b/core/lib/zksync_core/src/house_keeper/periodic_job.rs similarity index 97% rename from core/lib/prover_utils/src/periodic_job.rs rename to core/lib/zksync_core/src/house_keeper/periodic_job.rs index e58ff33e7890..3f73a01ce200 100644 --- a/core/lib/prover_utils/src/periodic_job.rs +++ b/core/lib/zksync_core/src/house_keeper/periodic_job.rs @@ -1,6 +1,6 @@ use std::time::Duration; -use anyhow::Context as _; +use anyhow::Context; use async_trait::async_trait; use tokio::time::sleep; diff --git a/core/lib/zksync_core/src/house_keeper/prover_job_retry_manager.rs b/core/lib/zksync_core/src/house_keeper/prover_job_retry_manager.rs deleted file mode 100644 index f7b630475ea0..000000000000 --- a/core/lib/zksync_core/src/house_keeper/prover_job_retry_manager.rs +++ /dev/null @@ -1,56 +0,0 @@ -use std::time::Duration; - -use async_trait::async_trait; -use zksync_dal::ConnectionPool; -use zksync_prover_utils::periodic_job::PeriodicJob; - -#[derive(Debug)] -pub struct ProverJobRetryManager { - max_attempts: u32, - processing_timeout: Duration, - retry_interval_ms: u64, - prover_connection_pool: ConnectionPool, -} - -impl ProverJobRetryManager { - pub fn new( - max_attempts: u32, - processing_timeout: Duration, - retry_interval_ms: u64, - prover_connection_pool: ConnectionPool, - ) -> Self { - Self { - max_attempts, - processing_timeout, - retry_interval_ms, - prover_connection_pool, - } - } -} - -/// Invoked periodically to re-queue stuck prover jobs. -#[async_trait] -impl PeriodicJob for ProverJobRetryManager { - const SERVICE_NAME: &'static str = "ProverJobRetryManager"; - - async fn run_routine_task(&mut self) -> anyhow::Result<()> { - let stuck_jobs = self - .prover_connection_pool - .access_storage() - .await - .unwrap() - .prover_dal() - .requeue_stuck_jobs(self.processing_timeout, self.max_attempts) - .await; - let job_len = stuck_jobs.len(); - for stuck_job in stuck_jobs { - tracing::info!("re-queuing prover job {:?}", stuck_job); - } - metrics::counter!("server.prover.requeued_jobs", job_len as u64); - Ok(()) - } - - fn polling_interval_ms(&self) -> u64 { - self.retry_interval_ms - } -} diff --git a/core/lib/zksync_core/src/house_keeper/prover_queue_monitor.rs b/core/lib/zksync_core/src/house_keeper/prover_queue_monitor.rs deleted file mode 100644 index e0f598d5a590..000000000000 --- a/core/lib/zksync_core/src/house_keeper/prover_queue_monitor.rs +++ /dev/null @@ -1,82 +0,0 @@ -use async_trait::async_trait; -use zksync_config::configs::ProverGroupConfig; -use zksync_dal::ConnectionPool; -use zksync_prover_utils::{circuit_name_to_numeric_index, periodic_job::PeriodicJob}; - -#[derive(Debug)] -pub struct ProverStatsReporter { - reporting_interval_ms: u64, - prover_connection_pool: ConnectionPool, - config: ProverGroupConfig, -} - -impl ProverStatsReporter { - pub fn new( - reporting_interval_ms: u64, - prover_connection_pool: ConnectionPool, - config: ProverGroupConfig, - ) -> Self { - Self { - reporting_interval_ms, - prover_connection_pool, - config, - } - } -} - -/// Invoked periodically to push job statistics to Prometheus -/// Note: these values will be used for manually scaling provers. -#[async_trait] -impl PeriodicJob for ProverStatsReporter { - const SERVICE_NAME: &'static str = "ProverStatsReporter"; - - async fn run_routine_task(&mut self) -> anyhow::Result<()> { - let mut conn = self.prover_connection_pool.access_storage().await.unwrap(); - let stats = conn.prover_dal().get_prover_jobs_stats_per_circuit().await; - - for (circuit_name, stats) in stats.into_iter() { - let group_id = self - .config - .get_group_id_for_circuit_id(circuit_name_to_numeric_index(&circuit_name).unwrap()) - .unwrap(); - - metrics::gauge!( - "server.prover.jobs", - stats.queued as f64, - "type" => "queued", - "prover_group_id" => group_id.to_string(), - "circuit_name" => circuit_name.clone(), - "circuit_type" => circuit_name_to_numeric_index(&circuit_name).unwrap().to_string() - ); - - metrics::gauge!( - "server.prover.jobs", - stats.in_progress as f64, - "type" => "in_progress", - "prover_group_id" => group_id.to_string(), - "circuit_name" => circuit_name.clone(), - "circuit_type" => circuit_name_to_numeric_index(&circuit_name).unwrap().to_string() - ); - } - - if let Some(min_unproved_l1_batch_number) = - conn.prover_dal().min_unproved_l1_batch_number().await - { - metrics::gauge!("server.block_number", min_unproved_l1_batch_number.0 as f64, "stage" => "circuit_aggregation") - } - - let lag_by_circuit_type = conn - .prover_dal() - .min_unproved_l1_batch_number_by_basic_circuit_type() - .await; - - for (circuit_type, l1_batch_number) in lag_by_circuit_type { - metrics::gauge!("server.block_number", l1_batch_number.0 as f64, "stage" => format!("circuit_{}", circuit_type)); - } - Ok(()) - } - - fn polling_interval_ms(&self) -> u64 { - self.reporting_interval_ms - } -} diff --git a/core/lib/zksync_core/src/house_keeper/waiting_to_queued_fri_witness_job_mover.rs b/core/lib/zksync_core/src/house_keeper/waiting_to_queued_fri_witness_job_mover.rs index 1292ee3f44fa..df9208f1f451 100644 --- a/core/lib/zksync_core/src/house_keeper/waiting_to_queued_fri_witness_job_mover.rs +++ b/core/lib/zksync_core/src/house_keeper/waiting_to_queued_fri_witness_job_mover.rs @@ -1,6 +1,7 @@ use async_trait::async_trait; use zksync_dal::ConnectionPool; -use zksync_prover_utils::periodic_job::PeriodicJob; + +use crate::house_keeper::periodic_job::PeriodicJob; #[derive(Debug)] pub struct WaitingToQueuedFriWitnessJobMover { diff --git a/core/lib/zksync_core/src/house_keeper/waiting_to_queued_witness_job_mover.rs b/core/lib/zksync_core/src/house_keeper/waiting_to_queued_witness_job_mover.rs deleted file mode 100644 index 4521b4bfc47b..000000000000 --- a/core/lib/zksync_core/src/house_keeper/waiting_to_queued_witness_job_mover.rs +++ /dev/null @@ -1,95 +0,0 @@ -use async_trait::async_trait; -use zksync_dal::ConnectionPool; -use zksync_prover_utils::periodic_job::PeriodicJob; - -#[derive(Debug)] -pub struct WaitingToQueuedWitnessJobMover { - job_moving_interval_ms: u64, - prover_connection_pool: ConnectionPool, -} - -impl WaitingToQueuedWitnessJobMover { - pub fn new(job_mover_interval_ms: u64, prover_connection_pool: ConnectionPool) -> Self { - Self { - job_moving_interval_ms: job_mover_interval_ms, - prover_connection_pool, - } - } - - async fn move_jobs(&mut self) { - self.move_leaf_aggregation_jobs().await; - self.move_node_aggregation_jobs().await; - self.move_scheduler_jobs().await; - } - - async fn move_leaf_aggregation_jobs(&mut self) { - let mut conn = self.prover_connection_pool.access_storage().await.unwrap(); - let l1_batch_numbers = conn - .witness_generator_dal() - .move_leaf_aggregation_jobs_from_waiting_to_queued() - .await; - let len = l1_batch_numbers.len(); - for l1_batch_number in l1_batch_numbers { - tracing::info!( - "Marked leaf aggregation job for l1_batch {} as queued", - l1_batch_number - ); - } - metrics::counter!( - "server.leaf_witness_generator.waiting_to_queued_jobs_transitions", - len as u64 - ); - } - - async fn move_node_aggregation_jobs(&mut self) { - let mut conn = self.prover_connection_pool.access_storage().await.unwrap(); - let l1_batch_numbers = conn - .witness_generator_dal() - .move_node_aggregation_jobs_from_waiting_to_queued() - .await; - let len = l1_batch_numbers.len(); - for l1_batch_number in l1_batch_numbers { - tracing::info!( - "Marking node aggregation job for l1_batch {} as queued", - l1_batch_number - ); - } - metrics::counter!( - "server.node_witness_generator.waiting_to_queued_jobs_transitions", - len as u64 - ); - } - - async fn move_scheduler_jobs(&mut self) { - let mut conn = self.prover_connection_pool.access_storage().await.unwrap(); - let l1_batch_numbers = conn - .witness_generator_dal() - .move_scheduler_jobs_from_waiting_to_queued() - .await; - let len = l1_batch_numbers.len(); - for l1_batch_number in l1_batch_numbers { - tracing::info!( - "Marking scheduler aggregation job for l1_batch {} as queued", - l1_batch_number - ); - } - metrics::counter!( - "server.scheduler_witness_generator.waiting_to_queued_jobs_transitions", - len as u64 - ); - } -} - -#[async_trait] -impl PeriodicJob for WaitingToQueuedWitnessJobMover { - const SERVICE_NAME: &'static str = "WaitingToQueuedWitnessJobMover"; - - async fn run_routine_task(&mut self) -> anyhow::Result<()> { - self.move_jobs().await; - Ok(()) - } - - fn polling_interval_ms(&self) -> u64 { - self.job_moving_interval_ms - } -} diff --git a/core/lib/zksync_core/src/house_keeper/witness_generator_queue_monitor.rs b/core/lib/zksync_core/src/house_keeper/witness_generator_queue_monitor.rs deleted file mode 100644 index da816da3c668..000000000000 --- a/core/lib/zksync_core/src/house_keeper/witness_generator_queue_monitor.rs +++ /dev/null @@ -1,121 +0,0 @@ -use std::collections::HashMap; - -use async_trait::async_trait; -use zksync_dal::ConnectionPool; -use zksync_prover_utils::periodic_job::PeriodicJob; -use zksync_types::proofs::{AggregationRound, JobCountStatistics}; - -const WITNESS_GENERATOR_SERVICE_NAME: &str = "witness_generator"; - -#[derive(Debug)] -pub struct WitnessGeneratorStatsReporter { - reporting_interval_ms: u64, - prover_connection_pool: ConnectionPool, -} - -impl WitnessGeneratorStatsReporter { - pub fn new(reporting_interval_ms: u64, prover_connection_pool: ConnectionPool) -> Self { - Self { - reporting_interval_ms, - prover_connection_pool, - } - } - - async fn get_job_statistics( - prover_connection_pool: &ConnectionPool, - ) -> HashMap { - let mut conn = prover_connection_pool.access_storage().await.unwrap(); - HashMap::from([ - ( - AggregationRound::BasicCircuits, - conn.witness_generator_dal() - .get_witness_jobs_stats(AggregationRound::BasicCircuits) - .await, - ), - ( - AggregationRound::LeafAggregation, - conn.witness_generator_dal() - .get_witness_jobs_stats(AggregationRound::LeafAggregation) - .await, - ), - ( - AggregationRound::NodeAggregation, - conn.witness_generator_dal() - .get_witness_jobs_stats(AggregationRound::NodeAggregation) - .await, - ), - ( - AggregationRound::Scheduler, - conn.witness_generator_dal() - .get_witness_jobs_stats(AggregationRound::Scheduler) - .await, - ), - ]) - } -} - -fn emit_metrics_for_round(round: AggregationRound, stats: JobCountStatistics) { - if stats.queued > 0 || stats.in_progress > 0 { - tracing::trace!( - "Found {} free and {} in progress {:?} witness generators jobs", - stats.queued, - stats.in_progress, - round - ); - } - - metrics::gauge!( - format!("server.{}.jobs", WITNESS_GENERATOR_SERVICE_NAME), - stats.queued as f64, - "type" => "queued", - "round" => format!("{:?}", round) - ); - - metrics::gauge!( - format!("server.{}.jobs", WITNESS_GENERATOR_SERVICE_NAME), - stats.in_progress as f64, - "type" => "in_progress", - "round" => format!("{:?}", round) - ); -} - -/// Invoked periodically to push job statistics to Prometheus -/// Note: these values will be used for auto-scaling job processors -#[async_trait] -impl PeriodicJob for WitnessGeneratorStatsReporter { - const SERVICE_NAME: &'static str = "WitnessGeneratorStatsReporter"; - - async fn run_routine_task(&mut self) -> anyhow::Result<()> { - let stats_for_all_rounds = Self::get_job_statistics(&self.prover_connection_pool).await; - let mut aggregated = JobCountStatistics::default(); - for (round, stats) in stats_for_all_rounds { - emit_metrics_for_round(round, stats); - aggregated = aggregated + stats; - } - - if aggregated.queued > 0 { - tracing::trace!( - "Found {} free {} in progress witness generators jobs", - aggregated.queued, - aggregated.in_progress - ); - } - - metrics::gauge!( - format!("server.{}.jobs", WITNESS_GENERATOR_SERVICE_NAME), - aggregated.queued as f64, - "type" => "queued" - ); - - metrics::gauge!( - format!("server.{}.jobs", WITNESS_GENERATOR_SERVICE_NAME), - aggregated.in_progress as f64, - "type" => "in_progress" - ); - Ok(()) - } - - fn polling_interval_ms(&self) -> u64 { - self.reporting_interval_ms - } -} diff --git a/core/lib/zksync_core/src/l1_gas_price/gas_adjuster/mod.rs b/core/lib/zksync_core/src/l1_gas_price/gas_adjuster/mod.rs index 8fce05f02e3b..ac5d04134384 100644 --- a/core/lib/zksync_core/src/l1_gas_price/gas_adjuster/mod.rs +++ b/core/lib/zksync_core/src/l1_gas_price/gas_adjuster/mod.rs @@ -7,7 +7,8 @@ use std::{ use tokio::sync::watch; use zksync_config::GasAdjusterConfig; -use zksync_eth_client::{types::Error, EthInterface}; +use zksync_eth_client::{Error, EthInterface}; +use zksync_system_constants::L1_GAS_PER_PUBDATA_BYTE; use self::metrics::METRICS; use super::{L1GasPriceProvider, L1TxParamsProvider}; @@ -126,6 +127,11 @@ impl L1GasPriceProvider for GasAdjuster { // Bound the price if it's too high. self.bound_gas_price(calculated_price) } + + fn estimate_effective_pubdata_price(&self) -> u64 { + // For now, pubdata is only sent via calldata, so its price is pegged to the L1 gas price. + self.estimate_effective_gas_price() * L1_GAS_PER_PUBDATA_BYTE as u64 + } } impl L1TxParamsProvider for GasAdjuster { @@ -141,7 +147,7 @@ impl L1TxParamsProvider for GasAdjuster { // Currently we use an exponential formula. // The alternative is a linear one: - // let scale_factor = a + b * time_in_mempool as f64; + // `let scale_factor = a + b * time_in_mempool as f64;` let scale_factor = a * b.powf(time_in_mempool as f64); let median = self.statistics.median(); METRICS.median_base_fee_per_gas.set(median); @@ -158,11 +164,11 @@ impl L1TxParamsProvider for GasAdjuster { // Priority fee is set to constant, sourced from config. // Reasoning behind this is the following: - // High priority_fee means high demand for block space, - // which means base_fee will increase, which means priority_fee + // High `priority_fee` means high demand for block space, + // which means `base_fee` will increase, which means `priority_fee` // will decrease. The EIP-1559 mechanism is designed such that - // base_fee will balance out priority_fee in such a way that - // priority_fee will be a small fraction of the overall fee. + // `base_fee` will balance out `priority_fee` in such a way that + // `priority_fee` will be a small fraction of the overall fee. fn get_priority_fee(&self) -> u64 { self.config.default_priority_fee_per_gas } diff --git a/core/lib/zksync_core/src/l1_gas_price/gas_adjuster/tests.rs b/core/lib/zksync_core/src/l1_gas_price/gas_adjuster/tests.rs index 84ace37ecec4..2feb65f1cbd5 100644 --- a/core/lib/zksync_core/src/l1_gas_price/gas_adjuster/tests.rs +++ b/core/lib/zksync_core/src/l1_gas_price/gas_adjuster/tests.rs @@ -1,7 +1,7 @@ use std::{collections::VecDeque, sync::Arc}; use zksync_config::GasAdjusterConfig; -use zksync_eth_client::clients::mock::MockEthereum; +use zksync_eth_client::clients::MockEthereum; use super::{GasAdjuster, GasStatisticsInner}; diff --git a/core/lib/zksync_core/src/l1_gas_price/main_node_fetcher.rs b/core/lib/zksync_core/src/l1_gas_price/main_node_fetcher.rs index a3f7b92f0e46..04555728241c 100644 --- a/core/lib/zksync_core/src/l1_gas_price/main_node_fetcher.rs +++ b/core/lib/zksync_core/src/l1_gas_price/main_node_fetcher.rs @@ -1,18 +1,16 @@ use std::{ - sync::{ - atomic::{AtomicU64, Ordering}, - Arc, - }, + sync::{Arc, RwLock}, time::Duration, }; use tokio::sync::watch::Receiver; +use zksync_types::fee_model::FeeParams; use zksync_web3_decl::{ jsonrpsee::http_client::{HttpClient, HttpClientBuilder}, namespaces::ZksNamespaceClient, }; -use super::L1GasPriceProvider; +use crate::fee_model::BatchFeeModelInputProvider; const SLEEP_INTERVAL: Duration = Duration::from_secs(5); @@ -23,16 +21,16 @@ const SLEEP_INTERVAL: Duration = Duration::from_secs(5); /// The same algorithm cannot be consistently replicated on the external node side, /// since it relies on the configuration, which may change. #[derive(Debug)] -pub struct MainNodeGasPriceFetcher { +pub struct MainNodeFeeParamsFetcher { client: HttpClient, - gas_price: AtomicU64, + main_node_fee_params: RwLock, } -impl MainNodeGasPriceFetcher { +impl MainNodeFeeParamsFetcher { pub fn new(main_node_url: &str) -> Self { Self { client: Self::build_client(main_node_url), - gas_price: AtomicU64::new(1u64), // Start with 1 wei until the first update. + main_node_fee_params: RwLock::new(FeeParams::sensible_v1_default()), } } @@ -45,11 +43,11 @@ impl MainNodeGasPriceFetcher { pub async fn run(self: Arc, stop_receiver: Receiver) -> anyhow::Result<()> { loop { if *stop_receiver.borrow() { - tracing::info!("Stop signal received, MainNodeGasPriceFetcher is shutting down"); + tracing::info!("Stop signal received, MainNodeFeeParamsFetcher is shutting down"); break; } - let main_node_gas_price = match self.client.get_l1_gas_price().await { + let main_node_fee_params = match self.client.get_fee_params().await { Ok(price) => price, Err(err) => { tracing::warn!("Unable to get the gas price: {}", err); @@ -58,16 +56,16 @@ impl MainNodeGasPriceFetcher { continue; } }; - self.gas_price - .store(main_node_gas_price.as_u64(), Ordering::Relaxed); + *self.main_node_fee_params.write().unwrap() = main_node_fee_params; + tokio::time::sleep(SLEEP_INTERVAL).await; } Ok(()) } } -impl L1GasPriceProvider for MainNodeGasPriceFetcher { - fn estimate_effective_gas_price(&self) -> u64 { - self.gas_price.load(Ordering::Relaxed) +impl BatchFeeModelInputProvider for MainNodeFeeParamsFetcher { + fn get_fee_model_params(&self) -> FeeParams { + *self.main_node_fee_params.read().unwrap() } } diff --git a/core/lib/zksync_core/src/l1_gas_price/mod.rs b/core/lib/zksync_core/src/l1_gas_price/mod.rs index c2e5ab8adb7c..3ed508328c4d 100644 --- a/core/lib/zksync_core/src/l1_gas_price/mod.rs +++ b/core/lib/zksync_core/src/l1_gas_price/mod.rs @@ -1,7 +1,9 @@ //! This module determines the fees to pay in txs containing blocks submitted to the L1. +use std::fmt; + pub use gas_adjuster::GasAdjuster; -pub use main_node_fetcher::MainNodeGasPriceFetcher; +pub use main_node_fetcher::MainNodeFeeParamsFetcher; pub use singleton::GasAdjusterSingleton; mod gas_adjuster; @@ -10,10 +12,15 @@ pub mod singleton; /// Abstraction that provides information about the L1 gas price currently /// observed by the application. -pub trait L1GasPriceProvider { +pub trait L1GasPriceProvider: fmt::Debug + 'static + Send + Sync { /// Returns a best guess of a realistic value for the L1 gas price. /// Return value is in wei. fn estimate_effective_gas_price(&self) -> u64; + + /// Returns a best guess of a realistic value for the L1 pubdata price. + /// Note that starting with EIP4844 it will become independent from the gas price. + /// Return value is in wei. + fn estimate_effective_pubdata_price(&self) -> u64; } /// Extended version of `L1GasPriceProvider` that can provide parameters diff --git a/core/lib/zksync_core/src/l1_gas_price/singleton.rs b/core/lib/zksync_core/src/l1_gas_price/singleton.rs index d4d04c196961..639f00c52b95 100644 --- a/core/lib/zksync_core/src/l1_gas_price/singleton.rs +++ b/core/lib/zksync_core/src/l1_gas_price/singleton.rs @@ -6,7 +6,7 @@ use tokio::{ task::JoinHandle, }; use zksync_config::GasAdjusterConfig; -use zksync_eth_client::clients::http::QueryClient; +use zksync_eth_client::clients::QueryClient; use crate::l1_gas_price::GasAdjuster; diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index 67eac97d196f..cd1cb7b7f0ce 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -3,6 +3,7 @@ use std::{net::Ipv4Addr, str::FromStr, sync::Arc, time::Instant}; use anyhow::Context as _; +use fee_model::{ApiFeeInputProvider, MainNodeFeeInputProvider}; use futures::channel::oneshot; use prometheus_exporter::PrometheusExporterConfig; use temp_config_store::TempConfigStore; @@ -11,6 +12,7 @@ use zksync_circuit_breaker::{ l1_txs::FailedL1TransactionChecker, replication_lag::ReplicationLagChecker, CircuitBreaker, CircuitBreakerChecker, CircuitBreakerError, }; +use zksync_concurrency::{ctx, scope}; use zksync_config::{ configs::{ api::{MerkleTreeApiConfig, Web3JsonRpcConfig}, @@ -19,24 +21,25 @@ use zksync_config::{ StateKeeperConfig, }, contracts::ProverAtGenesis, - database::MerkleTreeMode, + database::{MerkleTreeConfig, MerkleTreeMode}, }, ApiConfig, ContractsConfig, DBConfig, ETHSenderConfig, PostgresConfig, }; use zksync_contracts::{governance_contract, BaseSystemContracts}; use zksync_dal::{healthcheck::ConnectionPoolHealthCheck, ConnectionPool}; use zksync_eth_client::{ - clients::http::{PKSigningClient, QueryClient}, - BoundEthInterface, EthInterface, + clients::{PKSigningClient, QueryClient}, + BoundEthInterface, CallFunctionArgs, EthInterface, }; use zksync_health_check::{CheckHealth, HealthStatus, ReactiveHealthCheck}; use zksync_object_store::{ObjectStore, ObjectStoreFactory}; -use zksync_prover_utils::periodic_job::PeriodicJob; use zksync_queued_job_processor::JobProcessor; use zksync_state::PostgresStorageCaches; use zksync_types::{ + fee_model::FeeModelConfig, protocol_version::{L1VerifierConfig, VerifierParams}, system_contracts::get_system_smart_contracts, + web3::contract::tokens::Detokenize, L2ChainId, PackedEthSignature, ProtocolVersionId, }; @@ -61,25 +64,25 @@ use crate::{ fri_scheduler_circuit_queuer::SchedulerCircuitQueuer, fri_witness_generator_jobs_retry_manager::FriWitnessGeneratorJobRetryManager, fri_witness_generator_queue_monitor::FriWitnessGeneratorStatsReporter, - gpu_prover_queue_monitor::GpuProverQueueMonitor, - prover_job_retry_manager::ProverJobRetryManager, prover_queue_monitor::ProverStatsReporter, + periodic_job::PeriodicJob, waiting_to_queued_fri_witness_job_mover::WaitingToQueuedFriWitnessJobMover, }, l1_gas_price::{GasAdjusterSingleton, L1GasPriceProvider}, - metadata_calculator::{ - MetadataCalculator, MetadataCalculatorConfig, MetadataCalculatorModeConfig, - }, + metadata_calculator::{MetadataCalculator, MetadataCalculatorConfig}, metrics::{InitStage, APP_METRICS}, - state_keeper::{create_state_keeper, MempoolFetcher, MempoolGuard, MiniblockSealer}, + state_keeper::{ + create_state_keeper, MempoolFetcher, MempoolGuard, MiniblockSealer, SequencerSealer, + }, }; pub mod api_server; pub mod basic_witness_input_producer; pub mod block_reverter; -mod consensus; +pub mod consensus; pub mod consistency_checker; pub mod eth_sender; pub mod eth_watch; +mod fee_model; pub mod gas_tracker; pub mod genesis; pub mod house_keeper; @@ -130,17 +133,13 @@ pub async fn genesis_init( }; let eth_client = QueryClient::new(eth_client_url)?; - let vk_hash: zksync_types::H256 = eth_client - .call_contract_function( - "verificationKeyHash", - (), - None, - Default::default(), - None, - contracts_config.verifier_addr, - zksync_contracts::verifier_contract(), - ) - .await?; + let args = CallFunctionArgs::new("verificationKeyHash", ()).for_contract( + contracts_config.verifier_addr, + zksync_contracts::verifier_contract(), + ); + + let vk_hash = eth_client.call_contract_function(args).await?; + let vk_hash = zksync_types::H256::from_tokens(vk_hash)?; assert_eq!( vk_hash, l1_verifier_config.recursion_scheduler_level_vk_hash, @@ -232,6 +231,8 @@ pub enum Component { Housekeeper, /// Component for exposing APIs to prover for providing proof generation data and accepting proofs. ProofDataHandler, + /// Component generating BFT consensus certificates for miniblocks. + Consensus, } #[derive(Debug)] @@ -266,6 +267,7 @@ impl FromStr for Components { "eth_tx_aggregator" => Ok(Components(vec![Component::EthTxAggregator])), "eth_tx_manager" => Ok(Components(vec![Component::EthTxManager])), "proof_data_handler" => Ok(Components(vec![Component::ProofDataHandler])), + "consensus" => Ok(Components(vec![Component::Consensus])), other => Err(format!("{} is not a valid component name", other)), } } @@ -507,6 +509,39 @@ pub async fn initialize_components( tracing::info!("initialized State Keeper in {elapsed:?}"); } + if components.contains(&Component::Consensus) { + let cfg = configs + .consensus_config + .clone() + .context("consensus component's config is missing")?; + let started_at = Instant::now(); + tracing::info!("initializing Consensus"); + let pool = connection_pool.clone(); + let mut stop_receiver = stop_receiver.clone(); + task_futures.push(tokio::spawn(async move { + scope::run!(&ctx::root(), |ctx, s| async { + s.spawn_bg(async { + // Consensus is a new component. + // For now in case of error we just log it and allow the server + // to continue running. + if let Err(err) = cfg.run(ctx, pool).await { + tracing::error!(%err, "Consensus actor failed"); + } else { + tracing::info!("Consensus actor stopped"); + } + Ok(()) + }); + let _ = stop_receiver.wait_for(|stop| *stop).await?; + Ok(()) + }) + .await + })); + + let elapsed = started_at.elapsed(); + APP_METRICS.init_latency[&InitStage::Consensus].set(elapsed); + tracing::info!("initialized Consensus in {elapsed:?}"); + } + let main_zksync_contract_address = contracts_config.diamond_proxy_addr; if components.contains(&Component::EthWatcher) { let started_at = Instant::now(); @@ -524,7 +559,7 @@ pub async fn initialize_components( start_eth_watch( eth_watch_config, eth_watch_pool, - query_client.clone(), + Box::new(query_client.clone()), main_zksync_contract_address, governance, stop_receiver.clone(), @@ -558,16 +593,15 @@ pub async fn initialize_components( eth_sender.sender.clone(), store_factory.create_store().await, ), + Arc::new(eth_client), contracts_config.validator_timelock_addr, contracts_config.l1_multicall3_addr, main_zksync_contract_address, nonce.as_u64(), ); - task_futures.push(tokio::spawn(eth_tx_aggregator_actor.run( - eth_sender_pool, - eth_client, - stop_receiver.clone(), - ))); + task_futures.push(tokio::spawn( + eth_tx_aggregator_actor.run(eth_sender_pool, stop_receiver.clone()), + )); let elapsed = started_at.elapsed(); APP_METRICS.init_latency[&InitStage::EthTxAggregator].set(elapsed); tracing::info!("initialized ETH-TxAggregator in {elapsed:?}"); @@ -592,7 +626,7 @@ pub async fn initialize_components( .get_or_init() .await .context("gas_adjuster.get_or_init()")?, - eth_client, + Arc::new(eth_client), ); task_futures.extend([tokio::spawn( eth_tx_manager_actor.run(eth_manager_pool, stop_receiver.clone()), @@ -680,10 +714,9 @@ async fn add_state_keeper_to_task_futures, - object_store: Box, + object_store: Arc, stop_receiver: watch::Receiver, ) -> anyhow::Result<()> { - let fair_l2_gas_price = state_keeper_config.fair_l2_gas_price; let pool_builder = ConnectionPool::singleton(postgres_config.master_url()?); let state_keeper_pool = pool_builder .build() @@ -699,6 +732,11 @@ async fn add_state_keeper_to_task_futures MetadataCalculatorModeConfig::Lightweight, - MerkleTreeMode::Full => MetadataCalculatorModeConfig::Full { - store_factory: Some(store_factory), - }, + let object_store = match db_config.merkle_tree.mode { + MerkleTreeMode::Lightweight => None, + MerkleTreeMode::Full => Some(store_factory.create_store().await), }; run_tree( task_futures, healthchecks, &postgres_config, - &db_config, + &db_config.merkle_tree, api_config, &operation_config, - mode, + object_store, stop_receiver, ) .await @@ -798,23 +837,24 @@ async fn run_tree( task_futures: &mut Vec>>, healthchecks: &mut Vec>, postgres_config: &PostgresConfig, - db_config: &DBConfig, + merkle_tree_config: &MerkleTreeConfig, api_config: Option<&MerkleTreeApiConfig>, operation_manager: &OperationsManagerConfig, - mode: MetadataCalculatorModeConfig<'_>, + object_store: Option>, stop_receiver: watch::Receiver, ) -> anyhow::Result<()> { let started_at = Instant::now(); - let mode_str = if matches!(mode, MetadataCalculatorModeConfig::Full { .. }) { + let mode_str = if matches!(merkle_tree_config.mode, MerkleTreeMode::Full) { "full" } else { "lightweight" }; tracing::info!("Initializing Merkle tree in {mode_str} mode"); - let config = - MetadataCalculatorConfig::for_main_node(&db_config.merkle_tree, operation_manager, mode); - let metadata_calculator = MetadataCalculator::new(&config).await; + let config = MetadataCalculatorConfig::for_main_node(merkle_tree_config, operation_manager); + let metadata_calculator = MetadataCalculator::new(config, object_store) + .await + .context("failed initializing metadata_calculator")?; if let Some(api_config) = api_config { let address = (Ipv4Addr::UNSPECIFIED, api_config.port).into(); let tree_reader = metadata_calculator.tree_reader(); @@ -896,32 +936,7 @@ async fn add_house_keeper_to_task_futures( .build() .await .context("failed to build a prover_connection_pool")?; - let prover_group_config = configs - .prover_group_config - .clone() - .context("prover_group_config")?; - let prover_configs = configs.prover_configs.clone().context("prover_configs")?; - let gpu_prover_queue = GpuProverQueueMonitor::new( - prover_group_config.synthesizer_per_gpu, - house_keeper_config.gpu_prover_queue_reporting_interval_ms, - prover_connection_pool.clone(), - ); - let config = prover_configs.non_gpu.clone(); - let prover_job_retry_manager = ProverJobRetryManager::new( - config.max_attempts, - config.proof_generation_timeout(), - house_keeper_config.prover_job_retrying_interval_ms, - prover_connection_pool.clone(), - ); - let prover_stats_reporter = ProverStatsReporter::new( - house_keeper_config.prover_stats_reporting_interval_ms, - prover_connection_pool.clone(), - prover_group_config.clone(), - ); - task_futures.push(tokio::spawn(gpu_prover_queue.run())); task_futures.push(tokio::spawn(l1_batch_metrics_reporter.run())); - task_futures.push(tokio::spawn(prover_stats_reporter.run())); - task_futures.push(tokio::spawn(prover_job_retry_manager.run())); // All FRI Prover related components are configured below. let fri_prover_config = configs @@ -1024,30 +1039,32 @@ fn build_storage_caches( Ok(storage_caches) } -async fn build_tx_sender( +async fn build_tx_sender( tx_sender_config: &TxSenderConfig, web3_json_config: &Web3JsonRpcConfig, state_keeper_config: &StateKeeperConfig, replica_pool: ConnectionPool, master_pool: ConnectionPool, - l1_gas_price_provider: Arc, + l1_gas_price_provider: Arc, storage_caches: PostgresStorageCaches, -) -> (TxSender, VmConcurrencyBarrier) { - let mut tx_sender_builder = TxSenderBuilder::new(tx_sender_config.clone(), replica_pool) +) -> (TxSender, VmConcurrencyBarrier) { + let sequencer_sealer = SequencerSealer::new(state_keeper_config.clone()); + let tx_sender_builder = TxSenderBuilder::new(tx_sender_config.clone(), replica_pool.clone()) .with_main_connection_pool(master_pool) - .with_state_keeper_config(state_keeper_config.clone()); - - // Add rate limiter if enabled. - if let Some(transactions_per_sec_limit) = web3_json_config.transactions_per_sec_limit { - tx_sender_builder = tx_sender_builder.with_rate_limiter(transactions_per_sec_limit); - }; + .with_sealer(Arc::new(sequencer_sealer)); let max_concurrency = web3_json_config.vm_concurrency_limit(); let (vm_concurrency_limiter, vm_barrier) = VmConcurrencyLimiter::new(max_concurrency); + let batch_fee_input_provider = ApiFeeInputProvider::new( + l1_gas_price_provider, + FeeModelConfig::from_state_keeper_config(state_keeper_config), + replica_pool, + ); + let tx_sender = tx_sender_builder .build( - l1_gas_price_provider, + Arc::new(batch_fee_input_provider), Arc::new(vm_concurrency_limiter), ApiContracts::load_from_disk(), storage_caches, @@ -1057,7 +1074,7 @@ async fn build_tx_sender( } #[allow(clippy::too_many_arguments)] -async fn run_http_api( +async fn run_http_api( postgres_config: &PostgresConfig, tx_sender_config: &TxSenderConfig, state_keeper_config: &StateKeeperConfig, @@ -1097,7 +1114,6 @@ async fn run_http_api( .http(api_config.web3_json_rpc.http_port) .with_last_miniblock_pool(last_miniblock_pool) .with_filter_limit(api_config.web3_json_rpc.filters_limit()) - .with_threads(api_config.web3_json_rpc.http_server_threads()) .with_tree_api(api_config.web3_json_rpc.tree_api_url()) .with_batch_request_size_limit(api_config.web3_json_rpc.max_batch_request_size()) .with_response_body_size_limit(api_config.web3_json_rpc.max_response_body_size()) @@ -1151,7 +1167,6 @@ async fn run_ws_api( .websocket_requests_per_minute_limit(), ) .with_polling_interval(api_config.web3_json_rpc.pubsub_interval()) - .with_threads(api_config.web3_json_rpc.ws_server_threads()) .with_tree_api(api_config.web3_json_rpc.tree_api_url()) .with_tx_sender(tx_sender, vm_barrier) .enable_api_namespaces(namespaces); diff --git a/core/lib/zksync_core/src/metadata_calculator/helpers.rs b/core/lib/zksync_core/src/metadata_calculator/helpers.rs index e0471cb238e9..c9396976948d 100644 --- a/core/lib/zksync_core/src/metadata_calculator/helpers.rs +++ b/core/lib/zksync_core/src/metadata_calculator/helpers.rs @@ -7,6 +7,7 @@ use std::{ time::Duration, }; +use anyhow::Context as _; use serde::{Deserialize, Serialize}; #[cfg(test)] use tokio::sync::mpsc; @@ -32,9 +33,27 @@ pub(crate) struct MerkleTreeInfo { pub leaf_count: u64, } +/// Health details for a Merkle tree. +#[derive(Debug, Serialize)] +#[serde(tag = "stage", rename_all = "snake_case")] +pub(super) enum MerkleTreeHealth { + Initialization, + Recovery { + chunk_count: u64, + recovered_chunk_count: u64, + }, + MainLoop(MerkleTreeInfo), +} + +impl From for Health { + fn from(details: MerkleTreeHealth) -> Self { + Self::from(HealthStatus::Ready).with_details(details) + } +} + impl From for Health { - fn from(tree_info: MerkleTreeInfo) -> Self { - Self::from(HealthStatus::Ready).with_details(tree_info) + fn from(info: MerkleTreeInfo) -> Self { + Self::from(HealthStatus::Ready).with_details(MerkleTreeHealth::MainLoop(info)) } } @@ -45,7 +64,7 @@ pub(super) async fn create_db( memtable_capacity: usize, stalled_writes_timeout: Duration, multi_get_chunk_size: usize, -) -> RocksDBWrapper { +) -> anyhow::Result { tokio::task::spawn_blocking(move || { create_db_sync( &path, @@ -56,7 +75,7 @@ pub(super) async fn create_db( ) }) .await - .unwrap() + .context("panicked creating Merkle tree RocksDB")? } fn create_db_sync( @@ -65,7 +84,7 @@ fn create_db_sync( memtable_capacity: usize, stalled_writes_timeout: Duration, multi_get_chunk_size: usize, -) -> RocksDBWrapper { +) -> anyhow::Result { tracing::info!( "Initializing Merkle tree database at `{path}` with {multi_get_chunk_size} multi-get chunk size, \ {block_cache_capacity}B block cache, {memtable_capacity}B memtable capacity, \ @@ -80,7 +99,7 @@ fn create_db_sync( large_memtable_capacity: Some(memtable_capacity), stalled_writes_retries: StalledWritesRetries::new(stalled_writes_timeout), }, - ); + )?; if cfg!(test) { // We need sync writes for the unit tests to execute reliably. With the default config, // some writes to RocksDB may occur, but not be visible to the test code. @@ -88,7 +107,7 @@ fn create_db_sync( } let mut db = RocksDBWrapper::from(db); db.set_multi_get_chunk_size(multi_get_chunk_size); - db + Ok(db) } /// Wrapper around the "main" tree implementation used by [`MetadataCalculator`]. @@ -319,7 +338,7 @@ pub(super) struct Delayer { delay_interval: Duration, // Notifies the tests about the next L1 batch number and tree root hash when the calculator // runs out of L1 batches to process. (Since RocksDB is exclusive, we cannot just create - // another instance to check these params on the test side without stopping the calc.) + // another instance to check these params on the test side without stopping the calculation.) #[cfg(test)] pub delay_notifier: mpsc::UnboundedSender<(L1BatchNumber, H256)>, } @@ -382,7 +401,8 @@ impl L1BatchWithLogs { let mut touched_slots = storage .storage_logs_dal() .get_touched_slots_for_l1_batch(l1_batch_number) - .await; + .await + .unwrap(); touched_slots_latency.observe_with_count(touched_slots.len()); let leaf_indices_latency = METRICS.start_load_stage(LoadChangesStage::LoadLeafIndices); @@ -391,7 +411,8 @@ impl L1BatchWithLogs { let l1_batches_for_initial_writes = storage .storage_logs_dal() .get_l1_batches_and_indices_for_initial_writes(&hashed_keys_for_writes) - .await; + .await + .unwrap(); leaf_indices_latency.observe_with_count(hashed_keys_for_writes.len()); let mut storage_logs = BTreeMap::new(); @@ -434,7 +455,8 @@ impl L1BatchWithLogs { mod tests { use tempfile::TempDir; use zksync_dal::ConnectionPool; - use zksync_types::{proofs::PrepareBasicCircuitsJob, L2ChainId, StorageKey, StorageLog}; + use zksync_prover_interface::inputs::PrepareBasicCircuitsJob; + use zksync_types::{L2ChainId, StorageKey, StorageLog}; use super::*; use crate::{ @@ -460,7 +482,8 @@ mod tests { let touched_slots = storage .storage_logs_dal() .get_touched_slots_for_l1_batch(l1_batch_number) - .await; + .await + .unwrap(); let mut storage_logs = BTreeMap::new(); @@ -472,11 +495,13 @@ mod tests { let previous_values = storage .storage_logs_dal() .get_previous_storage_values(&hashed_keys, l1_batch_number) - .await; + .await + .unwrap(); let l1_batches_for_initial_writes = storage .storage_logs_dal() .get_l1_batches_and_indices_for_initial_writes(&hashed_keys) - .await; + .await + .unwrap(); for storage_key in protective_reads { let previous_value = previous_values[&storage_key.hashed_key()].unwrap_or_default(); @@ -566,7 +591,8 @@ mod tests { Duration::ZERO, // writes should never be stalled in tests 500, ) - .await; + .await + .unwrap(); AsyncTree::new(db, MerkleTreeMode::Full) } diff --git a/core/lib/zksync_core/src/metadata_calculator/metrics.rs b/core/lib/zksync_core/src/metadata_calculator/metrics.rs index 87ab8fb377f7..e1f631641289 100644 --- a/core/lib/zksync_core/src/metadata_calculator/metrics.rs +++ b/core/lib/zksync_core/src/metadata_calculator/metrics.rs @@ -197,7 +197,7 @@ pub(super) enum ChunkRecoveryStage { #[metrics(prefix = "server_metadata_calculator_recovery")] pub(super) struct MetadataCalculatorRecoveryMetrics { /// Number of chunks recovered. - pub recovered_chunk_count: Gauge, + pub recovered_chunk_count: Gauge, /// Latency of a tree recovery stage (not related to the recovery of a particular chunk; /// those metrics are tracked in the `chunk_latency` histogram). #[metrics(buckets = Buckets::LATENCIES, unit = Unit::Seconds)] diff --git a/core/lib/zksync_core/src/metadata_calculator/mod.rs b/core/lib/zksync_core/src/metadata_calculator/mod.rs index 0cfea020203c..846b73c1004a 100644 --- a/core/lib/zksync_core/src/metadata_calculator/mod.rs +++ b/core/lib/zksync_core/src/metadata_calculator/mod.rs @@ -3,9 +3,11 @@ use std::{ future::{self, Future}, - time::Duration, + sync::Arc, + time::{Duration, Instant}, }; +use anyhow::Context as _; use tokio::sync::watch; use zksync_config::configs::{ chain::OperationsManagerConfig, @@ -14,16 +16,16 @@ use zksync_config::configs::{ use zksync_dal::{ConnectionPool, StorageProcessor}; use zksync_health_check::{HealthUpdater, ReactiveHealthCheck}; use zksync_merkle_tree::domain::TreeMetadata; -use zksync_object_store::{ObjectStore, ObjectStoreFactory}; +use zksync_object_store::ObjectStore; use zksync_types::{ block::L1BatchHeader, commitment::{L1BatchCommitment, L1BatchMetadata}, - H256, + ProtocolVersionId, H256, }; pub(crate) use self::helpers::{AsyncTreeReader, L1BatchWithLogs, MerkleTreeInfo}; use self::{ - helpers::{create_db, Delayer, GenericAsyncTree}, + helpers::{create_db, Delayer, GenericAsyncTree, MerkleTreeHealth}, metrics::{TreeUpdateStage, METRICS}, updater::TreeUpdater, }; @@ -36,36 +38,13 @@ mod recovery; pub(crate) mod tests; mod updater; -/// Part of [`MetadataCalculator`] related to the operation mode of the Merkle tree. -#[derive(Debug, Clone, Copy)] -pub enum MetadataCalculatorModeConfig<'a> { - /// In this mode, `MetadataCalculator` computes Merkle tree root hashes and some auxiliary information - /// for L1 batches, but not witness inputs. - Lightweight, - /// In this mode, `MetadataCalculator` will compute commitments and witness inputs for all storage operations - /// and optionally put witness inputs into the object store as provided by `store_factory` (e.g., GCS). - Full { - store_factory: Option<&'a ObjectStoreFactory>, - }, -} - -impl MetadataCalculatorModeConfig<'_> { - fn to_mode(self) -> MerkleTreeMode { - if matches!(self, Self::Full { .. }) { - MerkleTreeMode::Full - } else { - MerkleTreeMode::Lightweight - } - } -} - /// Configuration of [`MetadataCalculator`]. #[derive(Debug)] -pub struct MetadataCalculatorConfig<'a> { +pub struct MetadataCalculatorConfig { /// Filesystem path to the RocksDB instance that stores the tree. - pub db_path: &'a str, + pub db_path: String, /// Configuration of the Merkle tree mode. - pub mode: MetadataCalculatorModeConfig<'a>, + pub mode: MerkleTreeMode, /// Interval between polling Postgres for updates if no progress was made by the tree. pub delay_interval: Duration, /// Maximum number of L1 batches to get from Postgres on a single update iteration. @@ -82,15 +61,14 @@ pub struct MetadataCalculatorConfig<'a> { pub stalled_writes_timeout: Duration, } -impl<'a> MetadataCalculatorConfig<'a> { - pub(crate) fn for_main_node( - merkle_tree_config: &'a MerkleTreeConfig, - operation_config: &'a OperationsManagerConfig, - mode: MetadataCalculatorModeConfig<'a>, +impl MetadataCalculatorConfig { + pub fn for_main_node( + merkle_tree_config: &MerkleTreeConfig, + operation_config: &OperationsManagerConfig, ) -> Self { Self { - db_path: &merkle_tree_config.path, - mode, + db_path: merkle_tree_config.path.clone(), + mode: merkle_tree_config.mode, delay_interval: operation_config.delay_interval(), max_l1_batches_per_iter: merkle_tree_config.max_l1_batches_per_iter, multi_get_chunk_size: merkle_tree_config.multi_get_chunk_size, @@ -103,9 +81,9 @@ impl<'a> MetadataCalculatorConfig<'a> { #[derive(Debug)] pub struct MetadataCalculator { - tree: GenericAsyncTree, + config: MetadataCalculatorConfig, tree_reader: watch::Sender>, - object_store: Option>, + object_store: Option>, delayer: Delayer, health_updater: HealthUpdater, max_l1_batches_per_iter: usize, @@ -113,40 +91,24 @@ pub struct MetadataCalculator { impl MetadataCalculator { /// Creates a calculator with the specified `config`. - pub async fn new(config: &MetadataCalculatorConfig<'_>) -> Self { - assert!( + pub async fn new( + config: MetadataCalculatorConfig, + object_store: Option>, + ) -> anyhow::Result { + anyhow::ensure!( config.max_l1_batches_per_iter > 0, "Maximum L1 batches per iteration is misconfigured to be 0; please update it to positive value" ); - let mode = config.mode.to_mode(); - let object_store = match config.mode { - MetadataCalculatorModeConfig::Full { store_factory } => match store_factory { - Some(f) => Some(f.create_store().await), - None => None, - }, - MetadataCalculatorModeConfig::Lightweight => None, - }; - - let db = create_db( - config.db_path.into(), - config.block_cache_capacity, - config.memtable_capacity, - config.stalled_writes_timeout, - config.multi_get_chunk_size, - ) - .await; - let tree = GenericAsyncTree::new(db, mode).await; - let (_, health_updater) = ReactiveHealthCheck::new("tree"); - Self { - tree, + Ok(Self { tree_reader: watch::channel(None).0, object_store, delayer: Delayer::new(config.delay_interval), health_updater, max_l1_batches_per_iter: config.max_l1_batches_per_iter, - } + config, + }) } /// Returns a health check for this calculator. @@ -170,19 +132,52 @@ impl MetadataCalculator { } } + async fn create_tree(&self) -> anyhow::Result { + self.health_updater + .update(MerkleTreeHealth::Initialization.into()); + + let started_at = Instant::now(); + let db = create_db( + self.config.db_path.clone().into(), + self.config.block_cache_capacity, + self.config.memtable_capacity, + self.config.stalled_writes_timeout, + self.config.multi_get_chunk_size, + ) + .await + .with_context(|| { + format!( + "failed opening Merkle tree RocksDB with configuration {:?}", + self.config + ) + })?; + tracing::info!( + "Opened Merkle tree RocksDB with configuration {:?} in {:?}", + self.config, + started_at.elapsed() + ); + + Ok(GenericAsyncTree::new(db, self.config.mode).await) + } + pub async fn run( self, pool: ConnectionPool, stop_receiver: watch::Receiver, ) -> anyhow::Result<()> { - let tree = self - .tree + let tree = self.create_tree().await?; + let tree = tree .ensure_ready(&pool, &stop_receiver, &self.health_updater) .await?; let Some(tree) = tree else { return Ok(()); // recovery was aborted because a stop signal was received }; - self.tree_reader.send_replace(Some(tree.reader())); + let tree_reader = tree.reader(); + tracing::info!( + "Merkle tree is initialized and ready to process L1 batches: {:?}", + tree_reader.clone().info().await + ); + self.tree_reader.send_replace(Some(tree_reader)); let updater = TreeUpdater::new(tree, self.max_l1_batches_per_iter, self.object_store); updater @@ -220,10 +215,12 @@ impl MetadataCalculator { events_queue_commitment: Option, bootloader_initial_content_commitment: Option, ) -> L1BatchMetadata { - let is_pre_boojum = header + // The commitment generation pre-boojum is the same for all the version, so in case the version is not present, we just supply the + // last pre-boojum version. + // TODO(PLA-731): make sure that protocol version is not an Option + let protocol_version = header .protocol_version - .map(|v| v.is_pre_boojum()) - .unwrap_or(true); + .unwrap_or(ProtocolVersionId::last_potentially_undefined()); let merkle_root_hash = tree_metadata.root_hash; @@ -239,12 +236,12 @@ impl MetadataCalculator { tree_metadata.state_diffs, bootloader_initial_content_commitment.unwrap_or_default(), events_queue_commitment.unwrap_or_default(), - is_pre_boojum, + protocol_version, ); let commitment_hash = commitment.hash(); tracing::trace!("L1 batch commitment: {commitment:?}"); - let l2_l1_messages_compressed = if is_pre_boojum { + let l2_l1_messages_compressed = if protocol_version.is_pre_boojum() { commitment.l2_l1_logs_compressed().to_vec() } else { commitment.system_logs_compressed().to_vec() diff --git a/core/lib/zksync_core/src/metadata_calculator/recovery.rs b/core/lib/zksync_core/src/metadata_calculator/recovery.rs deleted file mode 100644 index 52c254a1dbee..000000000000 --- a/core/lib/zksync_core/src/metadata_calculator/recovery.rs +++ /dev/null @@ -1,673 +0,0 @@ -//! High-level recovery logic for the Merkle tree. -//! -//! # Overview -//! -//! Tree recovery works by checking Postgres and Merkle tree state on Metadata calculator initialization. -//! Depending on these states, we can have one of the following situations: -//! -//! - Tree is recovering. -//! - Tree is empty and should be recovered (i.e., there's a snapshot in Postgres). -//! - Tree is empty and should be built from scratch. -//! - Tree is ready for normal operation (i.e., it's not empty and is not recovering). -//! -//! If recovery is necessary, it starts / resumes by loading the Postgres snapshot in chunks -//! and feeding each chunk to the tree. Chunks are loaded concurrently since this is the most -//! I/O-heavy operation; the concurrency is naturally limited by the number of connections to -//! Postgres in the supplied connection pool, but we explicitly use a [`Semaphore`] to control it -//! in order to not run into DB timeout errors. Before starting recovery in chunks, we filter out -//! chunks that have already been recovered by checking if the first key in a chunk is present -//! in the tree. (Note that for this to work, chunks **must** always be defined in the same way.) -//! -//! The recovery logic is fault-tolerant and supports graceful shutdown. If recovery is interrupted, -//! recovery of the remaining chunks will continue when Metadata calculator is restarted. -//! -//! Recovery performs basic sanity checks to ensure that the tree won't end up containing garbage data. -//! E.g., it's checked that the tree always recovers from the same snapshot; that the tree root hash -//! after recovery matches one in the Postgres snapshot etc. - -use std::{ - fmt, ops, - sync::atomic::{AtomicUsize, Ordering}, -}; - -use anyhow::Context as _; -use async_trait::async_trait; -use futures::future; -use serde::{Deserialize, Serialize}; -use tokio::sync::{watch, Mutex, Semaphore}; -use zksync_dal::{ConnectionPool, StorageProcessor}; -use zksync_health_check::{Health, HealthStatus, HealthUpdater}; -use zksync_merkle_tree::TreeEntry; -use zksync_types::{L1BatchNumber, MiniblockNumber, H256, U256}; -use zksync_utils::u256_to_h256; - -use super::{ - helpers::{AsyncTree, AsyncTreeRecovery, GenericAsyncTree}, - metrics::{ChunkRecoveryStage, RecoveryStage, RECOVERY_METRICS}, -}; - -/// Handler of recovery life cycle events. This functionality is encapsulated in a trait to be able -/// to control recovery behavior in tests. -#[async_trait] -trait HandleRecoveryEvent: fmt::Debug + Send + Sync { - fn recovery_started(&mut self, _chunk_count: usize, _recovered_chunk_count: usize) { - // Default implementation does nothing - } - - async fn chunk_started(&self) { - // Default implementation does nothing - } - - async fn chunk_recovered(&self) { - // Default implementation does nothing - } -} - -/// Information about a Merkle tree during its snapshot recovery. -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] -struct RecoveryMerkleTreeInfo { - mode: &'static str, // always set to "recovery" to distinguish from `MerkleTreeInfo` - chunk_count: usize, - recovered_chunk_count: usize, -} - -/// [`HealthUpdater`]-based [`HandleRecoveryEvent`] implementation. -#[derive(Debug)] -struct RecoveryHealthUpdater<'a> { - inner: &'a HealthUpdater, - chunk_count: usize, - recovered_chunk_count: AtomicUsize, -} - -impl<'a> RecoveryHealthUpdater<'a> { - fn new(inner: &'a HealthUpdater) -> Self { - Self { - inner, - chunk_count: 0, - recovered_chunk_count: AtomicUsize::new(0), - } - } -} - -#[async_trait] -impl HandleRecoveryEvent for RecoveryHealthUpdater<'_> { - fn recovery_started(&mut self, chunk_count: usize, recovered_chunk_count: usize) { - self.chunk_count = chunk_count; - *self.recovered_chunk_count.get_mut() = recovered_chunk_count; - RECOVERY_METRICS - .recovered_chunk_count - .set(recovered_chunk_count); - } - - async fn chunk_recovered(&self) { - let recovered_chunk_count = self.recovered_chunk_count.fetch_add(1, Ordering::SeqCst) + 1; - RECOVERY_METRICS - .recovered_chunk_count - .set(recovered_chunk_count); - let health = Health::from(HealthStatus::Ready).with_details(RecoveryMerkleTreeInfo { - mode: "recovery", - chunk_count: self.chunk_count, - recovered_chunk_count, - }); - self.inner.update(health); - } -} - -#[derive(Debug, Clone, Copy)] -struct SnapshotParameters { - miniblock: MiniblockNumber, - expected_root_hash: H256, - log_count: u64, -} - -impl SnapshotParameters { - /// This is intentionally not configurable because chunks must be the same for the entire recovery - /// (i.e., not changed after a node restart). - const DESIRED_CHUNK_SIZE: u64 = 200_000; - - async fn new(pool: &ConnectionPool, l1_batch: L1BatchNumber) -> anyhow::Result { - let mut storage = pool.access_storage().await?; - let (_, miniblock) = storage - .blocks_dal() - .get_miniblock_range_of_l1_batch(l1_batch) - .await - .with_context(|| format!("Failed getting miniblock range for L1 batch #{l1_batch}"))? - .with_context(|| format!("L1 batch #{l1_batch} doesn't have miniblocks"))?; - let expected_root_hash = storage - .blocks_dal() - .get_l1_batch_metadata(l1_batch) - .await - .with_context(|| format!("Failed getting metadata for L1 batch #{l1_batch}"))? - .with_context(|| format!("L1 batch #{l1_batch} has no metadata"))? - .metadata - .root_hash; - let log_count = storage - .storage_logs_dal() - .count_miniblock_storage_logs(miniblock) - .await - .with_context(|| format!("Failed getting number of logs for miniblock #{miniblock}"))?; - - Ok(Self { - miniblock, - expected_root_hash, - log_count, - }) - } - - fn chunk_count(&self) -> usize { - zksync_utils::ceil_div(self.log_count, Self::DESIRED_CHUNK_SIZE) as usize - } -} - -/// Options for tree recovery. -#[derive(Debug)] -struct RecoveryOptions<'a> { - chunk_count: usize, - concurrency_limit: usize, - events: Box, -} - -impl GenericAsyncTree { - /// Ensures that the tree is ready for the normal operation, recovering it from a Postgres snapshot - /// if necessary. - pub async fn ensure_ready( - self, - pool: &ConnectionPool, - stop_receiver: &watch::Receiver, - health_updater: &HealthUpdater, - ) -> anyhow::Result> { - let (tree, l1_batch) = match self { - Self::Ready(tree) => return Ok(Some(tree)), - Self::Recovering(tree) => { - let l1_batch = snapshot_l1_batch(pool).await?.context( - "Merkle tree is recovering, but Postgres doesn't contain snapshot L1 batch", - )?; - let recovered_version = tree.recovered_version(); - anyhow::ensure!( - u64::from(l1_batch.0) == recovered_version, - "Snapshot L1 batch in Postgres ({l1_batch}) differs from the recovered Merkle tree version \ - ({recovered_version})" - ); - tracing::info!("Resuming tree recovery with snapshot L1 batch #{l1_batch}"); - (tree, l1_batch) - } - Self::Empty { db, mode } => { - if let Some(l1_batch) = snapshot_l1_batch(pool).await? { - tracing::info!( - "Starting Merkle tree recovery with snapshot L1 batch #{l1_batch}" - ); - let tree = AsyncTreeRecovery::new(db, l1_batch.0.into(), mode); - (tree, l1_batch) - } else { - // Start the tree from scratch. The genesis block will be filled in `TreeUpdater::loop_updating_tree()`. - return Ok(Some(AsyncTree::new(db, mode))); - } - } - }; - - let snapshot = SnapshotParameters::new(pool, l1_batch).await?; - tracing::debug!("Obtained snapshot parameters: {snapshot:?}"); - let recovery_options = RecoveryOptions { - chunk_count: snapshot.chunk_count(), - concurrency_limit: pool.max_size() as usize, - events: Box::new(RecoveryHealthUpdater::new(health_updater)), - }; - tree.recover(snapshot, recovery_options, pool, stop_receiver) - .await - } -} - -impl AsyncTreeRecovery { - async fn recover( - mut self, - snapshot: SnapshotParameters, - mut options: RecoveryOptions<'_>, - pool: &ConnectionPool, - stop_receiver: &watch::Receiver, - ) -> anyhow::Result> { - let chunk_count = options.chunk_count; - let chunks: Vec<_> = Self::hashed_key_ranges(chunk_count).collect(); - tracing::info!( - "Recovering Merkle tree from Postgres snapshot in {chunk_count} concurrent chunks" - ); - - let mut storage = pool.access_storage().await?; - let remaining_chunks = self - .filter_chunks(&mut storage, snapshot.miniblock, &chunks) - .await?; - drop(storage); - options - .events - .recovery_started(chunk_count, chunk_count - remaining_chunks.len()); - tracing::info!( - "Filtered recovered key chunks; {} / {chunk_count} chunks remaining", - remaining_chunks.len() - ); - - let tree = Mutex::new(self); - let semaphore = Semaphore::new(options.concurrency_limit); - let chunk_tasks = remaining_chunks.into_iter().map(|chunk| async { - let _permit = semaphore - .acquire() - .await - .context("semaphore is never closed")?; - options.events.chunk_started().await; - Self::recover_key_chunk(&tree, snapshot.miniblock, chunk, pool, stop_receiver).await?; - options.events.chunk_recovered().await; - anyhow::Ok(()) - }); - future::try_join_all(chunk_tasks).await?; - - if *stop_receiver.borrow() { - return Ok(None); - } - - let finalize_latency = RECOVERY_METRICS.latency[&RecoveryStage::Finalize].start(); - let mut tree = tree.into_inner(); - let actual_root_hash = tree.root_hash().await; - anyhow::ensure!( - actual_root_hash == snapshot.expected_root_hash, - "Root hash of recovered tree {actual_root_hash:?} differs from expected root hash {:?}", - snapshot.expected_root_hash - ); - let tree = tree.finalize().await; - let finalize_latency = finalize_latency.observe(); - tracing::info!( - "Finished tree recovery in {finalize_latency:?}; resuming normal tree operation" - ); - Ok(Some(tree)) - } - - fn hashed_key_ranges(count: usize) -> impl Iterator> { - assert!(count > 0); - let mut stride = U256::MAX / count; - let stride_minus_one = if stride < U256::MAX { - stride += U256::one(); - stride - 1 - } else { - stride // `stride` is really 1 << 256 == U256::MAX + 1 - }; - - (0..count).map(move |i| { - let start = stride * i; - let (mut end, is_overflow) = stride_minus_one.overflowing_add(start); - if is_overflow { - end = U256::MAX; - } - u256_to_h256(start)..=u256_to_h256(end) - }) - } - - /// Filters out `key_chunks` for which recovery was successfully performed. - async fn filter_chunks( - &mut self, - storage: &mut StorageProcessor<'_>, - snapshot_miniblock: MiniblockNumber, - key_chunks: &[ops::RangeInclusive], - ) -> anyhow::Result>> { - let chunk_starts_latency = - RECOVERY_METRICS.latency[&RecoveryStage::LoadChunkStarts].start(); - let chunk_starts = storage - .storage_logs_dal() - .get_chunk_starts_for_miniblock(snapshot_miniblock, key_chunks) - .await - .context("Failed getting chunk starts")?; - let chunk_starts_latency = chunk_starts_latency.observe(); - tracing::debug!( - "Loaded start entries for {} chunks in {chunk_starts_latency:?}", - key_chunks.len() - ); - - let existing_starts = chunk_starts - .iter() - .enumerate() - .filter_map(|(i, &start)| Some((i, start?))); - let start_keys = existing_starts - .clone() - .map(|(_, start_entry)| start_entry.key) - .collect(); - let tree_entries = self.entries(start_keys).await; - - let mut output = vec![]; - for (tree_entry, (i, db_entry)) in tree_entries.into_iter().zip(existing_starts) { - if tree_entry.is_empty() { - output.push(key_chunks[i].clone()); - continue; - } - anyhow::ensure!( - tree_entry.value == db_entry.value && tree_entry.leaf_index == db_entry.leaf_index, - "Mismatch between entry for key {:0>64x} in Postgres snapshot for miniblock #{snapshot_miniblock} \ - ({db_entry:?}) and tree ({tree_entry:?}); the recovery procedure may be corrupted", - db_entry.key - ); - } - Ok(output) - } - - async fn recover_key_chunk( - tree: &Mutex, - snapshot_miniblock: MiniblockNumber, - key_chunk: ops::RangeInclusive, - pool: &ConnectionPool, - stop_receiver: &watch::Receiver, - ) -> anyhow::Result<()> { - let acquire_connection_latency = - RECOVERY_METRICS.chunk_latency[&ChunkRecoveryStage::AcquireConnection].start(); - let mut storage = pool.access_storage().await?; - acquire_connection_latency.observe(); - - if *stop_receiver.borrow() { - return Ok(()); - } - - let entries_latency = - RECOVERY_METRICS.chunk_latency[&ChunkRecoveryStage::LoadEntries].start(); - let all_entries = storage - .storage_logs_dal() - .get_tree_entries_for_miniblock(snapshot_miniblock, key_chunk.clone()) - .await - .with_context(|| { - format!("Failed getting entries for chunk {key_chunk:?} in snapshot for miniblock #{snapshot_miniblock}") - })?; - drop(storage); - let entries_latency = entries_latency.observe(); - tracing::debug!( - "Loaded {} entries for chunk {key_chunk:?} in {entries_latency:?}", - all_entries.len() - ); - - if *stop_receiver.borrow() { - return Ok(()); - } - - // Sanity check: all entry keys must be distinct. Otherwise, we may end up writing non-final values - // to the tree, since we don't enforce any ordering on entries besides by the hashed key. - for window in all_entries.windows(2) { - let [prev_entry, next_entry] = window else { - unreachable!(); - }; - anyhow::ensure!( - prev_entry.key != next_entry.key, - "node snapshot in Postgres is corrupted: entries {prev_entry:?} and {next_entry:?} \ - have same hashed_key" - ); - } - - let all_entries = all_entries - .into_iter() - .map(|entry| TreeEntry { - key: entry.key, - value: entry.value, - leaf_index: entry.leaf_index, - }) - .collect(); - let lock_tree_latency = - RECOVERY_METRICS.chunk_latency[&ChunkRecoveryStage::LockTree].start(); - let mut tree = tree.lock().await; - lock_tree_latency.observe(); - - if *stop_receiver.borrow() { - return Ok(()); - } - - let extend_tree_latency = - RECOVERY_METRICS.chunk_latency[&ChunkRecoveryStage::ExtendTree].start(); - tree.extend(all_entries).await; - let extend_tree_latency = extend_tree_latency.observe(); - tracing::debug!( - "Extended Merkle tree with entries for chunk {key_chunk:?} in {extend_tree_latency:?}" - ); - Ok(()) - } -} - -async fn snapshot_l1_batch(_pool: &ConnectionPool) -> anyhow::Result> { - Ok(None) // FIXME (PLA-708): implement real logic -} - -#[cfg(test)] -mod tests { - use std::{path::PathBuf, time::Duration}; - - use assert_matches::assert_matches; - use tempfile::TempDir; - use test_casing::test_casing; - use zksync_config::configs::database::MerkleTreeMode; - use zksync_health_check::{CheckHealth, ReactiveHealthCheck}; - use zksync_types::{L2ChainId, StorageLog}; - use zksync_utils::h256_to_u256; - - use super::*; - use crate::{ - genesis::{ensure_genesis_state, GenesisParams}, - metadata_calculator::{ - helpers::create_db, - tests::{extend_db_state, gen_storage_logs, run_calculator, setup_calculator}, - }, - }; - - #[test] - fn calculating_hashed_key_ranges_with_single_chunk() { - let mut ranges = AsyncTreeRecovery::hashed_key_ranges(1); - let full_range = ranges.next().unwrap(); - assert_eq!(full_range, H256::zero()..=H256([0xff; 32])); - } - - #[test] - fn calculating_hashed_key_ranges_for_256_chunks() { - let ranges = AsyncTreeRecovery::hashed_key_ranges(256); - let mut start = H256::zero(); - let mut end = H256([0xff; 32]); - - for (i, range) in ranges.enumerate() { - let i = u8::try_from(i).unwrap(); - start.0[0] = i; - end.0[0] = i; - assert_eq!(range, start..=end); - } - } - - #[test_casing(5, [3, 7, 23, 100, 255])] - fn calculating_hashed_key_ranges_for_arbitrary_chunks(chunk_count: usize) { - let ranges: Vec<_> = AsyncTreeRecovery::hashed_key_ranges(chunk_count).collect(); - assert_eq!(ranges.len(), chunk_count); - - for window in ranges.windows(2) { - let [prev_range, range] = window else { - unreachable!(); - }; - assert_eq!( - h256_to_u256(*range.start()), - h256_to_u256(*prev_range.end()) + 1 - ); - } - assert_eq!(*ranges.first().unwrap().start(), H256::zero()); - assert_eq!(*ranges.last().unwrap().end(), H256([0xff; 32])); - } - - #[test] - fn calculating_chunk_count() { - let mut snapshot = SnapshotParameters { - miniblock: MiniblockNumber(1), - log_count: 160_000_000, - expected_root_hash: H256::zero(), - }; - assert_eq!(snapshot.chunk_count(), 800); - - snapshot.log_count += 1; - assert_eq!(snapshot.chunk_count(), 801); - - snapshot.log_count = 100; - assert_eq!(snapshot.chunk_count(), 1); - } - - async fn create_tree_recovery(path: PathBuf, l1_batch: L1BatchNumber) -> AsyncTreeRecovery { - let db = create_db( - path, - 0, - 16 << 20, // 16 MiB, - Duration::ZERO, // writes should never be stalled in tests - 500, - ) - .await; - AsyncTreeRecovery::new(db, l1_batch.0.into(), MerkleTreeMode::Full) - } - - #[tokio::test] - async fn basic_recovery_workflow() { - let pool = ConnectionPool::test_pool().await; - let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); - let root_hash = prepare_recovery_snapshot(&pool, &temp_dir).await; - let snapshot = SnapshotParameters::new(&pool, L1BatchNumber(1)) - .await - .unwrap(); - - assert!(snapshot.log_count > 200); - assert_eq!(snapshot.miniblock, MiniblockNumber(1)); - assert_eq!(snapshot.expected_root_hash, root_hash); - - let (_stop_sender, stop_receiver) = watch::channel(false); - for chunk_count in [1, 4, 9, 16, 60, 256] { - println!("Recovering tree with {chunk_count} chunks"); - - let tree_path = temp_dir.path().join(format!("recovery-{chunk_count}")); - let tree = create_tree_recovery(tree_path, L1BatchNumber(1)).await; - let (health_check, health_updater) = ReactiveHealthCheck::new("tree"); - let recovery_options = RecoveryOptions { - chunk_count, - concurrency_limit: 1, - events: Box::new(RecoveryHealthUpdater::new(&health_updater)), - }; - let tree = tree - .recover(snapshot, recovery_options, &pool, &stop_receiver) - .await - .unwrap() - .expect("Tree recovery unexpectedly aborted"); - - assert_eq!(tree.root_hash(), root_hash); - let health = health_check.check_health().await; - assert_matches!(health.status(), HealthStatus::Ready); - } - } - - async fn prepare_recovery_snapshot(pool: &ConnectionPool, temp_dir: &TempDir) -> H256 { - let mut storage = pool.access_storage().await.unwrap(); - ensure_genesis_state(&mut storage, L2ChainId::from(270), &GenesisParams::mock()) - .await - .unwrap(); - let mut logs = gen_storage_logs(100..300, 1).pop().unwrap(); - - // Add all logs from the genesis L1 batch to `logs` so that they cover all state keys. - let genesis_logs = storage - .storage_logs_dal() - .get_touched_slots_for_l1_batch(L1BatchNumber(0)) - .await; - let genesis_logs = genesis_logs - .into_iter() - .map(|(key, value)| StorageLog::new_write_log(key, value)); - logs.extend(genesis_logs); - extend_db_state(&mut storage, vec![logs]).await; - drop(storage); - - // Ensure that metadata for L1 batch #1 is present in the DB. - let (calculator, _) = setup_calculator(&temp_dir.path().join("init"), pool).await; - run_calculator(calculator, pool.clone()).await - } - - #[derive(Debug)] - struct TestEventListener { - expected_recovered_chunks: usize, - stop_threshold: usize, - processed_chunk_count: AtomicUsize, - stop_sender: watch::Sender, - } - - impl TestEventListener { - fn new(stop_threshold: usize, stop_sender: watch::Sender) -> Self { - Self { - expected_recovered_chunks: 0, - stop_threshold, - processed_chunk_count: AtomicUsize::new(0), - stop_sender, - } - } - - fn expect_recovered_chunks(mut self, count: usize) -> Self { - self.expected_recovered_chunks = count; - self - } - } - - #[async_trait] - impl HandleRecoveryEvent for TestEventListener { - fn recovery_started(&mut self, _chunk_count: usize, recovered_chunk_count: usize) { - assert_eq!(recovered_chunk_count, self.expected_recovered_chunks); - } - - async fn chunk_recovered(&self) { - let processed_chunk_count = - self.processed_chunk_count.fetch_add(1, Ordering::SeqCst) + 1; - if processed_chunk_count >= self.stop_threshold { - self.stop_sender.send_replace(true); - } - } - } - - #[test_casing(3, [5, 7, 8])] - #[tokio::test] - async fn recovery_fault_tolerance(chunk_count: usize) { - let pool = ConnectionPool::test_pool().await; - let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); - let root_hash = prepare_recovery_snapshot(&pool, &temp_dir).await; - - let tree_path = temp_dir.path().join("recovery"); - let tree = create_tree_recovery(tree_path.clone(), L1BatchNumber(1)).await; - let (stop_sender, stop_receiver) = watch::channel(false); - let recovery_options = RecoveryOptions { - chunk_count, - concurrency_limit: 1, - events: Box::new(TestEventListener::new(1, stop_sender)), - }; - let snapshot = SnapshotParameters::new(&pool, L1BatchNumber(1)) - .await - .unwrap(); - assert!(tree - .recover(snapshot, recovery_options, &pool, &stop_receiver) - .await - .unwrap() - .is_none()); - - // Emulate a restart and recover 2 more chunks. - let mut tree = create_tree_recovery(tree_path.clone(), L1BatchNumber(1)).await; - assert_ne!(tree.root_hash().await, root_hash); - let (stop_sender, stop_receiver) = watch::channel(false); - let recovery_options = RecoveryOptions { - chunk_count, - concurrency_limit: 1, - events: Box::new(TestEventListener::new(2, stop_sender).expect_recovered_chunks(1)), - }; - assert!(tree - .recover(snapshot, recovery_options, &pool, &stop_receiver) - .await - .unwrap() - .is_none()); - - // Emulate another restart and recover remaining chunks. - let mut tree = create_tree_recovery(tree_path.clone(), L1BatchNumber(1)).await; - assert_ne!(tree.root_hash().await, root_hash); - let (stop_sender, stop_receiver) = watch::channel(false); - let recovery_options = RecoveryOptions { - chunk_count, - concurrency_limit: 1, - events: Box::new( - TestEventListener::new(usize::MAX, stop_sender).expect_recovered_chunks(3), - ), - }; - let tree = tree - .recover(snapshot, recovery_options, &pool, &stop_receiver) - .await - .unwrap() - .expect("Tree recovery unexpectedly aborted"); - assert_eq!(tree.root_hash(), root_hash); - } -} diff --git a/core/lib/zksync_core/src/metadata_calculator/recovery/mod.rs b/core/lib/zksync_core/src/metadata_calculator/recovery/mod.rs new file mode 100644 index 000000000000..f6b6f74fb2b2 --- /dev/null +++ b/core/lib/zksync_core/src/metadata_calculator/recovery/mod.rs @@ -0,0 +1,399 @@ +//! High-level recovery logic for the Merkle tree. +//! +//! # Overview +//! +//! Tree recovery works by checking Postgres and Merkle tree state on Metadata calculator initialization. +//! Depending on these states, we can have one of the following situations: +//! +//! - Tree is recovering. +//! - Tree is empty and should be recovered (i.e., there's a snapshot in Postgres). +//! - Tree is empty and should be built from scratch. +//! - Tree is ready for normal operation (i.e., it's not empty and is not recovering). +//! +//! If recovery is necessary, it starts / resumes by loading the Postgres snapshot in chunks +//! and feeding each chunk to the tree. Chunks are loaded concurrently since this is the most +//! I/O-heavy operation; the concurrency is naturally limited by the number of connections to +//! Postgres in the supplied connection pool, but we explicitly use a [`Semaphore`] to control it +//! in order to not run into DB timeout errors. Before starting recovery in chunks, we filter out +//! chunks that have already been recovered by checking if the first key in a chunk is present +//! in the tree. (Note that for this to work, chunks **must** always be defined in the same way.) +//! +//! The recovery logic is fault-tolerant and supports graceful shutdown. If recovery is interrupted, +//! recovery of the remaining chunks will continue when Metadata calculator is restarted. +//! +//! Recovery performs basic sanity checks to ensure that the tree won't end up containing garbage data. +//! E.g., it's checked that the tree always recovers from the same snapshot; that the tree root hash +//! after recovery matches one in the Postgres snapshot etc. + +use std::{ + fmt, ops, + sync::atomic::{AtomicU64, Ordering}, +}; + +use anyhow::Context as _; +use async_trait::async_trait; +use futures::future; +use tokio::sync::{watch, Mutex, Semaphore}; +use zksync_dal::{ConnectionPool, StorageProcessor}; +use zksync_health_check::HealthUpdater; +use zksync_merkle_tree::TreeEntry; +use zksync_types::{ + snapshots::{uniform_hashed_keys_chunk, SnapshotRecoveryStatus}, + MiniblockNumber, H256, +}; + +use super::{ + helpers::{AsyncTree, AsyncTreeRecovery, GenericAsyncTree, MerkleTreeHealth}, + metrics::{ChunkRecoveryStage, RecoveryStage, RECOVERY_METRICS}, +}; + +#[cfg(test)] +mod tests; + +/// Handler of recovery life cycle events. This functionality is encapsulated in a trait to be able +/// to control recovery behavior in tests. +#[async_trait] +trait HandleRecoveryEvent: fmt::Debug + Send + Sync { + fn recovery_started(&mut self, _chunk_count: u64, _recovered_chunk_count: u64) { + // Default implementation does nothing + } + + async fn chunk_started(&self) { + // Default implementation does nothing + } + + async fn chunk_recovered(&self) { + // Default implementation does nothing + } +} + +/// [`HealthUpdater`]-based [`HandleRecoveryEvent`] implementation. +#[derive(Debug)] +struct RecoveryHealthUpdater<'a> { + inner: &'a HealthUpdater, + chunk_count: u64, + recovered_chunk_count: AtomicU64, +} + +impl<'a> RecoveryHealthUpdater<'a> { + fn new(inner: &'a HealthUpdater) -> Self { + Self { + inner, + chunk_count: 0, + recovered_chunk_count: AtomicU64::new(0), + } + } +} + +#[async_trait] +impl HandleRecoveryEvent for RecoveryHealthUpdater<'_> { + fn recovery_started(&mut self, chunk_count: u64, recovered_chunk_count: u64) { + self.chunk_count = chunk_count; + *self.recovered_chunk_count.get_mut() = recovered_chunk_count; + RECOVERY_METRICS + .recovered_chunk_count + .set(recovered_chunk_count); + } + + async fn chunk_recovered(&self) { + let recovered_chunk_count = self.recovered_chunk_count.fetch_add(1, Ordering::SeqCst) + 1; + RECOVERY_METRICS + .recovered_chunk_count + .set(recovered_chunk_count); + let health = MerkleTreeHealth::Recovery { + chunk_count: self.chunk_count, + recovered_chunk_count, + }; + self.inner.update(health.into()); + } +} + +#[derive(Debug, Clone, Copy)] +struct SnapshotParameters { + miniblock: MiniblockNumber, + expected_root_hash: H256, + log_count: u64, +} + +impl SnapshotParameters { + /// This is intentionally not configurable because chunks must be the same for the entire recovery + /// (i.e., not changed after a node restart). + const DESIRED_CHUNK_SIZE: u64 = 200_000; + + async fn new(pool: &ConnectionPool, recovery: &SnapshotRecoveryStatus) -> anyhow::Result { + let miniblock = recovery.miniblock_number; + let expected_root_hash = recovery.l1_batch_root_hash; + + let mut storage = pool.access_storage().await?; + let log_count = storage + .storage_logs_dal() + .count_miniblock_storage_logs(miniblock) + .await + .with_context(|| format!("Failed getting number of logs for miniblock #{miniblock}"))?; + + Ok(Self { + miniblock, + expected_root_hash, + log_count, + }) + } + + fn chunk_count(&self) -> u64 { + self.log_count.div_ceil(Self::DESIRED_CHUNK_SIZE) + } +} + +/// Options for tree recovery. +#[derive(Debug)] +struct RecoveryOptions<'a> { + chunk_count: u64, + concurrency_limit: usize, + events: Box, +} + +impl GenericAsyncTree { + /// Ensures that the tree is ready for the normal operation, recovering it from a Postgres snapshot + /// if necessary. + pub async fn ensure_ready( + self, + pool: &ConnectionPool, + stop_receiver: &watch::Receiver, + health_updater: &HealthUpdater, + ) -> anyhow::Result> { + let (tree, snapshot_recovery) = match self { + Self::Ready(tree) => return Ok(Some(tree)), + Self::Recovering(tree) => { + let snapshot_recovery = get_snapshot_recovery(pool).await?.context( + "Merkle tree is recovering, but Postgres doesn't contain snapshot recovery information", + )?; + let recovered_version = tree.recovered_version(); + anyhow::ensure!( + u64::from(snapshot_recovery.l1_batch_number.0) == recovered_version, + "Snapshot L1 batch in Postgres ({snapshot_recovery:?}) differs from the recovered Merkle tree version \ + ({recovered_version})" + ); + tracing::info!("Resuming tree recovery with status: {snapshot_recovery:?}"); + (tree, snapshot_recovery) + } + Self::Empty { db, mode } => { + if let Some(snapshot_recovery) = get_snapshot_recovery(pool).await? { + tracing::info!( + "Starting Merkle tree recovery with status {snapshot_recovery:?}" + ); + let l1_batch = snapshot_recovery.l1_batch_number; + let tree = AsyncTreeRecovery::new(db, l1_batch.0.into(), mode); + (tree, snapshot_recovery) + } else { + // Start the tree from scratch. The genesis block will be filled in `TreeUpdater::loop_updating_tree()`. + return Ok(Some(AsyncTree::new(db, mode))); + } + } + }; + + let snapshot = SnapshotParameters::new(pool, &snapshot_recovery).await?; + tracing::debug!("Obtained snapshot parameters: {snapshot:?}"); + let recovery_options = RecoveryOptions { + chunk_count: snapshot.chunk_count(), + concurrency_limit: pool.max_size() as usize, + events: Box::new(RecoveryHealthUpdater::new(health_updater)), + }; + tree.recover(snapshot, recovery_options, pool, stop_receiver) + .await + } +} + +impl AsyncTreeRecovery { + async fn recover( + mut self, + snapshot: SnapshotParameters, + mut options: RecoveryOptions<'_>, + pool: &ConnectionPool, + stop_receiver: &watch::Receiver, + ) -> anyhow::Result> { + let chunk_count = options.chunk_count; + let chunks: Vec<_> = (0..chunk_count) + .map(|chunk_id| uniform_hashed_keys_chunk(chunk_id, chunk_count)) + .collect(); + tracing::info!( + "Recovering Merkle tree from Postgres snapshot in {chunk_count} concurrent chunks" + ); + + let mut storage = pool.access_storage().await?; + let remaining_chunks = self + .filter_chunks(&mut storage, snapshot.miniblock, &chunks) + .await?; + drop(storage); + options + .events + .recovery_started(chunk_count, chunk_count - remaining_chunks.len() as u64); + tracing::info!( + "Filtered recovered key chunks; {} / {chunk_count} chunks remaining", + remaining_chunks.len() + ); + + let tree = Mutex::new(self); + let semaphore = Semaphore::new(options.concurrency_limit); + let chunk_tasks = remaining_chunks.into_iter().map(|chunk| async { + let _permit = semaphore + .acquire() + .await + .context("semaphore is never closed")?; + options.events.chunk_started().await; + Self::recover_key_chunk(&tree, snapshot.miniblock, chunk, pool, stop_receiver).await?; + options.events.chunk_recovered().await; + anyhow::Ok(()) + }); + future::try_join_all(chunk_tasks).await?; + + if *stop_receiver.borrow() { + return Ok(None); + } + + let finalize_latency = RECOVERY_METRICS.latency[&RecoveryStage::Finalize].start(); + let mut tree = tree.into_inner(); + let actual_root_hash = tree.root_hash().await; + anyhow::ensure!( + actual_root_hash == snapshot.expected_root_hash, + "Root hash of recovered tree {actual_root_hash:?} differs from expected root hash {:?}", + snapshot.expected_root_hash + ); + let tree = tree.finalize().await; + let finalize_latency = finalize_latency.observe(); + tracing::info!( + "Finished tree recovery in {finalize_latency:?}; resuming normal tree operation" + ); + Ok(Some(tree)) + } + + /// Filters out `key_chunks` for which recovery was successfully performed. + async fn filter_chunks( + &mut self, + storage: &mut StorageProcessor<'_>, + snapshot_miniblock: MiniblockNumber, + key_chunks: &[ops::RangeInclusive], + ) -> anyhow::Result>> { + let chunk_starts_latency = + RECOVERY_METRICS.latency[&RecoveryStage::LoadChunkStarts].start(); + let chunk_starts = storage + .storage_logs_dal() + .get_chunk_starts_for_miniblock(snapshot_miniblock, key_chunks) + .await + .context("Failed getting chunk starts")?; + let chunk_starts_latency = chunk_starts_latency.observe(); + tracing::debug!( + "Loaded start entries for {} chunks in {chunk_starts_latency:?}", + key_chunks.len() + ); + + let existing_starts = chunk_starts + .iter() + .enumerate() + .filter_map(|(i, &start)| Some((i, start?))); + let start_keys = existing_starts + .clone() + .map(|(_, start_entry)| start_entry.tree_key()) + .collect(); + let tree_entries = self.entries(start_keys).await; + + let mut output = vec![]; + for (tree_entry, (i, db_entry)) in tree_entries.into_iter().zip(existing_starts) { + if tree_entry.is_empty() { + output.push(key_chunks[i].clone()); + continue; + } + anyhow::ensure!( + tree_entry.value == db_entry.value && tree_entry.leaf_index == db_entry.leaf_index, + "Mismatch between entry for key {:0>64x} in Postgres snapshot for miniblock #{snapshot_miniblock} \ + ({db_entry:?}) and tree ({tree_entry:?}); the recovery procedure may be corrupted", + db_entry.key + ); + } + Ok(output) + } + + async fn recover_key_chunk( + tree: &Mutex, + snapshot_miniblock: MiniblockNumber, + key_chunk: ops::RangeInclusive, + pool: &ConnectionPool, + stop_receiver: &watch::Receiver, + ) -> anyhow::Result<()> { + let acquire_connection_latency = + RECOVERY_METRICS.chunk_latency[&ChunkRecoveryStage::AcquireConnection].start(); + let mut storage = pool.access_storage().await?; + acquire_connection_latency.observe(); + + if *stop_receiver.borrow() { + return Ok(()); + } + + let entries_latency = + RECOVERY_METRICS.chunk_latency[&ChunkRecoveryStage::LoadEntries].start(); + let all_entries = storage + .storage_logs_dal() + .get_tree_entries_for_miniblock(snapshot_miniblock, key_chunk.clone()) + .await + .with_context(|| { + format!("Failed getting entries for chunk {key_chunk:?} in snapshot for miniblock #{snapshot_miniblock}") + })?; + drop(storage); + let entries_latency = entries_latency.observe(); + tracing::debug!( + "Loaded {} entries for chunk {key_chunk:?} in {entries_latency:?}", + all_entries.len() + ); + + if *stop_receiver.borrow() { + return Ok(()); + } + + // Sanity check: all entry keys must be distinct. Otherwise, we may end up writing non-final values + // to the tree, since we don't enforce any ordering on entries besides by the hashed key. + for window in all_entries.windows(2) { + let [prev_entry, next_entry] = window else { + unreachable!(); + }; + anyhow::ensure!( + prev_entry.key != next_entry.key, + "node snapshot in Postgres is corrupted: entries {prev_entry:?} and {next_entry:?} \ + have same hashed_key" + ); + } + + let all_entries = all_entries + .into_iter() + .map(|entry| TreeEntry { + key: entry.tree_key(), + value: entry.value, + leaf_index: entry.leaf_index, + }) + .collect(); + let lock_tree_latency = + RECOVERY_METRICS.chunk_latency[&ChunkRecoveryStage::LockTree].start(); + let mut tree = tree.lock().await; + lock_tree_latency.observe(); + + if *stop_receiver.borrow() { + return Ok(()); + } + + let extend_tree_latency = + RECOVERY_METRICS.chunk_latency[&ChunkRecoveryStage::ExtendTree].start(); + tree.extend(all_entries).await; + let extend_tree_latency = extend_tree_latency.observe(); + tracing::debug!( + "Extended Merkle tree with entries for chunk {key_chunk:?} in {extend_tree_latency:?}" + ); + Ok(()) + } +} + +async fn get_snapshot_recovery( + pool: &ConnectionPool, +) -> anyhow::Result> { + let mut storage = pool.access_storage_tagged("metadata_calculator").await?; + Ok(storage + .snapshot_recovery_dal() + .get_applied_snapshot_status() + .await?) +} diff --git a/core/lib/zksync_core/src/metadata_calculator/recovery/tests.rs b/core/lib/zksync_core/src/metadata_calculator/recovery/tests.rs new file mode 100644 index 000000000000..5d1d37deeabd --- /dev/null +++ b/core/lib/zksync_core/src/metadata_calculator/recovery/tests.rs @@ -0,0 +1,315 @@ +//! Tests for metadata calculator snapshot recovery. + +use std::{path::PathBuf, time::Duration}; + +use assert_matches::assert_matches; +use tempfile::TempDir; +use test_casing::test_casing; +use tokio::sync::mpsc; +use zksync_config::configs::{ + chain::OperationsManagerConfig, + database::{MerkleTreeConfig, MerkleTreeMode}, +}; +use zksync_health_check::{CheckHealth, HealthStatus, ReactiveHealthCheck}; +use zksync_merkle_tree::{domain::ZkSyncTree, TreeInstruction}; +use zksync_types::{L1BatchNumber, L2ChainId, StorageLog}; + +use super::*; +use crate::{ + genesis::{ensure_genesis_state, GenesisParams}, + metadata_calculator::{ + helpers::create_db, + tests::{ + extend_db_state, extend_db_state_from_l1_batch, gen_storage_logs, run_calculator, + setup_calculator, + }, + MetadataCalculator, MetadataCalculatorConfig, + }, + utils::testonly::prepare_recovery_snapshot, +}; + +#[test] +fn calculating_chunk_count() { + let mut snapshot = SnapshotParameters { + miniblock: MiniblockNumber(1), + log_count: 160_000_000, + expected_root_hash: H256::zero(), + }; + assert_eq!(snapshot.chunk_count(), 800); + + snapshot.log_count += 1; + assert_eq!(snapshot.chunk_count(), 801); + + snapshot.log_count = 100; + assert_eq!(snapshot.chunk_count(), 1); +} + +async fn create_tree_recovery(path: PathBuf, l1_batch: L1BatchNumber) -> AsyncTreeRecovery { + let db = create_db( + path, + 0, + 16 << 20, // 16 MiB, + Duration::ZERO, // writes should never be stalled in tests + 500, + ) + .await + .unwrap(); + AsyncTreeRecovery::new(db, l1_batch.0.into(), MerkleTreeMode::Full) +} + +#[tokio::test] +async fn basic_recovery_workflow() { + let pool = ConnectionPool::test_pool().await; + let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); + let snapshot_recovery = prepare_recovery_snapshot_with_genesis(&pool, &temp_dir).await; + let snapshot = SnapshotParameters::new(&pool, &snapshot_recovery) + .await + .unwrap(); + + assert!(snapshot.log_count > 200); + + let (_stop_sender, stop_receiver) = watch::channel(false); + for chunk_count in [1, 4, 9, 16, 60, 256] { + println!("Recovering tree with {chunk_count} chunks"); + + let tree_path = temp_dir.path().join(format!("recovery-{chunk_count}")); + let tree = create_tree_recovery(tree_path, L1BatchNumber(1)).await; + let (health_check, health_updater) = ReactiveHealthCheck::new("tree"); + let recovery_options = RecoveryOptions { + chunk_count, + concurrency_limit: 1, + events: Box::new(RecoveryHealthUpdater::new(&health_updater)), + }; + let tree = tree + .recover(snapshot, recovery_options, &pool, &stop_receiver) + .await + .unwrap() + .expect("Tree recovery unexpectedly aborted"); + + assert_eq!(tree.root_hash(), snapshot_recovery.l1_batch_root_hash); + let health = health_check.check_health().await; + assert_matches!(health.status(), HealthStatus::Ready); + } +} + +async fn prepare_recovery_snapshot_with_genesis( + pool: &ConnectionPool, + temp_dir: &TempDir, +) -> SnapshotRecoveryStatus { + let mut storage = pool.access_storage().await.unwrap(); + ensure_genesis_state(&mut storage, L2ChainId::from(270), &GenesisParams::mock()) + .await + .unwrap(); + let mut logs = gen_storage_logs(100..300, 1).pop().unwrap(); + + // Add all logs from the genesis L1 batch to `logs` so that they cover all state keys. + let genesis_logs = storage + .storage_logs_dal() + .get_touched_slots_for_l1_batch(L1BatchNumber(0)) + .await + .unwrap(); + let genesis_logs = genesis_logs + .into_iter() + .map(|(key, value)| StorageLog::new_write_log(key, value)); + logs.extend(genesis_logs); + extend_db_state(&mut storage, vec![logs]).await; + drop(storage); + + // Ensure that metadata for L1 batch #1 is present in the DB. + let (calculator, _) = setup_calculator(&temp_dir.path().join("init"), pool).await; + let l1_batch_root_hash = run_calculator(calculator, pool.clone()).await; + + SnapshotRecoveryStatus { + l1_batch_number: L1BatchNumber(1), + l1_batch_root_hash, + miniblock_number: MiniblockNumber(1), + miniblock_root_hash: H256::zero(), // not used + storage_logs_chunks_processed: vec![], + } +} + +#[derive(Debug)] +struct TestEventListener { + expected_recovered_chunks: u64, + stop_threshold: u64, + processed_chunk_count: AtomicU64, + stop_sender: watch::Sender, +} + +impl TestEventListener { + fn new(stop_threshold: u64, stop_sender: watch::Sender) -> Self { + Self { + expected_recovered_chunks: 0, + stop_threshold, + processed_chunk_count: AtomicU64::new(0), + stop_sender, + } + } + + fn expect_recovered_chunks(mut self, count: u64) -> Self { + self.expected_recovered_chunks = count; + self + } +} + +#[async_trait] +impl HandleRecoveryEvent for TestEventListener { + fn recovery_started(&mut self, _chunk_count: u64, recovered_chunk_count: u64) { + assert_eq!(recovered_chunk_count, self.expected_recovered_chunks); + } + + async fn chunk_recovered(&self) { + let processed_chunk_count = self.processed_chunk_count.fetch_add(1, Ordering::SeqCst) + 1; + if processed_chunk_count >= self.stop_threshold { + self.stop_sender.send_replace(true); + } + } +} + +#[test_casing(3, [5, 7, 8])] +#[tokio::test] +async fn recovery_fault_tolerance(chunk_count: u64) { + let pool = ConnectionPool::test_pool().await; + let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); + let snapshot_recovery = prepare_recovery_snapshot_with_genesis(&pool, &temp_dir).await; + + let tree_path = temp_dir.path().join("recovery"); + let tree = create_tree_recovery(tree_path.clone(), L1BatchNumber(1)).await; + let (stop_sender, stop_receiver) = watch::channel(false); + let recovery_options = RecoveryOptions { + chunk_count, + concurrency_limit: 1, + events: Box::new(TestEventListener::new(1, stop_sender)), + }; + let snapshot = SnapshotParameters::new(&pool, &snapshot_recovery) + .await + .unwrap(); + assert!(tree + .recover(snapshot, recovery_options, &pool, &stop_receiver) + .await + .unwrap() + .is_none()); + + // Emulate a restart and recover 2 more chunks. + let mut tree = create_tree_recovery(tree_path.clone(), L1BatchNumber(1)).await; + assert_ne!(tree.root_hash().await, snapshot_recovery.l1_batch_root_hash); + let (stop_sender, stop_receiver) = watch::channel(false); + let recovery_options = RecoveryOptions { + chunk_count, + concurrency_limit: 1, + events: Box::new(TestEventListener::new(2, stop_sender).expect_recovered_chunks(1)), + }; + assert!(tree + .recover(snapshot, recovery_options, &pool, &stop_receiver) + .await + .unwrap() + .is_none()); + + // Emulate another restart and recover remaining chunks. + let mut tree = create_tree_recovery(tree_path.clone(), L1BatchNumber(1)).await; + assert_ne!(tree.root_hash().await, snapshot_recovery.l1_batch_root_hash); + let (stop_sender, stop_receiver) = watch::channel(false); + let recovery_options = RecoveryOptions { + chunk_count, + concurrency_limit: 1, + events: Box::new(TestEventListener::new(u64::MAX, stop_sender).expect_recovered_chunks(3)), + }; + let tree = tree + .recover(snapshot, recovery_options, &pool, &stop_receiver) + .await + .unwrap() + .expect("Tree recovery unexpectedly aborted"); + assert_eq!(tree.root_hash(), snapshot_recovery.l1_batch_root_hash); +} + +#[derive(Debug)] +enum RecoveryWorkflowCase { + Stop, + CreateBatch, +} + +impl RecoveryWorkflowCase { + const ALL: [Self; 2] = [Self::Stop, Self::CreateBatch]; +} + +#[test_casing(2, RecoveryWorkflowCase::ALL)] +#[tokio::test] +async fn entire_recovery_workflow(case: RecoveryWorkflowCase) { + let pool = ConnectionPool::test_pool().await; + // Emulate the recovered view of Postgres. Unlike with previous tests, we don't perform genesis. + let snapshot_logs = gen_storage_logs(100..300, 1).pop().unwrap(); + let mut storage = pool.access_storage().await.unwrap(); + let snapshot_recovery = prepare_recovery_snapshot(&mut storage, 23, &snapshot_logs).await; + + let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); + let merkle_tree_config = MerkleTreeConfig { + path: temp_dir.path().to_str().unwrap().to_owned(), + ..MerkleTreeConfig::default() + }; + let calculator_config = MetadataCalculatorConfig::for_main_node( + &merkle_tree_config, + &OperationsManagerConfig { delay_interval: 50 }, + ); + let mut calculator = MetadataCalculator::new(calculator_config, None) + .await + .unwrap(); + let (delay_sx, mut delay_rx) = mpsc::unbounded_channel(); + calculator.delayer.delay_notifier = delay_sx; + + let (stop_sender, stop_receiver) = watch::channel(false); + let tree_reader = calculator.tree_reader(); + let calculator_task = tokio::spawn(calculator.run(pool.clone(), stop_receiver)); + + match case { + // Wait until the tree is fully initialized and stop the calculator. + RecoveryWorkflowCase::Stop => { + let tree_info = tree_reader.await.info().await; + assert_eq!(tree_info.root_hash, snapshot_recovery.l1_batch_root_hash); + assert_eq!(tree_info.leaf_count, 200); + assert_eq!( + tree_info.next_l1_batch_number, + snapshot_recovery.l1_batch_number + 1 + ); + } + + // Emulate state keeper adding a new L1 batch to Postgres. + RecoveryWorkflowCase::CreateBatch => { + tree_reader.await; + + let mut storage = storage.start_transaction().await.unwrap(); + let mut new_logs = gen_storage_logs(500..600, 1).pop().unwrap(); + // Logs must be sorted by `log.key` to match their enum index assignment + new_logs.sort_unstable_by_key(|log| log.key); + + extend_db_state_from_l1_batch( + &mut storage, + snapshot_recovery.l1_batch_number + 1, + [new_logs.clone()], + ) + .await; + storage.commit().await.unwrap(); + + // Wait until the inserted L1 batch is processed by the calculator. + let new_root_hash = loop { + let (next_l1_batch, root_hash) = delay_rx.recv().await.unwrap(); + if next_l1_batch == snapshot_recovery.l1_batch_number + 2 { + break root_hash; + } + }; + + let all_tree_instructions: Vec<_> = snapshot_logs + .iter() + .chain(&new_logs) + .enumerate() + .map(|(i, log)| TreeInstruction::write(log.key, i as u64 + 1, log.value)) + .collect(); + let expected_new_root_hash = + ZkSyncTree::process_genesis_batch(&all_tree_instructions).root_hash; + assert_ne!(expected_new_root_hash, snapshot_recovery.l1_batch_root_hash); + assert_eq!(new_root_hash, expected_new_root_hash); + } + } + + stop_sender.send_replace(true); + calculator_task.await.expect("calculator panicked").unwrap(); +} diff --git a/core/lib/zksync_core/src/metadata_calculator/tests.rs b/core/lib/zksync_core/src/metadata_calculator/tests.rs index 4e480ce1d998..c5c99db624cd 100644 --- a/core/lib/zksync_core/src/metadata_calculator/tests.rs +++ b/core/lib/zksync_core/src/metadata_calculator/tests.rs @@ -1,32 +1,31 @@ //! Tests for the metadata calculator component life cycle. -// TODO (PLA-708): test full recovery life cycle - -use std::{future::Future, ops, panic, path::Path, time::Duration}; +use std::{future::Future, ops, panic, path::Path, sync::Arc, time::Duration}; use assert_matches::assert_matches; use itertools::Itertools; use tempfile::TempDir; use tokio::sync::{mpsc, watch}; -use zksync_config::configs::{chain::OperationsManagerConfig, database::MerkleTreeConfig}; -use zksync_contracts::BaseSystemContracts; +use zksync_config::configs::{ + chain::OperationsManagerConfig, + database::{MerkleTreeConfig, MerkleTreeMode}, +}; use zksync_dal::{ConnectionPool, StorageProcessor}; use zksync_health_check::{CheckHealth, HealthStatus}; use zksync_merkle_tree::domain::ZkSyncTree; use zksync_object_store::{ObjectStore, ObjectStoreFactory}; +use zksync_prover_interface::inputs::PrepareBasicCircuitsJob; use zksync_types::{ - block::{BlockGasCount, L1BatchHeader, MiniblockHasher, MiniblockHeader}, - proofs::PrepareBasicCircuitsJob, - AccountTreeId, Address, L1BatchNumber, L2ChainId, MiniblockNumber, ProtocolVersionId, + block::L1BatchHeader, AccountTreeId, Address, L1BatchNumber, L2ChainId, MiniblockNumber, StorageKey, StorageLog, H256, }; use zksync_utils::u32_to_h256; -use super::{ - GenericAsyncTree, L1BatchWithLogs, MetadataCalculator, MetadataCalculatorConfig, - MetadataCalculatorModeConfig, +use super::{GenericAsyncTree, L1BatchWithLogs, MetadataCalculator, MetadataCalculatorConfig}; +use crate::{ + genesis::{ensure_genesis_state, GenesisParams}, + utils::testonly::{create_l1_batch, create_miniblock}, }; -use crate::genesis::{ensure_genesis_state, GenesisParams}; const RUN_TIMEOUT: Duration = Duration::from_secs(30); @@ -50,8 +49,9 @@ async fn genesis_creation() { run_calculator(calculator, pool.clone()).await; let (calculator, _) = setup_calculator(temp_dir.path(), &pool).await; - let GenericAsyncTree::Ready(tree) = &calculator.tree else { - panic!("Unexpected tree state: {:?}", calculator.tree); + let tree = calculator.create_tree().await.unwrap(); + let GenericAsyncTree::Ready(tree) = tree else { + panic!("Unexpected tree state: {tree:?}"); }; assert_eq!(tree.next_l1_batch_number(), L1BatchNumber(1)); } @@ -78,8 +78,9 @@ async fn basic_workflow() { assert!(merkle_paths.iter().all(|log| log.is_write)); let (calculator, _) = setup_calculator(temp_dir.path(), &pool).await; - let GenericAsyncTree::Ready(tree) = &calculator.tree else { - panic!("Unexpected tree state: {:?}", calculator.tree); + let tree = calculator.create_tree().await.unwrap(); + let GenericAsyncTree::Ready(tree) = tree else { + panic!("Unexpected tree state: {tree:?}"); }; assert_eq!(tree.next_l1_batch_number(), L1BatchNumber(2)); } @@ -91,9 +92,9 @@ async fn expected_tree_hash(pool: &ConnectionPool) -> H256 { .get_sealed_l1_batch_number() .await .unwrap() - .0; + .expect("No L1 batches in Postgres"); let mut all_logs = vec![]; - for i in 0..=sealed_l1_batch_number { + for i in 0..=sealed_l1_batch_number.0 { let logs = L1BatchWithLogs::new(&mut storage, L1BatchNumber(i)).await; let logs = logs.unwrap().storage_logs; all_logs.extend(logs); @@ -239,16 +240,12 @@ async fn running_metadata_calculator_with_additional_blocks() { async fn shutting_down_calculator() { let pool = ConnectionPool::test_pool().await; let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB"); - let (merkle_tree_config, mut operation_config) = create_config(temp_dir.path()); + let (merkle_tree_config, mut operation_config) = + create_config(temp_dir.path(), MerkleTreeMode::Lightweight); operation_config.delay_interval = 30_000; // ms; chosen to be larger than `RUN_TIMEOUT` - let calculator = setup_calculator_with_options( - &merkle_tree_config, - &operation_config, - &pool, - MetadataCalculatorModeConfig::Lightweight, - ) - .await; + let calculator = + setup_calculator_with_options(&merkle_tree_config, &operation_config, &pool, None).await; reset_db_state(&pool, 5).await; @@ -286,13 +283,7 @@ async fn test_postgres_backup_recovery( // Re-insert the last batch without metadata immediately. storage .blocks_dal() - .insert_l1_batch( - batch_without_metadata, - &[], - BlockGasCount::default(), - &[], - &[], - ) + .insert_mock_l1_batch(batch_without_metadata) .await .unwrap(); insert_initial_writes_for_batch(&mut storage, batch_without_metadata.number).await; @@ -317,7 +308,7 @@ async fn test_postgres_backup_recovery( for batch_header in &removed_batches { let mut txn = storage.start_transaction().await.unwrap(); txn.blocks_dal() - .insert_l1_batch(batch_header, &[], BlockGasCount::default(), &[], &[]) + .insert_mock_l1_batch(batch_header) .await .unwrap(); insert_initial_writes_for_batch(&mut txn, batch_header.number).await; @@ -364,27 +355,29 @@ async fn postgres_backup_recovery_with_excluded_metadata() { pub(crate) async fn setup_calculator( db_path: &Path, pool: &ConnectionPool, -) -> (MetadataCalculator, Box) { - let store_factory = &ObjectStoreFactory::mock(); - let (merkle_tree_config, operation_manager) = create_config(db_path); - let mode = MetadataCalculatorModeConfig::Full { - store_factory: Some(store_factory), - }; +) -> (MetadataCalculator, Arc) { + let store_factory = ObjectStoreFactory::mock(); + let store = store_factory.create_store().await; + let (merkle_tree_config, operation_manager) = create_config(db_path, MerkleTreeMode::Full); let calculator = - setup_calculator_with_options(&merkle_tree_config, &operation_manager, pool, mode).await; + setup_calculator_with_options(&merkle_tree_config, &operation_manager, pool, Some(store)) + .await; (calculator, store_factory.create_store().await) } async fn setup_lightweight_calculator(db_path: &Path, pool: &ConnectionPool) -> MetadataCalculator { - let mode = MetadataCalculatorModeConfig::Lightweight; - let (db_config, operation_config) = create_config(db_path); - setup_calculator_with_options(&db_config, &operation_config, pool, mode).await + let (db_config, operation_config) = create_config(db_path, MerkleTreeMode::Lightweight); + setup_calculator_with_options(&db_config, &operation_config, pool, None).await } -fn create_config(db_path: &Path) -> (MerkleTreeConfig, OperationsManagerConfig) { +fn create_config( + db_path: &Path, + mode: MerkleTreeMode, +) -> (MerkleTreeConfig, OperationsManagerConfig) { let db_config = MerkleTreeConfig { path: path_to_string(&db_path.join("new")), - ..Default::default() + mode, + ..MerkleTreeConfig::default() }; let operation_config = OperationsManagerConfig { @@ -397,11 +390,13 @@ async fn setup_calculator_with_options( merkle_tree_config: &MerkleTreeConfig, operation_config: &OperationsManagerConfig, pool: &ConnectionPool, - mode: MetadataCalculatorModeConfig<'_>, + object_store: Option>, ) -> MetadataCalculator { let calculator_config = - MetadataCalculatorConfig::for_main_node(merkle_tree_config, operation_config, mode); - let metadata_calculator = MetadataCalculator::new(&calculator_config).await; + MetadataCalculatorConfig::for_main_node(merkle_tree_config, operation_config); + let metadata_calculator = MetadataCalculator::new(calculator_config, object_store) + .await + .unwrap(); let mut storage = pool.access_storage().await.unwrap(); if storage.blocks_dal().is_genesis_needed().await.unwrap() { @@ -457,6 +452,11 @@ pub(crate) async fn reset_db_state(pool: &ConnectionPool, num_batches: usize) { .delete_l1_batches(L1BatchNumber(0)) .await .unwrap(); + storage + .blocks_dal() + .delete_initial_writes(L1BatchNumber(0)) + .await + .unwrap(); storage .basic_witness_input_producer_dal() .delete_all_jobs() @@ -472,46 +472,33 @@ pub(super) async fn extend_db_state( new_logs: impl IntoIterator>, ) { let mut storage = storage.start_transaction().await.unwrap(); - let next_l1_batch = storage + let sealed_l1_batch = storage .blocks_dal() .get_sealed_l1_batch_number() .await .unwrap() - .0 - + 1; - - let base_system_contracts = BaseSystemContracts::load_from_disk(); - for (idx, batch_logs) in (next_l1_batch..).zip(new_logs) { - let batch_number = L1BatchNumber(idx); - let mut header = L1BatchHeader::new( - batch_number, - 0, - Address::default(), - base_system_contracts.hashes(), - Default::default(), - ); - header.is_finished = true; + .expect("no L1 batches in Postgres"); + extend_db_state_from_l1_batch(&mut storage, sealed_l1_batch + 1, new_logs).await; + storage.commit().await.unwrap(); +} + +pub(super) async fn extend_db_state_from_l1_batch( + storage: &mut StorageProcessor<'_>, + next_l1_batch: L1BatchNumber, + new_logs: impl IntoIterator>, +) { + assert!(storage.in_transaction(), "must be called in DB transaction"); + for (idx, batch_logs) in (next_l1_batch.0..).zip(new_logs) { + let header = create_l1_batch(idx); + let batch_number = header.number; // Assumes that L1 batch consists of only one miniblock. - let miniblock_number = MiniblockNumber(idx); - let miniblock_header = MiniblockHeader { - number: miniblock_number, - timestamp: header.timestamp, - hash: MiniblockHasher::new(miniblock_number, header.timestamp, H256::zero()) - .finalize(ProtocolVersionId::latest()), - l1_tx_count: header.l1_tx_count, - l2_tx_count: header.l2_tx_count, - base_fee_per_gas: header.base_fee_per_gas, - l1_gas_price: 0, - l2_fair_gas_price: 0, - base_system_contracts_hashes: base_system_contracts.hashes(), - protocol_version: Some(ProtocolVersionId::latest()), - virtual_blocks: 0, - }; + let miniblock_header = create_miniblock(idx); + let miniblock_number = miniblock_header.number; storage .blocks_dal() - .insert_l1_batch(&header, &[], BlockGasCount::default(), &[], &[]) + .insert_mock_l1_batch(&header) .await .unwrap(); storage @@ -528,9 +515,8 @@ pub(super) async fn extend_db_state( .mark_miniblocks_as_executed_in_l1_batch(batch_number) .await .unwrap(); - insert_initial_writes_for_batch(&mut storage, batch_number).await; + insert_initial_writes_for_batch(storage, batch_number).await; } - storage.commit().await.unwrap(); } async fn insert_initial_writes_for_batch( @@ -541,6 +527,7 @@ async fn insert_initial_writes_for_batch( .storage_logs_dal() .get_touched_slots_for_l1_batch(l1_batch_number) .await + .unwrap() .into_iter() .filter_map(|(key, value)| (!value.is_zero()).then_some(key)) .collect(); @@ -609,7 +596,8 @@ async fn remove_l1_batches( .blocks_dal() .get_sealed_l1_batch_number() .await - .unwrap(); + .unwrap() + .expect("no L1 batches in Postgres"); assert!(sealed_l1_batch_number >= last_l1_batch_to_keep); let mut batch_headers = vec![]; @@ -627,6 +615,11 @@ async fn remove_l1_batches( .delete_l1_batches(last_l1_batch_to_keep) .await .unwrap(); + storage + .blocks_dal() + .delete_initial_writes(last_l1_batch_to_keep) + .await + .unwrap(); batch_headers } @@ -645,7 +638,8 @@ async fn deduplication_works_as_expected() { let initial_writes = storage .storage_logs_dal() .get_l1_batches_and_indices_for_initial_writes(&hashed_keys) - .await; + .await + .unwrap(); assert_eq!(initial_writes.len(), hashed_keys.len()); assert!(initial_writes .values() @@ -664,7 +658,8 @@ async fn deduplication_works_as_expected() { let initial_writes = storage .storage_logs_dal() .get_l1_batches_and_indices_for_initial_writes(&hashed_keys) - .await; + .await + .unwrap(); assert_eq!(initial_writes.len(), hashed_keys.len()); assert!(initial_writes .values() @@ -673,7 +668,8 @@ async fn deduplication_works_as_expected() { let initial_writes = storage .storage_logs_dal() .get_l1_batches_and_indices_for_initial_writes(&new_hashed_keys) - .await; + .await + .unwrap(); assert_eq!(initial_writes.len(), new_hashed_keys.len()); assert!(initial_writes .values() @@ -689,7 +685,8 @@ async fn deduplication_works_as_expected() { let initial_writes = storage .storage_logs_dal() .get_l1_batches_and_indices_for_initial_writes(&no_op_hashed_keys) - .await; + .await + .unwrap(); assert!(initial_writes.is_empty()); let updated_logs: Vec<_> = no_op_logs @@ -706,7 +703,8 @@ async fn deduplication_works_as_expected() { let initial_writes = storage .storage_logs_dal() .get_l1_batches_and_indices_for_initial_writes(&no_op_hashed_keys) - .await; + .await + .unwrap(); assert_eq!(initial_writes.len(), no_op_hashed_keys.len() / 2); for key in no_op_hashed_keys.iter().step_by(2) { assert_eq!(initial_writes[key].0, L1BatchNumber(4)); diff --git a/core/lib/zksync_core/src/metadata_calculator/updater.rs b/core/lib/zksync_core/src/metadata_calculator/updater.rs index 575ba99bb284..917ab68fbff7 100644 --- a/core/lib/zksync_core/src/metadata_calculator/updater.rs +++ b/core/lib/zksync_core/src/metadata_calculator/updater.rs @@ -1,6 +1,6 @@ //! Tree updater trait and its implementations. -use std::{ops, time::Instant}; +use std::{ops, sync::Arc, time::Instant}; use anyhow::Context as _; use futures::{future, FutureExt}; @@ -11,7 +11,9 @@ use zksync_dal::{ConnectionPool, StorageProcessor}; use zksync_health_check::HealthUpdater; use zksync_merkle_tree::domain::TreeMetadata; use zksync_object_store::ObjectStore; -use zksync_types::{block::L1BatchHeader, writes::InitialStorageWrite, L1BatchNumber, H256, U256}; +use zksync_types::{ + block::L1BatchHeader, writes::InitialStorageWrite, L1BatchNumber, ProtocolVersionId, H256, U256, +}; use super::{ helpers::{AsyncTree, Delayer, L1BatchWithLogs}, @@ -24,14 +26,14 @@ use crate::utils::wait_for_l1_batch; pub(super) struct TreeUpdater { tree: AsyncTree, max_l1_batches_per_iter: usize, - object_store: Option>, + object_store: Option>, } impl TreeUpdater { pub fn new( tree: AsyncTree, max_l1_batches_per_iter: usize, - object_store: Option>, + object_store: Option>, ) -> Self { Self { tree, @@ -204,14 +206,14 @@ impl TreeUpdater { .await .unwrap(); - let is_pre_boojum = header + // TODO(PLA-731): ensure that the protocol version is always available. + let protocol_version = header .protocol_version - .map(|v| v.is_pre_boojum()) - .unwrap_or(true); - let events_queue_commitment = (!is_pre_boojum).then(|| { + .unwrap_or(ProtocolVersionId::last_potentially_undefined()); + let events_queue_commitment = (!protocol_version.is_pre_boojum()).then(|| { let events_queue = events_queue.expect("Events queue is required for post-boojum batch"); - events_queue_commitment(&events_queue, is_pre_boojum) + events_queue_commitment(&events_queue, protocol_version) .expect("Events queue commitment is required for post-boojum batch") }); events_queue_commitment_latency.observe(); @@ -225,7 +227,7 @@ impl TreeUpdater { .unwrap() .unwrap(); let bootloader_initial_content_commitment = - bootloader_initial_content_commitment(&initial_bootloader_contents, is_pre_boojum); + bootloader_initial_content_commitment(&initial_bootloader_contents, protocol_version); bootloader_commitment_latency.observe(); ( @@ -239,11 +241,15 @@ impl TreeUpdater { mut storage: StorageProcessor<'_>, next_l1_batch_to_seal: &mut L1BatchNumber, ) { - let last_sealed_l1_batch = storage + let Some(last_sealed_l1_batch) = storage .blocks_dal() .get_sealed_l1_batch_number() .await - .unwrap(); + .unwrap() + else { + tracing::trace!("No L1 batches to seal: Postgres storage is empty"); + return; + }; let last_requested_l1_batch = next_l1_batch_to_seal.0 + self.max_l1_batches_per_iter as u32 - 1; let last_requested_l1_batch = last_requested_l1_batch.min(last_sealed_l1_batch.0); @@ -300,7 +306,7 @@ impl TreeUpdater { tracing::info!( "Initialized metadata calculator with {max_batches_per_iter} max L1 batches per iteration. \ - Next L1 batch for Merkle tree: {next_l1_batch_to_seal}, current Postgres L1 batch: {current_db_batch}, \ + Next L1 batch for Merkle tree: {next_l1_batch_to_seal}, current Postgres L1 batch: {current_db_batch:?}, \ last L1 batch with metadata: {last_l1_batch_with_metadata:?}", max_batches_per_iter = self.max_l1_batches_per_iter ); diff --git a/core/lib/zksync_core/src/metrics.rs b/core/lib/zksync_core/src/metrics.rs index 2c1559aae277..56e8223b8939 100644 --- a/core/lib/zksync_core/src/metrics.rs +++ b/core/lib/zksync_core/src/metrics.rs @@ -18,6 +18,7 @@ pub(crate) enum InitStage { EthTxManager, Tree, BasicWitnessInputProducer, + Consensus, } impl fmt::Display for InitStage { @@ -32,6 +33,7 @@ impl fmt::Display for InitStage { Self::EthTxManager => formatter.write_str("eth_tx_manager"), Self::Tree => formatter.write_str("tree"), Self::BasicWitnessInputProducer => formatter.write_str("basic_witness_input_producer"), + Self::Consensus => formatter.write_str("consensus"), } } } diff --git a/core/lib/zksync_core/src/proof_data_handler/mod.rs b/core/lib/zksync_core/src/proof_data_handler/mod.rs index f1227d8298c9..56a48e18cd67 100644 --- a/core/lib/zksync_core/src/proof_data_handler/mod.rs +++ b/core/lib/zksync_core/src/proof_data_handler/mod.rs @@ -1,4 +1,4 @@ -use std::net::SocketAddr; +use std::{net::SocketAddr, sync::Arc}; use anyhow::Context as _; use axum::{extract::Path, routing::post, Json, Router}; @@ -9,9 +9,9 @@ use zksync_config::{ }; use zksync_dal::ConnectionPool; use zksync_object_store::ObjectStore; +use zksync_prover_interface::api::{ProofGenerationDataRequest, SubmitProofRequest}; use zksync_types::{ protocol_version::{L1VerifierConfig, VerifierParams}, - prover_server_api::{ProofGenerationDataRequest, SubmitProofRequest}, H256, }; @@ -34,7 +34,7 @@ fn fri_l1_verifier_config(contracts_config: &ContractsConfig) -> L1VerifierConfi pub(crate) async fn run_server( config: ProofDataHandlerConfig, contracts_config: ContractsConfig, - blob_store: Box, + blob_store: Arc, pool: ConnectionPool, mut stop_receiver: watch::Receiver, ) -> anyhow::Result<()> { diff --git a/core/lib/zksync_core/src/proof_data_handler/request_processor.rs b/core/lib/zksync_core/src/proof_data_handler/request_processor.rs index 5a3302ee926d..91b2f4124a0d 100644 --- a/core/lib/zksync_core/src/proof_data_handler/request_processor.rs +++ b/core/lib/zksync_core/src/proof_data_handler/request_processor.rs @@ -11,13 +11,13 @@ use zksync_config::configs::{ }; use zksync_dal::{ConnectionPool, SqlxError}; use zksync_object_store::{ObjectStore, ObjectStoreError}; +use zksync_prover_interface::api::{ + ProofGenerationData, ProofGenerationDataRequest, ProofGenerationDataResponse, + SubmitProofRequest, SubmitProofResponse, +}; use zksync_types::{ commitment::serialize_commitments, protocol_version::{FriProtocolVersionId, L1VerifierConfig}, - prover_server_api::{ - ProofGenerationData, ProofGenerationDataRequest, ProofGenerationDataResponse, - SubmitProofRequest, SubmitProofResponse, - }, web3::signing::keccak256, L1BatchNumber, H256, }; @@ -65,13 +65,13 @@ impl IntoResponse for RequestProcessorError { impl RequestProcessor { pub(crate) fn new( - blob_store: Box, + blob_store: Arc, pool: ConnectionPool, config: ProofDataHandlerConfig, l1_verifier_config: Option, ) -> Self { Self { - blob_store: Arc::from(blob_store), + blob_store, pool, config, l1_verifier_config, diff --git a/core/lib/zksync_core/src/reorg_detector/mod.rs b/core/lib/zksync_core/src/reorg_detector/mod.rs index f0ae656ce099..f645bfb96dbd 100644 --- a/core/lib/zksync_core/src/reorg_detector/mod.rs +++ b/core/lib/zksync_core/src/reorg_detector/mod.rs @@ -1,4 +1,4 @@ -use std::{fmt, future::Future, time::Duration}; +use std::{fmt, time::Duration}; use anyhow::Context as _; use async_trait::async_trait; @@ -15,7 +15,7 @@ use zksync_web3_decl::{ use crate::{ metrics::{CheckerComponent, EN_METRICS}, - utils::wait_for_l1_batch_with_metadata, + utils::{binary_search_with, wait_for_l1_batch_with_metadata}, }; #[cfg(test)] @@ -32,6 +32,13 @@ enum HashMatchError { Using an earlier snapshot could help." )] EarliestHashMismatch(L1BatchNumber), + #[error( + "Unrecoverable error: the earliest L1 batch #{0} in the local DB \ + is truncated on the main node. Make sure you're connected to the right network; \ + if you've recovered from a snapshot, re-check snapshot authenticity. \ + Using an earlier snapshot could help." + )] + EarliestL1BatchTruncated(L1BatchNumber), #[error("Internal error")] Internal(#[from] anyhow::Error), } @@ -48,6 +55,10 @@ fn is_transient_err(err: &RpcError) -> bool { #[async_trait] trait MainNodeClient: fmt::Debug + Send + Sync { + async fn sealed_miniblock_number(&self) -> Result; + + async fn sealed_l1_batch_number(&self) -> Result; + async fn miniblock_hash(&self, number: MiniblockNumber) -> Result, RpcError>; async fn l1_batch_root_hash(&self, number: L1BatchNumber) -> Result, RpcError>; @@ -55,6 +66,18 @@ trait MainNodeClient: fmt::Debug + Send + Sync { #[async_trait] impl MainNodeClient for HttpClient { + async fn sealed_miniblock_number(&self) -> Result { + let number = self.get_block_number().await?; + let number = u32::try_from(number).map_err(|err| RpcError::Custom(err.to_owned()))?; + Ok(MiniblockNumber(number)) + } + + async fn sealed_l1_batch_number(&self) -> Result { + let number = self.get_l1_batch_number().await?; + let number = u32::try_from(number).map_err(|err| RpcError::Custom(err.to_owned()))?; + Ok(L1BatchNumber(number)) + } + async fn miniblock_hash(&self, number: MiniblockNumber) -> Result, RpcError> { Ok(self .get_block_by_number(number.0.into(), false) @@ -85,10 +108,38 @@ impl UpdateCorrectBlock for () { last_correct_miniblock: MiniblockNumber, last_correct_l1_batch: L1BatchNumber, ) { - EN_METRICS.last_correct_batch[&CheckerComponent::ReorgDetector] - .set(last_correct_miniblock.0.into()); - EN_METRICS.last_correct_miniblock[&CheckerComponent::ReorgDetector] - .set(last_correct_l1_batch.0.into()); + let last_correct_miniblock = last_correct_miniblock.0.into(); + let prev_checked_miniblock = EN_METRICS.last_correct_miniblock + [&CheckerComponent::ReorgDetector] + .set(last_correct_miniblock); + if prev_checked_miniblock != last_correct_miniblock { + tracing::debug!("No reorg at miniblock #{last_correct_miniblock}"); + } + + let last_correct_l1_batch = last_correct_l1_batch.0.into(); + let prev_checked_l1_batch = EN_METRICS.last_correct_batch[&CheckerComponent::ReorgDetector] + .set(last_correct_l1_batch); + if prev_checked_l1_batch != last_correct_l1_batch { + tracing::debug!("No reorg at L1 batch #{last_correct_l1_batch}"); + } + } +} + +/// Output of hash match methods in [`ReorgDetector`]. +#[derive(Debug)] +enum MatchOutput { + Match, + Mismatch, + NoRemoteReference, +} + +impl MatchOutput { + fn new(is_match: bool) -> Self { + if is_match { + Self::Match + } else { + Self::Mismatch + } } } @@ -135,7 +186,7 @@ impl ReorgDetector { async fn miniblock_hashes_match( &self, miniblock_number: MiniblockNumber, - ) -> Result { + ) -> Result { let mut storage = self.pool.access_storage().await?; let local_hash = storage .blocks_dal() @@ -151,7 +202,7 @@ impl ReorgDetector { // Due to reorg, locally we may be ahead of the main node. // Lack of the hash on the main node is treated as a hash match, // We need to wait for our knowledge of main node to catch up. - return Ok(true); + return Ok(MatchOutput::NoRemoteReference); }; if remote_hash != local_hash { @@ -160,14 +211,39 @@ impl ReorgDetector { main node {remote_hash:?} (miniblock #{miniblock_number})" ); } - Ok(remote_hash == local_hash) + Ok(MatchOutput::new(remote_hash == local_hash)) + } + + /// Checks hash correspondence for the latest miniblock sealed both locally and on the main node. + async fn check_sealed_miniblock_hash( + &self, + sealed_miniblock_number: MiniblockNumber, + ) -> Result<(MiniblockNumber, bool), HashMatchError> { + let mut main_node_sealed_miniblock_number = sealed_miniblock_number; + loop { + let checked_number = sealed_miniblock_number.min(main_node_sealed_miniblock_number); + match self.miniblock_hashes_match(checked_number).await? { + MatchOutput::Match => break Ok((checked_number, true)), + MatchOutput::Mismatch => break Ok((checked_number, false)), + MatchOutput::NoRemoteReference => { + tracing::info!( + "Main node has no miniblock #{checked_number}; will check last miniblock on the main node" + ); + main_node_sealed_miniblock_number = + self.client.sealed_miniblock_number().await?; + tracing::debug!( + "Fetched last miniblock on the main node: #{main_node_sealed_miniblock_number}" + ); + } + } + } } /// Compares root hashes of the latest local batch and of the same batch from the main node. async fn root_hashes_match( &self, l1_batch_number: L1BatchNumber, - ) -> Result { + ) -> Result { let mut storage = self.pool.access_storage().await?; let local_hash = storage .blocks_dal() @@ -182,7 +258,7 @@ impl ReorgDetector { // Due to reorg, locally we may be ahead of the main node. // Lack of the root hash on the main node is treated as a hash match, // We need to wait for our knowledge of main node to catch up. - return Ok(true); + return Ok(MatchOutput::NoRemoteReference); }; if remote_hash != local_hash { @@ -191,7 +267,37 @@ impl ReorgDetector { main node {remote_hash:?} (L1 batch #{l1_batch_number})" ); } - Ok(remote_hash == local_hash) + Ok(MatchOutput::new(remote_hash == local_hash)) + } + + /// Checks hash correspondence for the latest L1 batch sealed and having metadata both locally and on the main node. + async fn check_sealed_l1_batch_root_hash( + &self, + sealed_l1_batch_number: L1BatchNumber, + ) -> Result<(L1BatchNumber, bool), HashMatchError> { + let mut main_node_sealed_l1_batch_number = sealed_l1_batch_number; + loop { + let checked_number = sealed_l1_batch_number.min(main_node_sealed_l1_batch_number); + match self.root_hashes_match(checked_number).await? { + MatchOutput::Match => break Ok((checked_number, true)), + MatchOutput::Mismatch => break Ok((checked_number, false)), + MatchOutput::NoRemoteReference => { + tracing::info!( + "Main node has no L1 batch #{checked_number}; will check last L1 batch on the main node" + ); + let fetched_number = self.client.sealed_l1_batch_number().await?; + tracing::debug!("Fetched last L1 batch on the main node: #{fetched_number}"); + let number_changed = fetched_number != main_node_sealed_l1_batch_number; + main_node_sealed_l1_batch_number = fetched_number; + + if !number_changed { + // May happen if the main node has an L1 batch, but its state root hash is not computed yet. + tracing::debug!("Last L1 batch number on the main node has not changed; waiting until its state hash is computed"); + tokio::time::sleep(self.sleep_interval / 10).await; + } + } + } + } } /// Localizes a re-org: performs binary search to determine the last non-diverged block. @@ -202,9 +308,16 @@ impl ReorgDetector { ) -> Result { // TODO (BFT-176, BFT-181): We have to look through the whole history, since batch status updater may mark // a block as executed even if the state diverges for it. - binary_search_with(known_valid_l1_batch.0, diverged_l1_batch.0, |number| { - self.root_hashes_match(L1BatchNumber(number)) - }) + binary_search_with( + known_valid_l1_batch.0, + diverged_l1_batch.0, + |number| async move { + Ok(match self.root_hashes_match(L1BatchNumber(number)).await? { + MatchOutput::Match | MatchOutput::NoRemoteReference => true, + MatchOutput::Mismatch => false, + }) + }, + ) .await .map(L1BatchNumber) } @@ -238,10 +351,18 @@ impl ReorgDetector { tracing::debug!( "Checking root hash match for earliest L1 batch #{earliest_l1_batch_number}" ); - if !self.root_hashes_match(earliest_l1_batch_number).await? { - return Err(HashMatchError::EarliestHashMismatch( - earliest_l1_batch_number, - )); + match self.root_hashes_match(earliest_l1_batch_number).await? { + MatchOutput::Match => { /* we're good */ } + MatchOutput::Mismatch => { + return Err(HashMatchError::EarliestHashMismatch( + earliest_l1_batch_number, + )) + } + MatchOutput::NoRemoteReference => { + return Err(HashMatchError::EarliestL1BatchTruncated( + earliest_l1_batch_number, + )) + } } loop { @@ -254,8 +375,11 @@ impl ReorgDetector { .get_last_l1_batch_number_with_metadata() .await? .context("L1 batches table unexpectedly emptied")?; - let sealed_miniblock_number = - storage.blocks_dal().get_sealed_miniblock_number().await?; + let sealed_miniblock_number = storage + .blocks_dal() + .get_sealed_miniblock_number() + .await? + .context("miniblocks table unexpectedly emptied")?; drop(storage); tracing::trace!( @@ -263,24 +387,27 @@ impl ReorgDetector { miniblock number #{sealed_miniblock_number}" ); - let root_hashes_match = self.root_hashes_match(sealed_l1_batch_number).await?; - let miniblock_hashes_match = - self.miniblock_hashes_match(sealed_miniblock_number).await?; + let (checked_l1_batch_number, root_hashes_match) = self + .check_sealed_l1_batch_root_hash(sealed_l1_batch_number) + .await?; + let (checked_miniblock_number, miniblock_hashes_match) = self + .check_sealed_miniblock_hash(sealed_miniblock_number) + .await?; - // The only event that triggers reorg detection and node rollback is if the + // The only event that triggers re-org detection and node rollback is if the // hash mismatch at the same block height is detected, be it miniblocks or batches. // // In other cases either there is only a height mismatch which means that one of // the nodes needs to do catching up; however, it is not certain that there is actually - // a reorg taking place. + // a re-org taking place. if root_hashes_match && miniblock_hashes_match { self.block_updater - .update_correct_block(sealed_miniblock_number, sealed_l1_batch_number); + .update_correct_block(checked_miniblock_number, checked_l1_batch_number); } else { let diverged_l1_batch_number = if root_hashes_match { - sealed_l1_batch_number + 1 // Non-sealed L1 batch has diverged + checked_l1_batch_number + 1 // Non-sealed L1 batch has diverged } else { - sealed_l1_batch_number + checked_l1_batch_number }; tracing::info!("Searching for the first diverged L1 batch"); @@ -301,21 +428,3 @@ impl ReorgDetector { } } } - -async fn binary_search_with(mut left: u32, mut right: u32, mut f: F) -> Result -where - F: FnMut(u32) -> Fut, - Fut: Future>, -{ - while left + 1 < right { - let middle = (left + right) / 2; - assert!(middle < right); // middle <= (right - 2 + right) / 2 = right - 1 - - if f(middle).await? { - left = middle; - } else { - right = middle; - } - } - Ok(left) -} diff --git a/core/lib/zksync_core/src/reorg_detector/tests.rs b/core/lib/zksync_core/src/reorg_detector/tests.rs index 6f09c0e9fee7..e9996b01139b 100644 --- a/core/lib/zksync_core/src/reorg_detector/tests.rs +++ b/core/lib/zksync_core/src/reorg_detector/tests.rs @@ -8,29 +8,22 @@ use std::{ use assert_matches::assert_matches; use test_casing::{test_casing, Product}; use tokio::sync::mpsc; -use zksync_contracts::BaseSystemContractsHashes; use zksync_dal::StorageProcessor; use zksync_types::{ - block::{BlockGasCount, L1BatchHeader, MiniblockHeader}, - Address, L2ChainId, ProtocolVersion, ProtocolVersionId, + block::{MiniblockHasher, MiniblockHeader}, + L2ChainId, ProtocolVersion, }; use super::*; -use crate::genesis::{ensure_genesis_state, GenesisParams}; +use crate::{ + genesis::{ensure_genesis_state, GenesisParams}, + utils::testonly::{create_l1_batch, create_miniblock}, +}; async fn store_miniblock(storage: &mut StorageProcessor<'_>, number: u32, hash: H256) { let header = MiniblockHeader { - number: MiniblockNumber(number), - timestamp: number.into(), hash, - l1_tx_count: 0, - l2_tx_count: 0, - base_fee_per_gas: 0, - l1_gas_price: 0, - l2_fair_gas_price: 0, - base_system_contracts_hashes: BaseSystemContractsHashes::default(), - protocol_version: Some(ProtocolVersionId::latest()), - virtual_blocks: 1, + ..create_miniblock(number) }; storage .blocks_dal() @@ -40,16 +33,10 @@ async fn store_miniblock(storage: &mut StorageProcessor<'_>, number: u32, hash: } async fn seal_l1_batch(storage: &mut StorageProcessor<'_>, number: u32, hash: H256) { - let header = L1BatchHeader::new( - L1BatchNumber(number), - number.into(), - Address::default(), - BaseSystemContractsHashes::default(), - ProtocolVersionId::latest(), - ); + let header = create_l1_batch(number); storage .blocks_dal() - .insert_l1_batch(&header, &[], BlockGasCount::default(), &[], &[]) + .insert_mock_l1_batch(&header) .await .unwrap(); storage @@ -74,8 +61,6 @@ async fn binary_search_with_simple_predicate() { } } -type ResponsesMap = HashMap; - #[derive(Debug, Clone, Copy)] enum RpcErrorKind { Transient, @@ -93,13 +78,33 @@ impl From for RpcError { #[derive(Debug, Default)] struct MockMainNodeClient { - miniblock_hash_responses: ResponsesMap, - l1_batch_root_hash_responses: ResponsesMap, + latest_miniblock_response: Option, + latest_l1_batch_response: Option, + miniblock_hash_responses: HashMap, + l1_batch_root_hash_responses: HashMap, error_kind: Arc>>, } #[async_trait] impl MainNodeClient for MockMainNodeClient { + async fn sealed_miniblock_number(&self) -> Result { + if let &Some(error_kind) = &*self.error_kind.lock().unwrap() { + return Err(error_kind.into()); + } + Ok(self + .latest_miniblock_response + .expect("unexpected `sealed_miniblock_number` request")) + } + + async fn sealed_l1_batch_number(&self) -> Result { + if let &Some(error_kind) = &*self.error_kind.lock().unwrap() { + return Err(error_kind.into()); + } + Ok(self + .latest_l1_batch_response + .expect("unexpected `sealed_l1_batch_number` request")) + } + async fn miniblock_hash(&self, number: MiniblockNumber) -> Result, RpcError> { if let &Some(error_kind) = &*self.error_kind.lock().unwrap() { return Err(error_kind.into()); @@ -141,18 +146,26 @@ impl UpdateCorrectBlock for mpsc::UnboundedSender<(MiniblockNumber, L1BatchNumbe async fn normal_reorg_function(snapshot_recovery: bool, with_transient_errors: bool) { let pool = ConnectionPool::test_pool().await; let mut storage = pool.access_storage().await.unwrap(); + let mut client = MockMainNodeClient::default(); if snapshot_recovery { storage .protocol_versions_dal() .save_protocol_version_with_tx(ProtocolVersion::default()) .await; } else { - ensure_genesis_state(&mut storage, L2ChainId::default(), &GenesisParams::mock()) - .await - .unwrap(); + let genesis_root_hash = + ensure_genesis_state(&mut storage, L2ChainId::default(), &GenesisParams::mock()) + .await + .unwrap(); + client.miniblock_hash_responses.insert( + MiniblockNumber(0), + MiniblockHasher::legacy_hash(MiniblockNumber(0)), + ); + client + .l1_batch_root_hash_responses + .insert(L1BatchNumber(0), genesis_root_hash); } - let mut client = MockMainNodeClient::default(); let l1_batch_numbers = if snapshot_recovery { 11_u32..=20 } else { @@ -243,12 +256,20 @@ async fn detector_stops_on_fatal_rpc_error() { async fn reorg_is_detected_on_batch_hash_mismatch() { let pool = ConnectionPool::test_pool().await; let mut storage = pool.access_storage().await.unwrap(); - ensure_genesis_state(&mut storage, L2ChainId::default(), &GenesisParams::mock()) - .await - .unwrap(); + let genesis_root_hash = + ensure_genesis_state(&mut storage, L2ChainId::default(), &GenesisParams::mock()) + .await + .unwrap(); + let mut client = MockMainNodeClient::default(); + client.miniblock_hash_responses.insert( + MiniblockNumber(0), + MiniblockHasher::legacy_hash(MiniblockNumber(0)), + ); + client + .l1_batch_root_hash_responses + .insert(L1BatchNumber(0), genesis_root_hash); let (_stop_sender, stop_receiver) = watch::channel(false); - let mut client = MockMainNodeClient::default(); let miniblock_hash = H256::from_low_u64_be(23); client .miniblock_hash_responses @@ -287,12 +308,20 @@ async fn reorg_is_detected_on_batch_hash_mismatch() { async fn reorg_is_detected_on_miniblock_hash_mismatch() { let pool = ConnectionPool::test_pool().await; let mut storage = pool.access_storage().await.unwrap(); - ensure_genesis_state(&mut storage, L2ChainId::default(), &GenesisParams::mock()) - .await - .unwrap(); + let mut client = MockMainNodeClient::default(); + let genesis_root_hash = + ensure_genesis_state(&mut storage, L2ChainId::default(), &GenesisParams::mock()) + .await + .unwrap(); + client.miniblock_hash_responses.insert( + MiniblockNumber(0), + MiniblockHasher::legacy_hash(MiniblockNumber(0)), + ); + client + .l1_batch_root_hash_responses + .insert(L1BatchNumber(0), genesis_root_hash); let (_stop_sender, stop_receiver) = watch::channel(false); - let mut client = MockMainNodeClient::default(); let miniblock_hash = H256::from_low_u64_be(23); client .miniblock_hash_responses @@ -365,6 +394,13 @@ async fn reorg_is_detected_on_historic_batch_hash_mismatch( seal_l1_batch(&mut storage, earliest_l1_batch_number, H256::zero()).await; let mut client = MockMainNodeClient::default(); + client + .miniblock_hash_responses + .insert(MiniblockNumber(earliest_l1_batch_number), H256::zero()); + client + .l1_batch_root_hash_responses + .insert(L1BatchNumber(earliest_l1_batch_number), H256::zero()); + let miniblock_and_l1_batch_hashes = l1_batch_numbers.clone().map(|number| { let mut miniblock_hash = H256::from_low_u64_be(number.into()); client @@ -507,3 +543,54 @@ async fn detector_errors_on_earliest_batch_hash_mismatch_with_snapshot_recovery( let err = detector.run_inner().await.unwrap_err(); assert_matches!(err, HashMatchError::EarliestHashMismatch(L1BatchNumber(3))); } + +#[tokio::test] +async fn reorg_is_detected_without_waiting_for_main_node_to_catch_up() { + let pool = ConnectionPool::test_pool().await; + let mut storage = pool.access_storage().await.unwrap(); + let genesis_root_hash = + ensure_genesis_state(&mut storage, L2ChainId::default(), &GenesisParams::mock()) + .await + .unwrap(); + // Fill in local storage with some data, so that it's ahead of the main node. + for number in 1..5 { + store_miniblock(&mut storage, number, H256::zero()).await; + seal_l1_batch(&mut storage, number, H256::zero()).await; + } + drop(storage); + + let mut client = MockMainNodeClient::default(); + client + .l1_batch_root_hash_responses + .insert(L1BatchNumber(0), genesis_root_hash); + for number in 1..3 { + client + .miniblock_hash_responses + .insert(MiniblockNumber(number), H256::zero()); + client + .l1_batch_root_hash_responses + .insert(L1BatchNumber(number), H256::zero()); + } + client + .miniblock_hash_responses + .insert(MiniblockNumber(3), H256::zero()); + client + .l1_batch_root_hash_responses + .insert(L1BatchNumber(3), H256::repeat_byte(0xff)); + client.latest_l1_batch_response = Some(L1BatchNumber(3)); + client.latest_miniblock_response = Some(MiniblockNumber(3)); + + let (_stop_sender, stop_receiver) = watch::channel(false); + let detector = ReorgDetector { + client: Box::new(client), + block_updater: Box::new(()), + pool, + stop_receiver, + sleep_interval: Duration::from_millis(10), + }; + let detector_task = tokio::spawn(detector.run()); + + let task_result = detector_task.await.unwrap(); + let last_correct_l1_batch = task_result.unwrap(); + assert_eq!(last_correct_l1_batch, Some(L1BatchNumber(2))); +} diff --git a/core/lib/zksync_core/src/state_keeper/batch_executor/mod.rs b/core/lib/zksync_core/src/state_keeper/batch_executor/mod.rs index 2267792297fd..65c71846478e 100644 --- a/core/lib/zksync_core/src/state_keeper/batch_executor/mod.rs +++ b/core/lib/zksync_core/src/state_keeper/batch_executor/mod.rs @@ -12,7 +12,7 @@ use multivm::{ }; use once_cell::sync::OnceCell; use tokio::{ - sync::{mpsc, oneshot}, + sync::{mpsc, oneshot, watch}, task::JoinHandle, }; use zksync_dal::ConnectionPool; @@ -21,7 +21,6 @@ use zksync_types::{vm_trace::Call, witness_block_state::WitnessBlockState, Trans use zksync_utils::bytecode::CompressedBytecodeInfo; use crate::{ - gas_tracker::{gas_count_from_metrics, gas_count_from_tx_and_metrics}, metrics::{InteractionType, TxStage, APP_METRICS}, state_keeper::{ metrics::{ExecutorCommand, TxExecutionStage, EXECUTOR_METRICS, KEEPER_METRICS}, @@ -38,8 +37,8 @@ pub(crate) enum TxExecutionResult { /// Successful execution of the tx and the block tip dry run. Success { tx_result: Box, - tx_metrics: ExecutionMetricsForCriteria, - bootloader_dry_run_metrics: ExecutionMetricsForCriteria, + tx_metrics: Box, + bootloader_dry_run_metrics: Box, bootloader_dry_run_result: Box, compressed_bytecodes: Vec, call_tracer_result: Vec, @@ -76,7 +75,8 @@ pub trait L1BatchExecutorBuilder: 'static + Send + Sync + fmt::Debug { &mut self, l1_batch_params: L1BatchEnv, system_env: SystemEnv, - ) -> BatchExecutorHandle; + stop_receiver: &watch::Receiver, + ) -> Option; } /// The default implementation of [`L1BatchExecutorBuilder`]. @@ -89,6 +89,7 @@ pub struct MainBatchExecutorBuilder { max_allowed_tx_gas_limit: U256, upload_witness_inputs_to_gcs: bool, enum_index_migration_chunk_size: usize, + optional_bytecode_compression: bool, } impl MainBatchExecutorBuilder { @@ -99,6 +100,7 @@ impl MainBatchExecutorBuilder { save_call_traces: bool, upload_witness_inputs_to_gcs: bool, enum_index_migration_chunk_size: usize, + optional_bytecode_compression: bool, ) -> Self { Self { state_keeper_db_path, @@ -107,6 +109,7 @@ impl MainBatchExecutorBuilder { max_allowed_tx_gas_limit, upload_witness_inputs_to_gcs, enum_index_migration_chunk_size, + optional_bytecode_compression, } } } @@ -117,25 +120,31 @@ impl L1BatchExecutorBuilder for MainBatchExecutorBuilder { &mut self, l1_batch_params: L1BatchEnv, system_env: SystemEnv, - ) -> BatchExecutorHandle { - let mut secondary_storage = RocksdbStorage::new(self.state_keeper_db_path.as_ref()); + stop_receiver: &watch::Receiver, + ) -> Option { + let mut secondary_storage = RocksdbStorage::builder(self.state_keeper_db_path.as_ref()) + .await + .expect("Failed initializing state keeper storage"); secondary_storage.enable_enum_index_migration(self.enum_index_migration_chunk_size); let mut conn = self .pool .access_storage_tagged("state_keeper") .await .unwrap(); - secondary_storage.update_from_postgres(&mut conn).await; - drop(conn); + let secondary_storage = secondary_storage + .synchronize(&mut conn, stop_receiver) + .await + .expect("Failed synchronizing secondary state keeper storage")?; - BatchExecutorHandle::new( + Some(BatchExecutorHandle::new( self.save_call_traces, self.max_allowed_tx_gas_limit, secondary_storage, l1_batch_params, system_env, self.upload_witness_inputs_to_gcs, - ) + self.optional_bytecode_compression, + )) } } @@ -158,6 +167,7 @@ impl BatchExecutorHandle { l1_batch_env: L1BatchEnv, system_env: SystemEnv, upload_witness_inputs_to_gcs: bool, + optional_bytecode_compression: bool, ) -> Self { // Since we process `BatchExecutor` commands one-by-one (the next command is never enqueued // until a previous command is processed), capacity 1 is enough for the commands channel. @@ -165,6 +175,7 @@ impl BatchExecutorHandle { let executor = BatchExecutor { save_call_traces, max_allowed_tx_gas_limit, + optional_bytecode_compression, commands: commands_receiver, }; @@ -204,7 +215,7 @@ impl BatchExecutorHandle { let res = response_receiver.await.unwrap(); let elapsed = latency.observe(); - if let TxExecutionResult::Success { tx_metrics, .. } = res { + if let TxExecutionResult::Success { tx_metrics, .. } = &res { let gas_per_nanosecond = tx_metrics.execution_metrics.computational_gas_used as f64 / elapsed.as_nanos() as f64; EXECUTOR_METRICS @@ -285,6 +296,7 @@ pub(super) enum Command { pub(super) struct BatchExecutor { save_call_traces: bool, max_allowed_tx_gas_limit: U256, + optional_bytecode_compression: bool, commands: mpsc::Receiver, } @@ -325,7 +337,7 @@ impl BatchExecutor { }; resp.send((vm_block_result, witness_block_state)).unwrap(); - // storage_view cannot be accessed while borrowed by the VM, + // `storage_view` cannot be accessed while borrowed by the VM, // so this is the only point at which storage metrics can be obtained let metrics = storage_view.as_ref().borrow_mut().metrics(); EXECUTOR_METRICS.batch_storage_interaction_duration[&InteractionType::GetValue] @@ -364,7 +376,12 @@ impl BatchExecutor { // Execute the transaction. let latency = KEEPER_METRICS.tx_execution_time[&TxExecutionStage::Execution].start(); - let (tx_result, compressed_bytecodes, call_tracer_result) = self.execute_tx_in_vm(tx, vm); + let (tx_result, compressed_bytecodes, call_tracer_result) = + if self.optional_bytecode_compression { + self.execute_tx_in_vm_with_optional_compression(tx, vm) + } else { + self.execute_tx_in_vm(tx, vm) + }; latency.observe(); APP_METRICS.processed_txs[&TxStage::StateKeeper].inc(); APP_METRICS.processed_l1_txs[&TxStage::StateKeeper].inc_by(tx.is_l1().into()); @@ -376,14 +393,18 @@ impl BatchExecutor { }; } - let tx_metrics = Self::get_execution_metrics(Some(tx), &tx_result); + let tx_metrics = ExecutionMetricsForCriteria::new(Some(tx), &tx_result); + + if !vm.has_enough_gas_for_batch_tip() { + return TxExecutionResult::BootloaderOutOfGasForBlockTip; + } let (bootloader_dry_run_result, bootloader_dry_run_metrics) = self.dryrun_block_tip(vm); match &bootloader_dry_run_result.result { ExecutionResult::Success { .. } => TxExecutionResult::Success { tx_result: Box::new(tx_result), - tx_metrics, - bootloader_dry_run_metrics, + tx_metrics: Box::new(tx_metrics), + bootloader_dry_run_metrics: Box::new(bootloader_dry_run_metrics), bootloader_dry_run_result: Box::new(bootloader_dry_run_result), compressed_bytecodes, call_tracer_result, @@ -432,11 +453,7 @@ impl BatchExecutor { result } - // Err when transaction is rejected. - // Ok(TxExecutionStatus::Success) when the transaction succeeded - // Ok(TxExecutionStatus::Failure) when the transaction failed. - // Note that failed transactions are considered properly processed and are included in blocks - fn execute_tx_in_vm( + fn execute_tx_in_vm_with_optional_compression( &self, tx: &Transaction, vm: &mut VmInstance, @@ -451,8 +468,8 @@ impl BatchExecutor { // that will not be published (e.g. due to out of gas), we use the following scheme: // We try to execute the transaction with compressed bytecodes. // If it fails and the compressed bytecodes have not been published, - // it means that there is no sense in pollutting the space of compressed bytecodes, - // and so we reexecute the transaction, but without compressions. + // it means that there is no sense in polluting the space of compressed bytecodes, + // and so we re-execute the transaction, but without compression. // Saving the snapshot before executing vm.make_snapshot(); @@ -464,7 +481,7 @@ impl BatchExecutor { vec![] }; - if let Ok(result) = + if let (Ok(()), result) = vm.inspect_transaction_with_bytecode_compression(tracer.into(), tx.clone(), true) { let compressed_bytecodes = vm.get_last_tx_compressed_bytecodes(); @@ -485,8 +502,10 @@ impl BatchExecutor { vec![] }; - let result = vm - .inspect_transaction_with_bytecode_compression(tracer.into(), tx.clone(), false) + let result = + vm.inspect_transaction_with_bytecode_compression(tracer.into(), tx.clone(), false); + result + .0 .expect("Compression can't fail if we don't apply it"); let compressed_bytecodes = vm.get_last_tx_compressed_bytecodes(); @@ -496,7 +515,46 @@ impl BatchExecutor { .unwrap() .take() .unwrap_or_default(); - (result, compressed_bytecodes, trace) + (result.1, compressed_bytecodes, trace) + } + + // Err when transaction is rejected. + // `Ok(TxExecutionStatus::Success)` when the transaction succeeded + // `Ok(TxExecutionStatus::Failure)` when the transaction failed. + // Note that failed transactions are considered properly processed and are included in blocks + fn execute_tx_in_vm( + &self, + tx: &Transaction, + vm: &mut VmInstance, + ) -> ( + VmExecutionResultAndLogs, + Vec, + Vec, + ) { + let call_tracer_result = Arc::new(OnceCell::default()); + let tracer = if self.save_call_traces { + vec![CallTracer::new(call_tracer_result.clone()).into_tracer_pointer()] + } else { + vec![] + }; + + let (published_bytecodes, mut result) = + vm.inspect_transaction_with_bytecode_compression(tracer.into(), tx.clone(), true); + if published_bytecodes.is_ok() { + let compressed_bytecodes = vm.get_last_tx_compressed_bytecodes(); + + let trace = Arc::try_unwrap(call_tracer_result) + .unwrap() + .take() + .unwrap_or_default(); + (result, compressed_bytecodes, trace) + } else { + // Transaction failed to publish bytecodes, we reject it so initiator doesn't pay fee. + result.result = ExecutionResult::Halt { + reason: Halt::FailedToPublishCompressedBytecodes, + }; + (result, Default::default(), Default::default()) + } } fn dryrun_block_tip( @@ -518,7 +576,7 @@ impl BatchExecutor { let stage_latency = KEEPER_METRICS.tx_execution_time[&TxExecutionStage::DryRunGetExecutionMetrics].start(); - let metrics = Self::get_execution_metrics(None, &block_tip_result); + let metrics = ExecutionMetricsForCriteria::new(None, &block_tip_result); stage_latency.observe(); let stage_latency = KEEPER_METRICS.tx_execution_time @@ -530,20 +588,4 @@ impl BatchExecutor { total_latency.observe(); (block_tip_result, metrics) } - - fn get_execution_metrics( - tx: Option<&Transaction>, - execution_result: &VmExecutionResultAndLogs, - ) -> ExecutionMetricsForCriteria { - let execution_metrics = execution_result.get_execution_metrics(tx); - let l1_gas = match tx { - Some(tx) => gas_count_from_tx_and_metrics(tx, &execution_metrics), - None => gas_count_from_metrics(&execution_metrics), - }; - - ExecutionMetricsForCriteria { - l1_gas, - execution_metrics, - } - } } diff --git a/core/lib/zksync_core/src/state_keeper/batch_executor/tests/tester.rs b/core/lib/zksync_core/src/state_keeper/batch_executor/tests/tester.rs index 6417c65a5f8f..dc7f9d0d9794 100644 --- a/core/lib/zksync_core/src/state_keeper/batch_executor/tests/tester.rs +++ b/core/lib/zksync_core/src/state_keeper/batch_executor/tests/tester.rs @@ -6,10 +6,10 @@ use multivm::{ vm_latest::constants::INITIAL_STORAGE_WRITE_PUBDATA_BYTES, }; use tempfile::TempDir; +use tokio::sync::watch; use zksync_config::configs::chain::StateKeeperConfig; use zksync_contracts::{get_loadnext_contract, test_contracts::LoadnextContractExecutionParams}; use zksync_dal::ConnectionPool; -use zksync_state::RocksdbStorage; use zksync_test_account::{Account, DeployContractsTx, TxType}; use zksync_types::{ ethabi::Token, fee::Fee, system_contracts::get_system_smart_contracts, @@ -24,10 +24,11 @@ use crate::{ state_keeper::{ batch_executor::BatchExecutorHandle, tests::{default_l1_batch_env, default_system_env, BASE_SYSTEM_CONTRACTS}, + L1BatchExecutorBuilder, MainBatchExecutorBuilder, }, }; -const DEFAULT_GAS_PER_PUBDATA: u32 = 100; +const DEFAULT_GAS_PER_PUBDATA: u32 = 10000; const CHAIN_ID: u32 = 270; /// Representation of configuration parameters used by the state keeper. @@ -86,33 +87,27 @@ impl Tester { /// Creates a batch executor instance. /// This function intentionally uses sensible defaults to not introduce boilerplate. pub(super) async fn create_batch_executor(&self) -> BatchExecutorHandle { + let mut builder = MainBatchExecutorBuilder::new( + self.db_dir.path().to_str().unwrap().to_owned(), + self.pool.clone(), + self.config.max_allowed_tx_gas_limit.into(), + self.config.save_call_traces, + self.config.upload_witness_inputs_to_gcs, + 100, + false, + ); + // Not really important for the batch executor - it operates over a single batch. - let (l1_batch, system_env) = self.batch_params( + let (l1_batch_env, system_env) = self.batch_params( L1BatchNumber(1), 100, self.config.validation_computational_gas_limit, ); - - let mut secondary_storage = RocksdbStorage::new(self.db_dir.path()); - let mut conn = self - .pool - .access_storage_tagged("state_keeper") + let (_stop_sender, stop_receiver) = watch::channel(false); + builder + .init_batch(l1_batch_env, system_env, &stop_receiver) .await - .unwrap(); - - secondary_storage.update_from_postgres(&mut conn).await; - drop(conn); - - // We don't use the builder because it would require us to clone the `ConnectionPool`, which is forbidden - // for the test pool (see the doc-comment on `TestPool` for details). - BatchExecutorHandle::new( - self.config.save_call_traces, - self.config.max_allowed_tx_gas_limit.into(), - secondary_storage, - l1_batch, - system_env, - self.config.upload_witness_inputs_to_gcs, - ) + .expect("Batch executor was interrupted") } /// Creates test batch params that can be fed into the VM. diff --git a/core/lib/zksync_core/src/state_keeper/extractors.rs b/core/lib/zksync_core/src/state_keeper/extractors.rs index e31020734f58..8f6f8cac5ba7 100644 --- a/core/lib/zksync_core/src/state_keeper/extractors.rs +++ b/core/lib/zksync_core/src/state_keeper/extractors.rs @@ -1,15 +1,8 @@ //! Pure functions that convert data as required by the state keeper. -use std::{ - convert::TryFrom, - fmt, - time::{Duration, Instant}, -}; +use std::{convert::TryFrom, fmt}; use chrono::{DateTime, TimeZone, Utc}; -use zksync_dal::StorageProcessor; -use zksync_types::{L1BatchNumber, U256}; -use zksync_utils::h256_to_u256; /// Displays a Unix timestamp (seconds since epoch) in human-readable form. Useful for logging. pub(super) fn display_timestamp(timestamp: u64) -> impl fmt::Display { @@ -34,42 +27,3 @@ pub(super) fn display_timestamp(timestamp: u64) -> impl fmt::Display { DisplayedTimestamp::Parsed, ) } - -pub(crate) async fn wait_for_prev_l1_batch_params( - storage: &mut StorageProcessor<'_>, - number: L1BatchNumber, -) -> (U256, u64) { - if number == L1BatchNumber(0) { - return (U256::default(), 0); - } - wait_for_l1_batch_params_unchecked(storage, number - 1).await -} - -/// # Warning -/// -/// If invoked for a `L1BatchNumber` of a non-existent l1 batch, will block current thread indefinitely. -async fn wait_for_l1_batch_params_unchecked( - storage: &mut StorageProcessor<'_>, - number: L1BatchNumber, -) -> (U256, u64) { - // If the state root is not known yet, this duration will be used to back off in the while loops - const SAFE_STATE_ROOT_INTERVAL: Duration = Duration::from_millis(100); - - let stage_started_at: Instant = Instant::now(); - loop { - let data = storage - .blocks_dal() - .get_l1_batch_state_root_and_timestamp(number) - .await - .unwrap(); - if let Some((root_hash, timestamp)) = data { - tracing::trace!( - "Waiting for hash of L1 batch #{number} took {:?}", - stage_started_at.elapsed() - ); - return (h256_to_u256(root_hash), timestamp); - } - - tokio::time::sleep(SAFE_STATE_ROOT_INTERVAL).await; - } -} diff --git a/core/lib/zksync_core/src/state_keeper/io/common.rs b/core/lib/zksync_core/src/state_keeper/io/common.rs index 857c7618d11a..54632c468ab4 100644 --- a/core/lib/zksync_core/src/state_keeper/io/common.rs +++ b/core/lib/zksync_core/src/state_keeper/io/common.rs @@ -4,16 +4,16 @@ use multivm::{ interface::{L1BatchEnv, L2BlockEnv, SystemEnv, TxExecutionMode}, vm_latest::constants::BLOCK_GAS_LIMIT, }; +use vm_utils::storage::load_l1_batch_params; use zksync_contracts::BaseSystemContracts; use zksync_dal::StorageProcessor; use zksync_types::{ - Address, L1BatchNumber, L2ChainId, MiniblockNumber, ProtocolVersionId, H256, U256, - ZKPORTER_IS_AVAILABLE, + fee_model::BatchFeeInput, Address, L1BatchNumber, L2ChainId, MiniblockNumber, + ProtocolVersionId, H256, U256, ZKPORTER_IS_AVAILABLE, }; use zksync_utils::u256_to_h256; use super::PendingBatchData; -use crate::state_keeper::extractors; /// Returns the parameters required to initialize the VM for the next L1 batch. #[allow(clippy::too_many_arguments)] @@ -22,8 +22,7 @@ pub(crate) fn l1_batch_params( fee_account: Address, l1_batch_timestamp: u64, previous_batch_hash: U256, - l1_gas_price: u64, - fair_l2_gas_price: u64, + fee_input: BatchFeeInput, first_miniblock_number: MiniblockNumber, prev_miniblock_hash: H256, base_system_contracts: BaseSystemContracts, @@ -46,8 +45,7 @@ pub(crate) fn l1_batch_params( previous_batch_hash: Some(u256_to_h256(previous_batch_hash)), number: current_l1_batch_number, timestamp: l1_batch_timestamp, - l1_gas_price, - fair_l2_gas_price, + fee_input, fee_account, enforced_base_fee: None, first_l2_block: L2BlockEnv { @@ -69,75 +67,6 @@ pub(crate) fn poll_iters(delay_interval: Duration, max_wait: Duration) -> usize ((max_wait_millis + delay_interval_millis - 1) / delay_interval_millis).max(1) as usize } -pub(crate) async fn load_l1_batch_params( - storage: &mut StorageProcessor<'_>, - current_l1_batch_number: L1BatchNumber, - fee_account: Address, - validation_computational_gas_limit: u32, - chain_id: L2ChainId, -) -> Option<(SystemEnv, L1BatchEnv)> { - // If miniblock doesn't exist (for instance if it's pending), it means that there is no unsynced state (i.e. no transactions - // were executed after the last sealed batch). - let pending_miniblock_number = { - let (_, last_miniblock_number_included_in_l1_batch) = storage - .blocks_dal() - .get_miniblock_range_of_l1_batch(current_l1_batch_number - 1) - .await - .unwrap() - .unwrap(); - last_miniblock_number_included_in_l1_batch + 1 - }; - let pending_miniblock_header = storage - .blocks_dal() - .get_miniblock_header(pending_miniblock_number) - .await - .unwrap()?; - - tracing::info!("Getting previous batch hash"); - let (previous_l1_batch_hash, _) = - extractors::wait_for_prev_l1_batch_params(storage, current_l1_batch_number).await; - - tracing::info!("Getting previous miniblock hash"); - let prev_miniblock_hash = storage - .blocks_dal() - .get_miniblock_header(pending_miniblock_number - 1) - .await - .unwrap() - .unwrap() - .hash; - - let base_system_contracts = storage - .storage_dal() - .get_base_system_contracts( - pending_miniblock_header - .base_system_contracts_hashes - .bootloader, - pending_miniblock_header - .base_system_contracts_hashes - .default_aa, - ) - .await; - - tracing::info!("Previous l1_batch_hash: {}", previous_l1_batch_hash); - Some(l1_batch_params( - current_l1_batch_number, - fee_account, - pending_miniblock_header.timestamp, - previous_l1_batch_hash, - pending_miniblock_header.l1_gas_price, - pending_miniblock_header.l2_fair_gas_price, - pending_miniblock_number, - prev_miniblock_hash, - base_system_contracts, - validation_computational_gas_limit, - pending_miniblock_header - .protocol_version - .expect("`protocol_version` must be set for pending miniblock"), - pending_miniblock_header.virtual_blocks, - chain_id, - )) -} - /// Loads the pending L1 block data from the database. pub(crate) async fn load_pending_batch( storage: &mut StorageProcessor<'_>, diff --git a/core/lib/zksync_core/src/state_keeper/io/fee_address_migration.rs b/core/lib/zksync_core/src/state_keeper/io/fee_address_migration.rs new file mode 100644 index 000000000000..aa1256a70ffd --- /dev/null +++ b/core/lib/zksync_core/src/state_keeper/io/fee_address_migration.rs @@ -0,0 +1,340 @@ +//! Temporary module for migrating fee addresses from L1 batches to miniblocks. + +// FIXME (PLA-728): remove after 2nd phase of `fee_account_address` migration + +use std::time::{Duration, Instant}; + +use anyhow::Context as _; +use tokio::sync::watch; +use zksync_dal::{ConnectionPool, StorageProcessor}; +use zksync_types::MiniblockNumber; + +/// Runs the migration for pending miniblocks. +pub(crate) async fn migrate_pending_miniblocks(storage: &mut StorageProcessor<'_>) { + let started_at = Instant::now(); + tracing::info!("Started migrating `fee_account_address` for pending miniblocks"); + + #[allow(deprecated)] + let l1_batches_have_fee_account_address = storage + .blocks_dal() + .check_l1_batches_have_fee_account_address() + .await + .expect("Failed getting metadata for l1_batches table"); + if !l1_batches_have_fee_account_address { + tracing::info!("`l1_batches.fee_account_address` column is removed; assuming that the migration is complete"); + return; + } + + #[allow(deprecated)] + let rows_affected = storage + .blocks_dal() + .copy_fee_account_address_for_pending_miniblocks() + .await + .expect("Failed migrating `fee_account_address` for pending miniblocks"); + let elapsed = started_at.elapsed(); + tracing::info!("Migrated `fee_account_address` for {rows_affected} miniblocks in {elapsed:?}"); +} + +/// Runs the migration for non-pending miniblocks. Should be run as a background task. +pub(crate) async fn migrate_miniblocks( + pool: ConnectionPool, + last_miniblock: MiniblockNumber, + stop_receiver: watch::Receiver, +) -> anyhow::Result<()> { + let MigrationOutput { + miniblocks_affected, + } = migrate_miniblocks_inner( + pool, + last_miniblock, + 100_000, + Duration::from_secs(1), + stop_receiver, + ) + .await?; + + tracing::info!("Finished fee address migration with {miniblocks_affected} affected miniblocks"); + Ok(()) +} + +#[derive(Debug, Default)] +struct MigrationOutput { + miniblocks_affected: u64, +} + +/// It's important for the `chunk_size` to be a constant; this ensures that each chunk is migrated atomically. +async fn migrate_miniblocks_inner( + pool: ConnectionPool, + last_miniblock: MiniblockNumber, + chunk_size: u32, + sleep_interval: Duration, + stop_receiver: watch::Receiver, +) -> anyhow::Result { + anyhow::ensure!(chunk_size > 0, "Chunk size must be positive"); + + let mut storage = pool.access_storage().await?; + #[allow(deprecated)] + let l1_batches_have_fee_account_address = storage + .blocks_dal() + .check_l1_batches_have_fee_account_address() + .await + .expect("Failed getting metadata for l1_batches table"); + drop(storage); + if !l1_batches_have_fee_account_address { + tracing::info!("`l1_batches.fee_account_address` column is removed; assuming that the migration is complete"); + return Ok(MigrationOutput::default()); + } + + let mut chunk_start = MiniblockNumber(0); + let mut miniblocks_affected = 0; + + tracing::info!( + "Migrating `fee_account_address` for miniblocks {chunk_start}..={last_miniblock} \ + in chunks of {chunk_size} miniblocks" + ); + while chunk_start <= last_miniblock { + let chunk_end = last_miniblock.min(chunk_start + chunk_size - 1); + let chunk = chunk_start..=chunk_end; + + let mut storage = pool.access_storage().await?; + let is_chunk_migrated = is_fee_address_migrated(&mut storage, chunk_start).await?; + + if is_chunk_migrated { + tracing::debug!("`fee_account_address` is migrated for chunk {chunk:?}"); + } else { + tracing::debug!("Migrating `fee_account_address` for miniblocks chunk {chunk:?}"); + + #[allow(deprecated)] + let rows_affected = storage + .blocks_dal() + .copy_fee_account_address_for_miniblocks(chunk.clone()) + .await + .with_context(|| format!("Failed migrating miniblocks chunk {chunk:?}"))?; + tracing::debug!("Migrated {rows_affected} miniblocks in chunk {chunk:?}"); + miniblocks_affected += rows_affected; + } + drop(storage); + + if *stop_receiver.borrow() { + tracing::info!("Stop signal received; fee address migration shutting down"); + return Ok(MigrationOutput { + miniblocks_affected, + }); + } + chunk_start = chunk_end + 1; + + if !is_chunk_migrated { + tokio::time::sleep(sleep_interval).await; + } + } + + Ok(MigrationOutput { + miniblocks_affected, + }) +} + +#[allow(deprecated)] +async fn is_fee_address_migrated( + storage: &mut StorageProcessor<'_>, + miniblock: MiniblockNumber, +) -> anyhow::Result { + storage + .blocks_dal() + .is_fee_address_migrated(miniblock) + .await + .with_context(|| format!("Failed getting fee address for miniblock #{miniblock}"))? + .with_context(|| format!("Miniblock #{miniblock} disappeared")) +} + +#[cfg(test)] +mod tests { + use test_casing::test_casing; + use zksync_contracts::BaseSystemContractsHashes; + use zksync_types::{ + block::L1BatchHeader, Address, L1BatchNumber, ProtocolVersion, ProtocolVersionId, + }; + + use super::*; + use crate::utils::testonly::create_miniblock; + + async fn prepare_storage(storage: &mut StorageProcessor<'_>) { + storage + .protocol_versions_dal() + .save_protocol_version_with_tx(ProtocolVersion::default()) + .await; + for number in 0..5 { + let miniblock = create_miniblock(number); + storage + .blocks_dal() + .insert_miniblock(&miniblock) + .await + .unwrap(); + + let l1_batch = L1BatchHeader::new( + L1BatchNumber(number), + number.into(), + BaseSystemContractsHashes::default(), + ProtocolVersionId::latest(), + ); + storage + .blocks_dal() + .insert_mock_l1_batch(&l1_batch) + .await + .unwrap(); + #[allow(deprecated)] + storage + .blocks_dal() + .set_l1_batch_fee_address( + l1_batch.number, + Address::from_low_u64_be(u64::from(number) + 1), + ) + .await + .unwrap(); + storage + .blocks_dal() + .mark_miniblocks_as_executed_in_l1_batch(l1_batch.number) + .await + .unwrap(); + } + } + + async fn assert_migration(storage: &mut StorageProcessor<'_>) { + for number in 0..5 { + assert!(is_fee_address_migrated(storage, MiniblockNumber(number)) + .await + .unwrap()); + + let fee_address = storage + .blocks_dal() + .get_fee_address_for_miniblock(MiniblockNumber(number)) + .await + .unwrap() + .expect("no fee address"); + let expected_address = Address::from_low_u64_be(u64::from(number) + 1); + assert_eq!(fee_address, expected_address); + } + } + + #[test_casing(3, [1, 2, 3])] + #[tokio::test] + async fn migration_basics(chunk_size: u32) { + let pool = ConnectionPool::test_pool().await; + let mut storage = pool.access_storage().await.unwrap(); + prepare_storage(&mut storage).await; + drop(storage); + + let (_stop_sender, stop_receiver) = watch::channel(false); + let result = migrate_miniblocks_inner( + pool.clone(), + MiniblockNumber(4), + chunk_size, + Duration::ZERO, + stop_receiver.clone(), + ) + .await + .unwrap(); + + assert_eq!(result.miniblocks_affected, 5); + + // Check that all blocks are migrated. + let mut storage = pool.access_storage().await.unwrap(); + assert_migration(&mut storage).await; + drop(storage); + + // Check that migration can run again w/o returning an error, hanging up etc. + let result = migrate_miniblocks_inner( + pool.clone(), + MiniblockNumber(4), + chunk_size, + Duration::ZERO, + stop_receiver, + ) + .await + .unwrap(); + + assert_eq!(result.miniblocks_affected, 0); + } + + #[test_casing(3, [1, 2, 3])] + #[tokio::test] + async fn stopping_and_resuming_migration(chunk_size: u32) { + let pool = ConnectionPool::test_pool().await; + let mut storage = pool.access_storage().await.unwrap(); + prepare_storage(&mut storage).await; + + let (_stop_sender, stop_receiver) = watch::channel(true); // signal stop right away + let result = migrate_miniblocks_inner( + pool.clone(), + MiniblockNumber(4), + chunk_size, + Duration::from_secs(1_000), + stop_receiver, + ) + .await + .unwrap(); + + // Migration should stop after a single chunk. + assert_eq!(result.miniblocks_affected, u64::from(chunk_size)); + + // Check that migration resumes from the same point. + let (_stop_sender, stop_receiver) = watch::channel(false); + let result = migrate_miniblocks_inner( + pool.clone(), + MiniblockNumber(4), + chunk_size, + Duration::ZERO, + stop_receiver, + ) + .await + .unwrap(); + + assert_eq!(result.miniblocks_affected, 5 - u64::from(chunk_size)); + assert_migration(&mut storage).await; + } + + #[test_casing(3, [1, 2, 3])] + #[tokio::test] + async fn new_blocks_added_during_migration(chunk_size: u32) { + let pool = ConnectionPool::test_pool().await; + let mut storage = pool.access_storage().await.unwrap(); + prepare_storage(&mut storage).await; + + let (_stop_sender, stop_receiver) = watch::channel(true); // signal stop right away + let result = migrate_miniblocks_inner( + pool.clone(), + MiniblockNumber(4), + chunk_size, + Duration::from_secs(1_000), + stop_receiver, + ) + .await + .unwrap(); + + // Migration should stop after a single chunk. + assert_eq!(result.miniblocks_affected, u64::from(chunk_size)); + + // Insert a new miniblock to the storage with a defined fee account address. + let mut miniblock = create_miniblock(5); + miniblock.fee_account_address = Address::repeat_byte(1); + storage + .blocks_dal() + .insert_miniblock(&miniblock) + .await + .unwrap(); + + // Resume the migration. + let (_stop_sender, stop_receiver) = watch::channel(false); + let result = migrate_miniblocks_inner( + pool.clone(), + MiniblockNumber(5), + chunk_size, + Duration::ZERO, + stop_receiver, + ) + .await + .unwrap(); + + // The new miniblock should not be affected. + assert_eq!(result.miniblocks_affected, 5 - u64::from(chunk_size)); + assert_migration(&mut storage).await; + } +} diff --git a/core/lib/zksync_core/src/state_keeper/io/mempool.rs b/core/lib/zksync_core/src/state_keeper/io/mempool.rs index f5a4df1c333d..f26860110032 100644 --- a/core/lib/zksync_core/src/state_keeper/io/mempool.rs +++ b/core/lib/zksync_core/src/state_keeper/io/mempool.rs @@ -8,8 +8,9 @@ use std::{ use async_trait::async_trait; use multivm::{ interface::{FinishedL1Batch, L1BatchEnv, SystemEnv}, - vm_latest::utils::fee::derive_base_fee_and_gas_per_pubdata, + utils::derive_base_fee_and_gas_per_pubdata, }; +use vm_utils::storage::wait_for_prev_l1_batch_params; use zksync_config::configs::chain::StateKeeperConfig; use zksync_dal::ConnectionPool; use zksync_mempool::L2TxFilter; @@ -23,12 +24,13 @@ use zksync_types::{ use zksync_utils::time::millis_since_epoch; use crate::{ - l1_gas_price::L1GasPriceProvider, + fee_model::BatchFeeModelInputProvider, state_keeper::{ extractors, io::{ common::{l1_batch_params, load_pending_batch, poll_iters}, - MiniblockParams, MiniblockSealerHandle, PendingBatchData, StateKeeperIO, + fee_address_migration, MiniblockParams, MiniblockSealerHandle, PendingBatchData, + StateKeeperIO, }, mempool_actor::l2_tx_filter, metrics::KEEPER_METRICS, @@ -43,21 +45,20 @@ use crate::{ /// Decides which batch parameters should be used for the new batch. /// This is an IO for the main server application. #[derive(Debug)] -pub(crate) struct MempoolIO { +pub(crate) struct MempoolIO { mempool: MempoolGuard, pool: ConnectionPool, - object_store: Box, + object_store: Arc, timeout_sealer: TimeoutSealer, filter: L2TxFilter, current_miniblock_number: MiniblockNumber, miniblock_sealer_handle: MiniblockSealerHandle, current_l1_batch_number: L1BatchNumber, fee_account: Address, - fair_l2_gas_price: u64, validation_computational_gas_limit: u32, delay_interval: Duration, // Used to keep track of gas prices to set accepted price per pubdata byte in blocks. - l1_gas_price_provider: Arc, + batch_fee_input_provider: Arc, l2_erc20_bridge_addr: Address, chain_id: L2ChainId, @@ -65,10 +66,7 @@ pub(crate) struct MempoolIO { virtual_blocks_per_miniblock: u32, } -impl IoSealCriteria for MempoolIO -where - G: L1GasPriceProvider + 'static + Send + Sync, -{ +impl IoSealCriteria for MempoolIO { fn should_seal_l1_batch_unconditionally(&mut self, manager: &UpdatesManager) -> bool { self.timeout_sealer .should_seal_l1_batch_unconditionally(manager) @@ -80,10 +78,7 @@ where } #[async_trait] -impl StateKeeperIO for MempoolIO -where - G: L1GasPriceProvider + 'static + Send + Sync, -{ +impl StateKeeperIO for MempoolIO { fn current_l1_batch_number(&self) -> L1BatchNumber { self.current_l1_batch_number } @@ -113,12 +108,10 @@ where .await?; // Initialize the filter for the transactions that come after the pending batch. // We use values from the pending block to match the filter with one used before the restart. - let (base_fee, gas_per_pubdata) = derive_base_fee_and_gas_per_pubdata( - l1_batch_env.l1_gas_price, - l1_batch_env.fair_l2_gas_price, - ); + let (base_fee, gas_per_pubdata) = + derive_base_fee_and_gas_per_pubdata(l1_batch_env.fee_input, system_env.version.into()); self.filter = L2TxFilter { - l1_gas_price: l1_batch_env.l1_gas_price, + fee_input: l1_batch_env.fee_input, fee_per_gas: base_fee, gas_per_pubdata: gas_per_pubdata as u32, }; @@ -136,26 +129,17 @@ where ) -> Option<(SystemEnv, L1BatchEnv)> { let deadline = Instant::now() + max_wait; + let prev_l1_batch_hash = self.load_previous_l1_batch_hash().await; + + let MiniblockHeader { + timestamp: prev_miniblock_timestamp, + hash: prev_miniblock_hash, + .. + } = self.load_previous_miniblock_header().await; + // Block until at least one transaction in the mempool can match the filter (or timeout happens). // This is needed to ensure that block timestamp is not too old. for _ in 0..poll_iters(self.delay_interval, max_wait) { - // We create a new filter each time, since parameters may change and a previously - // ignored transaction in the mempool may be scheduled for the execution. - self.filter = l2_tx_filter(self.l1_gas_price_provider.as_ref(), self.fair_l2_gas_price); - // We only need to get the root hash when we're certain that we have a new transaction. - if !self.mempool.has_next(&self.filter) { - tokio::time::sleep(self.delay_interval).await; - continue; - } - - let prev_l1_batch_hash = self.load_previous_l1_batch_hash().await; - - let MiniblockHeader { - timestamp: prev_miniblock_timestamp, - hash: prev_miniblock_hash, - .. - } = self.load_previous_miniblock_header().await; - // We cannot create two L1 batches or miniblocks with the same timestamp (forbidden by the bootloader). // Hence, we wait until the current timestamp is larger than the timestamp of the previous miniblock. // We can use `timeout_at` since `sleep_past` is cancel-safe; it only uses `sleep()` async calls. @@ -165,11 +149,10 @@ where ); let current_timestamp = current_timestamp.await.ok()?; - tracing::info!( - "(l1_gas_price, fair_l2_gas_price) for L1 batch #{} is ({}, {})", + tracing::trace!( + "Fee input for L1 batch #{} is {:#?}", self.current_l1_batch_number.0, - self.filter.l1_gas_price, - self.fair_l2_gas_price + self.filter.fee_input ); let mut storage = self.pool.access_storage().await.unwrap(); let (base_system_contracts, protocol_version) = storage @@ -177,13 +160,25 @@ where .base_system_contracts_by_timestamp(current_timestamp) .await; + // We create a new filter each time, since parameters may change and a previously + // ignored transaction in the mempool may be scheduled for the execution. + self.filter = l2_tx_filter( + self.batch_fee_input_provider.as_ref(), + protocol_version.into(), + ) + .await; + // We only need to get the root hash when we're certain that we have a new transaction. + if !self.mempool.has_next(&self.filter) { + tokio::time::sleep(self.delay_interval).await; + continue; + } + return Some(l1_batch_params( self.current_l1_batch_number, self.fee_account, current_timestamp, prev_l1_batch_hash, - self.filter.l1_gas_price, - self.fair_l2_gas_price, + self.filter.fee_input, self.current_miniblock_number, prev_miniblock_hash, base_system_contracts, @@ -274,7 +269,6 @@ where self.current_l1_batch_number, self.current_miniblock_number, self.l2_erc20_bridge_addr, - None, false, ); self.miniblock_sealer_handle.submit(command).await; @@ -325,7 +319,6 @@ where l1_batch_env, finished_batch, self.l2_erc20_bridge_addr, - None, ) .await; self.current_miniblock_number += 1; // Due to fictive miniblock being sealed. @@ -401,13 +394,13 @@ async fn sleep_past(timestamp: u64, miniblock: MiniblockNumber) -> u64 { } } -impl MempoolIO { +impl MempoolIO { #[allow(clippy::too_many_arguments)] pub(in crate::state_keeper) async fn new( mempool: MempoolGuard, - object_store: Box, + object_store: Arc, miniblock_sealer_handle: MiniblockSealerHandle, - l1_gas_price_provider: Arc, + batch_fee_input_provider: Arc, pool: ConnectionPool, config: &StateKeeperConfig, delay_interval: Duration, @@ -425,17 +418,20 @@ impl MempoolIO { ); let mut storage = pool.access_storage_tagged("state_keeper").await.unwrap(); - let last_sealed_l1_batch_header = storage + // TODO (PLA-703): Support no L1 batches / miniblocks in the storage + let last_sealed_l1_batch_number = storage .blocks_dal() - .get_newest_l1_batch_header() + .get_sealed_l1_batch_number() .await - .unwrap(); + .unwrap() + .expect("No L1 batches sealed"); let last_miniblock_number = storage .blocks_dal() .get_sealed_miniblock_number() .await - .unwrap(); - + .unwrap() + .expect("empty storage not supported"); // FIXME (PLA-703): handle empty storage + fee_address_migration::migrate_pending_miniblocks(&mut storage).await; drop(storage); Self { @@ -445,14 +441,13 @@ impl MempoolIO { timeout_sealer: TimeoutSealer::new(config), filter: L2TxFilter::default(), // ^ Will be initialized properly on the first newly opened batch - current_l1_batch_number: last_sealed_l1_batch_header.number + 1, + current_l1_batch_number: last_sealed_l1_batch_number + 1, miniblock_sealer_handle, current_miniblock_number: last_miniblock_number + 1, fee_account: config.fee_account_addr, - fair_l2_gas_price: config.fair_l2_gas_price, validation_computational_gas_limit, delay_interval, - l1_gas_price_provider, + batch_fee_input_provider, l2_erc20_bridge_addr, chain_id, virtual_blocks_interval: config.virtual_blocks_interval, @@ -473,8 +468,7 @@ impl MempoolIO { .await .unwrap(); let (batch_hash, _) = - extractors::wait_for_prev_l1_batch_params(&mut storage, self.current_l1_batch_number) - .await; + wait_for_prev_l1_batch_params(&mut storage, self.current_l1_batch_number).await; wait_latency.observe(); tracing::info!( @@ -517,7 +511,7 @@ impl MempoolIO { /// Getters required for testing the MempoolIO. #[cfg(test)] -impl MempoolIO { +impl MempoolIO { pub(super) fn filter(&self) -> &L2TxFilter { &self.filter } diff --git a/core/lib/zksync_core/src/state_keeper/io/mod.rs b/core/lib/zksync_core/src/state_keeper/io/mod.rs index d1366858116c..16cc15e03b01 100644 --- a/core/lib/zksync_core/src/state_keeper/io/mod.rs +++ b/core/lib/zksync_core/src/state_keeper/io/mod.rs @@ -21,6 +21,7 @@ use super::{ }; pub(crate) mod common; +pub(crate) mod fee_address_migration; pub(crate) mod mempool; pub(crate) mod seal_logic; #[cfg(test)] diff --git a/core/lib/zksync_core/src/state_keeper/io/seal_logic.rs b/core/lib/zksync_core/src/state_keeper/io/seal_logic.rs index 15f10ce3ce7d..974ec769325a 100644 --- a/core/lib/zksync_core/src/state_keeper/io/seal_logic.rs +++ b/core/lib/zksync_core/src/state_keeper/io/seal_logic.rs @@ -6,9 +6,14 @@ use std::{ time::{Duration, Instant}, }; +use chrono::Utc; use itertools::Itertools; -use multivm::interface::{FinishedL1Batch, L1BatchEnv}; -use zksync_dal::{blocks_dal::ConsensusBlockFields, StorageProcessor}; +use multivm::{ + interface::{FinishedL1Batch, L1BatchEnv}, + utils::get_max_gas_per_pubdata_byte, +}; +use vm_utils::storage::wait_for_prev_l1_batch_params; +use zksync_dal::StorageProcessor; use zksync_system_constants::ACCOUNT_CODE_STORAGE_ADDRESS; use zksync_types::{ block::{unpack_block_info, L1BatchHeader, MiniblockHeader}, @@ -22,10 +27,10 @@ use zksync_types::{ tx_execution_info::DeduplicatedWritesMetrics, IncludedTxLocation, TransactionExecutionResult, }, - zkevm_test_harness::witness::sort_storage_access::sort_storage_access_queries, - AccountTreeId, Address, ExecuteTransactionCommon, L1BatchNumber, L1BlockNumber, LogQuery, - MiniblockNumber, StorageKey, StorageLog, StorageLogQuery, StorageValue, Transaction, VmEvent, - CURRENT_VIRTUAL_BLOCK_INFO_POSITION, H256, SYSTEM_CONTEXT_ADDRESS, + zk_evm_types::LogQuery, + AccountTreeId, Address, ExecuteTransactionCommon, L1BatchNumber, L1BlockNumber, + MiniblockNumber, ProtocolVersionId, StorageKey, StorageLog, StorageLogQuery, StorageValue, + Transaction, VmEvent, CURRENT_VIRTUAL_BLOCK_INFO_POSITION, H256, SYSTEM_CONTEXT_ADDRESS, }; // TODO (SMA-1206): use seconds instead of milliseconds. use zksync_utils::{h256_to_u256, time::millis_since_epoch, u256_to_h256}; @@ -34,7 +39,11 @@ use crate::{ metrics::{BlockStage, MiniblockStage, APP_METRICS}, state_keeper::{ extractors, - metrics::{L1BatchSealStage, MiniblockSealStage, L1_BATCH_METRICS, MINIBLOCK_METRICS}, + metrics::{ + L1BatchSealStage, MiniblockSealStage, KEEPER_METRICS, L1_BATCH_METRICS, + MINIBLOCK_METRICS, + }, + types::ExecutionMetricsForCriteria, updates::{MiniblockSealCommand, UpdatesManager}, }, }; @@ -50,7 +59,6 @@ impl UpdatesManager { l1_batch_env: &L1BatchEnv, finished_batch: FinishedL1Batch, l2_erc20_bridge_addr: Address, - consensus: Option, ) { let started_at = Instant::now(); let progress = L1_BATCH_METRICS.start(L1BatchSealStage::VmFinalization); @@ -58,34 +66,44 @@ impl UpdatesManager { progress.observe(None); let progress = L1_BATCH_METRICS.start(L1BatchSealStage::FictiveMiniblock); - self.extend_from_fictive_transaction(finished_batch.block_tip_execution_result); + let ExecutionMetricsForCriteria { + l1_gas: batch_tip_l1_gas, + execution_metrics: batch_tip_execution_metrics, + } = ExecutionMetricsForCriteria::new(None, &finished_batch.block_tip_execution_result); + self.extend_from_fictive_transaction( + finished_batch.block_tip_execution_result, + batch_tip_l1_gas, + batch_tip_execution_metrics, + ); // Seal fictive miniblock with last events and storage logs. let miniblock_command = self.seal_miniblock_command( l1_batch_env.number, current_miniblock_number, l2_erc20_bridge_addr, - consensus, false, // fictive miniblocks don't have txs, so it's fine to pass `false` here. ); miniblock_command.seal_inner(&mut transaction, true).await; progress.observe(None); let progress = L1_BATCH_METRICS.start(L1BatchSealStage::LogDeduplication); - let (_, deduped_log_queries) = sort_storage_access_queries( + + progress.observe( finished_batch .final_execution_state - .storage_log_queries - .iter() - .map(|log| &log.log_query), + .deduplicated_storage_log_queries + .len(), ); - progress.observe(deduped_log_queries.len()); let (l1_tx_count, l2_tx_count) = l1_l2_tx_count(&self.l1_batch.executed_transactions); let (writes_count, reads_count) = storage_log_query_write_read_counts( &finished_batch.final_execution_state.storage_log_queries, ); - let (dedup_writes_count, dedup_reads_count) = - log_query_write_read_counts(deduped_log_queries.iter()); + let (dedup_writes_count, dedup_reads_count) = log_query_write_read_counts( + finished_batch + .final_execution_state + .deduplicated_storage_log_queries + .iter(), + ); tracing::info!( "Sealing L1 batch {current_l1_batch_number} with {total_tx_count} \ @@ -103,7 +121,7 @@ impl UpdatesManager { let progress = L1_BATCH_METRICS.start(L1BatchSealStage::InsertL1BatchHeader); let (_prev_hash, prev_timestamp) = - extractors::wait_for_prev_l1_batch_params(&mut transaction, l1_batch_env.number).await; + wait_for_prev_l1_batch_params(&mut transaction, l1_batch_env.number).await; assert!( prev_timestamp < l1_batch_env.timestamp, "Cannot seal L1 batch #{}: Timestamp of previous L1 batch ({}) >= provisional L1 batch timestamp ({}), \ @@ -118,9 +136,7 @@ impl UpdatesManager { let l1_batch = L1BatchHeader { number: l1_batch_env.number, - is_finished: true, timestamp: l1_batch_env.timestamp, - fee_account_address: l1_batch_env.fee_account, priority_ops_onchain_data: self.l1_batch.priority_ops_onchain_data.clone(), l1_tx_count: l1_tx_count as u16, l2_tx_count: l2_tx_count as u16, @@ -128,9 +144,6 @@ impl UpdatesManager { l2_to_l1_messages, bloom: Default::default(), used_contract_hashes: finished_batch.final_execution_state.used_contract_hashes, - base_fee_per_gas: l1_batch_env.base_fee(), - l1_gas_price: self.l1_gas_price(), - l2_fair_gas_price: self.fair_l2_gas_price(), base_system_contracts_hashes: self.base_system_contract_hashes(), protocol_version: Some(self.protocol_version()), system_logs: finished_batch.final_execution_state.system_logs, @@ -141,14 +154,19 @@ impl UpdatesManager { .final_execution_state .deduplicated_events_logs; + let final_bootloader_memory = finished_batch + .final_bootloader_memory + .clone() + .unwrap_or_default(); transaction .blocks_dal() .insert_l1_batch( &l1_batch, - finished_batch.final_bootloader_memory.as_ref().unwrap(), - self.l1_batch.l1_gas_count, + &final_bootloader_memory, + self.pending_l1_gas_count(), &events_queue, &finished_batch.final_execution_state.storage_refunds, + self.pending_execution_metrics().circuit_statistic, ) .await .unwrap(); @@ -173,7 +191,9 @@ impl UpdatesManager { progress.observe(None); let progress = L1_BATCH_METRICS.start(L1BatchSealStage::InsertProtectiveReads); - let (deduplicated_writes, protective_reads): (Vec<_>, Vec<_>) = deduped_log_queries + let (deduplicated_writes, protective_reads): (Vec<_>, Vec<_>) = finished_batch + .final_execution_state + .deduplicated_storage_log_queries .into_iter() .partition(|log_query| log_query.rw_flag); transaction @@ -331,11 +351,16 @@ impl MiniblockSealCommand { hash: self.miniblock.get_miniblock_hash(), l1_tx_count: l1_tx_count as u16, l2_tx_count: l2_tx_count as u16, + fee_account_address: self.fee_account_address, base_fee_per_gas: self.base_fee_per_gas, - l1_gas_price: self.l1_gas_price, - l2_fair_gas_price: self.fair_l2_gas_price, + batch_fee_input: self.fee_input, base_system_contracts_hashes: self.base_system_contracts_hashes, protocol_version: self.protocol_version, + gas_per_pubdata_limit: get_max_gas_per_pubdata_byte( + self.protocol_version + .unwrap_or(ProtocolVersionId::last_potentially_undefined()) + .into(), + ), virtual_blocks: self.miniblock.virtual_blocks, }; @@ -381,7 +406,8 @@ impl MiniblockSealCommand { transaction .storage_dal() .insert_factory_deps(miniblock_number, new_factory_deps) - .await; + .await + .unwrap(); } progress.observe(new_factory_deps_count); @@ -437,18 +463,6 @@ impl MiniblockSealCommand { .await; progress.observe(user_l2_to_l1_log_count); - let progress = MINIBLOCK_METRICS.start(MiniblockSealStage::InsertConsensus, is_fictive); - // We want to add miniblock consensus fields atomically with the miniblock data so that we - // don't need to deal with corner cases (e.g., a miniblock w/o consensus fields). - if let Some(consensus) = &self.consensus { - transaction - .blocks_dal() - .set_miniblock_consensus_fields(self.miniblock_number, consensus) - .await - .unwrap(); - } - progress.observe(None); - let progress = MINIBLOCK_METRICS.start(MiniblockSealStage::CommitMiniblock, is_fictive); let current_l2_virtual_block_info = transaction .storage_dal() @@ -457,12 +471,24 @@ impl MiniblockSealCommand { CURRENT_VIRTUAL_BLOCK_INFO_POSITION, )) .await + .expect("failed getting virtual block info from VM state") .unwrap_or_default(); let (current_l2_virtual_block_number, _) = unpack_block_info(h256_to_u256(current_l2_virtual_block_info)); transaction.commit().await.unwrap(); progress.observe(None); + + let progress = MINIBLOCK_METRICS.start(MiniblockSealStage::ReportTxMetrics, is_fictive); + self.miniblock.executed_transactions.iter().for_each(|tx| { + KEEPER_METRICS + .transaction_inclusion_delay + .observe(Duration::from_millis( + Utc::now().timestamp_millis() as u64 - tx.transaction.received_timestamp_ms, + )) + }); + progress.observe(Some(self.miniblock.executed_transactions.len())); + self.report_miniblock_metrics(started_at, current_l2_virtual_block_number); } diff --git a/core/lib/zksync_core/src/state_keeper/io/tests/mod.rs b/core/lib/zksync_core/src/state_keeper/io/tests/mod.rs index 70466ae48430..0dcd04084937 100644 --- a/core/lib/zksync_core/src/state_keeper/io/tests/mod.rs +++ b/core/lib/zksync_core/src/state_keeper/io/tests/mod.rs @@ -1,25 +1,31 @@ use std::time::Duration; use futures::FutureExt; -use multivm::vm_latest::utils::fee::derive_base_fee_and_gas_per_pubdata; +use multivm::utils::derive_base_fee_and_gas_per_pubdata; use zksync_contracts::BaseSystemContractsHashes; use zksync_dal::ConnectionPool; use zksync_mempool::L2TxFilter; use zksync_types::{ - block::BlockGasCount, tx::ExecutionMetrics, AccountTreeId, Address, L1BatchNumber, - MiniblockNumber, ProtocolVersionId, StorageKey, VmEvent, H256, U256, + block::BlockGasCount, + fee_model::{BatchFeeInput, PubdataIndependentBatchFeeModelInput}, + tx::ExecutionMetrics, + AccountTreeId, Address, L1BatchNumber, MiniblockNumber, ProtocolVersionId, StorageKey, VmEvent, + H256, U256, }; use zksync_utils::time::seconds_since_epoch; use self::tester::Tester; -use crate::state_keeper::{ - io::{MiniblockParams, MiniblockSealer, StateKeeperIO}, - mempool_actor::l2_tx_filter, - tests::{ - create_execution_result, create_l1_batch_metadata, create_transaction, - create_updates_manager, default_l1_batch_env, default_vm_block_result, Query, +use crate::{ + state_keeper::{ + io::{MiniblockParams, MiniblockSealer, StateKeeperIO}, + mempool_actor::l2_tx_filter, + tests::{ + create_execution_result, create_transaction, create_updates_manager, + default_l1_batch_env, default_vm_block_result, Query, + }, + updates::{MiniblockSealCommand, MiniblockUpdates, UpdatesManager}, }, - updates::{MiniblockSealCommand, MiniblockUpdates, UpdatesManager}, + utils::testonly::create_l1_batch_metadata, }; mod tester; @@ -46,25 +52,25 @@ async fn test_filter_with_pending_batch() { tester.genesis(&connection_pool).await; - // Insert a sealed batch so there will be a prev_l1_batch_state_root. + // Insert a sealed batch so there will be a `prev_l1_batch_state_root`. // These gas values are random and don't matter for filter calculation as there will be a // pending batch the filter will be based off of. tester - .insert_miniblock(&connection_pool, 1, 5, 55, 555) + .insert_miniblock(&connection_pool, 1, 5, BatchFeeInput::l1_pegged(55, 555)) .await; tester.insert_sealed_batch(&connection_pool, 1).await; // Inserting a pending miniblock that isn't included in a sealed batch means there is a pending batch. // The gas values are randomly chosen but so affect filter values calculation. - let (give_l1_gas_price, give_fair_l2_gas_price) = (100, 1000); + + let fee_input = BatchFeeInput::PubdataIndependent(PubdataIndependentBatchFeeModelInput { + l1_gas_price: 100, + fair_l2_gas_price: 1000, + fair_pubdata_price: 500, + }); + tester - .insert_miniblock( - &connection_pool, - 2, - 10, - give_l1_gas_price, - give_fair_l2_gas_price, - ) + .insert_miniblock(&connection_pool, 2, 10, fee_input) .await; let (mut mempool, _) = tester.create_test_mempool_io(connection_pool, 1).await; @@ -73,34 +79,35 @@ async fn test_filter_with_pending_batch() { mempool.load_pending_batch().await; let (want_base_fee, want_gas_per_pubdata) = - derive_base_fee_and_gas_per_pubdata(give_l1_gas_price, give_fair_l2_gas_price); + derive_base_fee_and_gas_per_pubdata(fee_input, ProtocolVersionId::latest().into()); let want_filter = L2TxFilter { - l1_gas_price: give_l1_gas_price, + fee_input, fee_per_gas: want_base_fee, gas_per_pubdata: want_gas_per_pubdata as u32, }; assert_eq!(mempool.filter(), &want_filter); } -/// Ensure that MempoolIO.filter is modified correctly if there is no pending batch. +/// Ensure that `MempoolIO.filter` is modified correctly if there is no pending batch. #[tokio::test] async fn test_filter_with_no_pending_batch() { let connection_pool = ConnectionPool::test_pool().await; let tester = Tester::new(); tester.genesis(&connection_pool).await; - // Insert a sealed batch so there will be a prev_l1_batch_state_root. + // Insert a sealed batch so there will be a `prev_l1_batch_state_root`. // These gas values are random and don't matter for filter calculation. tester - .insert_miniblock(&connection_pool, 1, 5, 55, 555) + .insert_miniblock(&connection_pool, 1, 5, BatchFeeInput::l1_pegged(55, 555)) .await; tester.insert_sealed_batch(&connection_pool, 1).await; // Create a copy of the tx filter that the mempool will use. let want_filter = l2_tx_filter( - &tester.create_gas_adjuster().await, - tester.fair_l2_gas_price(), - ); + &tester.create_batch_fee_input_provider().await, + ProtocolVersionId::latest().into(), + ) + .await; // Create a mempool without pending batch and ensure that filter is not initialized just yet. let (mut mempool, mut guard) = tester.create_test_mempool_io(connection_pool, 1).await; @@ -132,7 +139,7 @@ async fn test_timestamps_are_distinct( tester.set_timestamp(prev_miniblock_timestamp); tester - .insert_miniblock(&connection_pool, 1, 5, 55, 555) + .insert_miniblock(&connection_pool, 1, 5, BatchFeeInput::l1_pegged(55, 555)) .await; if delay_prev_miniblock_compared_to_batch { tester.set_timestamp(prev_miniblock_timestamp - 1); @@ -142,9 +149,10 @@ async fn test_timestamps_are_distinct( let (mut mempool, mut guard) = tester.create_test_mempool_io(connection_pool, 1).await; // Insert a transaction to trigger L1 batch creation. let tx_filter = l2_tx_filter( - &tester.create_gas_adjuster().await, - tester.fair_l2_gas_price(), - ); + &tester.create_batch_fee_input_provider().await, + ProtocolVersionId::latest().into(), + ) + .await; tester.insert_tx(&mut guard, tx_filter.fee_per_gas, tx_filter.gas_per_pubdata); let batch_params = mempool @@ -234,13 +242,16 @@ async fn processing_storage_logs_when_sealing_miniblock() { miniblock_number: MiniblockNumber(3), miniblock, first_tx_index: 0, - l1_gas_price: 100, - fair_l2_gas_price: 100, + fee_account_address: Address::repeat_byte(0x23), + fee_input: BatchFeeInput::PubdataIndependent(PubdataIndependentBatchFeeModelInput { + l1_gas_price: 100, + fair_l2_gas_price: 100, + fair_pubdata_price: 100, + }), base_fee_per_gas: 10, base_system_contracts_hashes: BaseSystemContractsHashes::default(), protocol_version: Some(ProtocolVersionId::latest()), l2_erc20_bridge_addr: Address::default(), - consensus: None, pre_insert_txs: false, }; let mut conn = connection_pool @@ -260,7 +271,8 @@ async fn processing_storage_logs_when_sealing_miniblock() { let touched_slots = conn .storage_logs_dal() .get_touched_slots_for_l1_batch(l1_batch_number) - .await; + .await + .unwrap(); // Keys that are only read must not be written to `storage_logs`. let account = AccountTreeId::default(); @@ -311,13 +323,16 @@ async fn processing_events_when_sealing_miniblock() { miniblock_number, miniblock, first_tx_index: 0, - l1_gas_price: 100, - fair_l2_gas_price: 100, + fee_account_address: Address::repeat_byte(0x23), + fee_input: BatchFeeInput::PubdataIndependent(PubdataIndependentBatchFeeModelInput { + l1_gas_price: 100, + fair_l2_gas_price: 100, + fair_pubdata_price: 100, + }), base_fee_per_gas: 10, base_system_contracts_hashes: BaseSystemContractsHashes::default(), protocol_version: Some(ProtocolVersionId::latest()), l2_erc20_bridge_addr: Address::default(), - consensus: None, pre_insert_txs: false, }; let mut conn = pool.access_storage_tagged("state_keeper").await.unwrap(); @@ -397,16 +412,15 @@ async fn test_miniblock_and_l1_batch_processing( .get_sealed_miniblock_number() .await .unwrap(), - MiniblockNumber(2) // + fictive miniblock + Some(MiniblockNumber(2)) // + fictive miniblock ); let l1_batch_header = conn .blocks_dal() .get_l1_batch_header(L1BatchNumber(1)) .await .unwrap() - .unwrap(); + .expect("No L1 batch #1"); assert_eq!(l1_batch_header.l2_tx_count, 1); - assert!(l1_batch_header.is_finished); } #[tokio::test] @@ -432,7 +446,6 @@ async fn miniblock_sealer_handle_blocking() { L1BatchNumber(1), MiniblockNumber(1), Address::default(), - None, false, ); sealer_handle.submit(seal_command).await; @@ -442,7 +455,6 @@ async fn miniblock_sealer_handle_blocking() { L1BatchNumber(1), MiniblockNumber(2), Address::default(), - None, false, ); { @@ -472,7 +484,6 @@ async fn miniblock_sealer_handle_blocking() { L1BatchNumber(2), MiniblockNumber(3), Address::default(), - None, false, ); sealer_handle.submit(seal_command).await; @@ -493,7 +504,6 @@ async fn miniblock_sealer_handle_parallel_processing() { L1BatchNumber(1), MiniblockNumber(i), Address::default(), - None, false, ); sealer_handle.submit(seal_command).await; diff --git a/core/lib/zksync_core/src/state_keeper/io/tests/tester.rs b/core/lib/zksync_core/src/state_keeper/io/tests/tester.rs index 5528ae9f206a..6624e808e668 100644 --- a/core/lib/zksync_core/src/state_keeper/io/tests/tester.rs +++ b/core/lib/zksync_core/src/state_keeper/io/tests/tester.rs @@ -6,19 +6,22 @@ use multivm::vm_latest::constants::BLOCK_GAS_LIMIT; use zksync_config::{configs::chain::StateKeeperConfig, GasAdjusterConfig}; use zksync_contracts::BaseSystemContracts; use zksync_dal::ConnectionPool; -use zksync_eth_client::clients::mock::MockEthereum; +use zksync_eth_client::clients::MockEthereum; use zksync_object_store::ObjectStoreFactory; use zksync_types::{ - block::{L1BatchHeader, MiniblockHeader}, + block::MiniblockHeader, + fee_model::{BatchFeeInput, FeeModelConfig, FeeModelConfigV1}, protocol_version::L1VerifierConfig, system_contracts::get_system_smart_contracts, - Address, L1BatchNumber, L2ChainId, MiniblockNumber, PriorityOpId, ProtocolVersionId, H256, + Address, L2ChainId, PriorityOpId, ProtocolVersionId, H256, }; use crate::{ + fee_model::MainNodeFeeInputProvider, genesis::create_genesis_l1_batch, l1_gas_price::GasAdjuster, state_keeper::{io::MiniblockSealer, tests::create_transaction, MempoolGuard, MempoolIO}, + utils::testonly::{create_l1_batch, create_miniblock}, }; #[derive(Debug)] @@ -36,7 +39,7 @@ impl Tester { } } - pub(super) async fn create_gas_adjuster(&self) -> GasAdjuster { + async fn create_gas_adjuster(&self) -> GasAdjuster { let eth_client = MockEthereum::default().with_fee_history(vec![0, 4, 6, 8, 7, 5, 5, 8, 10, 9]); @@ -56,8 +59,18 @@ impl Tester { .unwrap() } + pub(super) async fn create_batch_fee_input_provider(&self) -> MainNodeFeeInputProvider { + let gas_adjuster = Arc::new(self.create_gas_adjuster().await); + MainNodeFeeInputProvider::new( + gas_adjuster, + FeeModelConfig::V1(FeeModelConfigV1 { + minimal_l2_gas_price: self.minimal_l2_gas_price(), + }), + ) + } + // Constant value to be used both in tests and inside of the IO. - pub(super) fn fair_l2_gas_price(&self) -> u64 { + pub(super) fn minimal_l2_gas_price(&self) -> u64 { 100 } @@ -65,15 +78,22 @@ impl Tester { &self, pool: ConnectionPool, miniblock_sealer_capacity: usize, - ) -> (MempoolIO>, MempoolGuard) { + ) -> (MempoolIO, MempoolGuard) { let gas_adjuster = Arc::new(self.create_gas_adjuster().await); + let batch_fee_input_provider = MainNodeFeeInputProvider::new( + gas_adjuster, + FeeModelConfig::V1(FeeModelConfigV1 { + minimal_l2_gas_price: self.minimal_l2_gas_price(), + }), + ); + let mempool = MempoolGuard::new(PriorityOpId(0), 100); let (miniblock_sealer, miniblock_sealer_handle) = MiniblockSealer::new(pool.clone(), miniblock_sealer_capacity); tokio::spawn(miniblock_sealer.run()); let config = StateKeeperConfig { - fair_l2_gas_price: self.fair_l2_gas_price(), + minimal_l2_gas_price: self.minimal_l2_gas_price(), virtual_blocks_interval: 1, virtual_blocks_per_miniblock: 1, ..StateKeeperConfig::default() @@ -84,7 +104,7 @@ impl Tester { mempool.clone(), object_store, miniblock_sealer_handle, - gas_adjuster, + Arc::new(batch_fee_input_provider), pool, &config, Duration::from_secs(1), @@ -123,43 +143,28 @@ impl Tester { pool: &ConnectionPool, number: u32, base_fee_per_gas: u64, - l1_gas_price: u64, - l2_fair_gas_price: u64, + fee_input: BatchFeeInput, ) { let mut storage = pool.access_storage_tagged("state_keeper").await.unwrap(); storage .blocks_dal() .insert_miniblock(&MiniblockHeader { - number: MiniblockNumber(number), timestamp: self.current_timestamp, - hash: H256::default(), - l1_tx_count: 0, - l2_tx_count: 0, base_fee_per_gas, - l1_gas_price, - l2_fair_gas_price, + batch_fee_input: fee_input, base_system_contracts_hashes: self.base_system_contracts.hashes(), - protocol_version: Some(ProtocolVersionId::latest()), - virtual_blocks: 0, + ..create_miniblock(number) }) .await .unwrap(); } pub(super) async fn insert_sealed_batch(&self, pool: &ConnectionPool, number: u32) { - let mut batch_header = L1BatchHeader::new( - L1BatchNumber(number), - self.current_timestamp, - Address::default(), - self.base_system_contracts.hashes(), - Default::default(), - ); - batch_header.is_finished = true; - + let batch_header = create_l1_batch(number); let mut storage = pool.access_storage_tagged("state_keeper").await.unwrap(); storage .blocks_dal() - .insert_l1_batch(&batch_header, &[], Default::default(), &[], &[]) + .insert_mock_l1_batch(&batch_header) .await .unwrap(); storage diff --git a/core/lib/zksync_core/src/state_keeper/keeper.rs b/core/lib/zksync_core/src/state_keeper/keeper.rs index 3cc153120c26..14829c5cf615 100644 --- a/core/lib/zksync_core/src/state_keeper/keeper.rs +++ b/core/lib/zksync_core/src/state_keeper/keeper.rs @@ -1,11 +1,13 @@ use std::{ convert::Infallible, + future::{self, Future}, time::{Duration, Instant}, }; use anyhow::Context as _; use multivm::interface::{Halt, L1BatchEnv, SystemEnv}; use tokio::sync::watch; +use zksync_dal::ConnectionPool; use zksync_types::{ block::MiniblockExecutionData, l2::TransactionType, protocol_version::ProtocolUpgradeTx, storage_writes_deduplicator::StorageWritesDeduplicator, Transaction, @@ -20,7 +22,7 @@ use super::{ types::ExecutionMetricsForCriteria, updates::UpdatesManager, }; -use crate::gas_tracker::gas_count_from_writes; +use crate::{gas_tracker::gas_count_from_writes, state_keeper::io::fee_address_migration}; /// Amount of time to block on waiting for some resource. The exact value is not really important, /// we only need it to not block on waiting indefinitely and be able to process cancellation requests. @@ -58,7 +60,7 @@ pub struct ZkSyncStateKeeper { stop_receiver: watch::Receiver, io: Box, batch_executor_base: Box, - sealer: Option, + sealer: Box, } impl ZkSyncStateKeeper { @@ -66,26 +68,28 @@ impl ZkSyncStateKeeper { stop_receiver: watch::Receiver, io: Box, batch_executor_base: Box, - sealer: ConditionalSealer, + sealer: Box, ) -> Self { Self { stop_receiver, io, batch_executor_base, - sealer: Some(sealer), + sealer, } } - pub fn without_sealer( - stop_receiver: watch::Receiver, - io: Box, - batch_executor_base: Box, - ) -> Self { - Self { - stop_receiver, - io, - batch_executor_base, - sealer: None, + /// Temporary method to migrate fee addresses from L1 batches to miniblocks. + pub fn run_fee_address_migration( + &self, + pool: ConnectionPool, + ) -> impl Future> { + let last_miniblock = self.io.current_miniblock_number() - 1; + let stop_receiver = self.stop_receiver.clone(); + async move { + fee_address_migration::migrate_miniblocks(pool, last_miniblock, stop_receiver).await?; + future::pending::<()>().await; + // ^ Since this is run as a task, we don't want it to exit on success (this would shut down the node). + anyhow::Ok(()) } } @@ -171,8 +175,13 @@ impl ZkSyncStateKeeper { let mut batch_executor = self .batch_executor_base - .init_batch(l1_batch_env.clone(), system_env.clone()) - .await; + .init_batch( + l1_batch_env.clone(), + system_env.clone(), + &self.stop_receiver, + ) + .await + .ok_or(Error::Canceled)?; self.restore_state(&batch_executor, &mut updates_manager, pending_miniblocks) .await?; @@ -223,8 +232,13 @@ impl ZkSyncStateKeeper { ); batch_executor = self .batch_executor_base - .init_batch(l1_batch_env.clone(), system_env.clone()) - .await; + .init_batch( + l1_batch_env.clone(), + system_env.clone(), + &self.stop_receiver, + ) + .await + .ok_or(Error::Canceled)?; let version_changed = system_env.version != sealed_batch_protocol_version; @@ -322,9 +336,13 @@ impl ZkSyncStateKeeper { .. } = result else { - return Err(anyhow::anyhow!( + tracing::error!( "Re-executing stored tx failed. Tx: {tx:?}. Err: {:?}", result.err() + ); + return Err(anyhow::anyhow!( + "Re-executing stored tx failed. It means that transaction was executed \ + successfully before, but failed after a restart." ) .into()); }; @@ -332,7 +350,7 @@ impl ZkSyncStateKeeper { let ExecutionMetricsForCriteria { l1_gas: tx_l1_gas_this_tx, execution_metrics: tx_execution_metrics, - } = tx_metrics; + } = *tx_metrics; let tx_hash = tx.hash(); let is_l1 = tx.is_l1(); @@ -362,6 +380,10 @@ impl ZkSyncStateKeeper { } } + tracing::debug!( + "All the transactions from the pending state were re-executed successfully" + ); + // We've processed all the miniblocks, and right now we're initializing the next *actual* miniblock. let new_miniblock_params = self .wait_for_new_miniblock_params(updates_manager.miniblock.timestamp) @@ -447,7 +469,7 @@ impl ZkSyncStateKeeper { let ExecutionMetricsForCriteria { l1_gas: tx_l1_gas_this_tx, execution_metrics: tx_execution_metrics, - } = tx_metrics; + } = *tx_metrics; updates_manager.extend_from_executed_transaction( tx, *tx_result, @@ -517,7 +539,7 @@ impl ZkSyncStateKeeper { l1_gas: tx_l1_gas_this_tx, execution_metrics: tx_execution_metrics, .. - } = tx_metrics; + } = *tx_metrics; updates_manager.extend_from_executed_transaction( tx, *tx_result, @@ -588,7 +610,7 @@ impl ZkSyncStateKeeper { let ExecutionMetricsForCriteria { l1_gas: tx_l1_gas_this_tx, execution_metrics: tx_execution_metrics, - } = *tx_metrics; + } = **tx_metrics; tracing::trace!( "finished tx {:?} by {:?} (is_l1: {}) (#{} in l1 batch {}) (#{} in miniblock {}) \ @@ -611,7 +633,7 @@ impl ZkSyncStateKeeper { let ExecutionMetricsForCriteria { l1_gas: finish_block_l1_gas, execution_metrics: finish_block_execution_metrics, - } = *bootloader_dry_run_metrics; + } = **bootloader_dry_run_metrics; let encoding_len = tx.encoding_len(); @@ -651,18 +673,14 @@ impl ZkSyncStateKeeper { writes_metrics: block_writes_metrics, }; - if let Some(sealer) = &self.sealer { - sealer.should_seal_l1_batch( - self.io.current_l1_batch_number().0, - updates_manager.batch_timestamp() as u128 * 1_000, - updates_manager.pending_executed_transactions_len() + 1, - &block_data, - &tx_data, - updates_manager.protocol_version(), - ) - } else { - SealResolution::NoSeal - } + self.sealer.should_seal_l1_batch( + self.io.current_l1_batch_number().0, + updates_manager.batch_timestamp() as u128 * 1_000, + updates_manager.pending_executed_transactions_len() + 1, + &block_data, + &tx_data, + updates_manager.protocol_version(), + ) } }; (resolution, exec_result) diff --git a/core/lib/zksync_core/src/state_keeper/mempool_actor.rs b/core/lib/zksync_core/src/state_keeper/mempool_actor.rs index 4797ed0006cd..7c57be2450de 100644 --- a/core/lib/zksync_core/src/state_keeper/mempool_actor.rs +++ b/core/lib/zksync_core/src/state_keeper/mempool_actor.rs @@ -1,27 +1,28 @@ use std::{sync::Arc, time::Duration}; -use multivm::vm_latest::utils::fee::derive_base_fee_and_gas_per_pubdata; +use anyhow::Context as _; +use multivm::utils::derive_base_fee_and_gas_per_pubdata; use tokio::sync::watch; use zksync_config::configs::chain::MempoolConfig; use zksync_dal::ConnectionPool; use zksync_mempool::L2TxFilter; +use zksync_types::VmVersion; use super::{metrics::KEEPER_METRICS, types::MempoolGuard}; -use crate::l1_gas_price::L1GasPriceProvider; +use crate::{api_server::execution_sandbox::BlockArgs, fee_model::BatchFeeModelInputProvider}; /// Creates a mempool filter for L2 transactions based on the current L1 gas price. /// The filter is used to filter out transactions from the mempool that do not cover expenses /// to process them. -pub fn l2_tx_filter( - gas_price_provider: &G, - fair_l2_gas_price: u64, +pub async fn l2_tx_filter( + batch_fee_input_provider: &dyn BatchFeeModelInputProvider, + vm_version: VmVersion, ) -> L2TxFilter { - let effective_gas_price = gas_price_provider.estimate_effective_gas_price(); + let fee_input = batch_fee_input_provider.get_batch_fee_input().await; - let (base_fee, gas_per_pubdata) = - derive_base_fee_and_gas_per_pubdata(effective_gas_price, fair_l2_gas_price); + let (base_fee, gas_per_pubdata) = derive_base_fee_and_gas_per_pubdata(fee_input, vm_version); L2TxFilter { - l1_gas_price: effective_gas_price, + fee_input, fee_per_gas: base_fee, gas_per_pubdata: gas_per_pubdata as u32, } @@ -30,20 +31,20 @@ pub fn l2_tx_filter( #[derive(Debug)] pub struct MempoolFetcher { mempool: MempoolGuard, - l1_gas_price_provider: Arc, + batch_fee_input_provider: Arc, sync_interval: Duration, sync_batch_size: usize, } -impl MempoolFetcher { +impl MempoolFetcher { pub fn new( mempool: MempoolGuard, - l1_gas_price_provider: Arc, + batch_fee_input_provider: Arc, config: &MempoolConfig, ) -> Self { Self { mempool, - l1_gas_price_provider, + batch_fee_input_provider, sync_interval: config.sync_interval(), sync_batch_size: config.sync_batch_size, } @@ -54,19 +55,23 @@ impl MempoolFetcher { pool: ConnectionPool, remove_stuck_txs: bool, stuck_tx_timeout: Duration, - fair_l2_gas_price: u64, stop_receiver: watch::Receiver, ) -> anyhow::Result<()> { { - let mut storage = pool.access_storage_tagged("state_keeper").await.unwrap(); + let mut storage = pool.access_storage_tagged("state_keeper").await?; if remove_stuck_txs { let removed_txs = storage .transactions_dal() .remove_stuck_txs(stuck_tx_timeout) - .await; - tracing::info!("Number of stuck txs was removed: {}", removed_txs); + .await + .context("failed removing stuck transactions")?; + tracing::info!("Number of stuck txs was removed: {removed_txs}"); } - storage.transactions_dal().reset_mempool().await; + storage + .transactions_dal() + .reset_mempool() + .await + .context("failed resetting mempool")?; } loop { @@ -75,20 +80,37 @@ impl MempoolFetcher { break; } let latency = KEEPER_METRICS.mempool_sync.start(); - let mut storage = pool.access_storage_tagged("state_keeper").await.unwrap(); + let mut storage = pool.access_storage_tagged("state_keeper").await?; let mempool_info = self.mempool.get_mempool_info(); - let l2_tx_filter = l2_tx_filter(self.l1_gas_price_provider.as_ref(), fair_l2_gas_price); + + let latest_miniblock = BlockArgs::pending(&mut storage) + .await + .context("failed obtaining latest miniblock")?; + let protocol_version = latest_miniblock + .resolve_block_info(&mut storage) + .await + .with_context(|| format!("failed resolving block info for {latest_miniblock:?}"))? + .protocol_version; + + let l2_tx_filter = l2_tx_filter( + self.batch_fee_input_provider.as_ref(), + protocol_version.into(), + ) + .await; let (transactions, nonces) = storage .transactions_dal() .sync_mempool( - mempool_info.stashed_accounts, - mempool_info.purged_accounts, + &mempool_info.stashed_accounts, + &mempool_info.purged_accounts, l2_tx_filter.gas_per_pubdata, l2_tx_filter.fee_per_gas, self.sync_batch_size, ) - .await; + .await + .context("failed syncing mempool")?; + drop(storage); + let all_transactions_loaded = transactions.len() < self.sync_batch_size; self.mempool.insert(transactions, nonces); latency.observe(); diff --git a/core/lib/zksync_core/src/state_keeper/metrics.rs b/core/lib/zksync_core/src/state_keeper/metrics.rs index 8daccb5a3aa8..aa65c16f7de1 100644 --- a/core/lib/zksync_core/src/state_keeper/metrics.rs +++ b/core/lib/zksync_core/src/state_keeper/metrics.rs @@ -52,6 +52,9 @@ pub(crate) struct StateKeeperMetrics { /// Time spent waiting for the header of a previous miniblock. #[metrics(buckets = Buckets::LATENCIES)] pub load_previous_miniblock_header: Histogram, + /// The time it takes for transactions to be included in a block. Representative of the time user must wait before their transaction is confirmed. + #[metrics(buckets = Buckets::LATENCIES)] + pub transaction_inclusion_delay: Histogram, /// Time spent by the state keeper on transaction execution. #[metrics(buckets = Buckets::LATENCIES)] pub tx_execution_time: Family>, @@ -248,8 +251,8 @@ pub(super) enum MiniblockSealStage { InsertEvents, ExtractL2ToL1Logs, InsertL2ToL1Logs, - InsertConsensus, CommitMiniblock, + ReportTxMetrics, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelSet)] diff --git a/core/lib/zksync_core/src/state_keeper/mod.rs b/core/lib/zksync_core/src/state_keeper/mod.rs index ee71a93bcf4c..b1534d9612f0 100644 --- a/core/lib/zksync_core/src/state_keeper/mod.rs +++ b/core/lib/zksync_core/src/state_keeper/mod.rs @@ -7,7 +7,6 @@ use zksync_config::{ }; use zksync_dal::ConnectionPool; use zksync_object_store::ObjectStore; -use zksync_system_constants::MAX_TXS_IN_BLOCK; use self::io::MempoolIO; pub use self::{ @@ -16,9 +15,9 @@ pub use self::{ keeper::ZkSyncStateKeeper, }; pub(crate) use self::{ - mempool_actor::MempoolFetcher, seal_criteria::ConditionalSealer, types::MempoolGuard, + mempool_actor::MempoolFetcher, seal_criteria::SequencerSealer, types::MempoolGuard, }; -use crate::l1_gas_price::L1GasPriceProvider; +use crate::fee_model::BatchFeeModelInputProvider; mod batch_executor; pub(crate) mod extractors; @@ -26,14 +25,14 @@ pub(crate) mod io; mod keeper; mod mempool_actor; pub(crate) mod metrics; -pub(crate) mod seal_criteria; +pub mod seal_criteria; #[cfg(test)] pub(crate) mod tests; pub(crate) mod types; pub(crate) mod updates; #[allow(clippy::too_many_arguments)] -pub(crate) async fn create_state_keeper( +pub(crate) async fn create_state_keeper( contracts_config: &ContractsConfig, state_keeper_config: StateKeeperConfig, db_config: &DBConfig, @@ -41,21 +40,11 @@ pub(crate) async fn create_state_keeper( mempool_config: &MempoolConfig, pool: ConnectionPool, mempool: MempoolGuard, - l1_gas_price_provider: Arc, + batch_fee_input_provider: Arc, miniblock_sealer_handle: MiniblockSealerHandle, - object_store: Box, + object_store: Arc, stop_receiver: watch::Receiver, -) -> ZkSyncStateKeeper -where - G: L1GasPriceProvider + 'static + Send + Sync, -{ - assert!( - state_keeper_config.transaction_slots <= MAX_TXS_IN_BLOCK, - "Configured transaction_slots ({}) must be lower than the bootloader constant MAX_TXS_IN_BLOCK={}", - state_keeper_config.transaction_slots, - MAX_TXS_IN_BLOCK - ); - +) -> ZkSyncStateKeeper { let batch_executor_base = MainBatchExecutorBuilder::new( db_config.state_keeper_db_path.clone(), pool.clone(), @@ -63,13 +52,14 @@ where state_keeper_config.save_call_traces, state_keeper_config.upload_witness_inputs_to_gcs, state_keeper_config.enum_index_migration_chunk_size(), + false, ); let io = MempoolIO::new( mempool, object_store, miniblock_sealer_handle, - l1_gas_price_provider, + batch_fee_input_provider, pool, &state_keeper_config, mempool_config.delay_interval(), @@ -79,11 +69,11 @@ where ) .await; - let sealer = ConditionalSealer::new(state_keeper_config); + let sealer = SequencerSealer::new(state_keeper_config); ZkSyncStateKeeper::new( stop_receiver, Box::new(io), Box::new(batch_executor_base), - sealer, + Box::new(sealer), ) } diff --git a/core/lib/zksync_core/src/state_keeper/seal_criteria/conditional_sealer.rs b/core/lib/zksync_core/src/state_keeper/seal_criteria/conditional_sealer.rs index 2b5fb9fba485..cc7ba37ef9c8 100644 --- a/core/lib/zksync_core/src/state_keeper/seal_criteria/conditional_sealer.rs +++ b/core/lib/zksync_core/src/state_keeper/seal_criteria/conditional_sealer.rs @@ -1,7 +1,10 @@ //! This module represents the conditional sealer, which can decide whether the batch //! should be sealed after executing a particular transaction. -//! It is used on the main node to decide when the batch should be sealed (as opposed to the external node, -//! which unconditionally follows the instructions from the main node). +//! +//! The conditional sealer abstraction allows to implement different sealing strategies, e.g. the actual +//! sealing strategy for the main node or noop sealer for the external node. + +use std::fmt; use zksync_config::configs::chain::StateKeeperConfig; use zksync_types::ProtocolVersionId; @@ -9,28 +12,51 @@ use zksync_types::ProtocolVersionId; use super::{criteria, SealCriterion, SealData, SealResolution, AGGREGATION_METRICS}; /// Checks if an L1 batch should be sealed after executing a transaction. +pub trait ConditionalSealer: 'static + fmt::Debug + Send + Sync { + /// Finds a reason why a transaction with the specified `data` is unexecutable. + /// + /// Can be used to determine whether the transaction can be executed by the sequencer. + fn find_unexecutable_reason( + &self, + data: &SealData, + protocol_version: ProtocolVersionId, + ) -> Option<&'static str>; + + /// Returns the action that should be taken by the state keeper after executing a transaction. + fn should_seal_l1_batch( + &self, + l1_batch_number: u32, + block_open_timestamp_ms: u128, + tx_count: usize, + block_data: &SealData, + tx_data: &SealData, + protocol_version: ProtocolVersionId, + ) -> SealResolution; +} + +/// Implementation of [`ConditionalSealer`] used by the main node. +/// Internally uses a set of [`SealCriterion`]s to determine whether the batch should be sealed. /// /// The checks are deterministic, i.e., should depend solely on execution metrics and [`StateKeeperConfig`]. /// Non-deterministic seal criteria are expressed using [`IoSealCriteria`](super::IoSealCriteria). #[derive(Debug)] -pub struct ConditionalSealer { +pub struct SequencerSealer { config: StateKeeperConfig, sealers: Vec>, } -impl ConditionalSealer { - /// Finds a reason why a transaction with the specified `data` is unexecutable. - pub(crate) fn find_unexecutable_reason( - config: &StateKeeperConfig, +impl ConditionalSealer for SequencerSealer { + fn find_unexecutable_reason( + &self, data: &SealData, protocol_version: ProtocolVersionId, ) -> Option<&'static str> { - for sealer in &Self::default_sealers() { + for sealer in &self.sealers { const MOCK_BLOCK_TIMESTAMP: u128 = 0; const TX_COUNT: usize = 1; let resolution = sealer.should_seal( - config, + &self.config, MOCK_BLOCK_TIMESTAMP, TX_COUNT, data, @@ -44,20 +70,7 @@ impl ConditionalSealer { None } - pub(crate) fn new(config: StateKeeperConfig) -> Self { - let sealers = Self::default_sealers(); - Self { config, sealers } - } - - #[cfg(test)] - pub(in crate::state_keeper) fn with_sealers( - config: StateKeeperConfig, - sealers: Vec>, - ) -> Self { - Self { config, sealers } - } - - pub fn should_seal_l1_batch( + fn should_seal_l1_batch( &self, l1_batch_number: u32, block_open_timestamp_ms: u128, @@ -99,18 +112,57 @@ impl ConditionalSealer { } final_seal_resolution } +} + +impl SequencerSealer { + pub(crate) fn new(config: StateKeeperConfig) -> Self { + let sealers = Self::default_sealers(); + Self { config, sealers } + } + + #[cfg(test)] + pub(in crate::state_keeper) fn with_sealers( + config: StateKeeperConfig, + sealers: Vec>, + ) -> Self { + Self { config, sealers } + } fn default_sealers() -> Vec> { vec![ Box::new(criteria::SlotsCriterion), Box::new(criteria::GasCriterion), Box::new(criteria::PubDataBytesCriterion), - Box::new(criteria::InitialWritesCriterion), - Box::new(criteria::RepeatedWritesCriterion), - Box::new(criteria::MaxCyclesCriterion), - Box::new(criteria::ComputationalGasCriterion), + Box::new(criteria::CircuitsCriterion), Box::new(criteria::TxEncodingSizeCriterion), - Box::new(criteria::L2ToL1LogsCriterion), ] } } + +/// Implementation of [`ConditionalSealer`] that never seals the batch. +/// Can be used in contexts where, for example, state keeper configuration is not available, +/// or the decision to seal batch is taken by some other component. +#[derive(Debug)] +pub struct NoopSealer; + +impl ConditionalSealer for NoopSealer { + fn find_unexecutable_reason( + &self, + _data: &SealData, + _protocol_version: ProtocolVersionId, + ) -> Option<&'static str> { + None + } + + fn should_seal_l1_batch( + &self, + _l1_batch_number: u32, + _block_open_timestamp_ms: u128, + _tx_count: usize, + _block_data: &SealData, + _tx_data: &SealData, + _protocol_version: ProtocolVersionId, + ) -> SealResolution { + SealResolution::NoSeal + } +} diff --git a/core/lib/zksync_core/src/state_keeper/seal_criteria/criteria/geometry_seal_criteria.rs b/core/lib/zksync_core/src/state_keeper/seal_criteria/criteria/geometry_seal_criteria.rs index 9f99554e58a2..1ae5899a9c4b 100644 --- a/core/lib/zksync_core/src/state_keeper/seal_criteria/criteria/geometry_seal_criteria.rs +++ b/core/lib/zksync_core/src/state_keeper/seal_criteria/criteria/geometry_seal_criteria.rs @@ -1,12 +1,7 @@ use std::fmt; -use multivm::vm_latest::constants::{ERGS_PER_CIRCUIT, MAX_CYCLES_FOR_TX}; use zksync_config::configs::chain::StateKeeperConfig; -use zksync_types::{ - circuit::{GEOMETRY_CONFIG, SCHEDULER_UPPER_BOUND}, - tx::tx_execution_info::{DeduplicatedWritesMetrics, ExecutionMetrics}, - ProtocolVersionId, -}; +use zksync_types::{tx::tx_execution_info::ExecutionMetrics, ProtocolVersionId}; // Local uses use crate::state_keeper::seal_criteria::{SealCriterion, SealData, SealResolution}; @@ -15,20 +10,12 @@ use crate::state_keeper::seal_criteria::{SealCriterion, SealData, SealResolution // Otherwise witness generation will fail and proof won't be generated. #[derive(Debug, Default)] -pub struct RepeatedWritesCriterion; -#[derive(Debug, Default)] -pub struct InitialWritesCriterion; -#[derive(Debug, Default)] -pub struct MaxCyclesCriterion; -#[derive(Debug, Default)] -pub struct ComputationalGasCriterion; -#[derive(Debug, Default)] -pub struct L2ToL1LogsCriterion; +pub struct CircuitsCriterion; trait MetricExtractor { const PROM_METRIC_CRITERION_NAME: &'static str; fn limit_per_block(protocol_version: ProtocolVersionId) -> usize; - fn extract(metric: &ExecutionMetrics, writes: &DeduplicatedWritesMetrics) -> usize; + fn extract(metric: &ExecutionMetrics) -> usize; } impl SealCriterion for T @@ -51,15 +38,13 @@ where * config.close_block_at_geometry_percentage) .round(); - if T::extract(&tx_data.execution_metrics, &tx_data.writes_metrics) > reject_bound as usize { + if T::extract(&tx_data.execution_metrics) > reject_bound as usize { SealResolution::Unexecutable("ZK proof cannot be generated for a transaction".into()) - } else if T::extract(&block_data.execution_metrics, &block_data.writes_metrics) + } else if T::extract(&block_data.execution_metrics) >= T::limit_per_block(protocol_version_id) { SealResolution::ExcludeAndSeal - } else if T::extract(&block_data.execution_metrics, &block_data.writes_metrics) - > close_bound as usize - { + } else if T::extract(&block_data.execution_metrics) > close_bound as usize { SealResolution::IncludeAndSeal } else { SealResolution::NoSeal @@ -71,90 +56,28 @@ where } } -impl MetricExtractor for RepeatedWritesCriterion { - const PROM_METRIC_CRITERION_NAME: &'static str = "repeated_storage_writes"; - - fn limit_per_block(protocol_version_id: ProtocolVersionId) -> usize { - if protocol_version_id.is_pre_boojum() { - GEOMETRY_CONFIG.limit_for_repeated_writes_pubdata_hasher as usize - } else { - // In boojum there is no limit for repeated writes. - usize::MAX - } - } - - fn extract(_metrics: &ExecutionMetrics, writes: &DeduplicatedWritesMetrics) -> usize { - writes.repeated_storage_writes - } -} - -impl MetricExtractor for InitialWritesCriterion { - const PROM_METRIC_CRITERION_NAME: &'static str = "initial_storage_writes"; - - fn limit_per_block(protocol_version_id: ProtocolVersionId) -> usize { - if protocol_version_id.is_pre_boojum() { - GEOMETRY_CONFIG.limit_for_initial_writes_pubdata_hasher as usize - } else { - // In boojum there is no limit for initial writes. - usize::MAX - } - } - - fn extract(_metrics: &ExecutionMetrics, writes: &DeduplicatedWritesMetrics) -> usize { - writes.initial_storage_writes - } -} - -impl MetricExtractor for MaxCyclesCriterion { - const PROM_METRIC_CRITERION_NAME: &'static str = "max_cycles"; - - fn limit_per_block(_protocol_version_id: ProtocolVersionId) -> usize { - MAX_CYCLES_FOR_TX as usize - } - - fn extract(metrics: &ExecutionMetrics, _writes: &DeduplicatedWritesMetrics) -> usize { - metrics.cycles_used as usize - } -} - -impl MetricExtractor for ComputationalGasCriterion { - const PROM_METRIC_CRITERION_NAME: &'static str = "computational_gas"; +impl MetricExtractor for CircuitsCriterion { + const PROM_METRIC_CRITERION_NAME: &'static str = "circuits"; fn limit_per_block(_protocol_version_id: ProtocolVersionId) -> usize { // We subtract constant to take into account that circuits may be not fully filled. // This constant should be greater than number of circuits types // but we keep it larger to be on the safe side. - const MARGIN_NUMBER_OF_CIRCUITS: usize = 100; - const MAX_NUMBER_OF_MUTLIINSTANCE_CIRCUITS: usize = - SCHEDULER_UPPER_BOUND as usize - MARGIN_NUMBER_OF_CIRCUITS; + const MARGIN_NUMBER_OF_CIRCUITS: usize = 10000; + const MAX_NUMBER_OF_CIRCUITS: usize = (1 << 14) + (1 << 13) - MARGIN_NUMBER_OF_CIRCUITS; - MAX_NUMBER_OF_MUTLIINSTANCE_CIRCUITS * ERGS_PER_CIRCUIT as usize + MAX_NUMBER_OF_CIRCUITS } - fn extract(metrics: &ExecutionMetrics, _writes: &DeduplicatedWritesMetrics) -> usize { - metrics.computational_gas_used as usize - } -} - -impl MetricExtractor for L2ToL1LogsCriterion { - const PROM_METRIC_CRITERION_NAME: &'static str = "l2_to_l1_logs"; - - fn limit_per_block(protocol_version_id: ProtocolVersionId) -> usize { - if protocol_version_id.is_pre_boojum() { - GEOMETRY_CONFIG.limit_for_l1_messages_merklizer as usize - } else { - // In boojum there is no limit for L2 to L1 logs. - usize::MAX - } - } - - fn extract(metrics: &ExecutionMetrics, _writes: &DeduplicatedWritesMetrics) -> usize { - metrics.l2_to_l1_logs + fn extract(metrics: &ExecutionMetrics) -> usize { + metrics.circuit_statistic.total() } } #[cfg(test)] mod tests { + use zksync_types::circuit::CircuitStatistic; + use super::*; fn get_config() -> StateKeeperConfig { @@ -167,7 +90,6 @@ mod tests { fn test_no_seal_block_resolution( block_execution_metrics: ExecutionMetrics, - block_writes_metrics: DeduplicatedWritesMetrics, criterion: &dyn SealCriterion, protocol_version: ProtocolVersionId, ) { @@ -178,7 +100,6 @@ mod tests { 0, &SealData { execution_metrics: block_execution_metrics, - writes_metrics: block_writes_metrics, ..SealData::default() }, &SealData::default(), @@ -189,7 +110,6 @@ mod tests { fn test_include_and_seal_block_resolution( block_execution_metrics: ExecutionMetrics, - block_writes_metrics: DeduplicatedWritesMetrics, criterion: &dyn SealCriterion, protocol_version: ProtocolVersionId, ) { @@ -200,7 +120,6 @@ mod tests { 0, &SealData { execution_metrics: block_execution_metrics, - writes_metrics: block_writes_metrics, ..SealData::default() }, &SealData::default(), @@ -211,7 +130,6 @@ mod tests { fn test_exclude_and_seal_block_resolution( block_execution_metrics: ExecutionMetrics, - block_writes_metrics: DeduplicatedWritesMetrics, criterion: &dyn SealCriterion, protocol_version: ProtocolVersionId, ) { @@ -222,7 +140,6 @@ mod tests { 0, &SealData { execution_metrics: block_execution_metrics, - writes_metrics: block_writes_metrics, ..SealData::default() }, &SealData::default(), @@ -233,7 +150,6 @@ mod tests { fn test_unexecutable_tx_resolution( tx_execution_metrics: ExecutionMetrics, - tx_writes_metrics: DeduplicatedWritesMetrics, criterion: &dyn SealCriterion, protocol_version: ProtocolVersionId, ) { @@ -245,7 +161,6 @@ mod tests { &SealData::default(), &SealData { execution_metrics: tx_execution_metrics, - writes_metrics: tx_writes_metrics, ..SealData::default() }, protocol_version, @@ -257,165 +172,61 @@ mod tests { ); } - macro_rules! test_scenario_execution_metrics { - ($criterion: tt, $metric_name: ident, $metric_type: ty, $protocol_version: expr) => { - let config = get_config(); - let writes_metrics = DeduplicatedWritesMetrics::default(); - let block_execution_metrics = ExecutionMetrics { - $metric_name: ($criterion::limit_per_block($protocol_version) / 2) as $metric_type, - ..ExecutionMetrics::default() - }; - test_no_seal_block_resolution( - block_execution_metrics, - writes_metrics, - &$criterion, - $protocol_version, - ); - - let block_execution_metrics = ExecutionMetrics { - $metric_name: ($criterion::limit_per_block($protocol_version) - 1) as $metric_type, - ..ExecutionMetrics::default() - }; - - test_include_and_seal_block_resolution( - block_execution_metrics, - writes_metrics, - &$criterion, - $protocol_version, - ); - - let block_execution_metrics = ExecutionMetrics { - $metric_name: ($criterion::limit_per_block($protocol_version)) as $metric_type, - ..ExecutionMetrics::default() - }; - - test_exclude_and_seal_block_resolution( - block_execution_metrics, - writes_metrics, - &$criterion, - $protocol_version, - ); - - let tx_execution_metrics = ExecutionMetrics { - $metric_name: ($criterion::limit_per_block($protocol_version) as f64 - * config.reject_tx_at_geometry_percentage - + 1f64) - .round() as $metric_type, - ..ExecutionMetrics::default() - }; - - test_unexecutable_tx_resolution( - tx_execution_metrics, - writes_metrics, - &$criterion, - $protocol_version, - ); + #[test] + fn circuits_seal_criterion() { + let config = get_config(); + let protocol_version = ProtocolVersionId::latest(); + let block_execution_metrics = ExecutionMetrics { + circuit_statistic: CircuitStatistic { + main_vm: (CircuitsCriterion::limit_per_block(protocol_version) / 2) as f32, + ..CircuitStatistic::default() + }, + ..ExecutionMetrics::default() }; - } - - macro_rules! test_scenario_writes_metrics { - ($criterion:tt, $metric_name:ident, $metric_type:ty, $protocol_version:expr) => { - let config = get_config(); - let execution_metrics = ExecutionMetrics::default(); - let block_writes_metrics = DeduplicatedWritesMetrics { - $metric_name: ($criterion::limit_per_block($protocol_version) / 2) as $metric_type, - ..Default::default() - }; - test_no_seal_block_resolution( - execution_metrics, - block_writes_metrics, - &$criterion, - $protocol_version, - ); - - let block_writes_metrics = DeduplicatedWritesMetrics { - $metric_name: ($criterion::limit_per_block($protocol_version) - 1) as $metric_type, - ..Default::default() - }; - - test_include_and_seal_block_resolution( - execution_metrics, - block_writes_metrics, - &$criterion, - $protocol_version, - ); - - let block_writes_metrics = DeduplicatedWritesMetrics { - $metric_name: ($criterion::limit_per_block($protocol_version)) as $metric_type, - ..Default::default() - }; - - test_exclude_and_seal_block_resolution( - execution_metrics, - block_writes_metrics, - &$criterion, - $protocol_version, - ); - - let tx_writes_metrics = DeduplicatedWritesMetrics { - $metric_name: ($criterion::limit_per_block($protocol_version) as f64 - * config.reject_tx_at_geometry_percentage - + 1f64) - .round() as $metric_type, - ..Default::default() - }; + test_no_seal_block_resolution( + block_execution_metrics, + &CircuitsCriterion, + protocol_version, + ); - test_unexecutable_tx_resolution( - execution_metrics, - tx_writes_metrics, - &$criterion, - $protocol_version, - ); + let block_execution_metrics = ExecutionMetrics { + circuit_statistic: CircuitStatistic { + main_vm: (CircuitsCriterion::limit_per_block(protocol_version) - 1) as f32, + ..CircuitStatistic::default() + }, + ..ExecutionMetrics::default() }; - } - #[test] - fn repeated_writes_seal_criterion() { - test_scenario_writes_metrics!( - RepeatedWritesCriterion, - repeated_storage_writes, - usize, - ProtocolVersionId::Version17 + test_include_and_seal_block_resolution( + block_execution_metrics, + &CircuitsCriterion, + protocol_version, ); - } - #[test] - fn initial_writes_seal_criterion() { - test_scenario_writes_metrics!( - InitialWritesCriterion, - initial_storage_writes, - usize, - ProtocolVersionId::Version17 - ); - } + let block_execution_metrics = ExecutionMetrics { + circuit_statistic: CircuitStatistic { + main_vm: CircuitsCriterion::limit_per_block(protocol_version) as f32, + ..CircuitStatistic::default() + }, + ..ExecutionMetrics::default() + }; - #[test] - fn max_cycles_seal_criterion() { - test_scenario_execution_metrics!( - MaxCyclesCriterion, - cycles_used, - u32, - ProtocolVersionId::Version17 + test_exclude_and_seal_block_resolution( + block_execution_metrics, + &CircuitsCriterion, + protocol_version, ); - } - #[test] - fn computational_gas_seal_criterion() { - test_scenario_execution_metrics!( - ComputationalGasCriterion, - computational_gas_used, - u32, - ProtocolVersionId::Version17 - ); - } + let tx_execution_metrics = ExecutionMetrics { + circuit_statistic: CircuitStatistic { + main_vm: CircuitsCriterion::limit_per_block(protocol_version) as f32 + * config.reject_tx_at_geometry_percentage as f32 + + 1.0, + ..CircuitStatistic::default() + }, + ..ExecutionMetrics::default() + }; - #[test] - fn l2_to_l1_logs_seal_criterion() { - test_scenario_execution_metrics!( - L2ToL1LogsCriterion, - l2_to_l1_logs, - usize, - ProtocolVersionId::Version17 - ); + test_unexecutable_tx_resolution(tx_execution_metrics, &CircuitsCriterion, protocol_version); } } diff --git a/core/lib/zksync_core/src/state_keeper/seal_criteria/criteria/mod.rs b/core/lib/zksync_core/src/state_keeper/seal_criteria/criteria/mod.rs index 8e0d89e8e0f2..4e30f2a8b608 100644 --- a/core/lib/zksync_core/src/state_keeper/seal_criteria/criteria/mod.rs +++ b/core/lib/zksync_core/src/state_keeper/seal_criteria/criteria/mod.rs @@ -5,12 +5,7 @@ mod slots; mod tx_encoding_size; pub(in crate::state_keeper) use self::{ - gas::GasCriterion, - geometry_seal_criteria::{ - ComputationalGasCriterion, InitialWritesCriterion, L2ToL1LogsCriterion, MaxCyclesCriterion, - RepeatedWritesCriterion, - }, - pubdata_bytes::PubDataBytesCriterion, - slots::SlotsCriterion, + gas::GasCriterion, geometry_seal_criteria::CircuitsCriterion, + pubdata_bytes::PubDataBytesCriterion, slots::SlotsCriterion, tx_encoding_size::TxEncodingSizeCriterion, }; diff --git a/core/lib/zksync_core/src/state_keeper/seal_criteria/criteria/pubdata_bytes.rs b/core/lib/zksync_core/src/state_keeper/seal_criteria/criteria/pubdata_bytes.rs index 61f30d724a70..ec778cdf0836 100644 --- a/core/lib/zksync_core/src/state_keeper/seal_criteria/criteria/pubdata_bytes.rs +++ b/core/lib/zksync_core/src/state_keeper/seal_criteria/criteria/pubdata_bytes.rs @@ -26,7 +26,7 @@ impl SealCriterion for PubDataBytesCriterion { let block_size = block_data.execution_metrics.size() + block_data.writes_metrics.size(protocol_version); // For backward compatibility, we need to keep calculating the size of the pubdata based - // StorageDeduplication metrics. All vm versions + // `StorageDeduplication` metrics. All vm versions // after vm with virtual blocks will provide the size of the pubdata in the execution metrics. let tx_size = if tx_data.execution_metrics.pubdata_published == 0 { tx_data.execution_metrics.size() + tx_data.writes_metrics.size(protocol_version) diff --git a/core/lib/zksync_core/src/state_keeper/seal_criteria/criteria/slots.rs b/core/lib/zksync_core/src/state_keeper/seal_criteria/criteria/slots.rs index 4c21c41e5e40..41d99b8274b7 100644 --- a/core/lib/zksync_core/src/state_keeper/seal_criteria/criteria/slots.rs +++ b/core/lib/zksync_core/src/state_keeper/seal_criteria/criteria/slots.rs @@ -1,3 +1,4 @@ +use multivm::utils::get_bootloader_max_txs_in_batch; use zksync_types::ProtocolVersionId; use crate::state_keeper::seal_criteria::{ @@ -16,8 +17,15 @@ impl SealCriterion for SlotsCriterion { tx_count: usize, _block_data: &SealData, _tx_data: &SealData, - _protocol_version: ProtocolVersionId, + protocol_version: ProtocolVersionId, ) -> SealResolution { + let max_txs_in_batch = get_bootloader_max_txs_in_batch(protocol_version.into()); + assert!( + config.transaction_slots <= max_txs_in_batch, + "Configured transaction_slots ({}) must be lower than the bootloader constant MAX_TXS_IN_BLOCK={} for protocol version {}", + config.transaction_slots, max_txs_in_batch, protocol_version as u16 + ); + if tx_count >= config.transaction_slots { SealResolution::IncludeAndSeal } else { diff --git a/core/lib/zksync_core/src/state_keeper/seal_criteria/criteria/tx_encoding_size.rs b/core/lib/zksync_core/src/state_keeper/seal_criteria/criteria/tx_encoding_size.rs index ed24e3719338..02683e501d9b 100644 --- a/core/lib/zksync_core/src/state_keeper/seal_criteria/criteria/tx_encoding_size.rs +++ b/core/lib/zksync_core/src/state_keeper/seal_criteria/criteria/tx_encoding_size.rs @@ -1,4 +1,4 @@ -use multivm::vm_latest::constants::BOOTLOADER_TX_ENCODING_SPACE; +use multivm::utils::get_bootloader_encoding_space; use zksync_types::ProtocolVersionId; use crate::state_keeper::seal_criteria::{ @@ -16,18 +16,21 @@ impl SealCriterion for TxEncodingSizeCriterion { _tx_count: usize, block_data: &SealData, tx_data: &SealData, - _protocol_version_id: ProtocolVersionId, + protocol_version_id: ProtocolVersionId, ) -> SealResolution { + let bootloader_tx_encoding_space = + get_bootloader_encoding_space(protocol_version_id.into()); + let reject_bound = - (BOOTLOADER_TX_ENCODING_SPACE as f64 * config.reject_tx_at_geometry_percentage).round(); - let include_and_seal_bound = (BOOTLOADER_TX_ENCODING_SPACE as f64 + (bootloader_tx_encoding_space as f64 * config.reject_tx_at_geometry_percentage).round(); + let include_and_seal_bound = (bootloader_tx_encoding_space as f64 * config.close_block_at_geometry_percentage) .round(); if tx_data.cumulative_size > reject_bound as usize { let message = "Transaction cannot be included due to large encoding size"; SealResolution::Unexecutable(message.into()) - } else if block_data.cumulative_size > BOOTLOADER_TX_ENCODING_SPACE as usize { + } else if block_data.cumulative_size > bootloader_tx_encoding_space as usize { SealResolution::ExcludeAndSeal } else if block_data.cumulative_size > include_and_seal_bound as usize { SealResolution::IncludeAndSeal @@ -47,6 +50,9 @@ mod tests { #[test] fn seal_criterion() { + let bootloader_tx_encoding_space = + get_bootloader_encoding_space(ProtocolVersionId::latest().into()); + // Create an empty config and only setup fields relevant for the test. let config = StateKeeperConfig { reject_tx_at_geometry_percentage: 0.95, @@ -72,7 +78,7 @@ mod tests { 0, &SealData::default(), &SealData { - cumulative_size: BOOTLOADER_TX_ENCODING_SPACE as usize + 1, + cumulative_size: bootloader_tx_encoding_space as usize + 1, ..SealData::default() }, ProtocolVersionId::latest(), @@ -89,7 +95,7 @@ mod tests { 0, 0, &SealData { - cumulative_size: BOOTLOADER_TX_ENCODING_SPACE as usize + 1, + cumulative_size: bootloader_tx_encoding_space as usize + 1, ..SealData::default() }, &SealData { @@ -105,7 +111,7 @@ mod tests { 0, 0, &SealData { - cumulative_size: BOOTLOADER_TX_ENCODING_SPACE as usize, + cumulative_size: bootloader_tx_encoding_space as usize, ..SealData::default() }, &SealData { diff --git a/core/lib/zksync_core/src/state_keeper/seal_criteria/mod.rs b/core/lib/zksync_core/src/state_keeper/seal_criteria/mod.rs index 99cb25c654d8..bf44c7af0ecf 100644 --- a/core/lib/zksync_core/src/state_keeper/seal_criteria/mod.rs +++ b/core/lib/zksync_core/src/state_keeper/seal_criteria/mod.rs @@ -25,7 +25,7 @@ use zksync_utils::time::millis_since; mod conditional_sealer; pub(super) mod criteria; -pub(crate) use self::conditional_sealer::ConditionalSealer; +pub use self::conditional_sealer::{ConditionalSealer, NoopSealer, SequencerSealer}; use super::{extractors, metrics::AGGREGATION_METRICS, updates::UpdatesManager}; use crate::gas_tracker::{gas_count_from_tx_and_metrics, gas_count_from_writes}; @@ -104,7 +104,7 @@ impl SealData { } } -pub(super) trait SealCriterion: fmt::Debug + Send + 'static { +pub(super) trait SealCriterion: fmt::Debug + Send + Sync + 'static { fn should_seal( &self, config: &StateKeeperConfig, diff --git a/core/lib/zksync_core/src/state_keeper/tests/mod.rs b/core/lib/zksync_core/src/state_keeper/tests/mod.rs index c725cdcf010b..bfcfc524ffa0 100644 --- a/core/lib/zksync_core/src/state_keeper/tests/mod.rs +++ b/core/lib/zksync_core/src/state_keeper/tests/mod.rs @@ -20,13 +20,11 @@ use zksync_system_constants::ZKPORTER_IS_AVAILABLE; use zksync_types::{ aggregated_operations::AggregatedActionType, block::{BlockGasCount, MiniblockExecutionData, MiniblockHasher}, - commitment::{L1BatchMetaParameters, L1BatchMetadata}, - fee::Fee, - l2::L2Tx, - transaction_request::PaymasterParams, + fee_model::{BatchFeeInput, PubdataIndependentBatchFeeModelInput}, tx::tx_execution_info::ExecutionMetrics, - Address, L1BatchNumber, L2ChainId, LogQuery, MiniblockNumber, Nonce, ProtocolVersionId, - StorageLogQuery, StorageLogQueryType, Timestamp, Transaction, H256, U256, + zk_evm_types::{LogQuery, Timestamp}, + Address, L1BatchNumber, L2ChainId, MiniblockNumber, ProtocolVersionId, StorageLogQuery, + StorageLogQueryType, Transaction, H256, U256, }; mod tester; @@ -42,11 +40,12 @@ use crate::{ keeper::POLL_WAIT_DURATION, seal_criteria::{ criteria::{GasCriterion, SlotsCriterion}, - ConditionalSealer, + SequencerSealer, }, types::ExecutionMetricsForCriteria, updates::UpdatesManager, }, + utils::testonly::create_l2_transaction, }; pub(super) static BASE_SYSTEM_CONTRACTS: Lazy = @@ -73,8 +72,6 @@ pub(super) fn default_l1_batch_env( previous_batch_hash: None, number: L1BatchNumber(number), timestamp, - l1_gas_price: 1, - fair_l2_gas_price: 1, fee_account, enforced_base_fee: None, first_l2_block: L2BlockEnv { @@ -83,30 +80,11 @@ pub(super) fn default_l1_batch_env( prev_block_hash: MiniblockHasher::legacy_hash(MiniblockNumber(number - 1)), max_virtual_blocks_to_create: 1, }, - } -} - -pub(crate) fn create_l1_batch_metadata(number: u32) -> L1BatchMetadata { - L1BatchMetadata { - root_hash: H256::from_low_u64_be(number.into()), - rollup_last_leaf_index: u64::from(number) + 20, - merkle_root_hash: H256::from_low_u64_be(number.into()), - initial_writes_compressed: vec![], - repeated_writes_compressed: vec![], - commitment: H256::from_low_u64_be(number.into()), - l2_l1_messages_compressed: vec![], - l2_l1_merkle_root: H256::from_low_u64_be(number.into()), - block_meta_params: L1BatchMetaParameters { - zkporter_is_available: ZKPORTER_IS_AVAILABLE, - bootloader_code_hash: BASE_SYSTEM_CONTRACTS.bootloader.hash, - default_aa_code_hash: BASE_SYSTEM_CONTRACTS.default_aa.hash, - }, - aux_data_hash: H256::zero(), - meta_parameters_hash: H256::zero(), - pass_through_data_hash: H256::zero(), - events_queue_commitment: Some(H256::zero()), - bootloader_initial_content_commitment: Some(H256::zero()), - state_diffs_compressed: vec![], + fee_input: BatchFeeInput::PubdataIndependent(PubdataIndependentBatchFeeModelInput { + fair_l2_gas_price: 1, + fair_pubdata_price: 1, + l1_gas_price: 1, + }), } } @@ -121,6 +99,7 @@ pub(super) fn default_vm_block_result() -> FinishedL1Batch { final_execution_state: CurrentExecutionState { events: vec![], storage_log_queries: vec![], + deduplicated_storage_log_queries: vec![], used_contract_hashes: vec![], user_l2_to_l1_logs: vec![], system_logs: vec![], @@ -143,32 +122,6 @@ pub(super) fn create_updates_manager() -> UpdatesManager { ) } -pub(crate) fn create_l2_transaction(fee_per_gas: u64, gas_per_pubdata: u32) -> L2Tx { - let fee = Fee { - gas_limit: 1000_u64.into(), - max_fee_per_gas: fee_per_gas.into(), - max_priority_fee_per_gas: 0_u64.into(), - gas_per_pubdata_limit: gas_per_pubdata.into(), - }; - let mut tx = L2Tx::new_signed( - Address::random(), - vec![], - Nonce(0), - fee, - U256::zero(), - L2ChainId::from(271), - &H256::random(), - None, - PaymasterParams::default(), - ) - .unwrap(); - // Input means all transaction data (NOT calldata, but all tx fields) that came from the API. - // This input will be used for the derivation of the tx hash, so put some random to it to be sure - // that the transaction hash is unique. - tx.set_input(H256::random().0.to_vec(), H256::random()); - tx -} - pub(super) fn create_transaction(fee_per_gas: u64, gas_per_pubdata: u32) -> Transaction { create_l2_transaction(fee_per_gas, gas_per_pubdata).into() } @@ -199,6 +152,7 @@ pub(super) fn create_execution_result( computational_gas_used: 0, total_log_queries, pubdata_published: 0, + circuit_statistic: Default::default(), }, refunds: Refunds::default(), } @@ -250,7 +204,7 @@ async fn sealed_by_number_of_txs() { transaction_slots: 2, ..StateKeeperConfig::default() }; - let sealer = ConditionalSealer::with_sealers(config, vec![Box::new(SlotsCriterion)]); + let sealer = SequencerSealer::with_sealers(config, vec![Box::new(SlotsCriterion)]); TestScenario::new() .seal_miniblock_when(|updates| updates.miniblock.executed_transactions.len() == 1) @@ -271,10 +225,10 @@ async fn sealed_by_gas() { close_block_at_gas_percentage: 0.5, ..StateKeeperConfig::default() }; - let sealer = ConditionalSealer::with_sealers(config, vec![Box::new(GasCriterion)]); + let sealer = SequencerSealer::with_sealers(config, vec![Box::new(GasCriterion)]); let l1_gas_per_tx = BlockGasCount { - commit: 1, // Both txs together with block_base_cost would bring it over the block 31_001 commit bound. + commit: 1, // Both txs together with `block_base_cost` would bring it over the block `31_001` commit bound. prove: 0, execute: 0, }; @@ -320,7 +274,7 @@ async fn sealed_by_gas_then_by_num_tx() { transaction_slots: 3, ..StateKeeperConfig::default() }; - let sealer = ConditionalSealer::with_sealers( + let sealer = SequencerSealer::with_sealers( config, vec![Box::new(GasCriterion), Box::new(SlotsCriterion)], ); @@ -357,7 +311,7 @@ async fn batch_sealed_before_miniblock_does() { transaction_slots: 2, ..StateKeeperConfig::default() }; - let sealer = ConditionalSealer::with_sealers(config, vec![Box::new(SlotsCriterion)]); + let sealer = SequencerSealer::with_sealers(config, vec![Box::new(SlotsCriterion)]); // Miniblock sealer will not return true before the batch is sealed because the batch only has 2 txs. TestScenario::new() @@ -382,7 +336,7 @@ async fn rejected_tx() { transaction_slots: 2, ..StateKeeperConfig::default() }; - let sealer = ConditionalSealer::with_sealers(config, vec![Box::new(SlotsCriterion)]); + let sealer = SequencerSealer::with_sealers(config, vec![Box::new(SlotsCriterion)]); let rejected_tx = random_tx(1); TestScenario::new() @@ -404,7 +358,7 @@ async fn bootloader_tip_out_of_gas_flow() { transaction_slots: 2, ..StateKeeperConfig::default() }; - let sealer = ConditionalSealer::with_sealers(config, vec![Box::new(SlotsCriterion)]); + let sealer = SequencerSealer::with_sealers(config, vec![Box::new(SlotsCriterion)]); let first_tx = random_tx(1); let bootloader_out_of_gas_tx = random_tx(2); @@ -442,7 +396,7 @@ async fn pending_batch_is_applied() { transaction_slots: 3, ..StateKeeperConfig::default() }; - let sealer = ConditionalSealer::with_sealers(config, vec![Box::new(SlotsCriterion)]); + let sealer = SequencerSealer::with_sealers(config, vec![Box::new(SlotsCriterion)]); let pending_batch = pending_batch_data(vec![ MiniblockExecutionData { @@ -500,7 +454,7 @@ async fn unconditional_sealing() { transaction_slots: 2, ..StateKeeperConfig::default() }; - let sealer = ConditionalSealer::with_sealers(config, vec![Box::new(SlotsCriterion)]); + let sealer = SequencerSealer::with_sealers(config, vec![Box::new(SlotsCriterion)]); TestScenario::new() .seal_l1_batch_when(move |_| batch_seal_trigger_checker.load(Ordering::Relaxed)) @@ -530,7 +484,7 @@ async fn miniblock_timestamp_after_pending_batch() { transaction_slots: 2, ..StateKeeperConfig::default() }; - let sealer = ConditionalSealer::with_sealers(config, vec![Box::new(SlotsCriterion)]); + let sealer = SequencerSealer::with_sealers(config, vec![Box::new(SlotsCriterion)]); let pending_batch = pending_batch_data(vec![MiniblockExecutionData { number: MiniblockNumber(1), @@ -574,7 +528,7 @@ async fn time_is_monotonic() { transaction_slots: 2, ..StateKeeperConfig::default() }; - let sealer = ConditionalSealer::with_sealers(config, vec![Box::new(SlotsCriterion)]); + let sealer = SequencerSealer::with_sealers(config, vec![Box::new(SlotsCriterion)]); TestScenario::new() .seal_miniblock_when(|updates| updates.miniblock.executed_transactions.len() == 1) @@ -625,7 +579,7 @@ async fn protocol_upgrade() { transaction_slots: 2, ..StateKeeperConfig::default() }; - let sealer = ConditionalSealer::with_sealers(config, vec![Box::new(SlotsCriterion)]); + let sealer = SequencerSealer::with_sealers(config, vec![Box::new(SlotsCriterion)]); TestScenario::new() .seal_miniblock_when(|updates| updates.miniblock.executed_transactions.len() == 1) diff --git a/core/lib/zksync_core/src/state_keeper/tests/tester.rs b/core/lib/zksync_core/src/state_keeper/tests/tester.rs index 2c26370a22a9..ca65b1653260 100644 --- a/core/lib/zksync_core/src/state_keeper/tests/tester.rs +++ b/core/lib/zksync_core/src/state_keeper/tests/tester.rs @@ -15,21 +15,22 @@ use multivm::{ }; use tokio::sync::{mpsc, watch}; use zksync_types::{ - block::MiniblockExecutionData, protocol_version::ProtocolUpgradeTx, + block::MiniblockExecutionData, fee_model::BatchFeeInput, protocol_version::ProtocolUpgradeTx, witness_block_state::WitnessBlockState, Address, L1BatchNumber, L2ChainId, MiniblockNumber, ProtocolVersionId, Transaction, H256, }; -use crate::state_keeper::{ - batch_executor::{BatchExecutorHandle, Command, L1BatchExecutorBuilder, TxExecutionResult}, - io::{MiniblockParams, PendingBatchData, StateKeeperIO}, - seal_criteria::{ConditionalSealer, IoSealCriteria}, - tests::{ - create_l2_transaction, default_l1_batch_env, default_vm_block_result, BASE_SYSTEM_CONTRACTS, +use crate::{ + state_keeper::{ + batch_executor::{BatchExecutorHandle, Command, L1BatchExecutorBuilder, TxExecutionResult}, + io::{MiniblockParams, PendingBatchData, StateKeeperIO}, + seal_criteria::{IoSealCriteria, SequencerSealer}, + tests::{default_l1_batch_env, default_vm_block_result, BASE_SYSTEM_CONTRACTS}, + types::ExecutionMetricsForCriteria, + updates::UpdatesManager, + ZkSyncStateKeeper, }, - types::ExecutionMetricsForCriteria, - updates::UpdatesManager, - ZkSyncStateKeeper, + utils::testonly::create_l2_transaction, }; const FEE_ACCOUNT: Address = Address::repeat_byte(0x11); @@ -189,7 +190,7 @@ impl TestScenario { /// Launches the test. /// Provided `SealManager` is expected to be externally configured to adhere the written scenario logic. - pub(crate) async fn run(self, sealer: ConditionalSealer) { + pub(crate) async fn run(self, sealer: SequencerSealer) { assert!(!self.actions.is_empty(), "Test scenario can't be empty"); let batch_executor_base = TestBatchExecutorBuilder::new(&self); @@ -199,7 +200,7 @@ impl TestScenario { stop_receiver, Box::new(io), Box::new(batch_executor_base), - sealer, + Box::new(sealer), ); let sk_thread = tokio::spawn(sk.run()); @@ -241,14 +242,14 @@ pub(crate) fn successful_exec() -> TxExecutionResult { statistics: Default::default(), refunds: Default::default(), }), - tx_metrics: ExecutionMetricsForCriteria { + tx_metrics: Box::new(ExecutionMetricsForCriteria { l1_gas: Default::default(), execution_metrics: Default::default(), - }, - bootloader_dry_run_metrics: ExecutionMetricsForCriteria { + }), + bootloader_dry_run_metrics: Box::new(ExecutionMetricsForCriteria { l1_gas: Default::default(), execution_metrics: Default::default(), - }, + }), bootloader_dry_run_result: Box::new(VmExecutionResultAndLogs { result: ExecutionResult::Success { output: vec![] }, logs: Default::default(), @@ -271,11 +272,11 @@ pub(crate) fn successful_exec_with_metrics( statistics: Default::default(), refunds: Default::default(), }), - tx_metrics, - bootloader_dry_run_metrics: ExecutionMetricsForCriteria { + tx_metrics: Box::new(tx_metrics), + bootloader_dry_run_metrics: Box::new(ExecutionMetricsForCriteria { l1_gas: Default::default(), execution_metrics: Default::default(), - }, + }), bootloader_dry_run_result: Box::new(VmExecutionResultAndLogs { result: ExecutionResult::Success { output: vec![] }, logs: Default::default(), @@ -451,7 +452,8 @@ impl L1BatchExecutorBuilder for TestBatchExecutorBuilder { &mut self, _l1batch_params: L1BatchEnv, _system_env: SystemEnv, - ) -> BatchExecutorHandle { + _stop_receiver: &watch::Receiver, + ) -> Option { let (commands_sender, commands_receiver) = mpsc::channel(1); let executor = TestBatchExecutor::new( @@ -461,7 +463,7 @@ impl L1BatchExecutorBuilder for TestBatchExecutorBuilder { ); let handle = tokio::task::spawn_blocking(move || executor.run()); - BatchExecutorHandle::from_raw(handle, commands_sender) + Some(BatchExecutorHandle::from_raw(handle, commands_sender)) } } @@ -542,8 +544,7 @@ pub(crate) struct TestIO { stop_sender: watch::Sender, batch_number: L1BatchNumber, timestamp: u64, - l1_gas_price: u64, - fair_l2_gas_price: u64, + fee_input: BatchFeeInput, miniblock_number: MiniblockNumber, fee_account: Address, scenario: TestScenario, @@ -560,8 +561,7 @@ impl TestIO { stop_sender, batch_number: L1BatchNumber(1), timestamp: 1, - l1_gas_price: 1, - fair_l2_gas_price: 1, + fee_input: BatchFeeInput::default(), miniblock_number: MiniblockNumber(1), fee_account: FEE_ACCOUNT, scenario, @@ -650,8 +650,7 @@ impl StateKeeperIO for TestIO { previous_batch_hash: Some(H256::zero()), number: self.batch_number, timestamp: self.timestamp, - l1_gas_price: self.l1_gas_price, - fair_l2_gas_price: self.fair_l2_gas_price, + fee_input: self.fee_input, fee_account: self.fee_account, enforced_base_fee: None, first_l2_block: first_miniblock_info, @@ -771,8 +770,8 @@ impl StateKeeperIO for TestIO { } } -/// `L1BatchExecutorBuilder` which doesn't check anything at all. -/// Accepts all transactions. +/// `L1BatchExecutorBuilder` which doesn't check anything at all. Accepts all transactions. +// FIXME: move to `utils`? #[derive(Debug)] pub(crate) struct MockBatchExecutorBuilder; @@ -782,8 +781,9 @@ impl L1BatchExecutorBuilder for MockBatchExecutorBuilder { &mut self, _l1batch_params: L1BatchEnv, _system_env: SystemEnv, - ) -> BatchExecutorHandle { - let (send, recv) = tokio::sync::mpsc::channel(1); + _stop_receiver: &watch::Receiver, + ) -> Option { + let (send, recv) = mpsc::channel(1); let handle = tokio::task::spawn(async { let mut recv = recv; while let Some(cmd) = recv.recv().await { @@ -799,6 +799,6 @@ impl L1BatchExecutorBuilder for MockBatchExecutorBuilder { } } }); - BatchExecutorHandle::from_raw(handle, send) + Some(BatchExecutorHandle::from_raw(handle, send)) } } diff --git a/core/lib/zksync_core/src/state_keeper/types.rs b/core/lib/zksync_core/src/state_keeper/types.rs index 5e74cc1b4dee..2dbce8dd2076 100644 --- a/core/lib/zksync_core/src/state_keeper/types.rs +++ b/core/lib/zksync_core/src/state_keeper/types.rs @@ -3,12 +3,14 @@ use std::{ sync::{Arc, Mutex}, }; +use multivm::interface::VmExecutionResultAndLogs; use zksync_mempool::{L2TxFilter, MempoolInfo, MempoolStore}; use zksync_types::{ block::BlockGasCount, tx::ExecutionMetrics, Address, Nonce, PriorityOpId, Transaction, }; use super::metrics::StateKeeperGauges; +use crate::gas_tracker::{gas_count_from_metrics, gas_count_from_tx_and_metrics}; #[derive(Debug, Clone)] pub struct MempoolGuard(Arc>); @@ -64,3 +66,21 @@ pub struct ExecutionMetricsForCriteria { pub l1_gas: BlockGasCount, pub execution_metrics: ExecutionMetrics, } + +impl ExecutionMetricsForCriteria { + pub fn new( + tx: Option<&Transaction>, + execution_result: &VmExecutionResultAndLogs, + ) -> ExecutionMetricsForCriteria { + let execution_metrics = execution_result.get_execution_metrics(tx); + let l1_gas = match tx { + Some(tx) => gas_count_from_tx_and_metrics(tx, &execution_metrics), + None => gas_count_from_metrics(&execution_metrics), + }; + + ExecutionMetricsForCriteria { + l1_gas, + execution_metrics, + } + } +} diff --git a/core/lib/zksync_core/src/state_keeper/updates/miniblock_updates.rs b/core/lib/zksync_core/src/state_keeper/updates/miniblock_updates.rs index 5d001fd76892..4dd561e72aa7 100644 --- a/core/lib/zksync_core/src/state_keeper/updates/miniblock_updates.rs +++ b/core/lib/zksync_core/src/state_keeper/updates/miniblock_updates.rs @@ -59,13 +59,21 @@ impl MiniblockUpdates { } } - pub(crate) fn extend_from_fictive_transaction(&mut self, result: VmExecutionResultAndLogs) { + pub(crate) fn extend_from_fictive_transaction( + &mut self, + result: VmExecutionResultAndLogs, + l1_gas_count: BlockGasCount, + execution_metrics: ExecutionMetrics, + ) { self.events.extend(result.logs.events); self.storage_logs.extend(result.logs.storage_logs); self.user_l2_to_l1_logs .extend(result.logs.user_l2_to_l1_logs); self.system_l2_to_l1_logs .extend(result.logs.system_l2_to_l1_logs); + + self.l1_gas_count += l1_gas_count; + self.block_execution_metrics += execution_metrics; } pub(crate) fn extend_from_executed_transaction( diff --git a/core/lib/zksync_core/src/state_keeper/updates/mod.rs b/core/lib/zksync_core/src/state_keeper/updates/mod.rs index ad5e9e432d43..faee5a5fbffd 100644 --- a/core/lib/zksync_core/src/state_keeper/updates/mod.rs +++ b/core/lib/zksync_core/src/state_keeper/updates/mod.rs @@ -1,8 +1,11 @@ -use multivm::interface::{L1BatchEnv, VmExecutionResultAndLogs}; +use multivm::{ + interface::{L1BatchEnv, VmExecutionResultAndLogs}, + utils::get_batch_base_fee, +}; use zksync_contracts::BaseSystemContractsHashes; -use zksync_dal::blocks_dal::ConsensusBlockFields; use zksync_types::{ - block::BlockGasCount, storage_writes_deduplicator::StorageWritesDeduplicator, + block::BlockGasCount, fee_model::BatchFeeInput, + storage_writes_deduplicator::StorageWritesDeduplicator, tx::tx_execution_info::ExecutionMetrics, vm_trace::Call, Address, L1BatchNumber, MiniblockNumber, ProtocolVersionId, Transaction, }; @@ -23,8 +26,8 @@ pub mod miniblock_updates; #[derive(Debug, Clone, PartialEq)] pub struct UpdatesManager { batch_timestamp: u64, - l1_gas_price: u64, - fair_l2_gas_price: u64, + fee_account_address: Address, + batch_fee_input: BatchFeeInput, base_fee_per_gas: u64, base_system_contract_hashes: BaseSystemContractsHashes, protocol_version: ProtocolVersionId, @@ -41,9 +44,9 @@ impl UpdatesManager { ) -> Self { Self { batch_timestamp: l1_batch_env.timestamp, - l1_gas_price: l1_batch_env.l1_gas_price, - fair_l2_gas_price: l1_batch_env.fair_l2_gas_price, - base_fee_per_gas: l1_batch_env.base_fee(), + fee_account_address: l1_batch_env.fee_account, + batch_fee_input: l1_batch_env.fee_input, + base_fee_per_gas: get_batch_base_fee(&l1_batch_env, protocol_version.into()), protocol_version, base_system_contract_hashes, l1_batch: L1BatchUpdates::new(), @@ -66,20 +69,11 @@ impl UpdatesManager { self.base_system_contract_hashes } - pub(crate) fn l1_gas_price(&self) -> u64 { - self.l1_gas_price - } - - pub(crate) fn fair_l2_gas_price(&self) -> u64 { - self.fair_l2_gas_price - } - pub(crate) fn seal_miniblock_command( &self, l1_batch_number: L1BatchNumber, miniblock_number: MiniblockNumber, l2_erc20_bridge_addr: Address, - consensus: Option, pre_insert_txs: bool, ) -> MiniblockSealCommand { MiniblockSealCommand { @@ -87,13 +81,12 @@ impl UpdatesManager { miniblock_number, miniblock: self.miniblock.clone(), first_tx_index: self.l1_batch.executed_transactions.len(), - l1_gas_price: self.l1_gas_price, - fair_l2_gas_price: self.fair_l2_gas_price, + fee_account_address: self.fee_account_address, + fee_input: self.batch_fee_input, base_fee_per_gas: self.base_fee_per_gas, base_system_contracts_hashes: self.base_system_contract_hashes, protocol_version: Some(self.protocol_version), l2_erc20_bridge_addr, - consensus, pre_insert_txs, } } @@ -123,10 +116,16 @@ impl UpdatesManager { ); } - pub(crate) fn extend_from_fictive_transaction(&mut self, result: VmExecutionResultAndLogs) { + pub(crate) fn extend_from_fictive_transaction( + &mut self, + result: VmExecutionResultAndLogs, + l1_gas_count: BlockGasCount, + execution_metrics: ExecutionMetrics, + ) { self.storage_writes_deduplicator .apply(&result.logs.storage_logs); - self.miniblock.extend_from_fictive_transaction(result); + self.miniblock + .extend_from_fictive_transaction(result, l1_gas_count, execution_metrics); } /// Pushes a new miniblock with the specified timestamp into this manager. The previously @@ -168,13 +167,12 @@ pub(crate) struct MiniblockSealCommand { pub miniblock_number: MiniblockNumber, pub miniblock: MiniblockUpdates, pub first_tx_index: usize, - pub l1_gas_price: u64, - pub fair_l2_gas_price: u64, + pub fee_account_address: Address, + pub fee_input: BatchFeeInput, pub base_fee_per_gas: u64, pub base_system_contracts_hashes: BaseSystemContractsHashes, pub protocol_version: Option, pub l2_erc20_bridge_addr: Address, - pub consensus: Option, /// Whether transactions should be pre-inserted to DB. /// Should be set to `true` for EN's IO as EN doesn't store transactions in DB /// before they are included into miniblocks. diff --git a/core/lib/zksync_core/src/sync_layer/batch_status_updater.rs b/core/lib/zksync_core/src/sync_layer/batch_status_updater.rs deleted file mode 100644 index 8924fa5c5db5..000000000000 --- a/core/lib/zksync_core/src/sync_layer/batch_status_updater.rs +++ /dev/null @@ -1,365 +0,0 @@ -use std::time::Duration; - -use chrono::{DateTime, Utc}; -use tokio::sync::watch::Receiver; -use zksync_dal::ConnectionPool; -use zksync_types::{ - aggregated_operations::AggregatedActionType, api::BlockDetails, L1BatchNumber, MiniblockNumber, - H256, -}; -use zksync_web3_decl::{ - jsonrpsee::http_client::{HttpClient, HttpClientBuilder}, - namespaces::ZksNamespaceClient, - RpcResult, -}; - -use super::metrics::{FetchStage, L1BatchStage, FETCHER_METRICS}; -use crate::metrics::EN_METRICS; - -/// Represents a change in the batch status. -/// It may be a batch being committed, proven or executed. -#[derive(Debug)] -pub(crate) struct BatchStatusChange { - pub(crate) number: L1BatchNumber, - pub(crate) l1_tx_hash: H256, - pub(crate) happened_at: DateTime, -} - -#[derive(Debug, Default)] -struct StatusChanges { - commit: Vec, - prove: Vec, - execute: Vec, -} - -impl StatusChanges { - fn new() -> Self { - Self::default() - } - - /// Returns true if there are no status changes. - fn is_empty(&self) -> bool { - self.commit.is_empty() && self.prove.is_empty() && self.execute.is_empty() - } -} - -/// Module responsible for fetching the batch status changes, i.e. one that monitors whether the -/// locally applied batch was committed, proven or executed on L1. -/// -/// In essence, it keeps track of the last batch number per status, and periodically polls the main -/// node on these batches in order to see whether the status has changed. If some changes were picked up, -/// the module updates the database to mirror the state observable from the main node. -#[derive(Debug)] -pub struct BatchStatusUpdater { - client: HttpClient, - pool: ConnectionPool, - - last_executed_l1_batch: L1BatchNumber, - last_proven_l1_batch: L1BatchNumber, - last_committed_l1_batch: L1BatchNumber, -} - -impl BatchStatusUpdater { - pub async fn new(main_node_url: &str, pool: ConnectionPool) -> Self { - let client = HttpClientBuilder::default() - .build(main_node_url) - .expect("Unable to create a main node client"); - - let mut storage = pool.access_storage_tagged("sync_layer").await.unwrap(); - let last_executed_l1_batch = storage - .blocks_dal() - .get_number_of_last_l1_batch_executed_on_eth() - .await - .unwrap() - .unwrap_or_default(); - let last_proven_l1_batch = storage - .blocks_dal() - .get_number_of_last_l1_batch_proven_on_eth() - .await - .unwrap() - .unwrap_or_default(); - let last_committed_l1_batch = storage - .blocks_dal() - .get_number_of_last_l1_batch_committed_on_eth() - .await - .unwrap() - .unwrap_or_default(); - drop(storage); - - Self { - client, - pool, - - last_committed_l1_batch, - last_proven_l1_batch, - last_executed_l1_batch, - } - } - - pub async fn run(mut self, stop_receiver: Receiver) -> anyhow::Result<()> { - loop { - if *stop_receiver.borrow() { - tracing::info!("Stop signal received, exiting the batch status updater routine"); - return Ok(()); - } - // Status changes are created externally, so that even if we will receive a network error - // while requesting the changes, we will be able to process what we already fetched. - let mut status_changes = StatusChanges::new(); - if let Err(err) = self.get_status_changes(&mut status_changes).await { - tracing::warn!("Failed to get status changes from the database: {err}"); - }; - - if status_changes.is_empty() { - const DELAY_INTERVAL: Duration = Duration::from_secs(5); - tokio::time::sleep(DELAY_INTERVAL).await; - continue; - } - - self.apply_status_changes(status_changes).await; - } - } - - /// Goes through the already fetched batches trying to update their statuses. - /// Returns a collection of the status updates grouped by the operation type. - /// - /// Fetched changes are capped by the last locally applied batch number, so - /// it's safe to assume that every status change can safely be applied (no status - /// changes "from the future"). - async fn get_status_changes(&self, status_changes: &mut StatusChanges) -> RpcResult<()> { - let total_latency = EN_METRICS.update_batch_statuses.start(); - let last_sealed_batch = self - .pool - .access_storage_tagged("sync_layer") - .await - .unwrap() - .blocks_dal() - .get_newest_l1_batch_header() - .await - .unwrap() - .number; - - let mut last_committed_l1_batch = self.last_committed_l1_batch; - let mut last_proven_l1_batch = self.last_proven_l1_batch; - let mut last_executed_l1_batch = self.last_executed_l1_batch; - - let mut batch = last_executed_l1_batch.next(); - // In this loop we try to progress on the batch statuses, utilizing the same request to the node to potentially - // update all three statuses (e.g. if the node is still syncing), but also skipping the gaps in the statuses - // (e.g. if the last executed batch is 10, but the last proven is 20, we don't need to check the batches 11-19). - while batch <= last_sealed_batch { - // While we may receive `None` for the `self.current_l1_batch`, it's OK: open batch is guaranteed to not - // be sent to L1. - let request_latency = FETCHER_METRICS.requests[&FetchStage::GetMiniblockRange].start(); - let Some((start_miniblock, _)) = self.client.get_miniblock_range(batch).await? else { - return Ok(()); - }; - request_latency.observe(); - - // We could've used any miniblock from the range, all of them share the same info. - let request_latency = FETCHER_METRICS.requests[&FetchStage::GetBlockDetails].start(); - let Some(batch_info) = self - .client - .get_block_details(MiniblockNumber(start_miniblock.as_u32())) - .await? - else { - // We cannot recover from an external API inconsistency. - panic!( - "Node API is inconsistent: miniblock {} was reported to be a part of {} L1 batch, \ - but API has no information about this miniblock", start_miniblock, batch - ); - }; - request_latency.observe(); - - Self::update_committed_batch(status_changes, &batch_info, &mut last_committed_l1_batch); - Self::update_proven_batch(status_changes, &batch_info, &mut last_proven_l1_batch); - Self::update_executed_batch(status_changes, &batch_info, &mut last_executed_l1_batch); - - // Check whether we can skip a part of the range. - if batch_info.base.commit_tx_hash.is_none() { - // No committed batches after this one. - break; - } else if batch_info.base.prove_tx_hash.is_none() && batch < last_committed_l1_batch { - // The interval between this batch and the last committed one is not proven. - batch = last_committed_l1_batch.next(); - } else if batch_info.base.executed_at.is_none() && batch < last_proven_l1_batch { - // The interval between this batch and the last proven one is not executed. - batch = last_proven_l1_batch.next(); - } else { - batch += 1; - } - } - - total_latency.observe(); - Ok(()) - } - - fn update_committed_batch( - status_changes: &mut StatusChanges, - batch_info: &BlockDetails, - last_committed_l1_batch: &mut L1BatchNumber, - ) { - if batch_info.base.commit_tx_hash.is_some() - && batch_info.l1_batch_number == last_committed_l1_batch.next() - { - assert!( - batch_info.base.committed_at.is_some(), - "Malformed API response: batch is committed, but has no commit timestamp" - ); - status_changes.commit.push(BatchStatusChange { - number: batch_info.l1_batch_number, - l1_tx_hash: batch_info.base.commit_tx_hash.unwrap(), - happened_at: batch_info.base.committed_at.unwrap(), - }); - tracing::info!("Batch {}: committed", batch_info.l1_batch_number); - FETCHER_METRICS.l1_batch[&L1BatchStage::Committed] - .set(batch_info.l1_batch_number.0.into()); - *last_committed_l1_batch += 1; - } - } - - fn update_proven_batch( - status_changes: &mut StatusChanges, - batch_info: &BlockDetails, - last_proven_l1_batch: &mut L1BatchNumber, - ) { - if batch_info.base.prove_tx_hash.is_some() - && batch_info.l1_batch_number == last_proven_l1_batch.next() - { - assert!( - batch_info.base.proven_at.is_some(), - "Malformed API response: batch is proven, but has no prove timestamp" - ); - status_changes.prove.push(BatchStatusChange { - number: batch_info.l1_batch_number, - l1_tx_hash: batch_info.base.prove_tx_hash.unwrap(), - happened_at: batch_info.base.proven_at.unwrap(), - }); - tracing::info!("Batch {}: proven", batch_info.l1_batch_number); - FETCHER_METRICS.l1_batch[&L1BatchStage::Proven] - .set(batch_info.l1_batch_number.0.into()); - *last_proven_l1_batch += 1; - } - } - - fn update_executed_batch( - status_changes: &mut StatusChanges, - batch_info: &BlockDetails, - last_executed_l1_batch: &mut L1BatchNumber, - ) { - if batch_info.base.execute_tx_hash.is_some() - && batch_info.l1_batch_number == last_executed_l1_batch.next() - { - assert!( - batch_info.base.executed_at.is_some(), - "Malformed API response: batch is executed, but has no execute timestamp" - ); - status_changes.execute.push(BatchStatusChange { - number: batch_info.l1_batch_number, - l1_tx_hash: batch_info.base.execute_tx_hash.unwrap(), - happened_at: batch_info.base.executed_at.unwrap(), - }); - tracing::info!("Batch {}: executed", batch_info.l1_batch_number); - FETCHER_METRICS.l1_batch[&L1BatchStage::Executed] - .set(batch_info.l1_batch_number.0.into()); - *last_executed_l1_batch += 1; - } - } - - /// Inserts the provided status changes into the database. - /// The status changes are applied to the database by inserting bogus confirmed transactions (with - /// some fields missing/substituted) only to satisfy API needs; this component doesn't expect the updated - /// tables to be ever accessed by the `eth_sender` module. - async fn apply_status_changes(&mut self, changes: StatusChanges) { - let total_latency = EN_METRICS.batch_status_updater_loop_iteration.start(); - let mut connection = self.pool.access_storage_tagged("sync_layer").await.unwrap(); - - let mut transaction = connection.start_transaction().await.unwrap(); - - let last_sealed_batch = transaction - .blocks_dal() - .get_newest_l1_batch_header() - .await - .unwrap() - .number; - - for change in changes.commit.into_iter() { - tracing::info!( - "Commit status change: number {}, hash {}, happened at {}", - change.number, - change.l1_tx_hash, - change.happened_at - ); - - assert!( - change.number <= last_sealed_batch, - "Incorrect update state: unknown batch marked as committed" - ); - - transaction - .eth_sender_dal() - .insert_bogus_confirmed_eth_tx( - change.number, - AggregatedActionType::Commit, - change.l1_tx_hash, - change.happened_at, - ) - .await - .unwrap(); - self.last_committed_l1_batch = change.number; - } - for change in changes.prove.into_iter() { - tracing::info!( - "Prove status change: number {}, hash {}, happened at {}", - change.number, - change.l1_tx_hash, - change.happened_at - ); - - assert!( - change.number <= self.last_committed_l1_batch, - "Incorrect update state: proven batch must be committed" - ); - - transaction - .eth_sender_dal() - .insert_bogus_confirmed_eth_tx( - change.number, - AggregatedActionType::PublishProofOnchain, - change.l1_tx_hash, - change.happened_at, - ) - .await - .unwrap(); - self.last_proven_l1_batch = change.number; - } - for change in changes.execute.into_iter() { - tracing::info!( - "Execute status change: number {}, hash {}, happened at {}", - change.number, - change.l1_tx_hash, - change.happened_at - ); - - assert!( - change.number <= self.last_proven_l1_batch, - "Incorrect update state: executed batch must be proven" - ); - - transaction - .eth_sender_dal() - .insert_bogus_confirmed_eth_tx( - change.number, - AggregatedActionType::Execute, - change.l1_tx_hash, - change.happened_at, - ) - .await - .unwrap(); - self.last_executed_l1_batch = change.number; - } - - transaction.commit().await.unwrap(); - - total_latency.observe(); - } -} diff --git a/core/lib/zksync_core/src/sync_layer/batch_status_updater/mod.rs b/core/lib/zksync_core/src/sync_layer/batch_status_updater/mod.rs new file mode 100644 index 000000000000..4a670349723c --- /dev/null +++ b/core/lib/zksync_core/src/sync_layer/batch_status_updater/mod.rs @@ -0,0 +1,470 @@ +//! Component responsible for updating L1 batch status. + +use std::{fmt, time::Duration}; + +use anyhow::Context as _; +use async_trait::async_trait; +use chrono::{DateTime, Utc}; +#[cfg(test)] +use tokio::sync::mpsc; +use tokio::sync::watch; +use zksync_dal::{ConnectionPool, StorageProcessor}; +use zksync_types::{ + aggregated_operations::AggregatedActionType, api, L1BatchNumber, MiniblockNumber, H256, +}; +use zksync_web3_decl::{ + jsonrpsee::{ + core::ClientError, + http_client::{HttpClient, HttpClientBuilder}, + }, + namespaces::ZksNamespaceClient, +}; + +use super::metrics::{FetchStage, FETCHER_METRICS}; +use crate::{metrics::EN_METRICS, utils::projected_first_l1_batch}; + +#[cfg(test)] +mod tests; + +fn l1_batch_stage_to_action_str(stage: AggregatedActionType) -> &'static str { + match stage { + AggregatedActionType::Commit => "committed", + AggregatedActionType::PublishProofOnchain => "proven", + AggregatedActionType::Execute => "executed", + } +} + +/// Represents a change in the batch status. +/// It may be a batch being committed, proven or executed. +#[derive(Debug)] +struct BatchStatusChange { + number: L1BatchNumber, + l1_tx_hash: H256, + happened_at: DateTime, +} + +#[derive(Debug, Default)] +struct StatusChanges { + commit: Vec, + prove: Vec, + execute: Vec, +} + +impl StatusChanges { + /// Returns true if there are no status changes. + fn is_empty(&self) -> bool { + self.commit.is_empty() && self.prove.is_empty() && self.execute.is_empty() + } +} + +#[derive(Debug, thiserror::Error)] +enum UpdaterError { + #[error("JSON-RPC error communicating with main node")] + Web3(#[from] ClientError), + #[error("Internal error")] + Internal(#[from] anyhow::Error), +} + +impl From for UpdaterError { + fn from(err: zksync_dal::SqlxError) -> Self { + Self::Internal(err.into()) + } +} + +#[async_trait] +trait MainNodeClient: fmt::Debug + Send + Sync { + /// Returns any miniblock in the specified L1 batch. + async fn resolve_l1_batch_to_miniblock( + &self, + number: L1BatchNumber, + ) -> Result, ClientError>; + + async fn block_details( + &self, + number: MiniblockNumber, + ) -> Result, ClientError>; +} + +#[async_trait] +impl MainNodeClient for HttpClient { + async fn resolve_l1_batch_to_miniblock( + &self, + number: L1BatchNumber, + ) -> Result, ClientError> { + let request_latency = FETCHER_METRICS.requests[&FetchStage::GetMiniblockRange].start(); + let number = self + .get_miniblock_range(number) + .await? + .map(|(start, _)| MiniblockNumber(start.as_u32())); + request_latency.observe(); + Ok(number) + } + + async fn block_details( + &self, + number: MiniblockNumber, + ) -> Result, ClientError> { + let request_latency = FETCHER_METRICS.requests[&FetchStage::GetBlockDetails].start(); + let details = self.get_block_details(number).await?; + request_latency.observe(); + Ok(details) + } +} + +/// Cursors for the last executed / proven / committed L1 batch numbers. +#[derive(Debug, Clone, Copy, PartialEq)] +struct UpdaterCursor { + last_executed_l1_batch: L1BatchNumber, + last_proven_l1_batch: L1BatchNumber, + last_committed_l1_batch: L1BatchNumber, +} + +impl UpdaterCursor { + async fn new(storage: &mut StorageProcessor<'_>) -> anyhow::Result { + let first_l1_batch_number = projected_first_l1_batch(storage).await?; + // Use the snapshot L1 batch, or the genesis batch if we are not using a snapshot. Technically, the snapshot L1 batch + // is not necessarily proven / executed yet, but since it and earlier batches are not stored, it serves + // a natural lower boundary for the cursor. + let starting_l1_batch_number = L1BatchNumber(first_l1_batch_number.saturating_sub(1)); + + let last_executed_l1_batch = storage + .blocks_dal() + .get_number_of_last_l1_batch_executed_on_eth() + .await? + .unwrap_or(starting_l1_batch_number); + let last_proven_l1_batch = storage + .blocks_dal() + .get_number_of_last_l1_batch_proven_on_eth() + .await? + .unwrap_or(starting_l1_batch_number); + let last_committed_l1_batch = storage + .blocks_dal() + .get_number_of_last_l1_batch_committed_on_eth() + .await? + .unwrap_or(starting_l1_batch_number); + Ok(Self { + last_executed_l1_batch, + last_proven_l1_batch, + last_committed_l1_batch, + }) + } + + fn extract_tx_hash_and_timestamp( + batch_info: &api::BlockDetails, + stage: AggregatedActionType, + ) -> (Option, Option>) { + match stage { + AggregatedActionType::Commit => { + (batch_info.base.commit_tx_hash, batch_info.base.committed_at) + } + AggregatedActionType::PublishProofOnchain => { + (batch_info.base.prove_tx_hash, batch_info.base.proven_at) + } + AggregatedActionType::Execute => { + (batch_info.base.execute_tx_hash, batch_info.base.executed_at) + } + } + } + + fn update( + &mut self, + status_changes: &mut StatusChanges, + batch_info: &api::BlockDetails, + ) -> anyhow::Result<()> { + for stage in [ + AggregatedActionType::Commit, + AggregatedActionType::PublishProofOnchain, + AggregatedActionType::Execute, + ] { + self.update_stage(status_changes, batch_info, stage)?; + } + Ok(()) + } + + fn update_stage( + &mut self, + status_changes: &mut StatusChanges, + batch_info: &api::BlockDetails, + stage: AggregatedActionType, + ) -> anyhow::Result<()> { + let (l1_tx_hash, happened_at) = Self::extract_tx_hash_and_timestamp(batch_info, stage); + let (last_l1_batch, changes_to_update) = match stage { + AggregatedActionType::Commit => ( + &mut self.last_committed_l1_batch, + &mut status_changes.commit, + ), + AggregatedActionType::PublishProofOnchain => { + (&mut self.last_proven_l1_batch, &mut status_changes.prove) + } + AggregatedActionType::Execute => ( + &mut self.last_executed_l1_batch, + &mut status_changes.execute, + ), + }; + + // Check whether we have all data for the update. + let Some(l1_tx_hash) = l1_tx_hash else { + return Ok(()); + }; + if batch_info.l1_batch_number != last_l1_batch.next() { + return Ok(()); + } + + let action_str = l1_batch_stage_to_action_str(stage); + let happened_at = happened_at.with_context(|| { + format!("Malformed API response: batch is {action_str}, but has no relevant timestamp") + })?; + changes_to_update.push(BatchStatusChange { + number: batch_info.l1_batch_number, + l1_tx_hash, + happened_at, + }); + tracing::info!("Batch {}: {action_str}", batch_info.l1_batch_number); + FETCHER_METRICS.l1_batch[&stage.into()].set(batch_info.l1_batch_number.0.into()); + *last_l1_batch += 1; + Ok(()) + } +} + +/// Component responsible for fetching the batch status changes, i.e. one that monitors whether the +/// locally applied batch was committed, proven or executed on L1. +/// +/// In essence, it keeps track of the last batch number per status, and periodically polls the main +/// node on these batches in order to see whether the status has changed. If some changes were picked up, +/// the module updates the database to mirror the state observable from the main node. This is required for other components +/// (e.g., the API server and the consistency checker) to function properly. E.g., the API server returns commit / prove / execute +/// L1 transaction information in `zks_getBlockDetails` and `zks_getL1BatchDetails` RPC methods. +#[derive(Debug)] +pub struct BatchStatusUpdater { + client: Box, + pool: ConnectionPool, + sleep_interval: Duration, + /// Test-only sender of status changes each time they are produced and applied to the storage. + #[cfg(test)] + changes_sender: mpsc::UnboundedSender, +} + +impl BatchStatusUpdater { + const DEFAULT_SLEEP_INTERVAL: Duration = Duration::from_secs(5); + + pub fn new(main_node_url: &str, pool: ConnectionPool) -> anyhow::Result { + let client = HttpClientBuilder::default() + .build(main_node_url) + .context("Unable to create a main node client")?; + Ok(Self::from_parts( + Box::new(client), + pool, + Self::DEFAULT_SLEEP_INTERVAL, + )) + } + + fn from_parts( + client: Box, + pool: ConnectionPool, + sleep_interval: Duration, + ) -> Self { + Self { + client, + pool, + sleep_interval, + #[cfg(test)] + changes_sender: mpsc::unbounded_channel().0, + } + } + + pub async fn run(self, stop_receiver: watch::Receiver) -> anyhow::Result<()> { + let mut storage = self.pool.access_storage_tagged("sync_layer").await?; + let mut cursor = UpdaterCursor::new(&mut storage).await?; + drop(storage); + tracing::info!("Initialized batch status updater cursor: {cursor:?}"); + + loop { + if *stop_receiver.borrow() { + tracing::info!("Stop signal received, exiting the batch status updater routine"); + return Ok(()); + } + + // Status changes are created externally, so that even if we will receive a network error + // while requesting the changes, we will be able to process what we already fetched. + let mut status_changes = StatusChanges::default(); + // Note that we don't update `cursor` here (it is copied), but rather only in `apply_status_changes`. + match self.get_status_changes(&mut status_changes, cursor).await { + Ok(()) => { /* everything went smoothly */ } + Err(UpdaterError::Web3(err)) => { + tracing::warn!("Failed to get status changes from the main node: {err}"); + } + Err(UpdaterError::Internal(err)) => return Err(err), + } + + if status_changes.is_empty() { + tokio::time::sleep(self.sleep_interval).await; + } else { + self.apply_status_changes(&mut cursor, status_changes) + .await?; + } + } + } + + /// Goes through the already fetched batches trying to update their statuses. + /// + /// Fetched changes are capped by the last locally applied batch number, so + /// it's safe to assume that every status change can safely be applied (no status + /// changes "from the future"). + async fn get_status_changes( + &self, + status_changes: &mut StatusChanges, + mut cursor: UpdaterCursor, + ) -> Result<(), UpdaterError> { + let total_latency = EN_METRICS.update_batch_statuses.start(); + let Some(last_sealed_batch) = self + .pool + .access_storage_tagged("sync_layer") + .await? + .blocks_dal() + .get_sealed_l1_batch_number() + .await? + else { + return Ok(()); // No L1 batches in the storage yet; do nothing. + }; + + let mut batch = cursor.last_executed_l1_batch.next(); + // In this loop we try to progress on the batch statuses, utilizing the same request to the node to potentially + // update all three statuses (e.g. if the node is still syncing), but also skipping the gaps in the statuses + // (e.g. if the last executed batch is 10, but the last proven is 20, we don't need to check the batches 11-19). + while batch <= last_sealed_batch { + // While we may receive `None` for the `self.current_l1_batch`, it's OK: open batch is guaranteed to not + // be sent to L1. + let miniblock_number = self.client.resolve_l1_batch_to_miniblock(batch).await?; + let Some(miniblock_number) = miniblock_number else { + return Ok(()); + }; + + let Some(batch_info) = self.client.block_details(miniblock_number).await? else { + // We cannot recover from an external API inconsistency. + let err = anyhow::anyhow!( + "Node API is inconsistent: miniblock {miniblock_number} was reported to be a part of {batch} L1 batch, \ + but API has no information about this miniblock", + ); + return Err(err.into()); + }; + + cursor.update(status_changes, &batch_info)?; + + // Check whether we can skip a part of the range. + if batch_info.base.commit_tx_hash.is_none() { + // No committed batches after this one. + break; + } else if batch_info.base.prove_tx_hash.is_none() + && batch < cursor.last_committed_l1_batch + { + // The interval between this batch and the last committed one is not proven. + batch = cursor.last_committed_l1_batch.next(); + } else if batch_info.base.executed_at.is_none() && batch < cursor.last_proven_l1_batch { + // The interval between this batch and the last proven one is not executed. + batch = cursor.last_proven_l1_batch.next(); + } else { + batch += 1; + } + } + + total_latency.observe(); + Ok(()) + } + + /// Inserts the provided status changes into the database. + /// The status changes are applied to the database by inserting bogus confirmed transactions (with + /// some fields missing/substituted) only to satisfy API needs; this component doesn't expect the updated + /// tables to be ever accessed by the `eth_sender` module. + async fn apply_status_changes( + &self, + cursor: &mut UpdaterCursor, + changes: StatusChanges, + ) -> anyhow::Result<()> { + let total_latency = EN_METRICS.batch_status_updater_loop_iteration.start(); + let mut connection = self.pool.access_storage_tagged("sync_layer").await?; + let mut transaction = connection.start_transaction().await?; + let last_sealed_batch = transaction + .blocks_dal() + .get_sealed_l1_batch_number() + .await? + .context("L1 batches disappeared from Postgres")?; + + for change in &changes.commit { + tracing::info!( + "Commit status change: number {}, hash {}, happened at {}", + change.number, + change.l1_tx_hash, + change.happened_at + ); + anyhow::ensure!( + change.number <= last_sealed_batch, + "Incorrect update state: unknown batch marked as committed" + ); + + transaction + .eth_sender_dal() + .insert_bogus_confirmed_eth_tx( + change.number, + AggregatedActionType::Commit, + change.l1_tx_hash, + change.happened_at, + ) + .await?; + cursor.last_committed_l1_batch = change.number; + } + + for change in &changes.prove { + tracing::info!( + "Prove status change: number {}, hash {}, happened at {}", + change.number, + change.l1_tx_hash, + change.happened_at + ); + anyhow::ensure!( + change.number <= cursor.last_committed_l1_batch, + "Incorrect update state: proven batch must be committed" + ); + + transaction + .eth_sender_dal() + .insert_bogus_confirmed_eth_tx( + change.number, + AggregatedActionType::PublishProofOnchain, + change.l1_tx_hash, + change.happened_at, + ) + .await?; + cursor.last_proven_l1_batch = change.number; + } + + for change in &changes.execute { + tracing::info!( + "Execute status change: number {}, hash {}, happened at {}", + change.number, + change.l1_tx_hash, + change.happened_at + ); + anyhow::ensure!( + change.number <= cursor.last_proven_l1_batch, + "Incorrect update state: executed batch must be proven" + ); + + transaction + .eth_sender_dal() + .insert_bogus_confirmed_eth_tx( + change.number, + AggregatedActionType::Execute, + change.l1_tx_hash, + change.happened_at, + ) + .await?; + cursor.last_executed_l1_batch = change.number; + } + transaction.commit().await?; + total_latency.observe(); + + #[cfg(test)] + self.changes_sender.send(changes).ok(); + Ok(()) + } +} diff --git a/core/lib/zksync_core/src/sync_layer/batch_status_updater/tests.rs b/core/lib/zksync_core/src/sync_layer/batch_status_updater/tests.rs new file mode 100644 index 000000000000..f18f316a9688 --- /dev/null +++ b/core/lib/zksync_core/src/sync_layer/batch_status_updater/tests.rs @@ -0,0 +1,442 @@ +//! Tests for batch status updater. + +use std::{future, sync::Arc}; + +use chrono::TimeZone; +use test_casing::{test_casing, Product}; +use tokio::sync::{watch, Mutex}; +use zksync_contracts::BaseSystemContractsHashes; +use zksync_types::{Address, L2ChainId, ProtocolVersionId}; + +use super::*; +use crate::{ + genesis::{ensure_genesis_state, GenesisParams}, + sync_layer::metrics::L1BatchStage, + utils::testonly::{create_l1_batch, create_miniblock, prepare_empty_recovery_snapshot}, +}; + +async fn seal_l1_batch(storage: &mut StorageProcessor<'_>, number: L1BatchNumber) { + let mut storage = storage.start_transaction().await.unwrap(); + // Insert a mock miniblock so that `get_block_details()` will return values. + let miniblock = create_miniblock(number.0); + storage + .blocks_dal() + .insert_miniblock(&miniblock) + .await + .unwrap(); + + let l1_batch = create_l1_batch(number.0); + storage + .blocks_dal() + .insert_mock_l1_batch(&l1_batch) + .await + .unwrap(); + storage + .blocks_dal() + .mark_miniblocks_as_executed_in_l1_batch(number) + .await + .unwrap(); + storage.commit().await.unwrap(); +} + +/// Mapping `L1BatchNumber` -> `L1BatchStage` for a continuous range of numbers. +#[derive(Debug, Clone, Default, PartialEq)] +struct L1BatchStagesMap { + first_batch_number: L1BatchNumber, + stages: Vec, +} + +impl L1BatchStagesMap { + fn empty(first_batch_number: L1BatchNumber, len: usize) -> Self { + Self { + first_batch_number, + stages: vec![L1BatchStage::Open; len], + } + } + + fn new(first_batch_number: L1BatchNumber, stages: Vec) -> Self { + assert!(stages.windows(2).all(|window| { + let [prev, next] = window else { unreachable!() }; + prev >= next + })); + Self { + first_batch_number, + stages, + } + } + + fn get(&self, number: L1BatchNumber) -> Option { + let Some(index) = number.0.checked_sub(self.first_batch_number.0) else { + return None; + }; + self.stages.get(index as usize).copied() + } + + fn iter(&self) -> impl Iterator + '_ { + self.stages + .iter() + .enumerate() + .map(|(i, &stage)| (self.first_batch_number + i as u32, stage)) + } + + fn update(&mut self, changes: &StatusChanges) { + self.update_to_stage(&changes.commit, L1BatchStage::Committed); + self.update_to_stage(&changes.prove, L1BatchStage::Proven); + self.update_to_stage(&changes.execute, L1BatchStage::Executed); + } + + fn update_to_stage(&mut self, batch_changes: &[BatchStatusChange], target: L1BatchStage) { + for change in batch_changes { + let number = change.number; + let index = number + .0 + .checked_sub(self.first_batch_number.0) + .unwrap_or_else(|| panic!("stage is missing for L1 batch #{number}")); + let stage = self + .stages + .get_mut(index as usize) + .unwrap_or_else(|| panic!("stage is missing for L1 batch #{number}")); + assert!( + *stage < target, + "Invalid update for L1 batch #{number}: {stage:?} -> {target:?}" + ); + *stage = target; + } + } + + async fn assert_storage(&self, storage: &mut StorageProcessor<'_>) { + for (number, stage) in self.iter() { + let local_details = storage + .blocks_web3_dal() + .get_block_details(MiniblockNumber(number.0)) + .await + .unwrap() + .unwrap_or_else(|| panic!("no details for block #{number}")); + let expected_details = mock_block_details(number.0, stage); + + assert_eq!( + local_details.base.commit_tx_hash, + expected_details.base.commit_tx_hash + ); + assert_eq!( + local_details.base.committed_at, + expected_details.base.committed_at + ); + assert_eq!( + local_details.base.prove_tx_hash, + expected_details.base.prove_tx_hash + ); + assert_eq!( + local_details.base.proven_at, + expected_details.base.proven_at + ); + assert_eq!( + local_details.base.execute_tx_hash, + expected_details.base.execute_tx_hash + ); + assert_eq!( + local_details.base.executed_at, + expected_details.base.executed_at + ); + } + } +} + +fn mock_block_details(number: u32, stage: L1BatchStage) -> api::BlockDetails { + api::BlockDetails { + number: MiniblockNumber(number), + l1_batch_number: L1BatchNumber(number), + base: api::BlockDetailsBase { + timestamp: number.into(), + l1_tx_count: 0, + l2_tx_count: 0, + root_hash: Some(H256::zero()), + status: api::BlockStatus::Sealed, + commit_tx_hash: (stage >= L1BatchStage::Committed).then(|| H256::repeat_byte(1)), + committed_at: (stage >= L1BatchStage::Committed) + .then(|| Utc.timestamp_opt(100, 0).unwrap()), + prove_tx_hash: (stage >= L1BatchStage::Proven).then(|| H256::repeat_byte(2)), + proven_at: (stage >= L1BatchStage::Proven).then(|| Utc.timestamp_opt(200, 0).unwrap()), + execute_tx_hash: (stage >= L1BatchStage::Executed).then(|| H256::repeat_byte(3)), + executed_at: (stage >= L1BatchStage::Executed) + .then(|| Utc.timestamp_opt(300, 0).unwrap()), + l1_gas_price: 1, + l2_fair_gas_price: 2, + base_system_contracts_hashes: BaseSystemContractsHashes::default(), + }, + operator_address: Address::zero(), + protocol_version: Some(ProtocolVersionId::default()), + } +} + +#[derive(Debug, Default)] +struct MockMainNodeClient(Arc>); + +impl From for MockMainNodeClient { + fn from(map: L1BatchStagesMap) -> Self { + Self(Arc::new(Mutex::new(map))) + } +} + +#[async_trait] +impl MainNodeClient for MockMainNodeClient { + async fn resolve_l1_batch_to_miniblock( + &self, + number: L1BatchNumber, + ) -> Result, ClientError> { + let map = self.0.lock().await; + Ok(map + .get(number) + .is_some() + .then_some(MiniblockNumber(number.0))) + } + + async fn block_details( + &self, + number: MiniblockNumber, + ) -> Result, ClientError> { + let map = self.0.lock().await; + let Some(stage) = map.get(L1BatchNumber(number.0)) else { + return Ok(None); + }; + Ok(Some(mock_block_details(number.0, stage))) + } +} + +fn mock_change(number: L1BatchNumber) -> BatchStatusChange { + BatchStatusChange { + number, + l1_tx_hash: H256::zero(), + happened_at: DateTime::default(), + } +} + +fn mock_updater( + client: MockMainNodeClient, + pool: ConnectionPool, +) -> (BatchStatusUpdater, mpsc::UnboundedReceiver) { + let (changes_sender, changes_receiver) = mpsc::unbounded_channel(); + let mut updater = + BatchStatusUpdater::from_parts(Box::new(client), pool, Duration::from_millis(10)); + updater.changes_sender = changes_sender; + (updater, changes_receiver) +} + +#[tokio::test] +async fn updater_cursor_for_storage_with_genesis_block() { + let pool = ConnectionPool::test_pool().await; + let mut storage = pool.access_storage().await.unwrap(); + ensure_genesis_state(&mut storage, L2ChainId::default(), &GenesisParams::mock()) + .await + .unwrap(); + for number in [1, 2] { + seal_l1_batch(&mut storage, L1BatchNumber(number)).await; + } + + let mut cursor = UpdaterCursor::new(&mut storage).await.unwrap(); + assert_eq!(cursor.last_committed_l1_batch, L1BatchNumber(0)); + assert_eq!(cursor.last_proven_l1_batch, L1BatchNumber(0)); + assert_eq!(cursor.last_executed_l1_batch, L1BatchNumber(0)); + + let (updater, _) = mock_updater(MockMainNodeClient::default(), pool.clone()); + let changes = StatusChanges { + commit: vec![mock_change(L1BatchNumber(1)), mock_change(L1BatchNumber(2))], + prove: vec![mock_change(L1BatchNumber(1))], + execute: vec![], + }; + updater + .apply_status_changes(&mut cursor, changes) + .await + .unwrap(); + + assert_eq!(cursor.last_committed_l1_batch, L1BatchNumber(2)); + assert_eq!(cursor.last_proven_l1_batch, L1BatchNumber(1)); + assert_eq!(cursor.last_executed_l1_batch, L1BatchNumber(0)); + + let restored_cursor = UpdaterCursor::new(&mut storage).await.unwrap(); + assert_eq!(restored_cursor, cursor); +} + +#[tokio::test] +async fn updater_cursor_after_snapshot_recovery() { + let pool = ConnectionPool::test_pool().await; + let mut storage = pool.access_storage().await.unwrap(); + prepare_empty_recovery_snapshot(&mut storage, 23).await; + + let cursor = UpdaterCursor::new(&mut storage).await.unwrap(); + assert_eq!(cursor.last_committed_l1_batch, L1BatchNumber(23)); + assert_eq!(cursor.last_proven_l1_batch, L1BatchNumber(23)); + assert_eq!(cursor.last_executed_l1_batch, L1BatchNumber(23)); +} + +#[test_casing(4, Product(([false, true], [false, true])))] +#[tokio::test] +async fn normal_updater_operation(snapshot_recovery: bool, async_batches: bool) { + let pool = ConnectionPool::test_pool().await; + let mut storage = pool.access_storage().await.unwrap(); + let first_batch_number = if snapshot_recovery { + prepare_empty_recovery_snapshot(&mut storage, 23).await; + L1BatchNumber(24) + } else { + ensure_genesis_state(&mut storage, L2ChainId::default(), &GenesisParams::mock()) + .await + .unwrap(); + L1BatchNumber(1) + }; + + let target_batch_stages = L1BatchStagesMap::new( + first_batch_number, + vec![ + L1BatchStage::Executed, + L1BatchStage::Proven, + L1BatchStage::Proven, + L1BatchStage::Committed, + L1BatchStage::Committed, + L1BatchStage::Open, + ], + ); + let batch_numbers: Vec<_> = target_batch_stages + .iter() + .map(|(number, _)| number) + .collect(); + + if !async_batches { + // Make all L1 batches present in the storage from the start. + for &number in &batch_numbers { + seal_l1_batch(&mut storage, number).await; + } + } + + let client = MockMainNodeClient::from(target_batch_stages.clone()); + let (updater, mut changes_receiver) = mock_updater(client, pool.clone()); + let (stop_sender, stop_receiver) = watch::channel(false); + let updater_task = tokio::spawn(updater.run(stop_receiver)); + + let batches_task = if async_batches { + let pool = pool.clone(); + tokio::spawn(async move { + let mut storage = pool.access_storage().await.unwrap(); + for &number in &batch_numbers { + seal_l1_batch(&mut storage, number).await; + tokio::time::sleep(Duration::from_millis(15)).await; + } + }) + } else { + tokio::spawn(future::ready(())) + }; + + let mut observed_batch_stages = + L1BatchStagesMap::empty(first_batch_number, target_batch_stages.stages.len()); + loop { + let changes = changes_receiver.recv().await.unwrap(); + observed_batch_stages.update(&changes); + if observed_batch_stages == target_batch_stages { + break; + } + } + + batches_task.await.unwrap(); + target_batch_stages.assert_storage(&mut storage).await; + stop_sender.send_replace(true); + updater_task.await.unwrap().expect("updater failed"); +} + +#[test_casing(2, [false, true])] +#[tokio::test] +async fn updater_with_gradual_main_node_updates(snapshot_recovery: bool) { + let pool = ConnectionPool::test_pool().await; + let mut storage = pool.access_storage().await.unwrap(); + let first_batch_number = if snapshot_recovery { + prepare_empty_recovery_snapshot(&mut storage, 23).await; + L1BatchNumber(24) + } else { + ensure_genesis_state(&mut storage, L2ChainId::default(), &GenesisParams::mock()) + .await + .unwrap(); + L1BatchNumber(1) + }; + + let target_batch_stages = L1BatchStagesMap::new( + first_batch_number, + vec![ + L1BatchStage::Executed, + L1BatchStage::Proven, + L1BatchStage::Proven, + L1BatchStage::Committed, + L1BatchStage::Committed, + L1BatchStage::Open, + ], + ); + let mut observed_batch_stages = + L1BatchStagesMap::empty(first_batch_number, target_batch_stages.stages.len()); + + for (number, _) in target_batch_stages.iter() { + seal_l1_batch(&mut storage, number).await; + } + + let client = MockMainNodeClient::from(observed_batch_stages.clone()); + + // Gradually update information provided by the main node. + let client_map = Arc::clone(&client.0); + let final_stages = target_batch_stages.clone(); + let storage_task = tokio::spawn(async move { + for max_stage in [ + L1BatchStage::Committed, + L1BatchStage::Proven, + L1BatchStage::Executed, + ] { + let mut client_map = client_map.lock().await; + for (stage, &final_stage) in client_map.stages.iter_mut().zip(&final_stages.stages) { + *stage = final_stage.min(max_stage); + } + drop(client_map); + tokio::time::sleep(Duration::from_millis(15)).await; + } + }); + + let (updater, mut changes_receiver) = mock_updater(client, pool.clone()); + let (stop_sender, stop_receiver) = watch::channel(false); + let updater_task = tokio::spawn(updater.run(stop_receiver)); + + loop { + let changes = changes_receiver.recv().await.unwrap(); + observed_batch_stages.update(&changes); + if observed_batch_stages == target_batch_stages { + break; + } + } + + storage_task.await.unwrap(); + target_batch_stages.assert_storage(&mut storage).await; + stop_sender.send_replace(true); + updater_task.await.unwrap().expect("updater failed"); + + drop(storage); + test_resuming_updater(pool, target_batch_stages).await; +} + +async fn test_resuming_updater(pool: ConnectionPool, initial_batch_stages: L1BatchStagesMap) { + let target_batch_stages = L1BatchStagesMap::new( + initial_batch_stages.first_batch_number, + vec![L1BatchStage::Executed; 6], + ); + + let client = MockMainNodeClient::from(target_batch_stages.clone()); + let (updater, mut changes_receiver) = mock_updater(client, pool.clone()); + let (stop_sender, stop_receiver) = watch::channel(false); + let updater_task = tokio::spawn(updater.run(stop_receiver)); + + let mut observed_batch_stages = initial_batch_stages; + loop { + let changes = changes_receiver.recv().await.unwrap(); + observed_batch_stages.update(&changes); + if observed_batch_stages == target_batch_stages { + break; + } + } + + let mut storage = pool.access_storage().await.unwrap(); + target_batch_stages.assert_storage(&mut storage).await; + stop_sender.send_replace(true); + updater_task.await.unwrap().expect("updater failed"); +} diff --git a/core/lib/zksync_core/src/sync_layer/external_io.rs b/core/lib/zksync_core/src/sync_layer/external_io.rs index d751cdc8d014..c800e83703f8 100644 --- a/core/lib/zksync_core/src/sync_layer/external_io.rs +++ b/core/lib/zksync_core/src/sync_layer/external_io.rs @@ -3,11 +3,13 @@ use std::{collections::HashMap, convert::TryInto, iter::FromIterator, time::Dura use async_trait::async_trait; use futures::future; use multivm::interface::{FinishedL1Batch, L1BatchEnv, SystemEnv}; +use vm_utils::storage::wait_for_prev_l1_batch_params; use zksync_contracts::{BaseSystemContracts, SystemContractCode}; use zksync_dal::ConnectionPool; use zksync_types::{ - ethabi::Address, protocol_version::ProtocolUpgradeTx, witness_block_state::WitnessBlockState, - L1BatchNumber, L2ChainId, MiniblockNumber, ProtocolVersionId, Transaction, H256, U256, + ethabi::Address, fee_model::BatchFeeInput, protocol_version::ProtocolUpgradeTx, + witness_block_state::WitnessBlockState, L1BatchNumber, L2ChainId, MiniblockNumber, + ProtocolVersionId, Transaction, H256, U256, }; use zksync_utils::{be_words_to_bytes, bytes_to_be_words}; @@ -19,10 +21,10 @@ use super::{ use crate::{ metrics::{BlockStage, APP_METRICS}, state_keeper::{ - extractors, io::{ common::{l1_batch_params, load_pending_batch, poll_iters}, - MiniblockParams, MiniblockSealerHandle, PendingBatchData, StateKeeperIO, + fee_address_migration, MiniblockParams, MiniblockSealerHandle, PendingBatchData, + StateKeeperIO, }, metrics::KEEPER_METRICS, seal_criteria::IoSealCriteria, @@ -70,21 +72,27 @@ impl ExternalIO { chain_id: L2ChainId, ) -> Self { let mut storage = pool.access_storage_tagged("sync_layer").await.unwrap(); - let last_sealed_l1_batch_header = storage + // TODO (PLA-703): Support no L1 batches / miniblocks in the storage + let last_sealed_l1_batch_number = storage .blocks_dal() - .get_newest_l1_batch_header() + .get_sealed_l1_batch_number() .await - .unwrap(); + .unwrap() + .expect("No L1 batches sealed"); let last_miniblock_number = storage .blocks_dal() .get_sealed_miniblock_number() .await - .unwrap(); + .unwrap() + .expect("empty storage not supported"); // FIXME (PLA-703): handle empty storage + // We must run the migration for pending miniblocks synchronously, since we use `fee_account_address` + // from a pending miniblock in `load_pending_batch()` implementation. + fee_address_migration::migrate_pending_miniblocks(&mut storage).await; drop(storage); tracing::info!( "Initialized the ExternalIO: current L1 batch number {}, current miniblock number {}", - last_sealed_l1_batch_header.number + 1, + last_sealed_l1_batch_number + 1, last_miniblock_number + 1, ); @@ -93,7 +101,7 @@ impl ExternalIO { Self { miniblock_sealer_handle, pool, - current_l1_batch_number: last_sealed_l1_batch_header.number + 1, + current_l1_batch_number: last_sealed_l1_batch_number + 1, current_miniblock_number: last_miniblock_number + 1, actions, sync_state, @@ -108,8 +116,7 @@ impl ExternalIO { let mut storage = self.pool.access_storage_tagged("sync_layer").await.unwrap(); let wait_latency = KEEPER_METRICS.wait_for_prev_hash_time.start(); let (hash, _) = - extractors::wait_for_prev_l1_batch_params(&mut storage, self.current_l1_batch_number) - .await; + wait_for_prev_l1_batch_params(&mut storage, self.current_l1_batch_number).await; wait_latency.observe(); hash } @@ -208,7 +215,8 @@ impl ExternalIO { self.current_miniblock_number, &HashMap::from_iter([(contract.hash, be_words_to_bytes(&contract.code))]), ) - .await; + .await + .unwrap(); contract } } @@ -224,10 +232,7 @@ impl IoSealCriteria for ExternalIO { } fn should_seal_miniblock(&mut self, _manager: &UpdatesManager) -> bool { - matches!( - self.actions.peek_action(), - Some(SyncAction::SealMiniblock(_)) - ) + matches!(self.actions.peek_action(), Some(SyncAction::SealMiniblock)) } } @@ -244,19 +249,6 @@ impl StateKeeperIO for ExternalIO { async fn load_pending_batch(&mut self) -> Option { let mut storage = self.pool.access_storage_tagged("sync_layer").await.unwrap(); - // TODO (BFT-99): Do not assume that fee account is the same as in previous batch. - let fee_account = storage - .blocks_dal() - .get_l1_batch_header(self.current_l1_batch_number - 1) - .await - .unwrap() - .unwrap_or_else(|| { - panic!( - "No block header for batch {}", - self.current_l1_batch_number - 1 - ) - }) - .fee_account_address; let pending_miniblock_number = { let (_, last_miniblock_number_included_in_l1_batch) = storage .blocks_dal() @@ -271,6 +263,7 @@ impl StateKeeperIO for ExternalIO { .get_miniblock_header(pending_miniblock_number) .await .unwrap()?; + let fee_account = pending_miniblock_header.fee_account_address; if pending_miniblock_header.protocol_version.is_none() { // Fetch protocol version ID for pending miniblocks to know which VM to use to re-execute them. @@ -313,6 +306,7 @@ impl StateKeeperIO for ExternalIO { timestamp, l1_gas_price, l2_fair_gas_price, + fair_pubdata_price, operator_address, protocol_version, first_miniblock_info: (miniblock_number, virtual_blocks), @@ -339,8 +333,12 @@ impl StateKeeperIO for ExternalIO { operator_address, timestamp, previous_l1_batch_hash, - l1_gas_price, - l2_fair_gas_price, + BatchFeeInput::for_protocol_version( + protocol_version, + l2_fair_gas_price, + fair_pubdata_price, + l1_gas_price, + ), miniblock_number, previous_miniblock_hash, base_system_contracts, @@ -452,7 +450,7 @@ impl StateKeeperIO for ExternalIO { async fn seal_miniblock(&mut self, updates_manager: &UpdatesManager) { let action = self.actions.pop_action(); - let Some(SyncAction::SealMiniblock(consensus)) = action else { + let Some(SyncAction::SealMiniblock) = action else { panic!("State keeper requested to seal miniblock, but the next action is {action:?}"); }; @@ -461,7 +459,6 @@ impl StateKeeperIO for ExternalIO { self.current_l1_batch_number, self.current_miniblock_number, self.l2_erc20_bridge_addr, - consensus, true, ); self.miniblock_sealer_handle.submit(command).await; @@ -481,7 +478,7 @@ impl StateKeeperIO for ExternalIO { finished_batch: FinishedL1Batch, ) -> anyhow::Result<()> { let action = self.actions.pop_action(); - let Some(SyncAction::SealBatch { consensus, .. }) = action else { + let Some(SyncAction::SealBatch { .. }) = action else { anyhow::bail!( "State keeper requested to seal the batch, but the next action is {action:?}" ); @@ -499,7 +496,6 @@ impl StateKeeperIO for ExternalIO { l1_batch_env, finished_batch, self.l2_erc20_bridge_addr, - consensus, ) .await; transaction.commit().await.unwrap(); diff --git a/core/lib/zksync_core/src/sync_layer/fetcher.rs b/core/lib/zksync_core/src/sync_layer/fetcher.rs index 17f205e87370..98e0a025ea80 100644 --- a/core/lib/zksync_core/src/sync_layer/fetcher.rs +++ b/core/lib/zksync_core/src/sync_layer/fetcher.rs @@ -2,7 +2,7 @@ use std::time::Duration; use anyhow::Context as _; use tokio::sync::watch; -use zksync_dal::{blocks_dal::ConsensusBlockFields, StorageProcessor}; +use zksync_dal::StorageProcessor; use zksync_types::{ api::en::SyncBlock, block::MiniblockHasher, Address, L1BatchNumber, MiniblockNumber, ProtocolVersionId, H256, @@ -22,7 +22,7 @@ const RETRY_DELAY_INTERVAL: Duration = Duration::from_secs(5); /// Common denominator for blocks fetched by an external node. #[derive(Debug)] -pub(super) struct FetchedBlock { +pub(crate) struct FetchedBlock { pub number: MiniblockNumber, pub l1_batch_number: L1BatchNumber, pub last_in_batch: bool, @@ -31,10 +31,10 @@ pub(super) struct FetchedBlock { pub reference_hash: Option, pub l1_gas_price: u64, pub l2_fair_gas_price: u64, + pub fair_pubdata_price: Option, pub virtual_blocks: u32, pub operator_address: Address, pub transactions: Vec, - pub consensus: Option, } impl FetchedBlock { @@ -60,17 +60,12 @@ impl TryFrom for FetchedBlock { reference_hash: block.hash, l1_gas_price: block.l1_gas_price, l2_fair_gas_price: block.l2_fair_gas_price, + fair_pubdata_price: block.fair_pubdata_price, virtual_blocks: block.virtual_blocks.unwrap_or(0), operator_address: block.operator_address, transactions: block .transactions .context("Transactions are always requested")?, - consensus: block - .consensus - .as_ref() - .map(ConsensusBlockFields::decode) - .transpose() - .context("ConsensusBlockFields::decode()")?, }) } } @@ -79,7 +74,7 @@ impl TryFrom for FetchedBlock { #[derive(Debug)] pub struct FetcherCursor { // Fields are public for testing purposes. - pub(super) next_miniblock: MiniblockNumber, + pub(crate) next_miniblock: MiniblockNumber, pub(super) prev_miniblock_hash: H256, pub(super) l1_batch: L1BatchNumber, } @@ -87,11 +82,13 @@ pub struct FetcherCursor { impl FetcherCursor { /// Loads the cursor from Postgres. pub async fn new(storage: &mut StorageProcessor<'_>) -> anyhow::Result { - let last_sealed_l1_batch_header = storage + // TODO (PLA-703): Support no L1 batches / miniblocks in the storage + let last_sealed_l1_batch_number = storage .blocks_dal() - .get_newest_l1_batch_header() + .get_sealed_l1_batch_number() .await - .context("Failed getting newest L1 batch header")?; + .context("Failed getting sealed L1 batch number")? + .context("No L1 batches sealed")?; let last_miniblock_header = storage .blocks_dal() .get_last_sealed_miniblock_header() @@ -113,10 +110,10 @@ impl FetcherCursor { // Decide whether the next batch should be explicitly opened or not. let l1_batch = if was_new_batch_open { // No `OpenBatch` action needed. - last_sealed_l1_batch_header.number + 1 + last_sealed_l1_batch_number + 1 } else { // We need to open the next batch. - last_sealed_l1_batch_header.number + last_sealed_l1_batch_number }; Ok(Self { @@ -126,7 +123,7 @@ impl FetcherCursor { }) } - pub(super) fn advance(&mut self, block: FetchedBlock) -> Vec { + pub(crate) fn advance(&mut self, block: FetchedBlock) -> Vec { assert_eq!(block.number, self.next_miniblock); let local_block_hash = block.compute_hash(self.prev_miniblock_hash); if let Some(reference_hash) = block.reference_hash { @@ -160,6 +157,7 @@ impl FetcherCursor { timestamp: block.timestamp, l1_gas_price: block.l1_gas_price, l2_fair_gas_price: block.l2_fair_gas_price, + fair_pubdata_price: block.fair_pubdata_price, operator_address: block.operator_address, protocol_version: block.protocol_version, // `block.virtual_blocks` can be `None` only for old VM versions where it's not used, so it's fine to provide any number. @@ -189,10 +187,9 @@ impl FetcherCursor { new_actions.push(SyncAction::SealBatch { // `block.virtual_blocks` can be `None` only for old VM versions where it's not used, so it's fine to provide any number. virtual_blocks: block.virtual_blocks, - consensus: block.consensus, }); } else { - new_actions.push(SyncAction::SealMiniblock(block.consensus)); + new_actions.push(SyncAction::SealMiniblock); } self.next_miniblock += 1; self.prev_miniblock_hash = local_block_hash; @@ -248,7 +245,7 @@ impl MainNodeFetcher { { tracing::warn!("Following transport error occurred: {err}"); tracing::info!("Trying again after a delay"); - tokio::time::sleep(RETRY_DELAY_INTERVAL).await; // TODO (BFT-100): Implement the fibonacci backoff. + tokio::time::sleep(RETRY_DELAY_INTERVAL).await; // TODO (BFT-100): Implement the Fibonacci back-off. } else { return Err(err.context("Unexpected error in the fetcher")); } diff --git a/core/lib/zksync_core/src/sync_layer/gossip/buffered/mod.rs b/core/lib/zksync_core/src/sync_layer/gossip/buffered/mod.rs deleted file mode 100644 index c4680cc3d7d2..000000000000 --- a/core/lib/zksync_core/src/sync_layer/gossip/buffered/mod.rs +++ /dev/null @@ -1,351 +0,0 @@ -//! Buffered [`BlockStore`] implementation. - -use std::{collections::BTreeMap, ops, time::Instant}; - -use async_trait::async_trait; -#[cfg(test)] -use zksync_concurrency::ctx::channel; -use zksync_concurrency::{ - ctx, scope, - sync::{self, watch, Mutex}, -}; -use zksync_consensus_roles::validator::{BlockNumber, FinalBlock, Payload}; -use zksync_consensus_storage::{BlockStore, WriteBlockStore}; - -use super::{ - metrics::{BlockResponseKind, METRICS}, - utils::MissingBlockNumbers, -}; - -#[cfg(test)] -mod tests; - -/// [`BlockStore`] variation that upholds additional invariants as to how blocks are processed. -/// -/// The invariants are as follows: -/// -/// - Stored blocks always have contiguous numbers; there are no gaps. -/// - Blocks can be scheduled to be added using [`Self::schedule_next_block()`] only. New blocks do not -/// appear in the store otherwise. -#[async_trait] -pub(super) trait ContiguousBlockStore: BlockStore { - /// Schedules a block to be added to the store. Unlike [`WriteBlockStore::put_block()`], - /// there is no expectation that the block is added to the store *immediately*. It's - /// expected that it will be added to the store eventually, which will be signaled via - /// a subscriber returned from [`BlockStore::subscribe_to_block_writes()`]. - /// - /// [`Buffered`] guarantees that this method will only ever be called: - /// - /// - with the next block (i.e., one immediately after [`BlockStore::head_block()`]) - /// - sequentially (i.e., multiple blocks cannot be scheduled at once) - async fn schedule_next_block(&self, ctx: &ctx::Ctx, block: &FinalBlock) -> ctx::Result<()>; -} - -/// In-memory buffer or [`FinalBlock`]s received from peers, but not executed and persisted locally yet. -/// -/// Unlike with executed / persisted blocks, there may be gaps between blocks in the buffer. -/// These blocks are shared with peers using the gossip network, but are not persisted and lost -/// on the node restart. -#[derive(Debug)] -struct BlockBuffer { - store_block_number: BlockNumber, - blocks: BTreeMap, -} - -impl BlockBuffer { - fn new(store_block_number: BlockNumber) -> Self { - Self { - store_block_number, - blocks: BTreeMap::new(), - } - } - - fn head_block(&self) -> Option { - self.blocks.values().next_back().cloned() - } - - #[tracing::instrument(level = "trace", skip(self))] - fn set_store_block(&mut self, store_block_number: BlockNumber) { - assert!( - store_block_number > self.store_block_number, - "`ContiguousBlockStore` invariant broken: unexpected new head block number" - ); - - self.store_block_number = store_block_number; - let old_len = self.blocks.len(); - self.blocks = self.blocks.split_off(&store_block_number.next()); - // ^ Removes all entries up to and including `store_block_number` - tracing::debug!("Removed {} blocks from buffer", old_len - self.blocks.len()); - METRICS.buffer_size.set(self.blocks.len()); - } - - fn last_contiguous_block_number(&self) -> BlockNumber { - // By design, blocks in the underlying store are always contiguous. - let mut last_number = self.store_block_number; - for &number in self.blocks.keys() { - if number > last_number.next() { - return last_number; - } - last_number = number; - } - last_number - } - - fn missing_block_numbers(&self, mut range: ops::Range) -> Vec { - // Clamp the range start so we don't produce extra missing blocks. - range.start = range.start.max(self.store_block_number.next()); - if range.is_empty() { - return vec![]; // Return early to not trigger panic in `BTreeMap::range()` - } - - let keys = self.blocks.range(range.clone()).map(|(&num, _)| num); - MissingBlockNumbers::new(range, keys).collect() - } - - fn put_block(&mut self, block: FinalBlock) { - let block_number = block.header.number; - assert!(block_number > self.store_block_number); - // ^ Must be checked previously - self.blocks.insert(block_number, block); - tracing::debug!(%block_number, "Inserted block in buffer"); - METRICS.buffer_size.set(self.blocks.len()); - } -} - -/// Events emitted by [`Buffered`] storage. -#[cfg(test)] -#[derive(Debug)] -pub(super) enum BufferedStorageEvent { - /// Update was received from the underlying storage. - UpdateReceived(BlockNumber), -} - -/// [`BlockStore`] with an in-memory buffer for pending blocks. -/// -/// # Data flow -/// -/// The store is plugged into the `SyncBlocks` actor, so that it can receive new blocks -/// from peers over the gossip network and to share blocks with peers. Received blocks are stored -/// in a [`BlockBuffer`]. The `SyncBlocks` actor doesn't guarantee that blocks are received in order, -/// so we have a background task that waits for successive blocks and feeds them to -/// the underlying storage ([`ContiguousBlockStore`]). The underlying storage executes and persists -/// blocks using the state keeper; see [`PostgresBlockStorage`](super::PostgresBlockStorage) for more details. -/// This logic is largely shared with the old syncing logic using JSON-RPC; the only differing part -/// is producing block data. -/// -/// Once a block is processed and persisted by the state keeper, it can be removed from the [`BlockBuffer`]; -/// we do this in another background task. Removing blocks from the buffer ensures that it doesn't -/// grow infinitely; it also allows to track syncing progress via metrics. -#[derive(Debug)] -pub(super) struct Buffered { - inner: T, - inner_subscriber: watch::Receiver, - block_writes_sender: watch::Sender, - buffer: Mutex, - #[cfg(test)] - events_sender: channel::UnboundedSender, -} - -impl Buffered { - /// Creates a new buffered storage. The buffer is initially empty. - pub fn new(store: T) -> Self { - let inner_subscriber = store.subscribe_to_block_writes(); - let store_block_number = *inner_subscriber.borrow(); - tracing::debug!( - store_block_number = store_block_number.0, - "Initialized buffer storage" - ); - Self { - inner: store, - inner_subscriber, - block_writes_sender: watch::channel(store_block_number).0, - buffer: Mutex::new(BlockBuffer::new(store_block_number)), - #[cfg(test)] - events_sender: channel::unbounded().0, - } - } - - #[cfg(test)] - fn set_events_sender(&mut self, sender: channel::UnboundedSender) { - self.events_sender = sender; - } - - pub(super) fn inner(&self) -> &T { - &self.inner - } - - #[cfg(test)] - async fn buffer_len(&self) -> usize { - self.buffer.lock().await.blocks.len() - } - - /// Listens to the updates in the underlying storage. - #[tracing::instrument(level = "trace", skip_all)] - async fn listen_to_updates(&self, ctx: &ctx::Ctx) { - let mut subscriber = self.inner_subscriber.clone(); - loop { - let store_block_number = { - let Ok(number) = sync::changed(ctx, &mut subscriber).await else { - return; // Do not propagate cancellation errors - }; - *number - }; - tracing::debug!( - store_block_number = store_block_number.0, - "Underlying block number updated" - ); - - let Ok(mut buffer) = sync::lock(ctx, &self.buffer).await else { - return; // Do not propagate cancellation errors - }; - buffer.set_store_block(store_block_number); - #[cfg(test)] - self.events_sender - .send(BufferedStorageEvent::UpdateReceived(store_block_number)); - } - } - - /// Schedules blocks in the underlying store as they are pushed to this store. - #[tracing::instrument(level = "trace", skip_all, err)] - async fn schedule_blocks(&self, ctx: &ctx::Ctx) -> ctx::Result<()> { - let mut blocks_subscriber = self.block_writes_sender.subscribe(); - - let mut next_scheduled_block_number = { - let Ok(buffer) = sync::lock(ctx, &self.buffer).await else { - return Ok(()); // Do not propagate cancellation errors - }; - buffer.store_block_number.next() - }; - loop { - loop { - let block = match self.buffered_block(ctx, next_scheduled_block_number).await { - Err(ctx::Canceled) => return Ok(()), // Do not propagate cancellation errors - Ok(None) => break, - Ok(Some(block)) => block, - }; - self.inner.schedule_next_block(ctx, &block).await?; - next_scheduled_block_number = next_scheduled_block_number.next(); - } - // Wait until some more blocks are pushed into the buffer. - let Ok(number) = sync::changed(ctx, &mut blocks_subscriber).await else { - return Ok(()); // Do not propagate cancellation errors - }; - tracing::debug!(block_number = number.0, "Received new block"); - } - } - - async fn buffered_block( - &self, - ctx: &ctx::Ctx, - number: BlockNumber, - ) -> ctx::OrCanceled> { - Ok(sync::lock(ctx, &self.buffer) - .await? - .blocks - .get(&number) - .cloned()) - } - - /// Runs background tasks for this store. This method **must** be spawned as a background task - /// which should be running as long at the [`Buffered`] is in use; otherwise, it will function incorrectly. - pub async fn run_background_tasks(&self, ctx: &ctx::Ctx) -> ctx::Result<()> { - scope::run!(ctx, |ctx, s| { - s.spawn(async { - self.listen_to_updates(ctx).await; - Ok(()) - }); - self.schedule_blocks(ctx) - }) - .await - } -} - -#[async_trait] -impl BlockStore for Buffered { - async fn head_block(&self, ctx: &ctx::Ctx) -> ctx::Result { - let buffered_head_block = sync::lock(ctx, &self.buffer).await?.head_block(); - if let Some(block) = buffered_head_block { - return Ok(block); - } - self.inner.head_block(ctx).await - } - - async fn first_block(&self, ctx: &ctx::Ctx) -> ctx::Result { - // First block is always situated in the underlying store - self.inner.first_block(ctx).await - } - - async fn last_contiguous_block_number(&self, ctx: &ctx::Ctx) -> ctx::Result { - Ok(sync::lock(ctx, &self.buffer) - .await? - .last_contiguous_block_number()) - } - - async fn block(&self, ctx: &ctx::Ctx, number: BlockNumber) -> ctx::Result> { - let started_at = Instant::now(); - { - let buffer = sync::lock(ctx, &self.buffer).await?; - if number > buffer.store_block_number { - let block = buffer.blocks.get(&number).cloned(); - METRICS.get_block_latency[&BlockResponseKind::InMemory] - .observe(started_at.elapsed()); - return Ok(block); - } - } - let block = self.inner.block(ctx, number).await?; - METRICS.get_block_latency[&BlockResponseKind::Persisted].observe(started_at.elapsed()); - Ok(block) - } - - async fn missing_block_numbers( - &self, - ctx: &ctx::Ctx, - range: ops::Range, - ) -> ctx::Result> { - // By design, the underlying store has no missing blocks. - Ok(sync::lock(ctx, &self.buffer) - .await? - .missing_block_numbers(range)) - } - - fn subscribe_to_block_writes(&self) -> watch::Receiver { - self.block_writes_sender.subscribe() - } -} - -#[async_trait] -impl WriteBlockStore for Buffered { - /// Verify that `payload` is a correct proposal for the block `block_number`. - async fn verify_payload( - &self, - _ctx: &ctx::Ctx, - _block_number: BlockNumber, - _payload: &Payload, - ) -> ctx::Result<()> { - // This is storage for non-validator nodes (aka full nodes), - // so verify_payload() won't be called. - // Still, it probably would be better to either - // * move verify_payload() to BlockStore, so that Buffered can just forward the call - // * create another separate trait for verify_payload. - // It will be clear what needs to be done when we implement multi-validator consensus for - // zksync-era. - unimplemented!() - } - - async fn put_block(&self, ctx: &ctx::Ctx, block: &FinalBlock) -> ctx::Result<()> { - let buffer_block_latency = METRICS.buffer_block_latency.start(); - { - let mut buffer = sync::lock(ctx, &self.buffer).await?; - let block_number = block.header.number; - if block_number <= buffer.store_block_number { - return Err(anyhow::anyhow!( - "Cannot replace a block #{block_number} since it is already present in the underlying storage", - ).into()); - } - buffer.put_block(block.clone()); - } - self.block_writes_sender.send_replace(block.header.number); - buffer_block_latency.observe(); - Ok(()) - } -} diff --git a/core/lib/zksync_core/src/sync_layer/gossip/buffered/tests.rs b/core/lib/zksync_core/src/sync_layer/gossip/buffered/tests.rs deleted file mode 100644 index acf15416ab26..000000000000 --- a/core/lib/zksync_core/src/sync_layer/gossip/buffered/tests.rs +++ /dev/null @@ -1,284 +0,0 @@ -//! Tests for buffered storage. - -use std::{iter, ops}; - -use assert_matches::assert_matches; -use async_trait::async_trait; -use rand::{rngs::StdRng, seq::SliceRandom, Rng}; -use test_casing::test_casing; -use zksync_concurrency::{ - ctx::{self, channel}, - scope, - sync::{self, watch}, - testonly::abort_on_panic, - time, -}; -use zksync_consensus_roles::validator::{BlockHeader, BlockNumber, FinalBlock, Payload}; -use zksync_consensus_storage::{BlockStore, InMemoryStorage, WriteBlockStore}; - -use super::*; - -fn init_store(rng: &mut impl Rng) -> (FinalBlock, InMemoryStorage) { - let payload = Payload(vec![]); - let genesis_block = FinalBlock { - header: BlockHeader::genesis(payload.hash(), BlockNumber(0)), - payload, - justification: rng.gen(), - }; - let block_store = InMemoryStorage::new(genesis_block.clone()); - (genesis_block, block_store) -} - -fn gen_blocks(rng: &mut impl Rng, genesis_block: FinalBlock, count: usize) -> Vec { - let blocks = iter::successors(Some(genesis_block), |parent| { - let payload = Payload(vec![]); - let header = BlockHeader { - parent: parent.header.hash(), - number: parent.header.number.next(), - payload: payload.hash(), - }; - Some(FinalBlock { - header, - payload, - justification: rng.gen(), - }) - }); - blocks.skip(1).take(count).collect() -} - -#[derive(Debug)] -struct MockContiguousStore { - inner: InMemoryStorage, - block_sender: channel::UnboundedSender, -} - -impl MockContiguousStore { - fn new(inner: InMemoryStorage) -> (Self, channel::UnboundedReceiver) { - let (block_sender, block_receiver) = channel::unbounded(); - let this = Self { - inner, - block_sender, - }; - (this, block_receiver) - } - - async fn run_updates( - &self, - ctx: &ctx::Ctx, - mut block_receiver: channel::UnboundedReceiver, - ) -> ctx::Result<()> { - let rng = &mut ctx.rng(); - while let Ok(block) = block_receiver.recv(ctx).await { - let head_block_number = self.head_block(ctx).await?.header.number; - assert_eq!(block.header.number, head_block_number.next()); - - let sleep_duration = time::Duration::milliseconds(rng.gen_range(0..5)); - ctx.sleep(sleep_duration).await?; - self.inner.put_block(ctx, &block).await?; - } - Ok(()) - } -} - -#[async_trait] -impl BlockStore for MockContiguousStore { - async fn head_block(&self, ctx: &ctx::Ctx) -> ctx::Result { - self.inner.head_block(ctx).await - } - - async fn first_block(&self, ctx: &ctx::Ctx) -> ctx::Result { - self.inner.first_block(ctx).await - } - - async fn last_contiguous_block_number(&self, ctx: &ctx::Ctx) -> ctx::Result { - self.inner.last_contiguous_block_number(ctx).await - } - - async fn block(&self, ctx: &ctx::Ctx, number: BlockNumber) -> ctx::Result> { - self.inner.block(ctx, number).await - } - - async fn missing_block_numbers( - &self, - ctx: &ctx::Ctx, - range: ops::Range, - ) -> ctx::Result> { - self.inner.missing_block_numbers(ctx, range).await - } - - fn subscribe_to_block_writes(&self) -> watch::Receiver { - self.inner.subscribe_to_block_writes() - } -} - -#[async_trait] -impl ContiguousBlockStore for MockContiguousStore { - async fn schedule_next_block(&self, _ctx: &ctx::Ctx, block: &FinalBlock) -> ctx::Result<()> { - tracing::trace!(block_number = block.header.number.0, "Scheduled next block"); - self.block_sender.send(block.clone()); - Ok(()) - } -} - -#[tracing::instrument(level = "trace", skip(shuffle_blocks))] -async fn test_buffered_storage( - initial_block_count: usize, - block_count: usize, - block_interval: time::Duration, - shuffle_blocks: impl FnOnce(&mut StdRng, &mut [FinalBlock]), -) { - abort_on_panic(); - let ctx = &ctx::test_root(&ctx::RealClock); - let rng = &mut ctx.rng(); - - let (genesis_block, block_store) = init_store(rng); - let mut initial_blocks = gen_blocks(rng, genesis_block.clone(), initial_block_count); - for block in &initial_blocks { - block_store.put_block(ctx, block).await.unwrap(); - } - initial_blocks.insert(0, genesis_block.clone()); - - let (block_store, block_receiver) = MockContiguousStore::new(block_store); - let mut buffered_store = Buffered::new(block_store); - let (events_sender, mut events_receiver) = channel::unbounded(); - buffered_store.set_events_sender(events_sender); - - // Check initial values returned by the store. - let last_initial_block = initial_blocks.last().unwrap().clone(); - assert_eq!( - buffered_store.head_block(ctx).await.unwrap(), - last_initial_block - ); - for block in &initial_blocks { - let block_result = buffered_store.block(ctx, block.header.number).await; - assert_eq!(block_result.unwrap().as_ref(), Some(block)); - } - let mut subscriber = buffered_store.subscribe_to_block_writes(); - assert_eq!( - *subscriber.borrow(), - BlockNumber(initial_block_count as u64) - ); - - let mut blocks = gen_blocks(rng, last_initial_block, block_count); - shuffle_blocks(rng, &mut blocks); - let last_block_number = BlockNumber((block_count + initial_block_count) as u64); - - scope::run!(ctx, |ctx, s| async { - s.spawn_bg(buffered_store.inner().run_updates(ctx, block_receiver)); - s.spawn_bg(buffered_store.run_background_tasks(ctx)); - - for (idx, block) in blocks.iter().enumerate() { - buffered_store.put_block(ctx, block).await?; - let new_block_number = *sync::changed(ctx, &mut subscriber).await?; - assert_eq!(new_block_number, block.header.number); - - // Check that all written blocks are immediately accessible. - for existing_block in initial_blocks.iter().chain(&blocks[0..=idx]) { - let number = existing_block.header.number; - assert_eq!( - buffered_store.block(ctx, number).await?.as_ref(), - Some(existing_block) - ); - } - assert_eq!(buffered_store.first_block(ctx).await?, genesis_block); - - let expected_head_block = blocks[0..=idx] - .iter() - .max_by_key(|block| block.header.number) - .unwrap(); - assert_eq!(buffered_store.head_block(ctx).await?, *expected_head_block); - - let expected_last_contiguous_block = blocks[(idx + 1)..] - .iter() - .map(|block| block.header.number) - .min() - .map_or(last_block_number, BlockNumber::prev); - assert_eq!( - buffered_store.last_contiguous_block_number(ctx).await?, - expected_last_contiguous_block - ); - - ctx.sleep(block_interval).await?; - } - - let mut inner_subscriber = buffered_store.inner().subscribe_to_block_writes(); - while buffered_store - .inner() - .last_contiguous_block_number(ctx) - .await? - < last_block_number - { - sync::changed(ctx, &mut inner_subscriber).await?; - } - - // Check events emitted by the buffered storage. This also ensures that all underlying storage - // updates are processed before proceeding to the following checks. - let expected_numbers = (initial_block_count as u64 + 1)..=last_block_number.0; - for expected_number in expected_numbers.map(BlockNumber) { - assert_matches!( - events_receiver.recv(ctx).await?, - BufferedStorageEvent::UpdateReceived(number) if number == expected_number - ); - } - - assert_eq!(buffered_store.buffer_len().await, 0); - Ok(()) - }) - .await - .unwrap(); -} - -// Choose intervals so that they are both smaller and larger than the sleep duration in -// `MockContiguousStore::run_updates()`. -const BLOCK_INTERVALS: [time::Duration; 4] = [ - time::Duration::ZERO, - time::Duration::milliseconds(3), - time::Duration::milliseconds(5), - time::Duration::milliseconds(10), -]; - -#[test_casing(4, BLOCK_INTERVALS)] -#[tokio::test] -async fn buffered_storage_with_sequential_blocks(block_interval: time::Duration) { - test_buffered_storage(0, 30, block_interval, |_, _| { - // Do not perform shuffling - }) - .await; -} - -#[test_casing(4, BLOCK_INTERVALS)] -#[tokio::test] -async fn buffered_storage_with_random_blocks(block_interval: time::Duration) { - test_buffered_storage(0, 30, block_interval, |rng, blocks| blocks.shuffle(rng)).await; -} - -#[test_casing(4, BLOCK_INTERVALS)] -#[tokio::test] -async fn buffered_storage_with_slightly_shuffled_blocks(block_interval: time::Duration) { - test_buffered_storage(0, 30, block_interval, |rng, blocks| { - for chunk in blocks.chunks_mut(4) { - chunk.shuffle(rng); - } - }) - .await; -} - -#[test_casing(4, BLOCK_INTERVALS)] -#[tokio::test] -async fn buffered_storage_with_initial_blocks(block_interval: time::Duration) { - test_buffered_storage(10, 20, block_interval, |_, _| { - // Do not perform shuffling - }) - .await; -} - -#[test_casing(4, BLOCK_INTERVALS)] -#[tokio::test] -async fn buffered_storage_with_initial_blocks_and_slight_shuffling(block_interval: time::Duration) { - test_buffered_storage(10, 20, block_interval, |rng, blocks| { - for chunk in blocks.chunks_mut(5) { - chunk.shuffle(rng); - } - }) - .await; -} diff --git a/core/lib/zksync_core/src/sync_layer/gossip/conversions.rs b/core/lib/zksync_core/src/sync_layer/gossip/conversions.rs index d991fbb4924b..de9f00093fa9 100644 --- a/core/lib/zksync_core/src/sync_layer/gossip/conversions.rs +++ b/core/lib/zksync_core/src/sync_layer/gossip/conversions.rs @@ -25,6 +25,7 @@ impl FetchedBlock { reference_hash: Some(payload.hash), l1_gas_price: payload.l1_gas_price, l2_fair_gas_price: payload.l2_fair_gas_price, + fair_pubdata_price: payload.fair_pubdata_price, virtual_blocks: payload.virtual_blocks, operator_address: payload.operator_address, transactions: payload.transactions, diff --git a/core/lib/zksync_core/src/sync_layer/gossip/metrics.rs b/core/lib/zksync_core/src/sync_layer/gossip/metrics.rs deleted file mode 100644 index 73caf510269b..000000000000 --- a/core/lib/zksync_core/src/sync_layer/gossip/metrics.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Metrics for gossip-powered syncing. - -use std::time::Duration; - -use vise::{Buckets, EncodeLabelSet, EncodeLabelValue, Family, Gauge, Histogram, Metrics, Unit}; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelValue, EncodeLabelSet)] -#[metrics(label = "kind", rename_all = "snake_case")] -pub(super) enum BlockResponseKind { - Persisted, - InMemory, -} - -#[derive(Debug, Metrics)] -#[metrics(prefix = "external_node_gossip_fetcher")] -pub(super) struct GossipFetcherMetrics { - /// Number of currently buffered unexecuted blocks. - pub buffer_size: Gauge, - /// Latency of a `get_block` call. - #[metrics(unit = Unit::Seconds, buckets = Buckets::LATENCIES)] - pub get_block_latency: Family>, - /// Latency of putting a block into the buffered storage. This may include the time to queue - /// block actions, but does not include block execution. - #[metrics(unit = Unit::Seconds, buckets = Buckets::LATENCIES)] - pub buffer_block_latency: Histogram, -} - -#[vise::register] -pub(super) static METRICS: vise::Global = vise::Global::new(); diff --git a/core/lib/zksync_core/src/sync_layer/gossip/mod.rs b/core/lib/zksync_core/src/sync_layer/gossip/mod.rs deleted file mode 100644 index 9360a169bbed..000000000000 --- a/core/lib/zksync_core/src/sync_layer/gossip/mod.rs +++ /dev/null @@ -1,108 +0,0 @@ -//! Consensus adapter for EN synchronization logic. - -use std::sync::Arc; - -use anyhow::Context as _; -use tokio::sync::watch; -use zksync_concurrency::{ctx, error::Wrap as _, scope}; -use zksync_consensus_executor::{Executor, ExecutorConfig}; -use zksync_consensus_roles::node; -use zksync_dal::ConnectionPool; -use zksync_types::Address; - -use self::{buffered::Buffered, storage::PostgresBlockStorage}; -use super::{fetcher::FetcherCursor, sync_action::ActionQueueSender}; - -mod buffered; -mod conversions; -mod metrics; -mod storage; -#[cfg(test)] -mod tests; -mod utils; - -/// Starts fetching L2 blocks using peer-to-peer gossip network. -pub async fn run_gossip_fetcher( - pool: ConnectionPool, - actions: ActionQueueSender, - executor_config: ExecutorConfig, - node_key: node::SecretKey, - mut stop_receiver: watch::Receiver, - operator_address: Address, -) -> anyhow::Result<()> { - scope::run!(&ctx::root(), |ctx, s| async { - s.spawn_bg(run_gossip_fetcher_inner( - ctx, - pool, - actions, - executor_config, - node_key, - operator_address, - )); - if stop_receiver.changed().await.is_err() { - tracing::warn!( - "Stop signal sender for gossip fetcher was dropped without sending a signal" - ); - } - tracing::info!("Stop signal received, gossip fetcher is shutting down"); - Ok(()) - }) - .await -} - -async fn run_gossip_fetcher_inner( - ctx: &ctx::Ctx, - pool: ConnectionPool, - actions: ActionQueueSender, - executor_config: ExecutorConfig, - node_key: node::SecretKey, - operator_address: Address, -) -> anyhow::Result<()> { - tracing::info!( - "Starting gossip fetcher with {executor_config:?} and node key {:?}", - node_key.public() - ); - - let mut storage = pool - .access_storage_tagged("sync_layer") - .await - .context("Failed acquiring Postgres connection for cursor")?; - let cursor = FetcherCursor::new(&mut storage) - .await - .context("FetcherCursor::new()")?; - drop(storage); - - let store = PostgresBlockStorage::new( - ctx, - pool, - actions, - cursor, - &executor_config.genesis_block, - operator_address, - ) - .await - .wrap("PostgresBlockStorage::new()")?; - let buffered = Arc::new(Buffered::new(store)); - let store = buffered.inner(); - - scope::run!(ctx, |ctx, s| async { - let executor = Executor::new(ctx, executor_config, node_key, buffered.clone()) - .await - .context("Node executor misconfiguration")?; - s.spawn_bg(async { - store - .run_background_tasks(ctx) - .await - .context("`PostgresBlockStorage` background tasks failed") - }); - s.spawn_bg(async { - buffered - .run_background_tasks(ctx) - .await - .context("`Buffered` storage background tasks failed") - }); - - executor.run(ctx).await.context("Node executor terminated") - }) - .await -} diff --git a/core/lib/zksync_core/src/sync_layer/gossip/storage/mod.rs b/core/lib/zksync_core/src/sync_layer/gossip/storage/mod.rs deleted file mode 100644 index bc5aeb946b27..000000000000 --- a/core/lib/zksync_core/src/sync_layer/gossip/storage/mod.rs +++ /dev/null @@ -1,358 +0,0 @@ -//! Storage implementation based on DAL. - -use std::ops; - -use anyhow::Context as _; -use async_trait::async_trait; -use zksync_concurrency::{ - ctx, - error::Wrap as _, - sync::{self, watch, Mutex}, - time, -}; -use zksync_consensus_roles::validator::{BlockNumber, FinalBlock}; -use zksync_consensus_storage::BlockStore; -use zksync_dal::{blocks_dal::ConsensusBlockFields, ConnectionPool, StorageProcessor}; -use zksync_types::{api::en::SyncBlock, Address, MiniblockNumber}; - -#[cfg(test)] -mod tests; - -use super::buffered::ContiguousBlockStore; -use crate::{ - consensus, - consensus::sync_block_to_consensus_block, - sync_layer::{ - fetcher::{FetchedBlock, FetcherCursor}, - sync_action::{ActionQueueSender, SyncAction}, - }, -}; - -#[derive(Debug)] -struct CursorWithCachedBlock { - inner: FetcherCursor, - maybe_last_block_in_batch: Option, -} - -impl From for CursorWithCachedBlock { - fn from(inner: FetcherCursor) -> Self { - Self { - inner, - maybe_last_block_in_batch: None, - } - } -} - -impl CursorWithCachedBlock { - fn advance(&mut self, block: FetchedBlock) -> Vec> { - let mut actions = Vec::with_capacity(2); - if let Some(mut prev_block) = self.maybe_last_block_in_batch.take() { - prev_block.last_in_batch = prev_block.l1_batch_number != block.l1_batch_number; - actions.push(self.inner.advance(prev_block)); - } - - // We take advantage of the fact that the last block in a batch is a *fictive* block that - // does not contain transactions. Thus, any block with transactions cannot be last in an L1 batch. - let can_be_last_in_batch = block.transactions.is_empty(); - if can_be_last_in_batch { - self.maybe_last_block_in_batch = Some(block); - // We cannot convert the block into actions yet, since we don't know whether it seals an L1 batch. - } else { - actions.push(self.inner.advance(block)); - } - actions - } -} - -/// Postgres-based [`BlockStore`] implementation. New blocks are scheduled to be written via -/// [`ContiguousBlockStore`] trait, which internally uses an [`ActionQueueSender`] to queue -/// block data (miniblock and L1 batch parameters, transactions) for the state keeper. Block data processing -/// is shared with JSON-RPC-based syncing. -#[derive(Debug)] -pub(super) struct PostgresBlockStorage { - pool: ConnectionPool, - first_block_number: MiniblockNumber, - actions: ActionQueueSender, - block_sender: watch::Sender, - cursor: Mutex, - operator_address: Address, -} - -impl PostgresBlockStorage { - /// Creates a new storage handle. `pool` should have multiple connections to work efficiently. - pub async fn new( - ctx: &ctx::Ctx, - pool: ConnectionPool, - actions: ActionQueueSender, - cursor: FetcherCursor, - genesis_block: &FinalBlock, - operator_address: Address, - ) -> ctx::Result { - let mut storage = ctx.wait(pool.access_storage_tagged("sync_layer")).await??; - Self::ensure_genesis_block(ctx, &mut storage, genesis_block, operator_address) - .await - .wrap("ensure_genesis_block()")?; - drop(storage); - - let first_block_number = u32::try_from(genesis_block.header.number.0) - .context("Block number overflow for genesis block")?; - let first_block_number = MiniblockNumber(first_block_number); - - Ok(Self::new_unchecked( - pool, - first_block_number, - actions, - cursor, - operator_address, - )) - } - - fn new_unchecked( - pool: ConnectionPool, - first_block_number: MiniblockNumber, - actions: ActionQueueSender, - cursor: FetcherCursor, - operator_address: Address, - ) -> Self { - let current_block_number = cursor.next_miniblock.0.saturating_sub(1).into(); - Self { - pool, - first_block_number, - actions, - block_sender: watch::channel(BlockNumber(current_block_number)).0, - cursor: Mutex::new(cursor.into()), - operator_address, - } - } - - async fn ensure_genesis_block( - ctx: &ctx::Ctx, - storage: &mut StorageProcessor<'_>, - genesis_block: &FinalBlock, - operator_address: Address, - ) -> ctx::Result<()> { - let block_number = u32::try_from(genesis_block.header.number.0) - .context("Block number overflow for genesis block")?; - let block = Self::sync_block( - ctx, - storage, - MiniblockNumber(block_number), - operator_address, - ) - .await - .wrap("sync_block();")?; - let block = block - .with_context(|| { - format!("Genesis block #{block_number} (first block with consensus data) is not present in Postgres") - })?; - let actual_consensus_fields = block.consensus.clone(); - - // Some of the following checks are duplicated in `Executor` initialization, but it's necessary - // to run them if the genesis consensus block is not present locally. - let expected_payload = consensus::Payload::decode(&genesis_block.payload) - .context("Cannot decode genesis block payload")?; - let actual_payload: consensus::Payload = block.try_into()?; - if actual_payload != expected_payload { - return Err(anyhow::anyhow!( - "Genesis block payload from Postgres {actual_payload:?} does not match the configured one \ - {expected_payload:?}" - ).into()); - } - - let expected_consensus_fields = ConsensusBlockFields { - parent: genesis_block.header.parent, - justification: genesis_block.justification.clone(), - }; - if let Some(actual_consensus_fields) = &actual_consensus_fields { - let actual_consensus_fields = ConsensusBlockFields::decode(actual_consensus_fields) - .context("ConsensusBlockFields::decode()")?; - // While justifications may differ among nodes for an arbitrary block, we assume that - // the genesis block has a hardcoded justification. - if actual_consensus_fields != expected_consensus_fields { - return Err(anyhow::anyhow!( - "Genesis block consensus fields in Postgres {actual_consensus_fields:?} do not match \ - the configured ones {expected_consensus_fields:?}" - ).into()); - } - } else { - tracing::info!( - "Postgres doesn't have consensus fields for genesis block; saving {expected_consensus_fields:?}" - ); - ctx.wait(storage.blocks_dal().set_miniblock_consensus_fields( - MiniblockNumber(block_number), - &expected_consensus_fields, - )) - .await? - .context("Failed saving consensus fields for genesis block")?; - } - Ok(()) - } - - /// Runs background tasks for this store. This method **must** be spawned as a background task - /// which should be running as long at the [`PostgresBlockStorage`] is in use; otherwise, - /// it will function incorrectly. - pub async fn run_background_tasks(&self, ctx: &ctx::Ctx) -> anyhow::Result<()> { - const POLL_INTERVAL: time::Duration = time::Duration::milliseconds(50); - loop { - let sealed_miniblock_number = match self.sealed_miniblock_number(ctx).await { - Ok(number) => number, - Err(ctx::Error::Internal(err)) => return Err(err), - Err(ctx::Error::Canceled(_)) => return Ok(()), // Do not propagate cancellation errors - }; - self.block_sender.send_if_modified(|number| { - if *number != sealed_miniblock_number { - *number = sealed_miniblock_number; - true - } else { - false - } - }); - if let Err(ctx::Canceled) = ctx.sleep(POLL_INTERVAL).await { - return Ok(()); // Do not propagate cancellation errors - } - } - } - - async fn storage(&self, ctx: &ctx::Ctx) -> ctx::Result> { - Ok(ctx - .wait(self.pool.access_storage_tagged("sync_layer")) - .await? - .context("Failed to connect to Postgres")?) - } - - async fn sync_block( - ctx: &ctx::Ctx, - storage: &mut StorageProcessor<'_>, - number: MiniblockNumber, - operator_address: Address, - ) -> ctx::Result> { - Ok(ctx - .wait( - storage - .sync_dal() - .sync_block(number, operator_address, true), - ) - .await? - .with_context(|| format!("Failed getting miniblock #{number} from Postgres"))?) - } - - async fn block( - ctx: &ctx::Ctx, - storage: &mut StorageProcessor<'_>, - number: MiniblockNumber, - operator_address: Address, - ) -> ctx::Result> { - let Some(block) = Self::sync_block(ctx, storage, number, operator_address) - .await - .wrap("Self::sync_block()")? - else { - return Ok(None); - }; - let block = - sync_block_to_consensus_block(block).context("sync_block_to_consensus_block()")?; - Ok(Some(block)) - } - - async fn sealed_miniblock_number(&self, ctx: &ctx::Ctx) -> ctx::Result { - let mut storage = self.storage(ctx).await.wrap("storage()")?; - let number = ctx - .wait(storage.blocks_dal().get_sealed_miniblock_number()) - .await? - .context("Failed getting sealed miniblock number")?; - Ok(BlockNumber(number.0.into())) - } -} - -#[async_trait] -impl BlockStore for PostgresBlockStorage { - async fn head_block(&self, ctx: &ctx::Ctx) -> ctx::Result { - let mut storage = self.storage(ctx).await.wrap("storage()")?; - let miniblock_number = ctx - .wait(storage.blocks_dal().get_sealed_miniblock_number()) - .await? - .context("Failed getting sealed miniblock number")?; - // ^ The number can get stale, but it's OK for our purposes - Ok( - Self::block(ctx, &mut storage, miniblock_number, self.operator_address) - .await - .wrap("Self::block()")? - .with_context(|| { - format!("Miniblock #{miniblock_number} disappeared from Postgres") - })?, - ) - } - - async fn first_block(&self, ctx: &ctx::Ctx) -> ctx::Result { - let mut storage = self.storage(ctx).await.wrap("storage()")?; - Ok(Self::block( - ctx, - &mut storage, - self.first_block_number, - self.operator_address, - ) - .await - .wrap("Self::block()")? - .context("Genesis miniblock not present in Postgres")?) - } - - async fn last_contiguous_block_number(&self, ctx: &ctx::Ctx) -> ctx::Result { - self.sealed_miniblock_number(ctx) - .await - .wrap("sealed_miniblock_number()") - } - - async fn block(&self, ctx: &ctx::Ctx, number: BlockNumber) -> ctx::Result> { - let Ok(number) = u32::try_from(number.0) else { - return Ok(None); - }; - let number = MiniblockNumber(number); - if number < self.first_block_number { - return Ok(None); - } - let mut storage = self.storage(ctx).await.wrap("storage()")?; - Self::block(ctx, &mut storage, number, self.operator_address) - .await - .wrap("Self::block()") - } - - async fn missing_block_numbers( - &self, - ctx: &ctx::Ctx, - range: ops::Range, - ) -> ctx::Result> { - let mut output = vec![]; - let first_block_number = u64::from(self.first_block_number.0); - let numbers_before_first_block = (range.start.0..first_block_number).map(BlockNumber); - output.extend(numbers_before_first_block); - - let last_block_number = self - .sealed_miniblock_number(ctx) - .await - .wrap("sealed_miniblock_number()")?; - let numbers_after_last_block = (last_block_number.next().0..range.end.0).map(BlockNumber); - output.extend(numbers_after_last_block); - - // By design, no blocks are missing in the `first_block_number..=last_block_number` range. - Ok(output) - } - - fn subscribe_to_block_writes(&self) -> watch::Receiver { - self.block_sender.subscribe() - } -} - -#[async_trait] -impl ContiguousBlockStore for PostgresBlockStorage { - async fn schedule_next_block(&self, ctx: &ctx::Ctx, block: &FinalBlock) -> ctx::Result<()> { - // last_in_batch` is always set to `false` by this call; it is properly set by `CursorWithCachedBlock`. - let fetched_block = - FetchedBlock::from_gossip_block(block, false).context("from_gossip_block()")?; - let actions = sync::lock(ctx, &self.cursor).await?.advance(fetched_block); - for actions_chunk in actions { - // We don't wrap this in `ctx.wait()` because `PostgresBlockStorage` will get broken - // if it gets reused after context cancellation. - self.actions.push_actions(actions_chunk).await; - } - Ok(()) - } -} diff --git a/core/lib/zksync_core/src/sync_layer/gossip/storage/tests.rs b/core/lib/zksync_core/src/sync_layer/gossip/storage/tests.rs deleted file mode 100644 index d8b1eff0e24b..000000000000 --- a/core/lib/zksync_core/src/sync_layer/gossip/storage/tests.rs +++ /dev/null @@ -1,376 +0,0 @@ -//! Tests for Postgres storage implementation. - -use rand::{thread_rng, Rng}; -use zksync_concurrency::{scope, testonly::abort_on_panic}; -use zksync_consensus_roles::validator; -use zksync_types::L2ChainId; - -use super::*; -use crate::{ - genesis::{ensure_genesis_state, GenesisParams}, - sync_layer::{ - gossip::tests::{ - add_consensus_fields, assert_first_block_actions, assert_second_block_actions, - block_payload, create_genesis_block, load_final_block, - }, - tests::{run_state_keeper_with_multiple_miniblocks, OPERATOR_ADDRESS}, - ActionQueue, - }, -}; - -const TEST_TIMEOUT: time::Duration = time::Duration::seconds(10); - -#[tokio::test] -async fn block_store_basics_for_postgres() { - abort_on_panic(); - let pool = ConnectionPool::test_pool().await; - run_state_keeper_with_multiple_miniblocks(pool.clone()).await; - - let mut storage = pool.access_storage().await.unwrap(); - add_consensus_fields(&mut storage, &thread_rng().gen(), 0..3).await; - let cursor = FetcherCursor::new(&mut storage).await.unwrap(); - drop(storage); - let (actions_sender, _) = ActionQueue::new(); - let storage = PostgresBlockStorage::new_unchecked( - pool.clone(), - MiniblockNumber(0), - actions_sender, - cursor, - OPERATOR_ADDRESS, - ); - - let ctx = &ctx::test_root(&ctx::RealClock); - let genesis_block = BlockStore::first_block(&storage, ctx).await.unwrap(); - assert_eq!(genesis_block.header.number, BlockNumber(0)); - let head_block = BlockStore::head_block(&storage, ctx).await.unwrap(); - assert_eq!(head_block.header.number, BlockNumber(2)); - let last_contiguous_block_number = storage.last_contiguous_block_number(ctx).await.unwrap(); - assert_eq!(last_contiguous_block_number, BlockNumber(2)); - - let block = storage - .block(ctx, BlockNumber(1)) - .await - .unwrap() - .expect("no block #1"); - assert_eq!(block.header.number, BlockNumber(1)); - let missing_block = storage.block(ctx, BlockNumber(3)).await.unwrap(); - assert!(missing_block.is_none(), "{missing_block:?}"); -} - -#[tokio::test] -async fn subscribing_to_block_updates_for_postgres() { - abort_on_panic(); - let pool = ConnectionPool::test_pool().await; - let mut storage = pool.access_storage().await.unwrap(); - if storage.blocks_dal().is_genesis_needed().await.unwrap() { - ensure_genesis_state(&mut storage, L2ChainId::default(), &GenesisParams::mock()) - .await - .unwrap(); - } - let cursor = FetcherCursor::new(&mut storage).await.unwrap(); - // ^ This is logically incorrect (the storage should not be updated other than using - // `ContiguousBlockStore`), but for testing subscriptions this is fine. - drop(storage); - let (actions_sender, _) = ActionQueue::new(); - let storage = PostgresBlockStorage::new_unchecked( - pool.clone(), - MiniblockNumber(0), - actions_sender, - cursor, - OPERATOR_ADDRESS, - ); - let mut subscriber = storage.subscribe_to_block_writes(); - - let ctx = &ctx::test_root(&ctx::RealClock); - scope::run!(&ctx.with_timeout(TEST_TIMEOUT), |ctx, s| async { - s.spawn_bg(storage.run_background_tasks(ctx)); - s.spawn(async { - run_state_keeper_with_multiple_miniblocks(pool.clone()).await; - Ok(()) - }); - - loop { - let block = *sync::changed(ctx, &mut subscriber).await?; - if block == BlockNumber(2) { - // We should receive at least the last update. - break; - } - } - Ok(()) - }) - .await - .unwrap(); -} - -#[tokio::test] -async fn processing_new_blocks() { - abort_on_panic(); - let pool = ConnectionPool::test_pool().await; - run_state_keeper_with_multiple_miniblocks(pool.clone()).await; - - let mut storage = pool.access_storage().await.unwrap(); - add_consensus_fields(&mut storage, &thread_rng().gen(), 0..3).await; - let first_block = load_final_block(&mut storage, 1).await; - let second_block = load_final_block(&mut storage, 2).await; - storage - .transactions_dal() - .reset_transactions_state(MiniblockNumber(0)) - .await; - storage - .blocks_dal() - .delete_miniblocks(MiniblockNumber(0)) - .await - .unwrap(); - let cursor = FetcherCursor::new(&mut storage).await.unwrap(); - drop(storage); - - let (actions_sender, mut actions) = ActionQueue::new(); - let storage = PostgresBlockStorage::new_unchecked( - pool.clone(), - MiniblockNumber(0), - actions_sender, - cursor, - OPERATOR_ADDRESS, - ); - let ctx = &ctx::test_root(&ctx::RealClock); - let ctx = &ctx.with_timeout(TEST_TIMEOUT); - storage - .schedule_next_block(ctx, &first_block) - .await - .unwrap(); - assert_first_block_actions(&mut actions).await; - - storage - .schedule_next_block(ctx, &second_block) - .await - .unwrap(); - assert_second_block_actions(&mut actions).await; -} - -#[tokio::test] -async fn ensuring_consensus_fields_for_genesis_block() { - abort_on_panic(); - let ctx = &ctx::test_root(&ctx::RealClock); - let pool = ConnectionPool::test_pool().await; - let mut storage = pool.access_storage().await.unwrap(); - if storage.blocks_dal().is_genesis_needed().await.unwrap() { - ensure_genesis_state(&mut storage, L2ChainId::default(), &GenesisParams::mock()) - .await - .unwrap(); - } - let cursor = FetcherCursor::new(&mut storage).await.unwrap(); - let block_payload = block_payload(&mut storage, 0).await.encode(); - drop(storage); - - let validator_key = validator::SecretKey::generate(&mut ctx.rng()); - let genesis_block = create_genesis_block(&validator_key, 0, block_payload.clone()); - - let (actions_sender, _) = ActionQueue::new(); - PostgresBlockStorage::new( - ctx, - pool.clone(), - actions_sender, - cursor, - &genesis_block, - OPERATOR_ADDRESS, - ) - .await - .unwrap(); - - // Check that the consensus fields are persisted for the genesis block. - let mut storage = pool.access_storage().await.unwrap(); - let sync_block = storage - .sync_dal() - .sync_block(MiniblockNumber(0), Address::default(), false) - .await - .unwrap() - .expect("No genesis block"); - assert!(sync_block.consensus.is_some()); - let cursor = FetcherCursor::new(&mut storage).await.unwrap(); - let other_cursor = FetcherCursor::new(&mut storage).await.unwrap(); - drop(storage); - - // Check that the storage can be initialized again. - let (actions_sender, _) = ActionQueue::new(); - PostgresBlockStorage::new( - ctx, - pool.clone(), - actions_sender, - cursor, - &genesis_block, - OPERATOR_ADDRESS, - ) - .await - .unwrap(); - - // Create a genesis block with another validator. - let validator_key = validator::SecretKey::generate(&mut ctx.rng()); - let other_genesis_block = create_genesis_block(&validator_key, 0, block_payload); - - // Storage should not be able to initialize with other genesis block. - let (actions_sender, _) = ActionQueue::new(); - PostgresBlockStorage::new( - ctx, - pool, - actions_sender, - other_cursor, - &other_genesis_block, - OPERATOR_ADDRESS, - ) - .await - .unwrap_err(); -} - -#[tokio::test] -async fn genesis_block_payload_mismatch() { - abort_on_panic(); - let ctx = &ctx::test_root(&ctx::RealClock); - let pool = ConnectionPool::test_pool().await; - let mut storage = pool.access_storage().await.unwrap(); - if storage.blocks_dal().is_genesis_needed().await.unwrap() { - ensure_genesis_state(&mut storage, L2ChainId::default(), &GenesisParams::mock()) - .await - .unwrap(); - } - let cursor = FetcherCursor::new(&mut storage).await.unwrap(); - let other_cursor = FetcherCursor::new(&mut storage).await.unwrap(); - - let bogus_block_payload = validator::Payload(vec![]); - let validator_key = validator::SecretKey::generate(&mut ctx.rng()); - let genesis_block = create_genesis_block(&validator_key, 0, bogus_block_payload); - - let (actions_sender, _) = ActionQueue::new(); - PostgresBlockStorage::new( - ctx, - pool.clone(), - actions_sender, - cursor, - &genesis_block, - OPERATOR_ADDRESS, - ) - .await - .unwrap_err(); - - let mut bogus_block_payload = block_payload(&mut storage, 0).await; - bogus_block_payload.timestamp += 1; - let genesis_block = create_genesis_block(&validator_key, 0, bogus_block_payload.encode()); - - let (actions_sender, _) = ActionQueue::new(); - PostgresBlockStorage::new( - ctx, - pool.clone(), - actions_sender, - other_cursor, - &genesis_block, - OPERATOR_ADDRESS, - ) - .await - .unwrap_err(); -} - -#[tokio::test] -async fn missing_genesis_block() { - abort_on_panic(); - let ctx = &ctx::test_root(&ctx::RealClock); - let pool = ConnectionPool::test_pool().await; - let mut storage = pool.access_storage().await.unwrap(); - if storage.blocks_dal().is_genesis_needed().await.unwrap() { - ensure_genesis_state(&mut storage, L2ChainId::default(), &GenesisParams::mock()) - .await - .unwrap(); - } - let cursor = FetcherCursor::new(&mut storage).await.unwrap(); - let block_payload = block_payload(&mut storage, 0).await.encode(); - drop(storage); - - // Create a genesis block for the (non-existing) block #2. - let validator_key = validator::SecretKey::generate(&mut ctx.rng()); - let genesis_block = create_genesis_block(&validator_key, 2, block_payload.clone()); - - let (actions_sender, _) = ActionQueue::new(); - PostgresBlockStorage::new( - ctx, - pool, - actions_sender, - cursor, - &genesis_block, - OPERATOR_ADDRESS, - ) - .await - .unwrap_err(); -} - -#[tokio::test] -async fn using_non_zero_genesis_block() { - abort_on_panic(); - let ctx = &ctx::test_root(&ctx::RealClock); - let pool = ConnectionPool::test_pool().await; - run_state_keeper_with_multiple_miniblocks(pool.clone()).await; - - let mut storage = pool.access_storage().await.unwrap(); - let cursor = FetcherCursor::new(&mut storage).await.unwrap(); - let block_payload = block_payload(&mut storage, 2).await.encode(); - drop(storage); - - let validator_key = validator::SecretKey::generate(&mut ctx.rng()); - let genesis_block = create_genesis_block(&validator_key, 2, block_payload.clone()); - - let (actions_sender, _) = ActionQueue::new(); - let store = PostgresBlockStorage::new( - ctx, - pool, - actions_sender, - cursor, - &genesis_block, - OPERATOR_ADDRESS, - ) - .await - .unwrap(); - - let head_block = store.head_block(ctx).await.unwrap(); - assert_eq!(head_block.header.number, BlockNumber(2)); - assert_eq!( - head_block.header.parent, - validator::BlockHeaderHash::from_bytes([0; 32]) - ); - let first_block = store.first_block(ctx).await.unwrap(); - assert_eq!(first_block.header.number, BlockNumber(2)); - let last_contiguous_block_number = store.last_contiguous_block_number(ctx).await.unwrap(); - assert_eq!(last_contiguous_block_number, BlockNumber(2)); - - let block = store.block(ctx, BlockNumber(2)).await.unwrap(); - assert_eq!(block, Some(head_block)); - for number in [0, 1, 3] { - let missing_block = store.block(ctx, BlockNumber(number)).await.unwrap(); - assert!(missing_block.is_none()); - } - - let missing_blocks = store - .missing_block_numbers(ctx, BlockNumber(0)..BlockNumber(5)) - .await - .unwrap(); - assert_eq!( - missing_blocks, - [ - BlockNumber(0), - BlockNumber(1), - BlockNumber(3), - BlockNumber(4) - ] - ); - let missing_blocks = store - .missing_block_numbers(ctx, BlockNumber(0)..BlockNumber(2)) - .await - .unwrap(); - assert_eq!(missing_blocks, [BlockNumber(0), BlockNumber(1)]); - let missing_blocks = store - .missing_block_numbers(ctx, BlockNumber(2)..BlockNumber(5)) - .await - .unwrap(); - assert_eq!(missing_blocks, [BlockNumber(3), BlockNumber(4)]); - let missing_blocks = store - .missing_block_numbers(ctx, BlockNumber(2)..BlockNumber(3)) - .await - .unwrap(); - assert_eq!(missing_blocks, []); -} diff --git a/core/lib/zksync_core/src/sync_layer/gossip/tests.rs b/core/lib/zksync_core/src/sync_layer/gossip/tests.rs deleted file mode 100644 index ad9b00e9c153..000000000000 --- a/core/lib/zksync_core/src/sync_layer/gossip/tests.rs +++ /dev/null @@ -1,534 +0,0 @@ -//! Tests for consensus adapters for EN synchronization logic. - -use std::ops; - -use assert_matches::assert_matches; -use test_casing::{test_casing, Product}; -use zksync_concurrency::{ctx, scope, testonly::abort_on_panic, time}; -use zksync_consensus_executor::testonly::FullValidatorConfig; -use zksync_consensus_roles::validator::{self, FinalBlock}; -use zksync_consensus_storage::{InMemoryStorage, WriteBlockStore}; -use zksync_dal::{blocks_dal::ConsensusBlockFields, ConnectionPool, StorageProcessor}; -use zksync_types::{api::en::SyncBlock, L1BatchNumber, MiniblockNumber, H256}; - -use super::*; -use crate::{ - consensus, - sync_layer::{ - sync_action::SyncAction, - tests::{ - mock_l1_batch_hash_computation, run_state_keeper_with_multiple_l1_batches, - run_state_keeper_with_multiple_miniblocks, StateKeeperHandles, OPERATOR_ADDRESS, - }, - ActionQueue, - }, -}; - -const CLOCK_SPEEDUP: i64 = 20; -const POLL_INTERVAL: time::Duration = time::Duration::milliseconds(50 * CLOCK_SPEEDUP); - -async fn load_sync_block(storage: &mut StorageProcessor<'_>, number: u32) -> SyncBlock { - storage - .sync_dal() - .sync_block(MiniblockNumber(number), OPERATOR_ADDRESS, true) - .await - .unwrap() - .unwrap_or_else(|| panic!("no sync block #{number}")) -} - -/// Loads a block from the storage and converts it to a `FinalBlock`. -pub(super) async fn load_final_block( - storage: &mut StorageProcessor<'_>, - number: u32, -) -> FinalBlock { - let sync_block = load_sync_block(storage, number).await; - consensus::sync_block_to_consensus_block(sync_block).unwrap() -} - -fn convert_sync_blocks(sync_blocks: Vec) -> Vec { - sync_blocks - .into_iter() - .map(|sync_block| consensus::sync_block_to_consensus_block(sync_block).unwrap()) - .collect() -} - -pub(super) async fn block_payload( - storage: &mut StorageProcessor<'_>, - number: u32, -) -> consensus::Payload { - let sync_block = load_sync_block(storage, number).await; - consensus::Payload::try_from(sync_block).unwrap() -} - -/// Adds consensus information for the specified `count` of miniblocks, starting from the genesis. -pub(super) async fn add_consensus_fields( - storage: &mut StorageProcessor<'_>, - validator_key: &validator::SecretKey, - block_numbers: ops::Range, -) { - let mut prev_block_hash = validator::BlockHeaderHash::from_bytes([0; 32]); - let validator_set = validator::ValidatorSet::new([validator_key.public()]).unwrap(); - for number in block_numbers { - let payload = block_payload(storage, number).await.encode(); - let block_header = validator::BlockHeader { - parent: prev_block_hash, - number: validator::BlockNumber(number.into()), - payload: payload.hash(), - }; - let replica_commit = validator::ReplicaCommit { - protocol_version: validator::ProtocolVersion::EARLIEST, - view: validator::ViewNumber(number.into()), - proposal: block_header, - }; - let replica_commit = validator_key.sign_msg(replica_commit); - let justification = validator::CommitQC::from(&[replica_commit], &validator_set) - .expect("Failed creating QC"); - - let consensus = ConsensusBlockFields { - parent: prev_block_hash, - justification, - }; - storage - .blocks_dal() - .set_miniblock_consensus_fields(MiniblockNumber(number), &consensus) - .await - .unwrap(); - prev_block_hash = block_header.hash(); - } -} - -/// Creates a genesis block for the consensus with the specified number / payload authored by a single validator. -pub(super) fn create_genesis_block( - validator_key: &validator::SecretKey, - number: u64, - payload: validator::Payload, -) -> FinalBlock { - let block_header = validator::BlockHeader { - parent: validator::BlockHeaderHash::from_bytes([0; 32]), - number: validator::BlockNumber(number), - payload: payload.hash(), - }; - let validator_set = validator::ValidatorSet::new([validator_key.public()]).unwrap(); - let replica_commit = validator::ReplicaCommit { - protocol_version: validator::ProtocolVersion::EARLIEST, - view: validator::ViewNumber(number), - proposal: block_header, - }; - let replica_commit = validator_key.sign_msg(replica_commit); - let justification = - validator::CommitQC::from(&[replica_commit], &validator_set).expect("Failed creating QC"); - FinalBlock { - header: block_header, - payload, - justification, - } -} - -pub(super) async fn assert_first_block_actions(actions: &mut ActionQueue) -> Vec { - let mut received_actions = vec![]; - while !matches!(received_actions.last(), Some(SyncAction::SealMiniblock(_))) { - received_actions.push(actions.recv_action().await); - } - assert_matches!( - received_actions.as_slice(), - [ - SyncAction::OpenBatch { - number: L1BatchNumber(1), - timestamp: 1, - first_miniblock_info: (MiniblockNumber(1), 1), - .. - }, - SyncAction::Tx(_), - SyncAction::Tx(_), - SyncAction::Tx(_), - SyncAction::Tx(_), - SyncAction::Tx(_), - SyncAction::SealMiniblock(_), - ] - ); - received_actions -} - -pub(super) async fn assert_second_block_actions(actions: &mut ActionQueue) -> Vec { - let mut received_actions = vec![]; - while !matches!(received_actions.last(), Some(SyncAction::SealMiniblock(_))) { - received_actions.push(actions.recv_action().await); - } - assert_matches!( - received_actions.as_slice(), - [ - SyncAction::Miniblock { - number: MiniblockNumber(2), - timestamp: 2, - virtual_blocks: 1, - }, - SyncAction::Tx(_), - SyncAction::Tx(_), - SyncAction::Tx(_), - SyncAction::SealMiniblock(_), - ] - ); - received_actions -} - -#[test_casing(4, Product(([false, true], [false, true])))] -#[tokio::test] -async fn syncing_via_gossip_fetcher(delay_first_block: bool, delay_second_block: bool) { - abort_on_panic(); - let pool = ConnectionPool::test_pool().await; - let tx_hashes = run_state_keeper_with_multiple_miniblocks(pool.clone()).await; - - let mut storage = pool.access_storage().await.unwrap(); - let genesis_block_payload = block_payload(&mut storage, 0).await.encode(); - let ctx = &ctx::test_root(&ctx::AffineClock::new(CLOCK_SPEEDUP as f64)); - let rng = &mut ctx.rng(); - let mut validator = FullValidatorConfig::for_single_validator( - rng, - genesis_block_payload, - validator::BlockNumber(0), - ); - let validator_set = validator.node_config.validators.clone(); - let external_node = validator.connect_full_node(rng); - - let genesis_block = validator.node_config.genesis_block.clone(); - add_consensus_fields(&mut storage, &validator.validator_key, 0..3).await; - let blocks = convert_sync_blocks(reset_storage(storage).await); - let [first_block, second_block] = blocks.as_slice() else { - unreachable!("Unexpected blocks in storage: {blocks:?}"); - }; - tracing::trace!("Node storage reset"); - - let validator_storage = Arc::new(InMemoryStorage::new(genesis_block)); - if !delay_first_block { - validator_storage.put_block(ctx, first_block).await.unwrap(); - if !delay_second_block { - validator_storage - .put_block(ctx, second_block) - .await - .unwrap(); - } - } - - let (actions_sender, mut actions) = ActionQueue::new(); - let (keeper_actions_sender, keeper_actions) = ActionQueue::new(); - let state_keeper = StateKeeperHandles::new(pool.clone(), keeper_actions, &[&tx_hashes]).await; - scope::run!(ctx, |ctx, s| async { - let validator = Executor::new( - ctx, - validator.node_config, - validator.node_key, - validator_storage.clone(), - ) - .await?; - // ^ We intentionally do not run consensus on the validator node, since it'll produce blocks - // with payloads that cannot be parsed by the external node. - - s.spawn_bg(validator.run(ctx)); - s.spawn_bg(run_gossip_fetcher_inner( - ctx, - pool.clone(), - actions_sender, - external_node.node_config, - external_node.node_key, - OPERATOR_ADDRESS, - )); - - if delay_first_block { - ctx.sleep(POLL_INTERVAL).await?; - validator_storage.put_block(ctx, first_block).await.unwrap(); - if !delay_second_block { - validator_storage - .put_block(ctx, second_block) - .await - .unwrap(); - } - } - - let received_actions = assert_first_block_actions(&mut actions).await; - // Manually replicate actions to the state keeper. - keeper_actions_sender.push_actions(received_actions).await; - - if delay_second_block { - validator_storage - .put_block(ctx, second_block) - .await - .unwrap(); - } - - let received_actions = assert_second_block_actions(&mut actions).await; - keeper_actions_sender.push_actions(received_actions).await; - state_keeper - .wait(|state| state.get_local_block() == MiniblockNumber(2)) - .await; - Ok(()) - }) - .await - .unwrap(); - - // Check that received blocks have consensus fields persisted. - let mut storage = pool.access_storage().await.unwrap(); - for number in [1, 2] { - let block = load_final_block(&mut storage, number).await; - block.justification.verify(&validator_set, 1).unwrap(); - } -} - -/// Returns the removed blocks. -async fn reset_storage(mut storage: StorageProcessor<'_>) -> Vec { - let sealed_miniblock_number = storage - .blocks_dal() - .get_sealed_miniblock_number() - .await - .unwrap(); - let mut blocks = vec![]; - for number in 1..=sealed_miniblock_number.0 { - blocks.push(load_sync_block(&mut storage, number).await); - } - - storage - .transactions_dal() - .reset_transactions_state(MiniblockNumber(0)) - .await; - storage - .blocks_dal() - .delete_miniblocks(MiniblockNumber(0)) - .await - .unwrap(); - storage - .blocks_dal() - .delete_l1_batches(L1BatchNumber(0)) - .await - .unwrap(); - blocks -} - -#[test_casing(4, [3, 2, 1, 0])] -#[tokio::test] -async fn syncing_via_gossip_fetcher_with_multiple_l1_batches(initial_block_count: usize) { - assert!(initial_block_count <= 3); - abort_on_panic(); - - let pool = ConnectionPool::test_pool().await; - let tx_hashes = run_state_keeper_with_multiple_l1_batches(pool.clone()).await; - let tx_hashes: Vec<_> = tx_hashes.iter().map(Vec::as_slice).collect(); - - let mut storage = pool.access_storage().await.unwrap(); - let genesis_block_payload = block_payload(&mut storage, 0).await.encode(); - let ctx = &ctx::test_root(&ctx::AffineClock::new(CLOCK_SPEEDUP as f64)); - let rng = &mut ctx.rng(); - let mut validator = FullValidatorConfig::for_single_validator( - rng, - genesis_block_payload, - validator::BlockNumber(0), - ); - let validator_set = validator.node_config.validators.clone(); - let external_node = validator.connect_full_node(rng); - - let genesis_block = validator.node_config.genesis_block.clone(); - add_consensus_fields(&mut storage, &validator.validator_key, 0..4).await; - let blocks = convert_sync_blocks(reset_storage(storage).await); - assert_eq!(blocks.len(), 3); // 2 real + 1 fictive blocks - tracing::trace!("Node storage reset"); - let (initial_blocks, delayed_blocks) = blocks.split_at(initial_block_count); - - let validator_storage = Arc::new(InMemoryStorage::new(genesis_block)); - for block in initial_blocks { - validator_storage.put_block(ctx, block).await.unwrap(); - } - - let (actions_sender, actions) = ActionQueue::new(); - let state_keeper = StateKeeperHandles::new(pool.clone(), actions, &tx_hashes).await; - scope::run!(ctx, |ctx, s| async { - let validator = Executor::new( - ctx, - validator.node_config, - validator.node_key, - validator_storage.clone(), - ) - .await?; - - s.spawn_bg(validator.run(ctx)); - s.spawn_bg(async { - for block in delayed_blocks { - ctx.sleep(POLL_INTERVAL).await?; - validator_storage.put_block(ctx, block).await?; - } - Ok(()) - }); - - s.spawn_bg(async { - mock_l1_batch_hash_computation(pool.clone(), 1).await; - Ok(()) - }); - s.spawn_bg(run_gossip_fetcher_inner( - ctx, - pool.clone(), - actions_sender, - external_node.node_config, - external_node.node_key, - OPERATOR_ADDRESS, - )); - - state_keeper - .wait(|state| state.get_local_block() == MiniblockNumber(3)) - .await; - Ok(()) - }) - .await - .unwrap(); - - // Check that received blocks have consensus fields persisted. - let mut storage = pool.access_storage().await.unwrap(); - for number in [1, 2, 3] { - let block = load_final_block(&mut storage, number).await; - block.validate(&validator_set, 1).unwrap(); - } -} - -#[test_casing(2, [1, 2])] -#[tokio::test(flavor = "multi_thread")] -async fn syncing_from_non_zero_block(first_block_number: u32) { - abort_on_panic(); - let pool = ConnectionPool::test_pool().await; - let tx_hashes = run_state_keeper_with_multiple_l1_batches(pool.clone()).await; - let tx_hashes: Vec<_> = tx_hashes.iter().map(Vec::as_slice).collect(); - - let mut storage = pool.access_storage().await.unwrap(); - let genesis_block_payload = block_payload(&mut storage, first_block_number) - .await - .encode(); - let ctx = &ctx::test_root(&ctx::AffineClock::new(CLOCK_SPEEDUP as f64)); - let rng = &mut ctx.rng(); - let mut validator = FullValidatorConfig::for_single_validator( - rng, - genesis_block_payload.clone(), - validator::BlockNumber(0), - ); - // Override the genesis block since it has an incorrect block number. - let genesis_block = create_genesis_block( - &validator.validator_key, - first_block_number.into(), - genesis_block_payload, - ); - validator.node_config.genesis_block = genesis_block.clone(); - let validator_set = validator.node_config.validators.clone(); - let external_node = validator.connect_full_node(rng); - - add_consensus_fields( - &mut storage, - &validator.validator_key, - first_block_number..4, - ) - .await; - let mut initial_blocks = reset_storage(storage).await; - let delayed_blocks = initial_blocks.split_off(first_block_number as usize); - assert!(!initial_blocks.is_empty()); - assert!(!delayed_blocks.is_empty()); - let delayed_blocks = convert_sync_blocks(delayed_blocks); - - // Re-insert initial blocks to the storage. This allows to more precisely emulate node syncing - // (e.g., missing L1 batch relation for the latest blocks). - insert_sync_blocks(pool.clone(), initial_blocks, &tx_hashes).await; - tracing::trace!("Re-inserted blocks to node storage"); - - let validator_storage = Arc::new(InMemoryStorage::new(genesis_block)); - let tx_hashes = if first_block_number >= 2 { - &tx_hashes[1..] // Skip transactions in L1 batch #1, since they won't be executed - } else { - &tx_hashes - }; - let (actions_sender, actions) = ActionQueue::new(); - let state_keeper = StateKeeperHandles::new(pool.clone(), actions, tx_hashes).await; - scope::run!(ctx, |ctx, s| async { - let validator = Executor::new( - ctx, - validator.node_config, - validator.node_key, - validator_storage.clone(), - ) - .await?; - - s.spawn_bg(async { validator.run(ctx).await.context("validator.run()") }); - - s.spawn_bg(async { - for block in &delayed_blocks { - ctx.sleep(POLL_INTERVAL).await?; - validator_storage - .put_block(ctx, block) - .await - .wrap("validator_stroage.put_block()")?; - } - Ok(()) - }); - - if first_block_number < 2 { - // L1 batch #1 will be sealed during the state keeper operation; we need to emulate - // computing metadata for it. - s.spawn_bg(async { - ctx.wait(mock_l1_batch_hash_computation(pool.clone(), 1)) - .await?; - Ok(()) - }); - } - - s.spawn_bg(async { - run_gossip_fetcher_inner( - ctx, - pool.clone(), - actions_sender, - external_node.node_config, - external_node.node_key, - OPERATOR_ADDRESS, - ) - .await - .context("run_gossip_fetcher_inner()") - }); - - ctx.wait(state_keeper.wait(|state| state.get_local_block() == MiniblockNumber(3))) - .await?; - Ok(()) - }) - .await - .unwrap(); - - // Check that received blocks have consensus fields persisted. - let mut storage = pool.access_storage().await.unwrap(); - for number in first_block_number..4 { - let block = load_final_block(&mut storage, number).await; - block.justification.verify(&validator_set, 1).unwrap(); - } -} - -async fn insert_sync_blocks(pool: ConnectionPool, blocks: Vec, tx_hashes: &[&[H256]]) { - let expected_block_number = blocks.last().expect("blocks cannot be empty").number; - let sealed_l1_batches = blocks - .iter() - .filter_map(|block| block.last_in_batch.then_some(block.l1_batch_number)); - let sealed_l1_batches: Vec<_> = sealed_l1_batches.collect(); - - let mut fetcher = FetcherCursor::new(&mut pool.access_storage().await.unwrap()) - .await - .unwrap(); - let (actions_sender, actions) = ActionQueue::new(); - let state_keeper = StateKeeperHandles::new(pool.clone(), actions, tx_hashes).await; - for block in blocks { - let block_actions = fetcher.advance(block.try_into().unwrap()); - actions_sender.push_actions(block_actions).await; - } - - let hash_tasks: Vec<_> = sealed_l1_batches - .into_iter() - .map(|l1_batch_number| { - tokio::spawn(mock_l1_batch_hash_computation( - pool.clone(), - l1_batch_number.0, - )) - }) - .collect(); - state_keeper - .wait(|state| state.get_local_block() == expected_block_number) - .await; - for hash_task in hash_tasks { - hash_task.await.unwrap(); - } -} diff --git a/core/lib/zksync_core/src/sync_layer/gossip/utils.rs b/core/lib/zksync_core/src/sync_layer/gossip/utils.rs deleted file mode 100644 index 8407821a2ec6..000000000000 --- a/core/lib/zksync_core/src/sync_layer/gossip/utils.rs +++ /dev/null @@ -1,48 +0,0 @@ -use std::{iter, ops}; - -use zksync_consensus_roles::validator::BlockNumber; - -/// Iterator over missing block numbers. -pub(crate) struct MissingBlockNumbers { - range: ops::Range, - existing_numbers: iter::Peekable, -} - -impl MissingBlockNumbers -where - I: Iterator, -{ - /// Creates a new iterator based on the provided params. - pub(crate) fn new(range: ops::Range, existing_numbers: I) -> Self { - Self { - range, - existing_numbers: existing_numbers.peekable(), - } - } -} - -impl Iterator for MissingBlockNumbers -where - I: Iterator, -{ - type Item = BlockNumber; - - fn next(&mut self) -> Option { - // Loop while existing numbers match the starting numbers from the range. The check - // that the range is non-empty is redundant given how `existing_numbers` are constructed - // (they are guaranteed to be lesser than the upper range bound); we add it just to be safe. - while !self.range.is_empty() - && matches!(self.existing_numbers.peek(), Some(&num) if num == self.range.start) - { - self.range.start = self.range.start.next(); - self.existing_numbers.next(); // Advance to the next number - } - - if self.range.is_empty() { - return None; - } - let next_number = self.range.start; - self.range.start = self.range.start.next(); - Some(next_number) - } -} diff --git a/core/lib/zksync_core/src/sync_layer/metrics.rs b/core/lib/zksync_core/src/sync_layer/metrics.rs index 3a431294b259..51c569b7fccf 100644 --- a/core/lib/zksync_core/src/sync_layer/metrics.rs +++ b/core/lib/zksync_core/src/sync_layer/metrics.rs @@ -3,6 +3,7 @@ use std::time::Duration; use vise::{Buckets, Counter, EncodeLabelSet, EncodeLabelValue, Family, Gauge, Histogram, Metrics}; +use zksync_types::aggregated_operations::AggregatedActionType; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelValue, EncodeLabelSet)] #[metrics(label = "stage", rename_all = "snake_case")] @@ -12,7 +13,9 @@ pub(super) enum FetchStage { SyncL2Block, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelValue, EncodeLabelSet)] +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, EncodeLabelValue, EncodeLabelSet, +)] #[metrics(label = "stage", rename_all = "snake_case")] pub(super) enum L1BatchStage { Open, @@ -21,6 +24,16 @@ pub(super) enum L1BatchStage { Executed, } +impl From for L1BatchStage { + fn from(ty: AggregatedActionType) -> Self { + match ty { + AggregatedActionType::Commit => Self::Committed, + AggregatedActionType::PublishProofOnchain => Self::Proven, + AggregatedActionType::Execute => Self::Executed, + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelValue, EncodeLabelSet)] #[metrics(label = "method", rename_all = "snake_case")] pub(super) enum CachedMethod { diff --git a/core/lib/zksync_core/src/sync_layer/mod.rs b/core/lib/zksync_core/src/sync_layer/mod.rs index df059947e3e3..e216ef4f8c55 100644 --- a/core/lib/zksync_core/src/sync_layer/mod.rs +++ b/core/lib/zksync_core/src/sync_layer/mod.rs @@ -3,7 +3,6 @@ mod client; pub mod external_io; pub mod fetcher; pub mod genesis; -mod gossip; mod metrics; pub(crate) mod sync_action; mod sync_state; @@ -11,6 +10,6 @@ mod sync_state; mod tests; pub use self::{ - client::MainNodeClient, external_io::ExternalIO, gossip::run_gossip_fetcher, - sync_action::ActionQueue, sync_state::SyncState, + client::MainNodeClient, external_io::ExternalIO, sync_action::ActionQueue, + sync_state::SyncState, }; diff --git a/core/lib/zksync_core/src/sync_layer/sync_action.rs b/core/lib/zksync_core/src/sync_layer/sync_action.rs index 994676def491..abaa1d933591 100644 --- a/core/lib/zksync_core/src/sync_layer/sync_action.rs +++ b/core/lib/zksync_core/src/sync_layer/sync_action.rs @@ -1,5 +1,4 @@ use tokio::sync::mpsc; -use zksync_dal::blocks_dal::ConsensusBlockFields; use zksync_types::{Address, L1BatchNumber, MiniblockNumber, ProtocolVersionId, Transaction}; use super::metrics::QUEUE_METRICS; @@ -52,7 +51,7 @@ impl ActionQueueSender { return Err(format!("Unexpected Tx: {:?}", actions)); } } - SyncAction::SealMiniblock(_) | SyncAction::SealBatch { .. } => { + SyncAction::SealMiniblock | SyncAction::SealBatch { .. } => { if !opened || miniblock_sealed { return Err(format!("Unexpected SealMiniblock/SealBatch: {:?}", actions)); } @@ -130,6 +129,7 @@ pub(crate) enum SyncAction { timestamp: u64, l1_gas_price: u64, l2_fair_gas_price: u64, + fair_pubdata_price: Option, operator_address: Address, protocol_version: ProtocolVersionId, // Miniblock number and virtual blocks count. @@ -145,13 +145,11 @@ pub(crate) enum SyncAction { /// that they are sealed, but at the same time the next miniblock may not exist yet. /// By having a dedicated action for that we prevent a situation where the miniblock is kept open on the EN until /// the next one is sealed on the main node. - SealMiniblock(Option), + SealMiniblock, /// Similarly to `SealMiniblock` we must be able to seal the batch even if there is no next miniblock yet. SealBatch { /// Virtual blocks count for the fictive miniblock. virtual_blocks: u32, - /// Consensus-related fields for the fictive miniblock. - consensus: Option, }, } @@ -173,6 +171,7 @@ mod tests { timestamp: 1, l1_gas_price: 1, l2_fair_gas_price: 1, + fair_pubdata_price: Some(1), operator_address: Default::default(), protocol_version: ProtocolVersionId::latest(), first_miniblock_info: (1.into(), 1), @@ -204,14 +203,11 @@ mod tests { } fn seal_miniblock() -> SyncAction { - SyncAction::SealMiniblock(None) + SyncAction::SealMiniblock } fn seal_batch() -> SyncAction { - SyncAction::SealBatch { - virtual_blocks: 1, - consensus: None, - } + SyncAction::SealBatch { virtual_blocks: 1 } } #[test] @@ -246,7 +242,7 @@ mod tests { // Unexpected tx (vec![tx()], "Unexpected Tx"), (vec![open_batch(), seal_miniblock(), tx()], "Unexpected Tx"), - // Unexpected OpenBatch/Miniblock + // Unexpected `OpenBatch/Miniblock` ( vec![miniblock(), miniblock()], "Unexpected OpenBatch/Miniblock", @@ -259,7 +255,7 @@ mod tests { vec![open_batch(), miniblock()], "Unexpected OpenBatch/Miniblock", ), - // Unexpected SealMiniblock + // Unexpected `SealMiniblock` (vec![seal_miniblock()], "Unexpected SealMiniblock"), ( vec![miniblock(), seal_miniblock(), seal_miniblock()], diff --git a/core/lib/zksync_core/src/sync_layer/sync_state.rs b/core/lib/zksync_core/src/sync_layer/sync_state.rs index 8ba2cbb4e98c..32a5c29c1988 100644 --- a/core/lib/zksync_core/src/sync_layer/sync_state.rs +++ b/core/lib/zksync_core/src/sync_layer/sync_state.rs @@ -36,11 +36,11 @@ impl SyncState { self.inner.read().unwrap().local_block.unwrap_or_default() } - pub(super) fn set_main_node_block(&self, block: MiniblockNumber) { + pub(crate) fn set_main_node_block(&self, block: MiniblockNumber) { let mut inner = self.inner.write().unwrap(); if let Some(local_block) = inner.local_block { if block.0 < local_block.0 { - // Probably it's fine -- will be checked by the reorg detector. + // Probably it's fine -- will be checked by the re-org detector. tracing::warn!( "main_node_block({}) is less than local_block({})", block, @@ -56,7 +56,7 @@ impl SyncState { let mut inner = self.inner.write().unwrap(); if let Some(main_node_block) = inner.main_node_block { if block.0 > main_node_block.0 { - // Probably it's fine -- will be checked by the reorg detector. + // Probably it's fine -- will be checked by the re-org detector. tracing::warn!( "local_block({}) is greater than main_node_block({})", block, @@ -86,7 +86,7 @@ impl SyncState { (inner.main_node_block, inner.local_block) { let Some(block_diff) = main_node_block.0.checked_sub(local_block.0) else { - // We're ahead of the main node, this situation is handled by the reorg detector. + // We're ahead of the main node, this situation is handled by the re-org detector. return (true, Some(0)); }; (block_diff <= SYNC_MINIBLOCK_DELTA, Some(block_diff)) @@ -137,7 +137,7 @@ mod tests { sync_state.set_main_node_block(MiniblockNumber(1)); sync_state.set_local_block(MiniblockNumber(2)); - // ^ should not panic, as we defer the situation to the reorg detector. + // ^ should not panic, as we defer the situation to the re-org detector. // At the same time, we should consider ourselves synced unless `ReorgDetector` tells us otherwise. assert!(sync_state.is_synced()); @@ -149,7 +149,7 @@ mod tests { sync_state.set_local_block(MiniblockNumber(2)); sync_state.set_main_node_block(MiniblockNumber(1)); - // ^ should not panic, as we defer the situation to the reorg detector. + // ^ should not panic, as we defer the situation to the re-org detector. // At the same time, we should consider ourselves synced unless `ReorgDetector` tells us otherwise. assert!(sync_state.is_synced()); diff --git a/core/lib/zksync_core/src/sync_layer/tests.rs b/core/lib/zksync_core/src/sync_layer/tests.rs index d11e0f783339..2fc010f4a78f 100644 --- a/core/lib/zksync_core/src/sync_layer/tests.rs +++ b/core/lib/zksync_core/src/sync_layer/tests.rs @@ -10,6 +10,7 @@ use tokio::{sync::watch, task::JoinHandle}; use zksync_config::configs::chain::NetworkConfig; use zksync_dal::{ConnectionPool, StorageProcessor}; use zksync_types::{ + fee_model::{BatchFeeInput, PubdataIndependentBatchFeeModelInput}, Address, L1BatchNumber, L2ChainId, MiniblockNumber, ProtocolVersionId, Transaction, H256, }; @@ -19,14 +20,15 @@ use crate::{ consensus::testonly::MockMainNodeClient, genesis::{ensure_genesis_state, GenesisParams}, state_keeper::{ - tests::{create_l1_batch_metadata, create_l2_transaction, TestBatchExecutorBuilder}, - MiniblockSealer, ZkSyncStateKeeper, + seal_criteria::NoopSealer, tests::TestBatchExecutorBuilder, MiniblockSealer, + ZkSyncStateKeeper, }, + utils::testonly::{create_l1_batch_metadata, create_l2_transaction}, }; const TEST_TIMEOUT: Duration = Duration::from_secs(10); const POLL_INTERVAL: Duration = Duration::from_millis(50); -pub const OPERATOR_ADDRESS: Address = Address::repeat_byte(1); +pub(crate) const OPERATOR_ADDRESS: Address = Address::repeat_byte(1); fn open_l1_batch(number: u32, timestamp: u64, first_miniblock_number: u32) -> SyncAction { SyncAction::OpenBatch { @@ -34,6 +36,7 @@ fn open_l1_batch(number: u32, timestamp: u64, first_miniblock_number: u32) -> Sy timestamp, l1_gas_price: 2, l2_fair_gas_price: 3, + fair_pubdata_price: Some(4), operator_address: OPERATOR_ADDRESS, protocol_version: ProtocolVersionId::latest(), first_miniblock_info: (MiniblockNumber(first_miniblock_number), 1), @@ -65,7 +68,7 @@ impl StateKeeperHandles { actions, sync_state.clone(), Box::::default(), - OPERATOR_ADDRESS, + Address::repeat_byte(1), u32::MAX, L2ChainId::default(), ) @@ -77,10 +80,11 @@ impl StateKeeperHandles { batch_executor_base.push_successful_transactions(tx_hashes_in_l1_batch); } - let state_keeper = ZkSyncStateKeeper::without_sealer( + let state_keeper = ZkSyncStateKeeper::new( stop_receiver, Box::new(io), Box::new(batch_executor_base), + Box::new(NoopSealer), ); Self { stop_sender, @@ -143,7 +147,7 @@ async fn external_io_basics() { let tx = create_l2_transaction(10, 100); let tx_hash = tx.hash(); let tx = SyncAction::Tx(Box::new(tx.into())); - let actions = vec![open_l1_batch, tx, SyncAction::SealMiniblock(None)]; + let actions = vec![open_l1_batch, tx, SyncAction::SealMiniblock]; let (actions_sender, action_queue) = ActionQueue::new(); let state_keeper = @@ -163,16 +167,25 @@ async fn external_io_basics() { .unwrap() .expect("Miniblock #1 is not persisted"); assert_eq!(miniblock.timestamp, 1); - assert_eq!(miniblock.l1_gas_price, 2); - assert_eq!(miniblock.l2_fair_gas_price, 3); + + let expected_fee_input = + BatchFeeInput::PubdataIndependent(PubdataIndependentBatchFeeModelInput { + fair_l2_gas_price: 3, + fair_pubdata_price: 4, + l1_gas_price: 2, + }); + + assert_eq!(miniblock.batch_fee_input, expected_fee_input); assert_eq!(miniblock.l1_tx_count, 0); assert_eq!(miniblock.l2_tx_count, 1); let tx_receipt = storage .transactions_web3_dal() - .get_transaction_receipt(tx_hash) + .get_transaction_receipts(&[tx_hash]) .await .unwrap() + .get(0) + .cloned() .expect("Transaction not persisted"); assert_eq!(tx_receipt.block_number, 1.into()); assert_eq!(tx_receipt.transaction_index, 0.into()); @@ -186,7 +199,7 @@ pub(super) async fn run_state_keeper_with_multiple_miniblocks(pool: ConnectionPo }); let first_miniblock_actions: Vec<_> = iter::once(open_l1_batch) .chain(txs) - .chain([SyncAction::SealMiniblock(None)]) + .chain([SyncAction::SealMiniblock]) .collect(); let open_miniblock = SyncAction::Miniblock { @@ -200,7 +213,7 @@ pub(super) async fn run_state_keeper_with_multiple_miniblocks(pool: ConnectionPo }); let second_miniblock_actions: Vec<_> = iter::once(open_miniblock) .chain(more_txs) - .chain([SyncAction::SealMiniblock(None)]) + .chain([SyncAction::SealMiniblock]) .collect(); let tx_hashes = extract_tx_hashes( @@ -240,7 +253,7 @@ async fn external_io_with_multiple_miniblocks() { let sync_block = storage .sync_dal() - .sync_block(MiniblockNumber(number), OPERATOR_ADDRESS, true) + .sync_block(MiniblockNumber(number), true) .await .unwrap() .unwrap_or_else(|| panic!("Sync block #{} is not persisted", number)); @@ -274,7 +287,7 @@ async fn test_external_io_recovery(pool: ConnectionPool, mut tx_hashes: Vec { + SyncAction::SealMiniblock => { assert_eq!(tx_count_in_miniblock, 1); } } @@ -490,8 +500,13 @@ async fn fetcher_with_real_server() { // Start the API server. let network_config = NetworkConfig::for_tests(); let (stop_sender, stop_receiver) = watch::channel(false); - let server_handles = - spawn_http_server(&network_config, pool.clone(), stop_receiver.clone()).await; + let server_handles = spawn_http_server( + &network_config, + pool.clone(), + Default::default(), + stop_receiver.clone(), + ) + .await; server_handles.wait_until_ready().await; let server_addr = &server_handles.local_addr; @@ -543,7 +558,7 @@ async fn fetcher_with_real_server() { assert_eq!(tx.hash(), tx_hashes.pop_front().unwrap()); tx_count_in_miniblock += 1; } - SyncAction::SealMiniblock(_) => { + SyncAction::SealMiniblock => { assert_eq!( tx_count_in_miniblock, miniblock_number_to_tx_count[¤t_miniblock_number] diff --git a/core/lib/zksync_core/src/temp_config_store.rs b/core/lib/zksync_core/src/temp_config_store.rs index 0c47f5325ac1..d50460a09243 100644 --- a/core/lib/zksync_core/src/temp_config_store.rs +++ b/core/lib/zksync_core/src/temp_config_store.rs @@ -8,13 +8,15 @@ use zksync_config::{ fri_prover_group::FriProverGroupConfig, house_keeper::HouseKeeperConfig, FriProofCompressorConfig, FriProverConfig, FriWitnessGeneratorConfig, PrometheusConfig, - ProofDataHandlerConfig, ProverGroupConfig, WitnessGeneratorConfig, + ProofDataHandlerConfig, WitnessGeneratorConfig, }, ApiConfig, ContractsConfig, DBConfig, ETHClientConfig, ETHSenderConfig, ETHWatchConfig, - GasAdjusterConfig, ObjectStoreConfig, PostgresConfig, ProverConfigs, + GasAdjusterConfig, ObjectStoreConfig, PostgresConfig, }; -// TODO (QIT-22): This structure is going to be removed when components will be respnsible for their own configs. +use crate::consensus; + +// TODO (QIT-22): This structure is going to be removed when components will be responsible for their own configs. /// A temporary config store allowing to pass deserialized configs from `zksync_server` to `zksync_core`. /// All the configs are optional, since for some component combination it is not needed to pass all the configs. #[derive(Debug)] @@ -35,7 +37,6 @@ pub struct TempConfigStore { pub fri_witness_generator_config: Option, pub prometheus_config: Option, pub proof_data_handler_config: Option, - pub prover_group_config: Option, pub witness_generator_config: Option, pub api_config: Option, pub contracts_config: Option, @@ -44,6 +45,6 @@ pub struct TempConfigStore { pub eth_sender_config: Option, pub eth_watch_config: Option, pub gas_adjuster_config: Option, - pub prover_configs: Option, pub object_store_config: Option, + pub consensus_config: Option, } diff --git a/core/lib/zksync_core/src/utils.rs b/core/lib/zksync_core/src/utils/mod.rs similarity index 65% rename from core/lib/zksync_core/src/utils.rs rename to core/lib/zksync_core/src/utils/mod.rs index 351b22350a38..9b3fa3da7991 100644 --- a/core/lib/zksync_core/src/utils.rs +++ b/core/lib/zksync_core/src/utils/mod.rs @@ -1,11 +1,54 @@ //! Miscellaneous utils used by multiple components. -use std::time::Duration; +use std::{future::Future, time::Duration}; +use anyhow::Context as _; +use async_trait::async_trait; use tokio::sync::watch; -use zksync_dal::ConnectionPool; +use zksync_dal::{ConnectionPool, StorageProcessor}; use zksync_types::L1BatchNumber; +#[cfg(test)] +pub(crate) mod testonly; + +/// Fallible and async predicate for binary search. +#[async_trait] +pub(crate) trait BinarySearchPredicate: Send { + type Error; + + async fn eval(&mut self, argument: u32) -> Result; +} + +#[async_trait] +impl BinarySearchPredicate for F +where + F: Send + FnMut(u32) -> Fut, + Fut: Send + Future>, +{ + type Error = E; + + async fn eval(&mut self, argument: u32) -> Result { + self(argument).await + } +} + +/// Finds the greatest `u32` value for which `f` returns `true`. +pub(crate) async fn binary_search_with( + mut left: u32, + mut right: u32, + mut predicate: P, +) -> Result { + while left + 1 < right { + let middle = (left + right) / 2; + if predicate.eval(middle).await? { + left = middle; + } else { + right = middle; + } + } + Ok(left) +} + /// Repeatedly polls the DB until there is an L1 batch. We may not have such a batch initially /// if the DB is recovered from an application-level snapshot. /// @@ -70,6 +113,19 @@ pub(crate) async fn wait_for_l1_batch_with_metadata( } } +/// Returns the projected number of the first locally available L1 batch. The L1 batch is **not** +/// guaranteed to be present in the storage! +pub(crate) async fn projected_first_l1_batch( + storage: &mut StorageProcessor<'_>, +) -> anyhow::Result { + let snapshot_recovery = storage + .snapshot_recovery_dal() + .get_applied_snapshot_status() + .await + .context("failed getting snapshot recovery status")?; + Ok(snapshot_recovery.map_or(L1BatchNumber(0), |recovery| recovery.l1_batch_number + 1)) +} + #[cfg(test)] mod tests { use zksync_types::L2ChainId; @@ -77,6 +133,15 @@ mod tests { use super::*; use crate::genesis::{ensure_genesis_state, GenesisParams}; + #[tokio::test] + async fn test_binary_search() { + for divergence_point in [1, 50, 51, 100] { + let mut f = |x| async move { Ok::<_, ()>(x < divergence_point) }; + let result = binary_search_with(0, 100, &mut f).await; + assert_eq!(result, Ok(divergence_point - 1)); + } + } + #[tokio::test] async fn waiting_for_l1_batch_success() { let pool = ConnectionPool::test_pool().await; diff --git a/core/lib/zksync_core/src/utils/testonly.rs b/core/lib/zksync_core/src/utils/testonly.rs new file mode 100644 index 000000000000..3684e2af9091 --- /dev/null +++ b/core/lib/zksync_core/src/utils/testonly.rs @@ -0,0 +1,202 @@ +//! Test utils. + +use multivm::utils::get_max_gas_per_pubdata_byte; +use zksync_contracts::BaseSystemContractsHashes; +use zksync_dal::StorageProcessor; +use zksync_merkle_tree::{domain::ZkSyncTree, TreeInstruction}; +use zksync_system_constants::ZKPORTER_IS_AVAILABLE; +use zksync_types::{ + block::{L1BatchHeader, MiniblockHeader}, + commitment::{L1BatchMetaParameters, L1BatchMetadata}, + fee::Fee, + fee_model::BatchFeeInput, + l2::L2Tx, + snapshots::SnapshotRecoveryStatus, + transaction_request::PaymasterParams, + Address, L1BatchNumber, L2ChainId, MiniblockNumber, Nonce, ProtocolVersion, ProtocolVersionId, + StorageLog, H256, U256, +}; + +use crate::l1_gas_price::L1GasPriceProvider; + +/// Creates a miniblock header with the specified number and deterministic contents. +pub(crate) fn create_miniblock(number: u32) -> MiniblockHeader { + MiniblockHeader { + number: MiniblockNumber(number), + timestamp: number.into(), + hash: H256::from_low_u64_be(number.into()), + l1_tx_count: 0, + l2_tx_count: 0, + base_fee_per_gas: 100, + batch_fee_input: BatchFeeInput::l1_pegged(100, 100), + fee_account_address: Address::zero(), + gas_per_pubdata_limit: get_max_gas_per_pubdata_byte(ProtocolVersionId::latest().into()), + base_system_contracts_hashes: BaseSystemContractsHashes::default(), + protocol_version: Some(ProtocolVersionId::latest()), + virtual_blocks: 1, + } +} + +/// Creates an L1 batch header with the specified number and deterministic contents. +pub(crate) fn create_l1_batch(number: u32) -> L1BatchHeader { + L1BatchHeader::new( + L1BatchNumber(number), + number.into(), + BaseSystemContractsHashes::default(), + ProtocolVersionId::latest(), + ) +} + +/// Creates metadata for an L1 batch with the specified number. +pub(crate) fn create_l1_batch_metadata(number: u32) -> L1BatchMetadata { + L1BatchMetadata { + root_hash: H256::from_low_u64_be(number.into()), + rollup_last_leaf_index: u64::from(number) + 20, + merkle_root_hash: H256::from_low_u64_be(number.into()), + initial_writes_compressed: vec![], + repeated_writes_compressed: vec![], + commitment: H256::from_low_u64_be(number.into()), + l2_l1_messages_compressed: vec![], + l2_l1_merkle_root: H256::from_low_u64_be(number.into()), + block_meta_params: L1BatchMetaParameters { + zkporter_is_available: ZKPORTER_IS_AVAILABLE, + bootloader_code_hash: BaseSystemContractsHashes::default().bootloader, + default_aa_code_hash: BaseSystemContractsHashes::default().default_aa, + }, + aux_data_hash: H256::zero(), + meta_parameters_hash: H256::zero(), + pass_through_data_hash: H256::zero(), + events_queue_commitment: Some(H256::zero()), + bootloader_initial_content_commitment: Some(H256::zero()), + state_diffs_compressed: vec![], + } +} + +/// Creates an L2 transaction with randomized parameters. +pub(crate) fn create_l2_transaction(fee_per_gas: u64, gas_per_pubdata: u32) -> L2Tx { + let fee = Fee { + gas_limit: 1000_u64.into(), + max_fee_per_gas: fee_per_gas.into(), + max_priority_fee_per_gas: 0_u64.into(), + gas_per_pubdata_limit: gas_per_pubdata.into(), + }; + let mut tx = L2Tx::new_signed( + Address::random(), + vec![], + Nonce(0), + fee, + U256::zero(), + L2ChainId::from(271), + &H256::random(), + None, + PaymasterParams::default(), + ) + .unwrap(); + // Input means all transaction data (NOT calldata, but all tx fields) that came from the API. + // This input will be used for the derivation of the tx hash, so put some random to it to be sure + // that the transaction hash is unique. + tx.set_input(H256::random().0.to_vec(), H256::random()); + tx +} + +/// Prepares a recovery snapshot without performing genesis. +pub(crate) async fn prepare_recovery_snapshot( + storage: &mut StorageProcessor<'_>, + l1_batch_number: u32, + snapshot_logs: &[StorageLog], +) -> SnapshotRecoveryStatus { + let mut storage = storage.start_transaction().await.unwrap(); + + let written_keys: Vec<_> = snapshot_logs.iter().map(|log| log.key).collect(); + let tree_instructions: Vec<_> = snapshot_logs + .iter() + .enumerate() + .map(|(i, log)| TreeInstruction::write(log.key, i as u64 + 1, log.value)) + .collect(); + let l1_batch_root_hash = ZkSyncTree::process_genesis_batch(&tree_instructions).root_hash; + + storage + .protocol_versions_dal() + .save_protocol_version_with_tx(ProtocolVersion::default()) + .await; + // TODO (PLA-596): Don't insert L1 batches / miniblocks once the relevant foreign keys are removed + let miniblock = create_miniblock(l1_batch_number); + storage + .blocks_dal() + .insert_miniblock(&miniblock) + .await + .unwrap(); + let l1_batch = create_l1_batch(l1_batch_number); + storage + .blocks_dal() + .insert_mock_l1_batch(&l1_batch) + .await + .unwrap(); + + storage + .storage_logs_dedup_dal() + .insert_initial_writes(l1_batch.number, &written_keys) + .await; + storage + .storage_logs_dal() + .insert_storage_logs(miniblock.number, &[(H256::zero(), snapshot_logs.to_vec())]) + .await; + storage + .storage_dal() + .apply_storage_logs(&[(H256::zero(), snapshot_logs.to_vec())]) + .await; + + let snapshot_recovery = SnapshotRecoveryStatus { + l1_batch_number: l1_batch.number, + l1_batch_root_hash, + miniblock_number: miniblock.number, + miniblock_root_hash: H256::zero(), // not used + storage_logs_chunks_processed: vec![true; 100], + }; + storage + .snapshot_recovery_dal() + .insert_initial_recovery_status(&snapshot_recovery) + .await + .unwrap(); + storage.commit().await.unwrap(); + snapshot_recovery +} + +// TODO (PLA-596): Replace with `prepare_recovery_snapshot(.., &[])` +pub(crate) async fn prepare_empty_recovery_snapshot( + storage: &mut StorageProcessor<'_>, + l1_batch_number: u32, +) -> SnapshotRecoveryStatus { + storage + .protocol_versions_dal() + .save_protocol_version_with_tx(ProtocolVersion::default()) + .await; + + let snapshot_recovery = SnapshotRecoveryStatus { + l1_batch_number: l1_batch_number.into(), + l1_batch_root_hash: H256::zero(), + miniblock_number: l1_batch_number.into(), + miniblock_root_hash: H256::zero(), // not used + storage_logs_chunks_processed: vec![true; 100], + }; + storage + .snapshot_recovery_dal() + .insert_initial_recovery_status(&snapshot_recovery) + .await + .unwrap(); + snapshot_recovery +} + +/// Mock [`L1GasPriceProvider`] that returns a constant value. +#[derive(Debug)] +pub(crate) struct MockL1GasPriceProvider(pub u64); + +impl L1GasPriceProvider for MockL1GasPriceProvider { + fn estimate_effective_gas_price(&self) -> u64 { + self.0 + } + + fn estimate_effective_pubdata_price(&self) -> u64 { + self.0 * u64::from(zksync_system_constants::L1_GAS_PER_PUBDATA_BYTE) + } +} diff --git a/core/tests/cross_external_nodes_checker/README.md b/core/tests/cross_external_nodes_checker/README.md deleted file mode 100644 index 78c1fe48b40e..000000000000 --- a/core/tests/cross_external_nodes_checker/README.md +++ /dev/null @@ -1,44 +0,0 @@ -# zkSync Cross External Nodes Consistency Checker - -This tool is used to check the consistency of external node instances against the main node. The tool has two main -checkers: - -1. RPC Checker, which checks the consistency of the RPC API of the external node against the main node. -2. PubSub Checker, which checks the consistency of the PubSub API of the external node against the main node. - -Without any arguments, the tool will run both checkers. The RPC Checker will run in Triggered mode, checking all -available blocks, and the PubSub Checker will run for as long as the RPC Checker is working. - -Do note that for the PubSub Checker to properly check the consistency between the nodes, enough time needs to pass. That -is because the PubSub clients may start out of sync. Minimal recommended amount of time for the PubSub Checker is 80 -seconds, which would guarantee at least 20 miniblocks checked. - -## Running locally - -Run the server - -``` -zk init -zk server --components api,tree,eth,state_keeper -``` - -Run the EN - -``` -zk env ext-node -zk clean --database -zk db setup -zk external-node -``` - -Run integration tests to populate the main node with data. - -``` -zk test i server -``` - -Run the checker - -``` -zk run cross-en-checker -``` diff --git a/core/tests/cross_external_nodes_checker/src/checker.rs b/core/tests/cross_external_nodes_checker/src/checker.rs deleted file mode 100644 index 2aa8aa9c4e6c..000000000000 --- a/core/tests/cross_external_nodes_checker/src/checker.rs +++ /dev/null @@ -1,906 +0,0 @@ -use std::{ - cmp::Ordering::{Equal, Greater, Less}, - collections::HashMap, - fmt::Debug, - time::Duration, -}; - -use serde_json::Value; -use tokio::{sync::watch::Receiver, time::sleep}; -use zksync_types::{ - api::{BlockDetails, BlockNumber, L1BatchDetails}, - web3::types::U64, - L1BatchNumber, MiniblockNumber, H256, -}; -use zksync_utils::wait_for_tasks::wait_for_tasks; -use zksync_web3_decl::{ - jsonrpsee::{ - core::ClientError, - http_client::{HttpClient, HttpClientBuilder}, - }, - namespaces::{EnNamespaceClient, EthNamespaceClient, ZksNamespaceClient}, - types::FilterBuilder, - RpcResult, -}; - -use crate::{ - config::{CheckerConfig, RpcMode}, - divergence::{Divergence, DivergenceDetails}, - helpers::compare_json, -}; - -#[derive(Debug, Clone)] -pub struct Checker { - /// 'Triggered' to run once. 'Continuous' to run forever. - mode: RpcMode, - /// Client for interacting with the main node. - main_node_client: HttpClient, - /// Client for interacting with the instance nodes. - instance_clients: Vec, - /// Check all miniblocks starting from this. If 'None' then check from genesis. Inclusive. - start_miniblock: Option, - /// For Triggered mode. If 'None' then check all available miniblocks. Inclusive. - finish_miniblock: Option, - /// In seconds, how often to poll the instance node for new miniblocks. - instance_poll_period: u64, - /// Maps instance URL to a list of its divergences. - divergences: HashMap>, - /// How often should blocks logs be checked. - log_check_interval: u32, - /// Next batch number to check for each instance. - next_batch_to_check: HashMap, - /// The maximum number of transactions to be checked at random in each miniblock. - max_transactions_to_check: Option, -} - -#[derive(Debug, Clone)] -pub struct InstanceHttpClient { - pub url: String, - pub client: HttpClient, -} - -impl Checker { - pub fn new(config: &CheckerConfig) -> Self { - let (main_node_client, instance_clients) = Self::setup_clients( - config - .main_node_http_url - .clone() - .expect("An RPC URL for the main node has to be provided for RPC mode."), - config - .instances_http_urls - .clone() - .expect("RPC URLs for the EN instances have to be provided for RPC mode."), - ); - - let last_checked_batch = instance_clients - .iter() - .map(|instance| (instance.url.clone(), L1BatchNumber(0))) - .collect(); - - let mode = config - .rpc_mode - .expect("The RPC Checker has to be provided an RPC mode"); - - Self { - mode, - main_node_client, - instance_clients, - start_miniblock: config.start_miniblock.map(|n| n.into()), - finish_miniblock: config.finish_miniblock.map(|n| n.into()), - instance_poll_period: config.instance_poll_period.unwrap_or(10), - divergences: HashMap::new(), - log_check_interval: 1, // TODO (BFT-192): make configurable if we want to keep it. - next_batch_to_check: last_checked_batch, - max_transactions_to_check: config.max_transactions_to_check, - } - } - - // Set up clients for the main node and all EN instances we want to check. - fn setup_clients( - main_node_url: String, - instances_urls: Vec, - ) -> (HttpClient, Vec) { - let main_node_client = HttpClientBuilder::default() - .build(main_node_url) - .expect("Failed to create an HTTP client for the main node"); - - let mut instance_clients: Vec = Vec::new(); - for url in instances_urls { - let client = HttpClientBuilder::default() - .build(url.clone()) - .expect("Failed to create an HTTP client for an instance of the external node"); - instance_clients.push(InstanceHttpClient { url, client }); - } - - (main_node_client, instance_clients) - } - - pub async fn run(mut self, stop_receiver: Receiver) -> anyhow::Result<()> { - match self.mode { - RpcMode::Triggered => { - tracing::info!("Starting Checker in Triggered mode"); - if let Err(e) = self.run_triggered().await { - self.log_divergences(); - tracing::error!("Error running in Triggered mode: {:?}", e); - } - // Ensure CI will fail if any divergences were found. - assert!(self.divergences.is_empty(), "Divergences found"); - } - RpcMode::Continuous => { - tracing::info!("Starting Checker in Continuous mode"); - if let Err(e) = self.run_continuous(stop_receiver).await { - tracing::error!("Error running in Continuous mode: {:?}", e); - } - } - } - Ok(()) - } - - // For each instance, spawn a task that will continuously poll the instance for new miniblocks - // and compare them with corresponding main node miniblocks. - // - // Errors in task loops exist the loop, stop the tasks, and cause all other tasks to exit too. - async fn run_continuous(&mut self, mut stop_receiver: Receiver) -> RpcResult<()> { - let mut join_handles = Vec::new(); - - for instance in &self.instance_clients { - let main_node_client = self.main_node_client.clone(); - let instance_client = instance.clone(); - let instance_stop_receiver = stop_receiver.clone(); - let mut checker = self.clone(); - - let handle = tokio::spawn(async move { - tracing::info!("Started a task to check instance {}", instance_client.url); - if let Err(e) = checker.run_node_level_checkers(&instance_client).await { - tracing::error!("Error checking instance {}: {:?}", instance_client.url, e); - }; - let mut next_block_to_check = checker.start_miniblock.unwrap_or(MiniblockNumber(0)); - - // - Get the next block the instance has to be checked. - // - Get the corresponding block from the main node. - // - Run the checkers through the blocks. - // - Maybe check batches. - loop { - tracing::debug!( - "entered loop to check miniblock #({}) for instance: {}", - next_block_to_check, - instance_client.url - ); - - if *instance_stop_receiver.borrow() { - break; - } - - let instance_miniblock = match instance_client - .client - .get_block_details(next_block_to_check) - .await - { - Ok(Some(miniblock)) => miniblock, - Ok(None) => { - tracing::debug!( - "No miniblock found for miniblock #({}). Sleeping for {} seconds", - next_block_to_check, - checker.instance_poll_period - ); - // The instance doesn't have a next block to check yet. For now, we wait until it does. - // TODO(BFT-165): Implement miniblock existence divergence checker. - sleep(Duration::from_secs(checker.instance_poll_period)).await; - continue; - } - Err(e) => { - tracing::error!( - "Error getting miniblock #({}) from instance: {}: {:?}", - next_block_to_check, - instance_client.url, - e - ); - break; - } - }; - - let main_node_miniblock = match main_node_client - .get_block_details(next_block_to_check) - .await - { - Ok(Some(miniblock)) => miniblock, - Ok(None) => { - tracing::error!( - "Miniblock #({}), which exists in external node instance {}, was not found in the main node", - next_block_to_check, instance_client.url - ); - break; - } - Err(e) => { - tracing::error!("Error getting miniblock from main node while checking instance {}: {:?}", instance_client.url, e); - break; - } - }; - - let main_node_miniblock_txs = match checker - .create_tx_map(&main_node_client, main_node_miniblock.number) - .await - { - Ok(tx_map) => tx_map, - Err(e) => { - tracing::error!("Error creating tx map for main node miniblock while checking instance {}: {}", instance_client.url, e); - break; - } - }; - - match checker - .compare_miniblocks( - &instance_client, - &main_node_miniblock_txs, - &main_node_miniblock, - &instance_miniblock, - ) - .await - { - Ok(_) => { - tracing::info!( - "successfully checked miniblock #({}) for instance: {}", - next_block_to_check, - instance_client.url - ); - } - Err(e) => { - tracing::error!( - "Error checking miniblock #({}) for instance {}: {:?}. Skipping this miniblock", - next_block_to_check, - instance_client.url, - e - ); - } - } - next_block_to_check += 1; - - if let Err(e) = checker - .maybe_check_batches(&instance_client, instance_miniblock.l1_batch_number) - .await - { - tracing::error!( - "Error comparing batch {} for instance {}: {:?}", - instance_miniblock.l1_batch_number, - instance_client.url, - e - ); - } - } - Ok(()) - }); - join_handles.push(handle); - } - - // Wait for either all tasks to finish or a stop signal. - tokio::select! { - _ = wait_for_tasks(join_handles, None, None::>, false) => {}, - _ = stop_receiver.changed() => { - tracing::info!("Stop signal received, shutting down"); - }, - } - - Ok(()) - } - - // Iterate through all miniblocks to be checked. For each, run the checkers through every given instance. - async fn run_triggered(&mut self) -> RpcResult<()> { - let start_miniblock = self.start_miniblock.unwrap_or(MiniblockNumber(0)); - let finish_miniblock = match self.finish_miniblock { - Some(finish_miniblock) => finish_miniblock, - None => { - let highest_main_node_miniblock = self.main_node_client.get_block_number().await?; - MiniblockNumber(highest_main_node_miniblock.as_u32()) - } - }; - - for instance_client in self.instance_clients.clone() { - self.run_node_level_checkers(&instance_client).await?; - } - - for miniblock_num_to_check in start_miniblock.0..=finish_miniblock.0 { - let main_node_miniblock = match self - .main_node_client - .get_block_details(MiniblockNumber(miniblock_num_to_check)) - .await - { - Ok(Some(miniblock)) => miniblock, - Ok(None) => panic!("No miniblock found for existing miniblock number {:?}", miniblock_num_to_check), - Err(e) => panic!("Couldn't fetch existing main node miniblock header for miniblock {:?} due to error: {:?}", miniblock_num_to_check, e), - }; - - let main_node_miniblock_txs = self - .create_tx_map(&self.main_node_client, main_node_miniblock.number) - .await?; - - for instance_client in self.instance_clients.clone() { - let instance_miniblock = match instance_client - .client - .get_block_details(MiniblockNumber(miniblock_num_to_check)) - .await? - { - Some(miniblock) => miniblock, - None => { - // TODO(BFT-165): Implement Miniblock Existence Checker - tracing::warn!( - "No miniblock found for miniblock #({}) in instance {}. skipping checking it for now.", - miniblock_num_to_check, - instance_client.url - ); - continue; - } - }; - - self.compare_miniblocks( - &instance_client, - &main_node_miniblock_txs, - &main_node_miniblock, - &instance_miniblock, - ) - .await?; - - self.maybe_check_batches(&instance_client, main_node_miniblock.l1_batch_number) - .await?; - - tracing::info!( - "successfully checked miniblock #({}) for instance: {}", - miniblock_num_to_check, - instance_client.url - ); - } - } - - self.log_divergences(); - - Ok(()) - } - - async fn maybe_check_batches( - &mut self, - instance_client: &InstanceHttpClient, - miniblock_batch_number: L1BatchNumber, - ) -> RpcResult<()> { - let instance_batch_to_check = self - .next_batch_to_check - .get(instance_client.url.as_str()) - .expect("All instance URLs must exists in next_batch_to_check"); - tracing::debug!("Maybe checking batch {}", miniblock_batch_number); - - // We should check batches only the first time we encounter them per instance - // (i.e., next_instance_batch_to_check == miniblock_batch_number) - match instance_batch_to_check.cmp(&miniblock_batch_number) { - Greater => return Ok(()), // This batch has already been checked. - Less => { - // Either somehow a batch wasn't checked or a non-genesis miniblock was set as the start - // miniblock. In the latter case, update the `next_batch_to_check` map and check the batch. - if self.start_miniblock == Some(MiniblockNumber(0)) { - return Err(ClientError::Custom(format!( - "the next batch number to check (#{}) is less than current miniblock batch number (#{}) for instance {}", - instance_batch_to_check, - miniblock_batch_number, - instance_client.url - ))); - } - *self - .next_batch_to_check - .get_mut(instance_client.url.as_str()) - .unwrap() = miniblock_batch_number; - } - Equal => {} - } - - let main_node_batch = match self - .main_node_client - .get_l1_batch_details(miniblock_batch_number) - .await - { - Ok(Some(batch)) => batch, - Ok(None) => panic!( - "No batch found for existing batch with batch number {}", - miniblock_batch_number - ), - Err(e) => panic!( - "Couldn't fetch existing main node batch for batch number {} due to error: {:?}", - miniblock_batch_number, e - ), - }; - - let instance_batch = match instance_client - .client - .get_l1_batch_details(miniblock_batch_number) - .await? - { - Some(batch) => batch, - None => { - // TODO(BFT-165): Implement batch existence checker. - tracing::warn!( - "No batch found for batch #({}) in instance {}. skipping checking it for now.", - miniblock_batch_number, - instance_client.url - ); - return Ok(()); - } - }; - - self.check_batch_details(main_node_batch, instance_batch, &instance_client.url); - - *self - .next_batch_to_check - .get_mut(instance_client.url.as_str()) - .unwrap() += 1; - - Ok(()) - } - - // Check divergences using all checkers for every given pair of miniblocks. - async fn compare_miniblocks( - &mut self, - instance_client: &InstanceHttpClient, - main_node_tx_map: &HashMap, - main_node_miniblock: &BlockDetails, - instance_miniblock: &BlockDetails, - ) -> RpcResult<()> { - self.check_miniblock_details( - &instance_client.url, - main_node_miniblock, - instance_miniblock, - ); - - // Also checks tx receipts and tx details - self.check_transactions(main_node_tx_map, instance_miniblock, instance_client) - .await?; - - self.check_logs(instance_client, main_node_miniblock.number) - .await?; - - Ok(()) - } - - // Run all the checkers that ought to be run once per instance (the non block-dependent checkers.) - async fn run_node_level_checkers( - &mut self, - instance_client: &InstanceHttpClient, - ) -> RpcResult<()> { - self.check_chain_id(instance_client).await?; - self.check_main_contract(instance_client).await?; - self.check_bridge_contracts(instance_client).await?; - self.check_l1_chain_id(instance_client).await?; - Ok(()) - } - - // Add a divergence in Triggered mode; log it in Continuous mode. - fn communicate_divergence(&mut self, url: &str, divergence: Divergence) { - match self.mode { - RpcMode::Triggered => { - // Add a divergence to the list of divergences for the given EN instance. - let divergences = self.divergences.entry(url.to_string()).or_default(); - divergences.push(divergence.clone()); - tracing::error!("{}", divergence); - } - RpcMode::Continuous => { - // Simply log for now. TODO(BFT-177): Add grafana metrics. - tracing::error!("{}", divergence); - } - } - } - - // Create a mapping from the tx hash to a json representation of the tx. - async fn create_tx_map( - &self, - client: &HttpClient, - miniblock_num: MiniblockNumber, - ) -> RpcResult> { - let txs = client - .sync_l2_block(miniblock_num, true) - .await? - .and_then(|block| block.transactions) - .unwrap_or_default(); - - let mut tx_map = HashMap::new(); - for tx in txs { - tx_map.insert( - tx.hash(), - serde_json::to_value(tx).expect("tx serialization fail"), - ); - } - - Ok(tx_map) - } - - fn log_divergences(&mut self) { - if self.divergences.is_empty() { - tracing::info!("No divergences found"); - return; - } - for (url, divergences) in &self.divergences { - tracing::error!("Divergences found for URL: {}", url); - for divergence in divergences { - tracing::error!("{}", divergence); - } - } - } -} - -// Separate impl for the checkers. -impl Checker { - fn check_batch_details( - &mut self, - main_node_batch: L1BatchDetails, - instance_batch: L1BatchDetails, - instance_url: &str, - ) { - tracing::debug!( - "Checking batch details for batch #({})", - main_node_batch.number - ); - let batch_differences = compare_json(&main_node_batch, &instance_batch, "".to_string()); - for (key, (main_node_val, instance_val)) in batch_differences { - self.communicate_divergence( - instance_url, - Divergence::BatchDetails(DivergenceDetails { - en_instance_url: instance_url.to_string(), - main_node_value: Some(format!("{}: {:?}", key, main_node_val)), - en_instance_value: Some(format!("{}: {:?}", key, instance_val)), - entity_id: Some(format!("Batch Number: {}", main_node_batch.number)), - miniblock_number: None, - }), - ); - } - } - - // TODO: What if when we checked the miniblock when the status was Sealed but not Verified? - fn check_miniblock_details( - &mut self, - instance_url: &str, - main_node_miniblock: &BlockDetails, - instance_miniblock: &BlockDetails, - ) { - tracing::debug!( - "Checking miniblock details for miniblock #({})", - main_node_miniblock.number - ); - let details_differences = - compare_json(main_node_miniblock, instance_miniblock, "".to_string()); - for (key, (main_node_val, instance_val)) in details_differences { - self.communicate_divergence( - instance_url, - Divergence::MiniblockDetails(DivergenceDetails { - en_instance_url: instance_url.to_string(), - main_node_value: Some(format!("{}: {:?}", key, main_node_val)), - en_instance_value: Some(format!("{}: {:?}", key, instance_val)), - entity_id: None, - miniblock_number: Some(main_node_miniblock.number), - }), - ); - } - } - - // Looks for txs existing in one node's miniblock and not the other, for - // discrepancies in the content of txs, and runs the individual transaction checkers. - async fn check_transactions( - &mut self, - main_node_tx_map: &HashMap, - instance_miniblock: &BlockDetails, - instance_client: &InstanceHttpClient, - ) -> RpcResult<()> { - let mut instance_tx_map = self - .create_tx_map(&instance_client.client, instance_miniblock.number) - .await?; - - tracing::debug!( - "Checking transactions for miniblock #({}) that has {} transactions", - instance_miniblock.number, - instance_tx_map.len(), - ); - - for (i, (tx_hash, main_node_tx)) in main_node_tx_map.iter().enumerate() { - if let Some(max_num) = self.max_transactions_to_check { - if i >= max_num { - return Ok(()); - } - } - match instance_tx_map.remove(tx_hash) { - Some(instance_tx) => { - if *main_node_tx != instance_tx { - let tx_differences = - compare_json(main_node_tx, &instance_tx, "".to_string()); - for (key, (main_node_val, instance_val)) in tx_differences { - self.communicate_divergence( - &instance_client.url, - Divergence::Transaction(DivergenceDetails { - en_instance_url: instance_client.url.to_string(), - main_node_value: Some(format!("{}: {:?}", key, main_node_val)), - en_instance_value: Some(format!("{}: {:?}", key, instance_val)), - entity_id: Some(format!("Tx Hash: {}", tx_hash)), - miniblock_number: Some(instance_miniblock.number), - }), - ); - } - } else { - self.check_transaction_receipt( - instance_client, - tx_hash, - instance_miniblock.number, - ) - .await?; - - self.check_transaction_details( - instance_client, - tx_hash, - instance_miniblock.number, - ) - .await?; - } - } - None => { - self.communicate_divergence( - &instance_client.url, - Divergence::Transaction(DivergenceDetails { - en_instance_url: instance_client.url.to_string(), - main_node_value: Some(tx_hash.to_string()), - en_instance_value: None, - entity_id: Some(format!("Tx Hash: {}", tx_hash)), - miniblock_number: Some(instance_miniblock.number), - }), - ); - tracing::debug!( - "Added divergence for a tx that is in main node but not in instance: {:?}", - tx_hash - ); - } - } - } - - // If there are txs left in the instance tx map, then they don't exist in the main node. - for tx_hash in instance_tx_map.keys() { - self.communicate_divergence( - &instance_client.url, - Divergence::Transaction(DivergenceDetails { - en_instance_url: instance_client.url.to_string(), - main_node_value: None, - en_instance_value: Some(tx_hash.to_string()), - entity_id: Some(format!("Tx Hash: {}", tx_hash)), - miniblock_number: Some(instance_miniblock.number), - }), - ); - tracing::debug!( - "Added divergence for a tx that is in instance but not in main node: {:?}", - tx_hash - ); - } - - Ok(()) - } - - async fn check_transaction_receipt( - &mut self, - instance_client: &InstanceHttpClient, - tx_hash: &H256, - miniblock_number: MiniblockNumber, - ) -> RpcResult<()> { - tracing::debug!( - "Checking receipts for a tx in miniblock {}", - miniblock_number - ); - - let main_node_receipt = self - .main_node_client - .get_transaction_receipt(*tx_hash) - .await?; - let instance_receipt = instance_client - .client - .get_transaction_receipt(*tx_hash) - .await?; - - let receipt_differences = - compare_json(&main_node_receipt, &instance_receipt, "".to_string()); - for (key, (main_node_val, instance_val)) in receipt_differences { - self.communicate_divergence( - &instance_client.url, - Divergence::TransactionReceipt(DivergenceDetails { - en_instance_url: instance_client.url.to_string(), - main_node_value: Some(format!("{}: {:?}", key, main_node_val)), - en_instance_value: Some(format!("{}: {:?}", key, instance_val)), - entity_id: Some(format!("Tx Hash: {}", tx_hash)), - miniblock_number: Some(miniblock_number), - }), - ); - } - - Ok(()) - } - - async fn check_transaction_details( - &mut self, - instance_client: &InstanceHttpClient, - tx_hash: &H256, - miniblock_number: MiniblockNumber, - ) -> RpcResult<()> { - tracing::debug!( - "Checking transaction details for a tx in miniblock {}", - miniblock_number - ); - - let main_node_tx_details = self - .main_node_client - .get_transaction_details(*tx_hash) - .await?; - let instance_tx_details = instance_client - .client - .get_transaction_details(*tx_hash) - .await?; - - let tx_details_differences = - compare_json(&main_node_tx_details, &instance_tx_details, "".to_string()); - for (key, (main_node_val, instance_val)) in tx_details_differences { - self.communicate_divergence( - &instance_client.url, - Divergence::TransactionDetails(DivergenceDetails { - en_instance_url: instance_client.url.to_string(), - main_node_value: Some(format!("{}: {:?}", key, main_node_val)), - en_instance_value: Some(format!("{}: {:?}", key, instance_val)), - entity_id: Some(format!("Tx Hash: {}", tx_hash)), - miniblock_number: Some(miniblock_number), - }), - ); - } - - Ok(()) - } - - async fn check_logs( - &mut self, - instance_client: &InstanceHttpClient, - current_miniblock_block_num: MiniblockNumber, - ) -> RpcResult<()> { - let from_block = current_miniblock_block_num - .0 - .checked_sub(self.log_check_interval); - let to_block = current_miniblock_block_num.0; - - if from_block < Some(0) || to_block % self.log_check_interval != 0 { - tracing::debug!("Skipping log check for miniblock {}", to_block); - return Ok(()); - } - tracing::debug!( - "Checking logs for miniblocks {}-{}", - from_block.unwrap(), - to_block - 1 - ); - - let filter = FilterBuilder::default() - .set_from_block(BlockNumber::Number(U64::from(from_block.unwrap()))) - .set_to_block(BlockNumber::Number(U64::from(&to_block - 1))) - .build(); - - let main_node_logs = match self.main_node_client.get_logs(filter.clone()).await { - Ok(logs) => logs, - Err(e) => { - // TODO(BFT-192): Be more specific with checking logs - tracing::error!("Failed to get logs from main node: {}", e); - return Ok(()); - } - }; - let instance_logs = match instance_client.client.get_logs(filter).await { - Ok(logs) => logs, - Err(e) => { - // TODO(BFT-192): Be more specific with checking logs - tracing::error!("Failed to get logs from instance: {}", e); - return Ok(()); - } - }; - - for (main_node_log, instance_log) in main_node_logs.iter().zip(instance_logs.iter()) { - let log_differences = compare_json(&main_node_log, &instance_log, "".to_string()); - for (key, (main_node_val, instance_val)) in log_differences { - self.communicate_divergence( - &instance_client.url, - Divergence::Log(DivergenceDetails { - en_instance_url: instance_client.url.to_string(), - main_node_value: Some(format!("{}: {:?}", key, main_node_val)), - en_instance_value: Some(format!("{}: {:?}", key, instance_val)), - entity_id: None, - miniblock_number: Some(MiniblockNumber( - main_node_log.block_number.unwrap().as_u32(), - )), - }), - ); - } - } - - Ok(()) - } - - async fn check_main_contract(&mut self, instance_client: &InstanceHttpClient) -> RpcResult<()> { - let main_node_main_contract = self.main_node_client.get_main_contract().await?; - let instance_main_contract = instance_client.client.get_main_contract().await?; - - let contract_differences = compare_json( - &main_node_main_contract, - &instance_main_contract, - "".to_string(), - ); - for (key, (main_node_val, instance_val)) in contract_differences { - self.communicate_divergence( - &instance_client.url, - Divergence::MainContracts(DivergenceDetails { - en_instance_url: instance_client.url.to_string(), - main_node_value: Some(format!("{} {:?}", key, main_node_val)), - en_instance_value: Some(format!("{} {:?}", key, instance_val)), - entity_id: None, - miniblock_number: None, - }), - ); - } - - Ok(()) - } - - async fn check_chain_id(&mut self, instance_client: &InstanceHttpClient) -> RpcResult<()> { - let main_node_chain_id = self.main_node_client.chain_id().await?; - let instance_chain_id = instance_client.client.chain_id().await?; - - if main_node_chain_id != instance_chain_id { - self.communicate_divergence( - &instance_client.url, - Divergence::ChainID(DivergenceDetails { - en_instance_url: instance_client.url.to_string(), - main_node_value: Some(main_node_chain_id), - en_instance_value: Some(instance_chain_id), - entity_id: None, - miniblock_number: None, - }), - ); - } - - Ok(()) - } - - async fn check_l1_chain_id(&mut self, instance_client: &InstanceHttpClient) -> RpcResult<()> { - let main_node_chain_id = self.main_node_client.l1_chain_id().await?; - let instance_chain_id = instance_client.client.l1_chain_id().await?; - - if main_node_chain_id != instance_chain_id { - self.communicate_divergence( - &instance_client.url, - Divergence::L1ChainID(DivergenceDetails { - en_instance_url: instance_client.url.to_string(), - main_node_value: Some(main_node_chain_id), - en_instance_value: Some(instance_chain_id), - entity_id: None, - miniblock_number: None, - }), - ); - } - - Ok(()) - } - - async fn check_bridge_contracts( - &mut self, - instance_client: &InstanceHttpClient, - ) -> RpcResult<()> { - let main_node_bridge_contracts = self.main_node_client.get_bridge_contracts().await?; - let instance_bridge_contracts = instance_client.client.get_bridge_contracts().await?; - - let receipt_differences = compare_json( - &main_node_bridge_contracts, - &instance_bridge_contracts, - "".to_string(), - ); - for (key, (main_node_val, instance_val)) in receipt_differences { - self.communicate_divergence( - &instance_client.url, - Divergence::BridgeContracts(DivergenceDetails { - en_instance_url: instance_client.url.to_string(), - main_node_value: Some(format!("{}: {:?}", key, main_node_val)), - en_instance_value: Some(format!("{}: {:?}", key, instance_val)), - entity_id: None, - miniblock_number: None, - }), - ); - } - - Ok(()) - } -} diff --git a/core/tests/cross_external_nodes_checker/src/config.rs b/core/tests/cross_external_nodes_checker/src/config.rs deleted file mode 100644 index 636a4fd9ae58..000000000000 --- a/core/tests/cross_external_nodes_checker/src/config.rs +++ /dev/null @@ -1,171 +0,0 @@ -use envy::prefixed; -use serde::Deserialize; - -#[derive(Debug, Deserialize, PartialEq)] -pub struct CheckerConfig { - #[serde(default = "default_mode")] - pub mode: Mode, - - #[serde(default = "default_rpc_mode")] - pub rpc_mode: Option, - - #[serde(default = "default_start_miniblock")] - pub start_miniblock: Option, - - #[serde(default = "default_finish_miniblock")] - pub finish_miniblock: Option, - - #[serde(default = "default_main_node_http_url")] - pub main_node_http_url: Option, - - #[serde(default = "default_instances_http_urls")] - pub instances_http_urls: Option>, - - #[serde(default = "default_main_node_ws_url")] - pub main_node_ws_url: Option, - - #[serde(default = "default_instances_ws_urls")] - pub instances_ws_urls: Option>, - - #[serde(default = "default_max_transactions_to_check")] - pub max_transactions_to_check: Option, - - #[serde(default = "default_instance_poll_period")] - pub instance_poll_period: Option, - - #[serde(default = "default_subscription_duration")] - pub subscription_duration: Option, -} - -#[derive(Copy, Clone, Debug, Deserialize, PartialEq)] -pub enum Mode { - Rpc, - PubSub, - All, -} - -impl Mode { - pub fn run_rpc(&self) -> bool { - matches!(self, Mode::Rpc | Mode::All) - } - - pub fn run_pubsub(&self) -> bool { - matches!(self, Mode::PubSub | Mode::All) - } -} - -#[derive(Copy, Clone, Debug, Deserialize, PartialEq)] -pub enum RpcMode { - Triggered, - Continuous, -} - -impl CheckerConfig { - pub fn from_env() -> Self { - prefixed("CHECKER_") - .from_env() - .unwrap_or_else(|err| panic!("Failed to load the checker config with error: {}", err)) - } -} - -// Default functions for each of the fields - -fn default_mode() -> Mode { - Mode::All -} - -fn default_rpc_mode() -> Option { - Some(RpcMode::Triggered) -} - -fn default_start_miniblock() -> Option { - None -} - -fn default_finish_miniblock() -> Option { - None -} - -fn default_main_node_http_url() -> Option { - Some("http://127.0.0.1:3050".to_string()) -} - -fn default_instances_http_urls() -> Option> { - Some(vec!["http://127.0.0.1:3060".to_string()]) -} - -fn default_main_node_ws_url() -> Option { - Some("ws://127.0.0.1:3051".to_string()) -} - -fn default_instances_ws_urls() -> Option> { - Some(vec!["ws://127.0.0.1:3061".to_string()]) -} - -fn default_max_transactions_to_check() -> Option { - Some(3) -} - -fn default_instance_poll_period() -> Option { - Some(10) -} - -fn default_subscription_duration() -> Option { - None -} - -#[cfg(test)] -mod tests { - use std::env; - - use super::*; - - #[test] - fn success() { - let config = r#" - CHECKER_MODE="Rpc" - CHECKER_RPC_MODE="Continuous" - CHECKER_START_MINIBLOCK="2" - CHECKER_FINISH_MINIBLOCK="4" - CHECKER_MAIN_NODE_HTTP_URL="http://127.0.0.1:1020" - CHECKER_INSTANCES_HTTP_URLS="http://127.0.0.1:1030,http://127.0.0.1:1020" - CHECKER_INSTANCE_POLL_PERIOD="60" - CHECKER_MAX_TRANSACTIONS_TO_CHECK="10" - CHECKER_SUBSCRIPTION_DURATION="120" - "#; - - set_env(config); - - let actual = CheckerConfig::from_env(); - let want = CheckerConfig { - mode: Mode::Rpc, - rpc_mode: Some(RpcMode::Continuous), - start_miniblock: Some(2), - finish_miniblock: Some(4), - main_node_http_url: Some("http://127.0.0.1:1020".into()), - instances_http_urls: Some(vec![ - "http://127.0.0.1:1030".into(), - "http://127.0.0.1:1020".into(), - ]), - main_node_ws_url: Some("ws://127.0.0.1:3051".into()), - instances_ws_urls: Some(vec!["ws://127.0.0.1:3061".into()]), - instance_poll_period: Some(60), - max_transactions_to_check: Some(10), - subscription_duration: Some(120), - }; - assert_eq!(actual, want); - } - - pub fn set_env(fixture: &str) { - for line in fixture.split('\n').map(str::trim) { - if line.is_empty() { - continue; - } - let elements: Vec<_> = line.split('=').collect(); - let variable_name = elements[0]; - let variable_value = elements[1].trim_matches('"'); - - env::set_var(variable_name, variable_value); - } - } -} diff --git a/core/tests/cross_external_nodes_checker/src/divergence.rs b/core/tests/cross_external_nodes_checker/src/divergence.rs deleted file mode 100644 index 18c910349f79..000000000000 --- a/core/tests/cross_external_nodes_checker/src/divergence.rs +++ /dev/null @@ -1,89 +0,0 @@ -use std::fmt; - -use zksync_types::{web3::types::U64, MiniblockNumber}; - -#[derive(Debug, Clone)] -pub(crate) enum Divergence { - BatchDetails(DivergenceDetails>), - MiniblockDetails(DivergenceDetails>), - Transaction(DivergenceDetails>), - TransactionReceipt(DivergenceDetails>), - TransactionDetails(DivergenceDetails>), - Log(DivergenceDetails>), - MainContracts(DivergenceDetails>), - BridgeContracts(DivergenceDetails>), - ChainID(DivergenceDetails>), - L1ChainID(DivergenceDetails>), - PubSubHeader(DivergenceDetails>), -} - -impl fmt::Display for Divergence { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Divergence::BatchDetails(details) => { - write!(f, "Batch Details divergence found: {}", details) - } - Divergence::MiniblockDetails(details) => { - write!(f, "Miniblock Details divergence found: {}", details) - } - Divergence::Transaction(details) => { - write!(f, "Transaction divergence found: {}", details) - } - Divergence::TransactionReceipt(details) => { - write!(f, "TransactionReceipt divergence found: {}", details) - } - Divergence::TransactionDetails(details) => { - write!(f, "TransactionDetails divergence found: {}", details) - } - Divergence::Log(details) => write!(f, "Log divergence found: {}", details), - Divergence::MainContracts(details) => { - write!(f, "MainContracts divergence found: {}", details) - } - Divergence::BridgeContracts(details) => { - write!(f, "BridgeContracts divergence found: {}", details) - } - Divergence::ChainID(details) => write!(f, "ChainID divergence found: {}", details), - Divergence::L1ChainID(details) => { - write!(f, "L1ChainID divergence found: {}", details) - } - Divergence::PubSubHeader(details) => { - write!(f, "PubSubHeader divergence found: {}", details) - } - } - } -} - -#[derive(Debug, Clone)] -pub(crate) struct DivergenceDetails { - pub(crate) en_instance_url: String, - pub(crate) main_node_value: T, - pub(crate) en_instance_value: T, - pub(crate) entity_id: Option, - pub(crate) miniblock_number: Option, -} - -impl fmt::Display for DivergenceDetails> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let main_node_value = match &self.main_node_value { - Some(value) => format!("{}", value), - None => String::from("None"), - }; - let en_instance_value = match &self.en_instance_value { - Some(value) => format!("{}", value), - None => String::from("None"), - }; - let entity_info = match self.entity_id { - Some(ref entity_id) => format!(", Entity ID: {}", entity_id), - None => String::from(""), - }; - let miniblock_number = match self.miniblock_number { - Some(ref number) => format!(", Miniblock number: {}", number), - None => String::from(""), - }; - write!( - f, - "Main node value: {}, EN instance value: {}{} in EN instance: {}{}", - main_node_value, en_instance_value, miniblock_number, self.en_instance_url, entity_info - ) - } -} diff --git a/core/tests/cross_external_nodes_checker/src/helpers.rs b/core/tests/cross_external_nodes_checker/src/helpers.rs deleted file mode 100644 index 6247b5e8c8ad..000000000000 --- a/core/tests/cross_external_nodes_checker/src/helpers.rs +++ /dev/null @@ -1,326 +0,0 @@ -use std::{collections::HashMap, future::Future, time::Duration}; - -use futures::channel::oneshot; -use serde_json::{Map, Value}; -use tokio::time::sleep; - -/// Sets up an interrupt handler and returns a future that resolves once an interrupt signal is received. -pub fn setup_sigint_handler() -> oneshot::Receiver<()> { - let (sigint_sender, sigint_receiver) = oneshot::channel(); - let mut sigint_sender = Some(sigint_sender); - ctrlc::set_handler(move || { - if let Some(sigint_sender) = sigint_sender.take() { - sigint_sender.send(()).ok(); - // ^ The send fails if `sigint_receiver` is dropped. We're OK with this, - // since at this point the node should be stopping anyway, or is not interested - // in listening to interrupt signals. - } - }) - .expect("Error setting Ctrl+C handler"); - - sigint_receiver -} - -pub fn compare_json( - a: &T, - b: &T, - path: String, -) -> HashMap, Option)> { - let a = serde_json::to_value(a).expect("serialization failure"); - let b = serde_json::to_value(b).expect("serialization failure"); - - if a == b { - return HashMap::new(); - } - - match (a, b) { - (Value::Object(ref a), Value::Object(ref b)) => compare_json_object(a, b, path), - (Value::Array(ref a), Value::Array(ref b)) => compare_json_array(a, b, path), - (a, b) => { - let mut res = HashMap::new(); - let a_val = if a.is_null() { None } else { Some(a) }; - let b_val = if b.is_null() { None } else { Some(b) }; - res.insert(path, (a_val, b_val)); - res - } - } -} - -fn compare_json_object( - a: &Map, - b: &Map, - path: String, -) -> HashMap, Option)> { - let mut differences = HashMap::new(); - - for (k, v) in a.iter() { - let new_path = if path.is_empty() { - k.clone() - } else { - format!("{}.{}", path, k) - }; - - differences.extend(compare_json(v, b.get(k).unwrap_or(&Value::Null), new_path)); - } - - for (k, v) in b.iter() { - if !a.contains_key(k) { - let new_path = if path.is_empty() { - k.clone() - } else { - format!("{}.{}", path, k) - }; - differences.insert(new_path, (None, Some(v.clone()))); - } - } - - differences -} - -fn compare_json_array( - a: &Vec, - b: &Vec, - path: String, -) -> HashMap, Option)> { - let mut differences = HashMap::new(); - - let len = a.len().max(b.len()); - for i in 0..len { - let new_path = format!("{}[{}]", path, i); - differences.extend(compare_json( - a.get(i).unwrap_or(&Value::Null), - b.get(i).unwrap_or(&Value::Null), - new_path, - )); - } - - differences -} - -#[derive(Debug, Clone)] -pub struct ExponentialBackoff { - pub max_retries: u32, - pub base_delay: Duration, - pub retry_message: String, -} - -impl ExponentialBackoff { - // Keep retrying until the operation returns Some or we reach the max number of retries. - pub async fn retry(&self, mut operation: F) -> Option - where - F: FnMut() -> Fut, - Fut: Future>, - { - for retry in 1..=self.max_retries { - if let Some(result) = operation().await { - return Some(result); - } - if retry == self.max_retries { - break; - } - let delay = self.base_delay * retry; - tracing::warn!( - "{} Retrying in {} seconds", - self.retry_message, - delay.as_secs() - ); - sleep(delay).await; - } - None - } -} - -#[cfg(test)] -mod tests { - use serde_json::json; - - use super::*; - - #[test] - fn test_same_json() { - let json1 = json!({ - "key1": "value1", - "key2": 2, - "key3": [ - "value2", - "+value3" - ] - }); - - let differences = compare_json(&json1, &json1, "".to_string()); - assert_eq!(differences.len(), 0); - } - - #[test] - fn test_deeply_nested_objects() { - let a = json!({ - "key1": { - "subkey1": { - "subsubkey1": "value1", - "subsubkey2": "value2" - }, - "subkey2": "value3" - }, - "key2": "value4" - }); - - let b = json!({ - "key1": { - "subkey1": { - "subsubkey1": "value1", - "subsubkey2": "value5" - }, - "subkey2": "value6" - }, - "key2": "value4" - }); - - let differences = compare_json(&a, &b, "".to_string()); - - assert_eq!(differences.len(), 2); - assert_eq!( - differences.get("key1.subkey1.subsubkey2"), - Some(&(Some(json!("value2")), Some(json!("value5")))) - ); - assert_eq!( - differences.get("key1.subkey2"), - Some(&(Some(json!("value3")), Some(json!("value6")))) - ); - } - - #[test] - fn test_diff_different_keys() { - let a = json!({ - "key1": "value1", - "key2": "value2" - }); - - let b = json!({ - "key1": "value1", - "key3": "value3" - }); - - let differences = compare_json(&a, &b, "".to_string()); - - assert_eq!(differences.len(), 2); - assert_eq!( - differences.get("key2"), - Some(&(Some(json!("value2")), None)) - ); - assert_eq!( - differences.get("key3"), - Some(&(None, Some(json!("value3")))) - ); - } - - #[test] - fn test_diff_different_types() { - let a = json!({ - "key1": true, - "key2": 123, - "key3": "value1" - }); - - let b = json!({ - "key1": false, - "key2": "123", - "key3": "value2" - }); - - let differences = compare_json(&a, &b, "".to_string()); - - assert_eq!(differences.len(), 3); - assert_eq!( - differences.get("key1"), - Some(&(Some(json!(true)), Some(json!(false)))) - ); - assert_eq!( - differences.get("key2"), - Some(&(Some(json!(123)), Some(json!("123")))) - ); - assert_eq!( - differences.get("key3"), - Some(&(Some(json!("value1")), Some(json!("value2")))) - ); - } - - #[test] - fn test_empty_jsons() { - let json1 = json!({}); - let json2 = json!([]); - - let differences = compare_json(&json1, &json1, "".to_string()); - assert_eq!(differences.len(), 0); - - let differences = compare_json(&json2, &json2, "".to_string()); - assert_eq!(differences.len(), 0); - - let differences = compare_json(&json1, &json2, "".to_string()); - assert_eq!(differences.len(), 1); - } - - #[test] - fn test_one_empty_json() { - let json1 = json!({}); - let json2 = json!({ - "key1": "value1", - "key2": 2, - }); - - let differences = compare_json(&json1, &json2, "".to_string()); - assert_eq!(differences.len(), 2); - - let differences = compare_json(&json2, &json1, "".to_string()); - assert_eq!(differences.len(), 2); - } - - #[test] - fn test_json_with_null() { - let a = json!({ - "key1": null, - "key2": "value2" - }); - - let b = json!({ - "key1": "value1", - "key2": null - }); - - let differences = compare_json(&a, &b, "".to_string()); - - assert_eq!(differences.len(), 2); - assert_eq!( - differences.get("key1"), - Some(&(None, Some(json!("value1")))) - ); - assert_eq!( - differences.get("key2"), - Some(&(Some(json!("value2")), None)) - ); - } - - #[test] - fn test_arrays_different_lengths() { - let a = json!([1, 2, 3]); - let b = json!([1, 2, 3, 4]); - - let differences = compare_json(&a, &b, "".to_string()); - - assert_eq!(differences.len(), 1); - assert_eq!(differences.get("[3]"), Some(&(None, Some(json!(4))))); - } - - #[test] - fn test_arrays_with_nested_objects() { - let a = json!([{"key1": "value1"}, {"key2": "value2"}]); - let b = json!([{"key1": "value1"}, {"key2": "value3"}]); - - let differences = compare_json(&a, &b, "".to_string()); - - assert_eq!(differences.len(), 1); - assert_eq!( - differences.get("[1].key2"), - Some(&(Some(json!("value2")), Some(json!("value3")))) - ); - } -} diff --git a/core/tests/cross_external_nodes_checker/src/main.rs b/core/tests/cross_external_nodes_checker/src/main.rs deleted file mode 100644 index 7199c1cbd32c..000000000000 --- a/core/tests/cross_external_nodes_checker/src/main.rs +++ /dev/null @@ -1,65 +0,0 @@ -use tokio::sync::watch; -use zksync_utils::wait_for_tasks::wait_for_tasks; - -use self::{checker::Checker, pubsub_checker::PubSubChecker}; -use crate::{config::CheckerConfig, helpers::setup_sigint_handler}; - -mod checker; -mod config; -mod divergence; -mod helpers; -mod pubsub_checker; - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let log_format = vlog::log_format_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let sentry_url = vlog::sentry_url_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let environment = vlog::environment_from_env(); - - let mut builder = vlog::ObservabilityBuilder::new().with_log_format(log_format); - if let Some(sentry_url) = sentry_url { - builder = builder - .with_sentry_url(&sentry_url) - .expect("Invalid Sentry URL") - .with_sentry_environment(environment); - } - let _guard = builder.build(); - - tracing::info!("Started the Cross Node Checker"); - - let config = CheckerConfig::from_env(); - tracing::info!("Loaded the checker config: {:?}", config); - - let mut join_handles = Vec::new(); - let sigint_receiver = setup_sigint_handler(); - let (stop_sender, stop_receiver) = watch::channel::(false); - - if config.mode.run_rpc() { - let cross_node_checker = Checker::new(&config); - let checker_stop_receiver = stop_receiver.clone(); - let checker_handle = - tokio::spawn(async move { cross_node_checker.run(checker_stop_receiver).await }); - join_handles.push(checker_handle); - } - - if config.mode.run_pubsub() { - let pubsub_checker = PubSubChecker::new(config).await; - let pubsub_stop_receiver = stop_receiver.clone(); - let pubsub_handle = - tokio::spawn(async move { pubsub_checker.run(pubsub_stop_receiver).await }); - join_handles.push(pubsub_handle); - } - - tokio::select! { - _ = wait_for_tasks(join_handles, None, None::>, false) => {}, - _ = sigint_receiver => { - let _ = stop_sender.send(true); - tracing::info!("Stop signal received, shutting down the cross EN Checker"); - }, - } - - Ok(()) -} diff --git a/core/tests/cross_external_nodes_checker/src/pubsub_checker.rs b/core/tests/cross_external_nodes_checker/src/pubsub_checker.rs deleted file mode 100644 index 3e000e83d8f5..000000000000 --- a/core/tests/cross_external_nodes_checker/src/pubsub_checker.rs +++ /dev/null @@ -1,311 +0,0 @@ -use std::{ - collections::HashMap, - sync::Arc, - time::{Duration, Instant}, -}; - -use anyhow::Context as _; -use tokio::{ - select, spawn, - sync::{watch::Receiver, Mutex as TokioMutex}, - time::timeout, -}; -use zksync_types::{web3::types::U64, MiniblockNumber}; -use zksync_utils::wait_for_tasks::wait_for_tasks; -use zksync_web3_decl::{ - jsonrpsee::{ - core::{ - client::{Subscription, SubscriptionClientT}, - ClientError, - }, - rpc_params, - ws_client::{WsClient, WsClientBuilder}, - }, - types::{BlockHeader, PubSubResult}, -}; - -use crate::{ - config::CheckerConfig, - divergence::{Divergence, DivergenceDetails}, - helpers::{compare_json, ExponentialBackoff}, -}; - -const MAX_RETRIES: u32 = 6; -const GRACE_PERIOD: Duration = Duration::from_secs(60); -const SUBSCRIPTION_TIMEOUT: Duration = Duration::from_secs(120); - -#[derive(Debug, Clone)] -pub struct PubSubChecker { - main_node_url: String, - instance_urls: Vec, - /// Time in seconds for a subscription to be active. If `None`, the subscription will run forever. - subscription_duration: Option, - /// Mapping of block numbers to the block header and the number of instances that still need to - /// check the corresponding header. This Hashmap is shared between all threads. - /// The number of instances is used to determine when to remove the block from the hashmap. - pub blocks: Arc>>, -} - -impl PubSubChecker { - pub async fn new(config: CheckerConfig) -> Self { - let duration = config.subscription_duration.map(Duration::from_secs); - Self { - main_node_url: config - .main_node_ws_url - .expect("WS URL for the main node has to be provided for PubSub mode."), - instance_urls: config - .instances_ws_urls - .expect("WS URLs for the EN instances have to be provided for PubSub mode."), - subscription_duration: duration, - blocks: Arc::new(TokioMutex::new(HashMap::new())), - } - } - - pub async fn run(&self, mut stop_receiver: Receiver) -> anyhow::Result<()> { - tracing::info!("Started pubsub checker"); - - let mut join_handles = Vec::new(); - - let this = self.clone(); - let main_stop_receiver = stop_receiver.clone(); - let handle = spawn(async move { - tracing::info!("Started a task to subscribe to the main node"); - if let Err(e) = this.subscribe_main(main_stop_receiver).await { - tracing::error!("Error in main node subscription task: {}", e); - } - Ok(()) - }); - join_handles.push(handle); - - let instance_urls = self.instance_urls.clone(); - for instance_url in &instance_urls { - let this = self.clone(); - let instance_stop_receiver = stop_receiver.clone(); - let url = instance_url.clone(); - let handle = spawn(async move { - tracing::info!("Started a task to subscribe to instance {}", url); - this.subscribe_instance(&url, instance_stop_receiver) - .await - .with_context(|| format!("Error in instance {} subscription task", url)) - }); - join_handles.push(handle); - } - - select! { - _ = wait_for_tasks(join_handles, None, None::>, false) => {}, - _ = stop_receiver.changed() => { - tracing::info!("Stop signal received, shutting down pubsub checker"); - }, - } - Ok(()) - } - - // Setup a client for the main node, subscribe, and insert incoming pubsub results into the shared hashmap. - async fn subscribe_main(&self, stop_receiver: Receiver) -> anyhow::Result<()> { - let client = self.setup_client(&self.main_node_url).await; - let params = rpc_params!["newHeads"]; - - let mut subscription: Subscription = client - .subscribe("eth_subscribe", params, "eth_unsubscribe") - .await?; - - let start = Instant::now(); - loop { - if self.check_if_loop_should_break(&stop_receiver, &start, &self.main_node_url) { - break; - } - - let no_res_timeout_duration = self.get_timeout_duration(&start); - let stream_res = timeout(no_res_timeout_duration, subscription.next()) - .await - .map_err(|_| - anyhow::anyhow!( - "OperationTimeout: Haven't gotten an item for over {} seconds subscribing to the main node", - no_res_timeout_duration.as_secs() - ) - )?; - let pubsub_res = stream_res.ok_or_else(|| anyhow::anyhow!("Stream has ended"))?; - - let (block_header, block_number) = self.extract_block_info(pubsub_res).await?; - - // Secure the lock for the map and insert the new header. - let mut blocks = self.blocks.lock().await; - blocks.insert(block_number, (block_header, self.instance_urls.len())); - tracing::debug!("Inserted block {} to main node map", block_number); - } - - Ok(()) - } - - // Setup a client for the instance node, subscribe, and compare incoming pubsub results to the main node's. - async fn subscribe_instance( - &self, - url: &str, - stop_receiver: Receiver, - ) -> anyhow::Result<()> { - let client = self.setup_client(url).await; - let params = rpc_params!["newHeads"]; - - let mut subscription: Subscription = client - .subscribe("eth_subscribe", params, "eth_unsubscribe") - .await?; - - let start = Instant::now(); - loop { - if self.check_if_loop_should_break(&stop_receiver, &start, url) { - break; - } - - let no_res_timeout_duration = self.get_timeout_duration(&start); - let stream_res = timeout(no_res_timeout_duration, subscription.next()) - .await - .map_err(|_| - anyhow::anyhow!( - "OperationTimeout: Haven't gotten an item for over {} seconds subscribing to instance {}", - no_res_timeout_duration.as_secs(), url - ) - )?; - let pubsub_res = stream_res.ok_or_else(|| anyhow::anyhow!("Stream has ended"))?; - let (instance_block_header, block_number) = self.extract_block_info(pubsub_res).await?; - tracing::debug!("Got block {} from instance {}", block_number, url); - - // Get the main node block header from the map and update its count. - // This should be retried because the map not having the block the instance does might - // just mean the main node subscriber is lagging. - let backoff = ExponentialBackoff { - max_retries: MAX_RETRIES, - base_delay: Duration::from_secs(1), - retry_message: format!( - "block {} is still not present in main node map for instance {}.", - block_number, url, - ), - }; - let main_node_value = backoff - // Wait for the block to appear in the main node map. - .retry(|| { - async move { - let mut blocks = self.blocks.lock().await; - let main_node_value = blocks.get(&block_number).cloned(); - match main_node_value { - Some((header, count)) => { - if count > 1 { - blocks.insert(block_number, (header.clone(), count - 1)); - } else { - blocks.remove(&block_number); - } - tracing::debug!("Updated blocks map: {:?}", blocks.keys()); - Some((header, count)) - } - None => None, // Retry - } - } - }) - .await; - - // If main node map contained the header, compare main & instance headers. - match main_node_value { - Some((main_node_header, _)) => { - self.check_headers(&main_node_header, &instance_block_header, url); - } - None => { - // If the main subscriber starts ahead of an instance subscriber, the map may - // start with block X while instance is looking for block X-1, which will never - // be in the map. We don't want to log an error for this case. - if start.elapsed() > GRACE_PERIOD { - tracing::error!( - "block {} has not been found in the main node map for instance {} after {} retries", - block_number, - url, - MAX_RETRIES - ); - } - } - }; - } - - Ok(()) - } - - fn get_timeout_duration(&self, start: &Instant) -> Duration { - match self.subscription_duration { - Some(duration) => std::cmp::min( - duration.checked_sub(start.elapsed()), - Some(SUBSCRIPTION_TIMEOUT), - ) - .unwrap(), - None => SUBSCRIPTION_TIMEOUT, - } - } - - fn check_if_loop_should_break( - &self, - stop_receiver: &Receiver, - start: &Instant, - url: &str, - ) -> bool { - if *stop_receiver.borrow() { - tracing::info!("Stop signal received, shutting down pubsub checker"); - return true; - } - if let Some(duration) = self.subscription_duration { - if start.elapsed() > duration { - tracing::info!("Client {} reached its subscription duration", url); - return true; - } - } - false - } - - async fn setup_client(&self, url: &str) -> WsClient { - WsClientBuilder::default() - .build(url) - .await - .expect("Failed to create a WS client") - } - - // Extract the block header and block number from the pubsub result that is expected to be a header. - async fn extract_block_info( - &self, - pubsub_res: Result, - ) -> Result<(BlockHeader, U64), anyhow::Error> { - let PubSubResult::Header(header) = pubsub_res? else { - return Err(anyhow::anyhow!("Received non-header pubsub result")); - }; - - let Some(block_number) = header.number else { - return Err(anyhow::anyhow!("Received header without block number.")); - }; - - Ok((header, block_number)) - } - - fn check_headers( - &self, - main_node_header: &BlockHeader, - instance_header: &BlockHeader, - instance_url: &str, - ) { - let header_differences = compare_json(&main_node_header, &instance_header, "".to_string()); - if header_differences.is_empty() { - tracing::info!( - "No divergences found in header for block {} for instance {}", - instance_header.number.unwrap().as_u64(), - instance_url - ); - } - for (key, (main_node_val, instance_val)) in header_differences { - tracing::error!( - "{}", - Divergence::PubSubHeader(DivergenceDetails { - en_instance_url: instance_url.to_string(), - main_node_value: Some(format!("{}: {:?}", key, main_node_val)), - en_instance_value: Some(format!("{}: {:?}", key, instance_val)), - entity_id: None, - miniblock_number: Some(MiniblockNumber( - main_node_header.number.unwrap().as_u32() - )), - }), - ); - } - } -} diff --git a/core/tests/loadnext/src/account/mod.rs b/core/tests/loadnext/src/account/mod.rs index 46b5d04ba235..9a1243151d0e 100644 --- a/core/tests/loadnext/src/account/mod.rs +++ b/core/tests/loadnext/src/account/mod.rs @@ -136,7 +136,7 @@ impl AccountLifespan { let is_l1_transaction = matches!(command.command_type, TxType::L1Execute | TxType::Deposit); if is_l1_transaction && l1_tx_count >= MAX_L1_TRANSACTIONS { - continue; // Skip command to not run out of ethereum on L1 + continue; // Skip command to not run out of Ethereum on L1 } // The new transaction should be sent only if mempool is not full diff --git a/core/tests/loadnext/src/account/tx_command_executor.rs b/core/tests/loadnext/src/account/tx_command_executor.rs index 5c51a68376d5..618a671bbb2e 100644 --- a/core/tests/loadnext/src/account/tx_command_executor.rs +++ b/core/tests/loadnext/src/account/tx_command_executor.rs @@ -20,7 +20,9 @@ use zksync_types::{ use crate::{ account::{AccountLifespan, ExecutionType}, command::{IncorrectnessModifier, TxCommand, TxType}, - constants::{ETH_CONFIRMATION_TIMEOUT, ETH_POLLING_INTERVAL}, + constants::{ + ETH_CONFIRMATION_TIMEOUT, ETH_POLLING_INTERVAL, MIN_ALLOWANCE_FOR_PAYMASTER_ESTIMATE, + }, corrupted_tx::Corrupted, report::ReportLabel, utils::format_gwei, @@ -201,7 +203,7 @@ impl AccountLifespan { }?; // Update current nonce for future txs - // If the transaction has a tx_hash and is small enough to be included in a block, this tx will change the nonce. + // If the transaction has a `tx_hash` and is small enough to be included in a block, this tx will change the nonce. // We can be sure that the nonce will be changed based on this assumption. if let SubmitResult::TxHash(_) = &result { self.current_nonce = Some(nonce + 1) @@ -228,6 +230,7 @@ impl AccountLifespan { .estimate_fee(Some(get_approval_based_paymaster_input_for_estimation( self.paymaster_address, self.main_l2_token, + MIN_ALLOWANCE_FOR_PAYMASTER_ESTIMATE.into(), ))) .await?; builder = builder.fee(fee.clone()); @@ -276,6 +279,7 @@ impl AccountLifespan { .estimate_fee(Some(get_approval_based_paymaster_input_for_estimation( self.paymaster_address, self.main_l2_token, + MIN_ALLOWANCE_FOR_PAYMASTER_ESTIMATE.into(), ))) .await?; builder = builder.fee(fee.clone()); @@ -403,6 +407,7 @@ impl AccountLifespan { .estimate_fee(Some(get_approval_based_paymaster_input_for_estimation( self.paymaster_address, self.main_l2_token, + MIN_ALLOWANCE_FOR_PAYMASTER_ESTIMATE.into(), ))) .await?; tracing::trace!( diff --git a/core/tests/loadnext/src/account_pool.rs b/core/tests/loadnext/src/account_pool.rs index 730a6d07b48d..a6ae8cd68163 100644 --- a/core/tests/loadnext/src/account_pool.rs +++ b/core/tests/loadnext/src/account_pool.rs @@ -90,7 +90,7 @@ impl AccountPool { /// Generates all the required test accounts and prepares `Wallet` objects. pub async fn new(config: &LoadtestConfig) -> anyhow::Result { let l2_chain_id = L2ChainId::try_from(config.l2_chain_id).unwrap(); - // Create a client for pinging the rpc. + // Create a client for pinging the RPC. let client = HttpClientBuilder::default() .build(&config.l2_rpc_address) .unwrap(); diff --git a/core/tests/loadnext/src/command/api.rs b/core/tests/loadnext/src/command/api.rs index 76ed5db57470..278f4e1a7496 100644 --- a/core/tests/loadnext/src/command/api.rs +++ b/core/tests/loadnext/src/command/api.rs @@ -73,7 +73,7 @@ async fn random_block_number(wallet: &SyncWallet, rng: &mut LoadtestRng) -> api: match block_number { BlockNumber::Committed => api::BlockNumber::Committed, BlockNumber::Number => { - // Choose a random block in the range [0, latest_committed_block_number). + // Choose a random block in the range `[0, latest_committed_block_number)`. match wallet .provider .get_block_by_number(api::BlockNumber::Committed, false) diff --git a/core/tests/loadnext/src/config.rs b/core/tests/loadnext/src/config.rs index 6620e3aed579..2cc6317059dc 100644 --- a/core/tests/loadnext/src/config.rs +++ b/core/tests/loadnext/src/config.rs @@ -152,8 +152,8 @@ fn default_l1_rpc_address() -> String { fn default_master_wallet_pk() -> String { // Use this key only for localhost because it is compromised! - // Using this key for rinkeby will result in losing rinkeby ETH. - // Corresponding wallet is 0x36615Cf349d7F6344891B1e7CA7C72883F5dc049 + // Using this key for Rinkeby will result in losing Rinkeby ETH. + // Corresponding wallet is `0x36615Cf349d7F6344891B1e7CA7C72883F5dc049` let result = "7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110".to_string(); tracing::info!("Using default MASTER_WALLET_PK: {result}"); result @@ -181,7 +181,7 @@ fn default_main_token() -> H160 { // Read token addresses from `etc/tokens/localhost.json`. Use the first one // as a main token since all of them are suitable. - // 0xeb8f08a975Ab53E34D8a0330E0D34de942C95926 for rinkeby + // `0xeb8f08a975Ab53E34D8a0330E0D34de942C95926` for Rinkeby let tokens = read_tokens(Network::Localhost).expect("Failed to parse tokens file"); let main_token = tokens.first().expect("Loaded tokens list is empty"); tracing::info!("Main token: {main_token:?}"); @@ -225,7 +225,7 @@ fn default_seed() -> Option { } fn default_l2_chain_id() -> u64 { - // 270 for rinkeby + // 270 for Rinkeby let result = L2ChainId::default().as_u64(); tracing::info!("Using default L2_CHAIN_ID: {result}"); result @@ -236,14 +236,14 @@ pub fn get_default_l2_rpc_address() -> String { } fn default_l2_rpc_address() -> String { - // https://z2-dev-api.zksync.dev:443 for stage2 + // `https://z2-dev-api.zksync.dev:443` for stage2 let result = get_default_l2_rpc_address(); tracing::info!("Using default L2_RPC_ADDRESS: {result}"); result } fn default_l2_ws_rpc_address() -> String { - // ws://z2-dev-api.zksync.dev:80/ws for stage2 + // `ws://z2-dev-api.zksync.dev:80/ws` for stage2 let result = "ws://127.0.0.1:3051".to_string(); tracing::info!("Using default L2_WS_RPC_ADDRESS: {result}"); result diff --git a/core/tests/loadnext/src/constants.rs b/core/tests/loadnext/src/constants.rs index 582a03f31f78..7ac66ab7e1e7 100644 --- a/core/tests/loadnext/src/constants.rs +++ b/core/tests/loadnext/src/constants.rs @@ -36,3 +36,8 @@ pub const MIN_PAYMASTER_BALANCE: u128 = 10u128.pow(18) * 50; /// If the paymaster balance is lower than MIN_PAYMASTER_BALANCE, /// loadtest will deposit funds to the paymaster account so that its balance reaches this value pub const TARGET_PAYMASTER_BALANCE: u128 = 10u128.pow(18) * 60; + +/// Min allowance for estimating the price for the paymaster transaction. +/// It should be roughly equal (or maybe a bit higher) than the actual used tokens in the transaction for the most precise +/// estimations. Note, however that is must not be higher than the ERC20 balance of the account. +pub const MIN_ALLOWANCE_FOR_PAYMASTER_ESTIMATE: u128 = 10u128.pow(18); diff --git a/core/tests/loadnext/src/executor.rs b/core/tests/loadnext/src/executor.rs index d6e233a1f491..42ef346ff7f7 100644 --- a/core/tests/loadnext/src/executor.rs +++ b/core/tests/loadnext/src/executor.rs @@ -54,7 +54,7 @@ impl Executor { ) -> anyhow::Result { let pool = AccountPool::new(&config).await?; - // derive l2 main token address + // derive L2 main token address let l2_main_token = pool .master_wallet .ethereum(&config.l1_rpc_address) @@ -442,6 +442,7 @@ impl Executor { let paymaster_params = get_approval_based_paymaster_input_for_estimation( paymaster_address, self.l2_main_token, + MIN_ALLOWANCE_FOR_PAYMASTER_ESTIMATE.into(), ); let fee = builder.estimate_fee(Some(paymaster_params)).await?; diff --git a/core/tests/loadnext/src/report_collector/metrics_collector.rs b/core/tests/loadnext/src/report_collector/metrics_collector.rs index 6c5867901b12..90775f039ebf 100644 --- a/core/tests/loadnext/src/report_collector/metrics_collector.rs +++ b/core/tests/loadnext/src/report_collector/metrics_collector.rs @@ -151,7 +151,7 @@ mod tests { #[test] fn histogram_window_size() { - // Vector of ((window_idx, window_size), expected_range)). + // Vector of `((window_idx, window_size), expected_range))`. let test_vector = [ ((0, 100), (0, 99)), ((1, 100), (100, 199)), diff --git a/core/tests/loadnext/src/rng.rs b/core/tests/loadnext/src/rng.rs index 3612a7c2a847..20f163e69ee2 100644 --- a/core/tests/loadnext/src/rng.rs +++ b/core/tests/loadnext/src/rng.rs @@ -45,7 +45,7 @@ impl LoadtestRng { // We chain the current seed bytes and the Ethereum private key together, // and then calculate the hash of this data. // This way we obtain a derived seed, unique for each wallet, which will result in - // an uniques set of operations for each account. + // an unique set of operations for each account. let input_bytes: Vec = self .seed .iter() diff --git a/core/tests/revert-test/tests/revert-and-restart.test.ts b/core/tests/revert-test/tests/revert-and-restart.test.ts index bbbd51368592..9911a5b06b5d 100644 --- a/core/tests/revert-test/tests/revert-and-restart.test.ts +++ b/core/tests/revert-test/tests/revert-and-restart.test.ts @@ -60,6 +60,12 @@ describe('Block reverting test', function () { let blocksCommittedBeforeRevert: number; let logs: fs.WriteStream; + let enable_consensus = process.env.ENABLE_CONSENSUS == 'true'; + let components = 'api,tree,eth,state_keeper'; + if (enable_consensus) { + components += ',consensus'; + } + before('create test wallet', async () => { tester = await Tester.init(process.env.CHAIN_ETH_NETWORK || 'localhost'); alice = tester.emptyWallet(); @@ -76,7 +82,7 @@ describe('Block reverting test', function () { process.env.DATABASE_MERKLE_TREE_MODE = 'full'; // Run server in background. - const components = 'api,tree,eth,state_keeper'; + utils.background(`zk server --components ${components}`, [null, logs, logs]); // Server may need some time to recompile if it's a cold run, so wait for it. let iter = 0; @@ -172,7 +178,7 @@ describe('Block reverting test', function () { process.env.ETH_SENDER_SENDER_AGGREGATED_BLOCK_EXECUTE_DEADLINE = '1'; // Run server. - utils.background('zk server --components api,tree,eth,state_keeper', [null, logs, logs]); + utils.background(`zk server --components ${components}`, [null, logs, logs]); await utils.sleep(10); const balanceBefore = await alice.getBalance(); @@ -209,7 +215,7 @@ describe('Block reverting test', function () { await killServerAndWaitForShutdown(tester); // Run again. - utils.background(`zk server --components=api,tree,eth,state_keeper`, [null, logs, logs]); + utils.background(`zk server --components=${components}`, [null, logs, logs]); await utils.sleep(10); // Trying to send a transaction from the same address again diff --git a/core/tests/test_account/Cargo.toml b/core/tests/test_account/Cargo.toml new file mode 100644 index 000000000000..2c6d206b8dd3 --- /dev/null +++ b/core/tests/test_account/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "zksync_test_account" +version = "0.1.0" +edition = "2018" +authors = ["The Matter Labs Team "] +homepage = "https://zksync.io/" +repository = "https://github.com/matter-labs/zksync-era" +license = "MIT OR Apache-2.0" +keywords = ["blockchain", "zksync"] +categories = ["cryptography"] +readme = "README.md" +publish = false + +[dependencies] +zksync_types = { path = "../../lib/types" } +zksync_system_constants = { path = "../../lib/constants" } +zksync_utils = { path = "../../lib/utils" } +zksync_eth_signer = { path = "../../lib/eth_signer" } +zksync_contracts = { path = "../../lib/contracts" } + +hex = "0.4" +ethabi = "18.0.0" diff --git a/core/lib/test_account/src/lib.rs b/core/tests/test_account/src/lib.rs similarity index 97% rename from core/lib/test_account/src/lib.rs rename to core/tests/test_account/src/lib.rs index 5a84c84f4f52..ec3c1b7a7b0f 100644 --- a/core/lib/test_account/src/lib.rs +++ b/core/tests/test_account/src/lib.rs @@ -4,7 +4,8 @@ use zksync_contracts::{ }; use zksync_eth_signer::{raw_ethereum_tx::TransactionParameters, EthereumSigner, PrivateKeySigner}; use zksync_system_constants::{ - CONTRACT_DEPLOYER_ADDRESS, MAX_GAS_PER_PUBDATA_BYTE, REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE, + CONTRACT_DEPLOYER_ADDRESS, DEFAULT_L2_TX_GAS_PER_PUBDATA_BYTE, + REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE, }; use zksync_types::{ fee::Fee, @@ -94,7 +95,7 @@ impl Account { gas_limit: U256::from(2000000000u32), max_fee_per_gas: U256::from(BASE_FEE), max_priority_fee_per_gas: U256::from(100), - gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), + gas_per_pubdata_limit: U256::from(DEFAULT_L2_TX_GAS_PER_PUBDATA_BYTE), } } diff --git a/core/tests/ts-integration/contracts/counter/zkVM_bytecode.txt b/core/tests/ts-integration/contracts/counter/zkVM_bytecode.txt new file mode 100644 index 000000000000..d47161d8fcdc --- /dev/null +++ b/core/tests/ts-integration/contracts/counter/zkVM_bytecode.txt @@ -0,0 +1 @@ +0x000100000000000200000000000103550000008003000039000000400030043f0000000003010019000000600330027000000027033001970000000102200190000000160000c13d000000040230008c000000550000413d000000000201043b000000e002200270000000290420009c0000001e0000a13d0000002a0420009c0000002b0000613d0000002b0420009c000000320000613d0000002c0120009c0000004a0000613d000000550000013d0000000001000416000000000101004b000000550000c13d0000002001000039000001000010044300000120000004430000002801000041000000970001042e0000002d0420009c000000470000613d0000002e0220009c000000550000c13d0000000002000416000000000202004b000000550000c13d000000040230008a000000200220008c000000550000413d0000000401100370000000000101043b000000570000013d0000000001000416000000000101004b000000550000c13d000000000100041a000000800010043f0000003101000041000000970001042e0000000002000416000000000202004b000000550000c13d000000040230008a000000200220008c000000550000413d0000000401100370000000000101043b000000000200041a0000000001120019000000000221004b000000000200001900000001020040390000000102200190000000570000613d0000002f0100004100000000001004350000001101000039000000040010043f000000300100004100000098000104300000000001000416000000000101004b000000550000c13d00000000010300190096005a0000040f009600730000040f000000400200043d00000000001204350000002701000041000000270320009c0000000002018019000000400120021000000032011001c7000000970001042e00000000010000190000009800010430000000000010041b0000000001000019000000970001042e000000040110008a00000033020000410000003f0310008c000000000300001900000000030220190000003301100197000000000401004b0000000002008019000000330110009c000000000203c019000000000102004b000000710000613d00000000010003670000002402100370000000000202043b000000000302004b0000000003000019000000010300c039000000000332004b000000710000c13d0000000401100370000000000101043b000000000001042d00000000010000190000009800010430000000000300041a0000000001130019000000000331004b0000000003000019000000010300403900000001033001900000007e0000c13d000000000010041b000000000202004b000000840000c13d000000000001042d0000002f0100004100000000001004350000001101000039000000040010043f00000030010000410000009800010430000000400100043d00000044021000390000003403000041000000000032043500000024021000390000001a030000390000000000320435000000350200004100000000002104350000000402100039000000200300003900000000003204350000002702000041000000270310009c0000000001028019000000400110021000000036011001c700000098000104300000009600000432000000970001042e000000980001043000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000200000000000000000000000000000040000001000000000000000000000000000000000000000000000000000000000000000000000000006d4ce63b000000000000000000000000000000000000000000000000000000006d4ce63c000000000000000000000000000000000000000000000000000000007cf5dab0000000000000000000000000000000000000000000000000000000008f9c4749000000000000000000000000000000000000000000000000000000000436dad60000000000000000000000000000000000000000000000000000000060fe47b14e487b7100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002400000000000000000000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000020000000000000000000000000800000000000000000000000000000000000000000000000000000000000000054686973206d6574686f6420616c77617973207265766572747300000000000008c379a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000000000000000000000000000005912077dbccfda7879a1765d5b280b2a37169a97193512ab62bd94e5027c06b3 \ No newline at end of file diff --git a/core/tests/ts-integration/hardhat.config.ts b/core/tests/ts-integration/hardhat.config.ts index 0626064aa0f5..00abe2b32efb 100644 --- a/core/tests/ts-integration/hardhat.config.ts +++ b/core/tests/ts-integration/hardhat.config.ts @@ -4,7 +4,7 @@ import '@matterlabs/hardhat-zksync-vyper'; export default { zksolc: { - version: '1.3.18', + version: '1.3.21', compilerSource: 'binary', settings: { isSystem: true diff --git a/core/tests/ts-integration/scripts/compile-yul.ts b/core/tests/ts-integration/scripts/compile-yul.ts index cefcfa902af0..bdf253644180 100644 --- a/core/tests/ts-integration/scripts/compile-yul.ts +++ b/core/tests/ts-integration/scripts/compile-yul.ts @@ -7,7 +7,7 @@ import { getZksolcUrl, saltFromUrl } from '@matterlabs/hardhat-zksync-solc'; import { getCompilersDir } from 'hardhat/internal/util/global-dir'; import path from 'path'; -const COMPILER_VERSION = '1.3.18'; +const COMPILER_VERSION = '1.3.21'; const IS_COMPILER_PRE_RELEASE = false; async function compilerLocation(): Promise { diff --git a/core/tests/ts-integration/src/env.ts b/core/tests/ts-integration/src/env.ts index 1f376e815d79..a0e5fc9ced43 100644 --- a/core/tests/ts-integration/src/env.ts +++ b/core/tests/ts-integration/src/env.ts @@ -137,6 +137,9 @@ type L1Token = { function getTokens(network: string): L1Token[] { const configPath = `${process.env.ZKSYNC_HOME}/etc/tokens/${network}.json`; + if (!fs.existsSync(configPath)) { + return []; + } return JSON.parse( fs.readFileSync(configPath, { encoding: 'utf-8' diff --git a/core/tests/ts-integration/tests/api/contract-verification.test.ts b/core/tests/ts-integration/tests/api/contract-verification.test.ts index acd2a7673577..61112ba685e2 100644 --- a/core/tests/ts-integration/tests/api/contract-verification.test.ts +++ b/core/tests/ts-integration/tests/api/contract-verification.test.ts @@ -9,8 +9,9 @@ import { sleep } from 'zksync-web3/build/src/utils'; // Regular expression to match ISO dates. const DATE_REGEX = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{6})?/; -const ZKSOLC_VERSION = 'v1.3.18'; +const ZKSOLC_VERSION = 'v1.3.21'; const SOLC_VERSION = '0.8.23'; +const ZK_VM_SOLC_VERSION = 'zkVM-0.8.23-1.0.0'; const ZKVYPER_VERSION = 'v1.3.13'; const VYPER_VERSION = '0.3.10'; @@ -67,6 +68,32 @@ describe('Tests for the contract verification API', () => { await expectVerifyRequestToSucceed(requestId, requestBody); }); + test('should test zkVM solc contract verification', async () => { + let artifact = contracts.counter; + // TODO: use plugin compilation when it's ready instead of pre-compiled bytecode. + artifact.bytecode = fs.readFileSync( + `${process.env.ZKSYNC_HOME}/core/tests/ts-integration/contracts/counter/zkVM_bytecode.txt`, + 'utf8' + ); + + const counterContract = await deployContract(alice, artifact, []); + const constructorArguments = counterContract.interface.encodeDeploy([]); + + const requestBody = { + contractAddress: counterContract.address, + contractName: 'contracts/counter/counter.sol:Counter', + sourceCode: getContractSource('counter/counter.sol'), + compilerZksolcVersion: ZKSOLC_VERSION, + compilerSolcVersion: ZK_VM_SOLC_VERSION, + optimizationUsed: true, + constructorArguments, + isSystem: true + }; + let requestId = await query('POST', '/contract_verification', undefined, requestBody); + + await expectVerifyRequestToSucceed(requestId, requestBody); + }); + test('should test multi-files contract verification', async () => { const contractFactory = new zksync.ContractFactory(contracts.create.abi, contracts.create.bytecode, alice); const contractHandle = await contractFactory.deploy({ diff --git a/core/tests/ts-integration/tests/api/web3.test.ts b/core/tests/ts-integration/tests/api/web3.test.ts index 000b61276be3..70ea34816e2d 100644 --- a/core/tests/ts-integration/tests/api/web3.test.ts +++ b/core/tests/ts-integration/tests/api/web3.test.ts @@ -39,12 +39,23 @@ describe('web3 API compatibility tests', () => { const blockWithTxsByNumber = await alice.provider.getBlockWithTransactions(blockNumber); expect(blockWithTxsByNumber.gasLimit).bnToBeGt(0); let sumTxGasUsed = ethers.BigNumber.from(0); + for (const tx of blockWithTxsByNumber.transactions) { const receipt = await alice.provider.getTransactionReceipt(tx.hash); sumTxGasUsed = sumTxGasUsed.add(receipt.gasUsed); } expect(blockWithTxsByNumber.gasUsed).bnToBeGte(sumTxGasUsed); + let expectedReceipts = []; + + for (const tx of blockWithTxsByNumber.transactions) { + const receipt = await alice.provider.send('eth_getTransactionReceipt', [tx.hash]); + expectedReceipts.push(receipt); + } + + let receipts = await alice.provider.send('eth_getBlockReceipts', [blockNumberHex]); + expect(receipts).toEqual(expectedReceipts); + // eth_getBlockByHash await alice.provider.getBlock(blockHash); const blockWithTxsByHash = await alice.provider.getBlockWithTransactions(blockHash); @@ -787,7 +798,7 @@ describe('web3 API compatibility tests', () => { test('Should check transaction signature', async () => { const CHAIN_ID = +process.env.CHAIN_ETH_ZKSYNC_NETWORK_ID!; const value = 1; - const gasLimit = 300000; + const gasLimit = 350000; const gasPrice = await alice.provider.getGasPrice(); const data = '0x'; const to = alice.address; diff --git a/core/tests/ts-integration/tests/contracts.test.ts b/core/tests/ts-integration/tests/contracts.test.ts index fea1b15845a5..e7d5fcf3a239 100644 --- a/core/tests/ts-integration/tests/contracts.test.ts +++ b/core/tests/ts-integration/tests/contracts.test.ts @@ -306,6 +306,30 @@ describe('Smart contract behavior checks', () => { ).toBeAccepted([]); }); + test('Should reject tx with not enough gas for publishing bytecode', async () => { + // Send a transaction with big unique factory dep and provide gas enough for validation but not for bytecode publishing. + // Transaction should be rejected by API. + + const BYTECODE_LEN = 50016; + const bytecode = ethers.utils.hexlify(ethers.utils.randomBytes(BYTECODE_LEN)); + + // Estimate gas for "no-op". It's a good estimate for validation gas. + const gasLimit = await alice.estimateGas({ + to: alice.address, + data: '0x' + }); + + await expect( + alice.sendTransaction({ + to: alice.address, + gasLimit, + customData: { + factoryDeps: [bytecode] + } + }) + ).toBeRejected('not enough gas to publish compressed bytecodes'); + }); + afterAll(async () => { await testMaster.deinitialize(); }); diff --git a/core/tests/ts-integration/tests/custom-erc20-bridge.test.ts b/core/tests/ts-integration/tests/custom-erc20-bridge.test.ts index 83f68728d475..e3c517c9ba3c 100644 --- a/core/tests/ts-integration/tests/custom-erc20-bridge.test.ts +++ b/core/tests/ts-integration/tests/custom-erc20-bridge.test.ts @@ -9,7 +9,7 @@ import { spawn as _spawn } from 'child_process'; import * as zksync from 'zksync-web3'; import * as ethers from 'ethers'; import { scaledGasPrice } from '../src/helpers'; -import { L1ERC20BridgeFactory, TransparentUpgradeableProxyFactory, AllowListFactory } from 'l1-contracts/typechain'; +import { L1ERC20BridgeFactory, TransparentUpgradeableProxyFactory } from 'l1-contracts/typechain'; import { sleep } from 'zk/build/utils'; describe('Tests for the custom bridge behavior', () => { @@ -36,18 +36,11 @@ describe('Tests for the custom bridge behavior', () => { }); await transferTx.wait(); - let allowList = new AllowListFactory(alice._signerL1()); - let allowListContract = await allowList.deploy(alice.address); - await allowListContract.deployTransaction.wait(2); - // load the l1bridge contract let l1bridgeFactory = new L1ERC20BridgeFactory(alice._signerL1()); const gasPrice = await scaledGasPrice(alice); - let l1Bridge = await l1bridgeFactory.deploy( - process.env.CONTRACTS_DIAMOND_PROXY_ADDR!, - allowListContract.address - ); + let l1Bridge = await l1bridgeFactory.deploy(process.env.CONTRACTS_DIAMOND_PROXY_ADDR!); await l1Bridge.deployTransaction.wait(2); let l1BridgeProxyFactory = new TransparentUpgradeableProxyFactory(alice._signerL1()); let l1BridgeProxy = await l1BridgeProxyFactory.deploy(l1Bridge.address, bob.address, '0x'); @@ -62,9 +55,6 @@ describe('Tests for the custom bridge behavior', () => { let command = `${baseCommandL1} initialize-bridges ${args}`; await spawn(command); - const setAccessModeTx = await allowListContract.setAccessMode(l1BridgeProxy.address, 2); - await setAccessModeTx.wait(); - let l1bridge2 = new L1ERC20BridgeFactory(alice._signerL1()).attach(l1BridgeProxy.address); const maxAttempts = 200; diff --git a/core/tests/ts-integration/tests/fees.test.ts b/core/tests/ts-integration/tests/fees.test.ts index 3ee5b9780a58..6041ec8c2b23 100644 --- a/core/tests/ts-integration/tests/fees.test.ts +++ b/core/tests/ts-integration/tests/fees.test.ts @@ -10,12 +10,15 @@ * */ import * as utils from 'zk/build/utils'; +import * as fs from 'fs'; import { TestMaster } from '../src/index'; import * as zksync from 'zksync-web3'; import { BigNumber, ethers } from 'ethers'; import { Token } from '../src/types'; +const logs = fs.createWriteStream('fees.log', { flags: 'a' }); + // Unless `RUN_FEE_TEST` is provided, skip the test suit const testFees = process.env.RUN_FEE_TEST ? describe : describe.skip; @@ -73,23 +76,51 @@ testFees('Test fees', () => { }) ).wait(); - let reports = ['ETH transfer:\n\n', 'ERC20 transfer:\n\n']; + // Warming up slots for the receiver + await ( + await alice.sendTransaction({ + to: receiver, + value: BigNumber.from(1) + }) + ).wait(); + + await ( + await alice.sendTransaction({ + data: aliceErc20.interface.encodeFunctionData('transfer', [receiver, BigNumber.from(1)]), + to: tokenDetails.l2Address + }) + ).wait(); + + let reports = [ + 'ETH transfer (to new):\n\n', + 'ETH transfer (to old):\n\n', + 'ERC20 transfer (to new):\n\n', + 'ERC20 transfer (to old):\n\n' + ]; for (const gasPrice of L1_GAS_PRICES_TO_TEST) { reports = await appendResults( alice, - [feeTestL1Receipt, feeTestL1ReceiptERC20], + [feeTestL1Receipt, feeTestL1Receipt, feeTestL1ReceiptERC20, feeTestL1ReceiptERC20], // We always regenerate new addresses for transaction requests in order to estimate the cost for a new account [ { to: ethers.Wallet.createRandom().address, value: BigNumber.from(1) }, + { + to: receiver, + value: BigNumber.from(1) + }, { data: aliceErc20.interface.encodeFunctionData('transfer', [ ethers.Wallet.createRandom().address, BigNumber.from(1) ]), to: tokenDetails.l2Address + }, + { + data: aliceErc20.interface.encodeFunctionData('transfer', [receiver, BigNumber.from(1)]), + to: tokenDetails.l2Address } ], gasPrice, @@ -147,7 +178,9 @@ async function updateReport( const estimatedPrice = estimatedL2GasPrice.mul(estimatedL2GasLimit); const balanceBefore = await sender.getBalance(); - await (await sender.sendTransaction(transactionRequest)).wait(); + const transaction = await sender.sendTransaction(transactionRequest); + console.log(`Sending transaction: ${transaction.hash}`); + await transaction.wait(); const balanceAfter = await sender.getBalance(); const balanceDiff = balanceBefore.sub(balanceAfter); @@ -193,9 +226,10 @@ async function setInternalL1GasPrice(provider: zksync.Provider, newPrice?: strin let command = 'zk server --components api,tree,eth,state_keeper'; command = `DATABASE_MERKLE_TREE_MODE=full ${command}`; if (newPrice) { - command = `ETH_SENDER_GAS_ADJUSTER_INTERNAL_ENFORCED_L1_GAS_PRICE=${newPrice} ${command}`; + // We need to ensure that each transaction gets into its own batch for more fair comparison. + command = `CHAIN_STATE_KEEPER_TRANSACTION_SLOTS=1 ETH_SENDER_GAS_ADJUSTER_INTERNAL_ENFORCED_L1_GAS_PRICE=${newPrice} ${command}`; } - const zkSyncServer = utils.background(command, 'ignore'); + const zkSyncServer = utils.background(command, [null, logs, logs]); if (disconnect) { zkSyncServer.unref(); diff --git a/core/tests/ts-integration/tests/l1.test.ts b/core/tests/ts-integration/tests/l1.test.ts index a1ef9564bd98..c0a846407943 100644 --- a/core/tests/ts-integration/tests/l1.test.ts +++ b/core/tests/ts-integration/tests/l1.test.ts @@ -278,7 +278,7 @@ describe('Tests for L1 behavior', () => { } const contract = await deployContract(alice, contracts.writesAndMessages, []); - const MAX_PUBDATA_PER_BATCH = ethers.BigNumber.from(SYSTEM_CONFIG['MAX_PUBDATA_PER_BATCH']); + const MAX_PUBDATA_PER_BATCH = ethers.BigNumber.from(SYSTEM_CONFIG['PRIORITY_TX_PUBDATA_PER_BATCH']); // We check that we will run out of gas if we send a bit // smaller than `MAX_PUBDATA_PER_BATCH` amount of pubdata in a single tx. const calldata = contract.interface.encodeFunctionData('big_l2_l1_message', [ @@ -338,60 +338,16 @@ function maxL2GasLimitForPriorityTxs(): number { let maxGasBodyLimit = +process.env.CONTRACTS_PRIORITY_TX_MAX_GAS_LIMIT!; const overhead = getOverheadForTransaction( - ethers.BigNumber.from(maxGasBodyLimit), - ethers.BigNumber.from(zksync.utils.REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT), - // We can just pass 0 as `encodingLength` because `overheadForPublicData` and `overheadForGas` - // will be greater than `overheadForLength` for large `gasLimit`. + // We can just pass 0 as `encodingLength` because the overhead for the transaction's slot + // will be greater than `overheadForLength` for a typical transacction ethers.BigNumber.from(0) ); return maxGasBodyLimit + overhead; } -function getOverheadForTransaction( - bodyGasLimit: ethers.BigNumber, - gasPricePerPubdata: ethers.BigNumber, - encodingLength: ethers.BigNumber -): number { - const BATCH_OVERHEAD_L2_GAS = ethers.BigNumber.from(SYSTEM_CONFIG['BATCH_OVERHEAD_L2_GAS']); - const L1_GAS_PER_PUBDATA_BYTE = ethers.BigNumber.from(SYSTEM_CONFIG['L1_GAS_PER_PUBDATA_BYTE']); - const BATCH_OVERHEAD_L1_GAS = ethers.BigNumber.from(SYSTEM_CONFIG['BATCH_OVERHEAD_L1_GAS']); - const BATCH_OVERHEAD_PUBDATA = BATCH_OVERHEAD_L1_GAS.div(L1_GAS_PER_PUBDATA_BYTE); - - const MAX_TRANSACTIONS_IN_BATCH = ethers.BigNumber.from(SYSTEM_CONFIG['MAX_TRANSACTIONS_IN_BATCH']); - const BOOTLOADER_TX_ENCODING_SPACE = ethers.BigNumber.from(SYSTEM_CONFIG['BOOTLOADER_TX_ENCODING_SPACE']); - // TODO (EVM-67): possibly charge overhead for pubdata - // const MAX_PUBDATA_PER_BATCH = ethers.BigNumber.from(SYSTEM_CONFIG['MAX_PUBDATA_PER_BATCH']); - const L2_TX_MAX_GAS_LIMIT = ethers.BigNumber.from(SYSTEM_CONFIG['L2_TX_MAX_GAS_LIMIT']); - - const maxBlockOverhead = BATCH_OVERHEAD_L2_GAS.add(BATCH_OVERHEAD_PUBDATA.mul(gasPricePerPubdata)); - - // The overhead from taking up the transaction's slot - const txSlotOverhead = ceilDiv(maxBlockOverhead, MAX_TRANSACTIONS_IN_BATCH); - let blockOverheadForTransaction = txSlotOverhead; - - // The overhead for occupying the bootloader memory can be derived from encoded_len - const overheadForLength = ceilDiv(encodingLength.mul(maxBlockOverhead), BOOTLOADER_TX_ENCODING_SPACE); - if (overheadForLength.gt(blockOverheadForTransaction)) { - blockOverheadForTransaction = overheadForLength; - } - - // The overhead for possible published public data - // TODO (EVM-67): possibly charge overhead for pubdata - // let maxPubdataInTx = ceilDiv(bodyGasLimit, gasPricePerPubdata); - // let overheadForPublicData = ceilDiv(maxPubdataInTx.mul(maxBlockOverhead), MAX_PUBDATA_PER_BATCH); - // if (overheadForPublicData.gt(blockOverheadForTransaction)) { - // blockOverheadForTransaction = overheadForPublicData; - // } - - // The overhead for gas that could be used to use single-instance circuits - let overheadForSingleInstanceCircuits = ceilDiv(bodyGasLimit.mul(maxBlockOverhead), L2_TX_MAX_GAS_LIMIT); - if (overheadForSingleInstanceCircuits.gt(blockOverheadForTransaction)) { - blockOverheadForTransaction = overheadForSingleInstanceCircuits; - } - - return blockOverheadForTransaction.toNumber(); -} +function getOverheadForTransaction(encodingLength: ethers.BigNumber): number { + const TX_SLOT_OVERHEAD_GAS = 10_000; + const TX_LENGTH_BYTE_OVERHEAD_GAS = 10; -function ceilDiv(a: ethers.BigNumber, b: ethers.BigNumber): ethers.BigNumber { - return a.add(b.sub(1)).div(b); + return Math.max(TX_SLOT_OVERHEAD_GAS, TX_LENGTH_BYTE_OVERHEAD_GAS * encodingLength.toNumber()); } diff --git a/core/tests/ts-integration/tests/system.test.ts b/core/tests/ts-integration/tests/system.test.ts index a72f56a4518f..1a4d9abb334e 100644 --- a/core/tests/ts-integration/tests/system.test.ts +++ b/core/tests/ts-integration/tests/system.test.ts @@ -361,7 +361,7 @@ describe('System behavior checks', () => { function bootloaderUtilsContract() { const BOOTLOADER_UTILS_ADDRESS = '0x000000000000000000000000000000000000800c'; const BOOTLOADER_UTILS = new ethers.utils.Interface( - require(`${process.env.ZKSYNC_HOME}/contracts/system-contracts/artifacts-zk/cache-zk/solpp-generated-contracts/BootloaderUtilities.sol/BootloaderUtilities.json`).abi + require(`${process.env.ZKSYNC_HOME}/contracts/system-contracts/artifacts-zk/contracts-preprocessed/BootloaderUtilities.sol/BootloaderUtilities.json`).abi ); return new ethers.Contract(BOOTLOADER_UTILS_ADDRESS, BOOTLOADER_UTILS, alice); diff --git a/core/tests/upgrade-test/tests/upgrade.test.ts b/core/tests/upgrade-test/tests/upgrade.test.ts index 38a7662603d7..b285d8b051b2 100644 --- a/core/tests/upgrade-test/tests/upgrade.test.ts +++ b/core/tests/upgrade-test/tests/upgrade.test.ts @@ -22,7 +22,7 @@ const L2_FORCE_DEPLOY_UPGRADER_ABI = new ethers.utils.Interface( require(`${process.env.ZKSYNC_HOME}/contracts/l2-contracts/artifacts-zk/cache-zk/solpp-generated-contracts/ForceDeployUpgrader.sol/ForceDeployUpgrader.json`).abi ); const COMPLEX_UPGRADER_ABI = new ethers.utils.Interface( - require(`${process.env.ZKSYNC_HOME}/contracts/system-contracts/artifacts-zk/cache-zk/solpp-generated-contracts/ComplexUpgrader.sol/ComplexUpgrader.json`).abi + require(`${process.env.ZKSYNC_HOME}/contracts/system-contracts/artifacts-zk/contracts-preprocessed/ComplexUpgrader.sol/ComplexUpgrader.json`).abi ); const COUNTER_BYTECODE = require(`${process.env.ZKSYNC_HOME}/core/tests/ts-integration/artifacts-zk/contracts/counter/counter.sol/Counter.json`).deployedBytecode; @@ -130,7 +130,7 @@ describe('Upgrade test', function () { }); step('Send l1 tx for saving new bootloader', async () => { - const path = `${process.env.ZKSYNC_HOME}/contracts/system-contracts/bootloader/build/artifacts/playground_batch.yul/playground_batch.yul.zbin`; + const path = `${process.env.ZKSYNC_HOME}/contracts/system-contracts/bootloader/build/artifacts/playground_batch.yul.zbin`; const bootloaderCode = ethers.utils.hexlify(fs.readFileSync(path)); bootloaderHash = ethers.utils.hexlify(hashBytecode(bootloaderCode)); const txHandle = await tester.syncWallet.requestExecute({ diff --git a/core/tests/vm-benchmark/README.md b/core/tests/vm-benchmark/README.md index 4d66f287a707..cecbdb31d0cf 100644 --- a/core/tests/vm-benchmark/README.md +++ b/core/tests/vm-benchmark/README.md @@ -1,7 +1,8 @@ # Benchmarking the VM -Currently all benchmarking happens on contract deployment bytecodes. These can execute arbitrary code, so that is -surprisingly useful. This library can be used to build more complex benchmarks, however. +Currently all benchmarking happens on contract deployment bytecodes. Since contract deployment bytecodes can execute +arbitrary code, they are surprisingly useful for benchmarking. This library can be used to build more complex +benchmarks, however. ## Benchmarking @@ -28,7 +29,7 @@ them to "benches/iai.rs". ## Profiling (Linux only) You can also use `sh perf.sh bytecode_file` to produce data that can be fed into the -[firefox profiler](profiler.firefox.com) for a specific bytecode. +[firefox profiler](https://profiler.firefox.com/) for a specific bytecode. ## Fuzzing diff --git a/core/tests/vm-benchmark/harness/src/lib.rs b/core/tests/vm-benchmark/harness/src/lib.rs index 33042adaaeb8..e4f26a20f497 100644 --- a/core/tests/vm-benchmark/harness/src/lib.rs +++ b/core/tests/vm-benchmark/harness/src/lib.rs @@ -4,16 +4,17 @@ use multivm::{ interface::{ L2BlockEnv, TxExecutionMode, VmExecutionMode, VmExecutionResultAndLogs, VmInterface, }, + utils::get_max_gas_per_pubdata_byte, vm_latest::{constants::BLOCK_GAS_LIMIT, HistoryEnabled, Vm}, }; use once_cell::sync::Lazy; use zksync_contracts::{deployer_contract, BaseSystemContracts}; use zksync_state::{InMemoryStorage, StorageView}; -use zksync_system_constants::ethereum::MAX_GAS_PER_PUBDATA_BYTE; use zksync_types::{ block::MiniblockHasher, ethabi::{encode, Token}, fee::Fee, + fee_model::BatchFeeInput, helpers::unix_timestamp_ms, l2::L2Tx, utils::storage_key_for_eth_balance, @@ -39,7 +40,7 @@ pub fn cut_to_allowed_bytecode_size(bytes: &[u8]) -> Option<&[u8]> { static STORAGE: Lazy = Lazy::new(|| { let mut storage = InMemoryStorage::with_system_contracts(hash_bytecode); - // give PRIVATE_KEY some money + // give `PRIVATE_KEY` some money let my_addr = PackedEthSignature::address_from_private_key(&PRIVATE_KEY).unwrap(); let key = storage_key_for_eth_balance(&my_addr); storage.set_value(key, zksync_utils::u256_to_h256(U256([0, 0, 1, 0]))); @@ -69,8 +70,10 @@ impl BenchmarkingVm { previous_batch_hash: None, number: L1BatchNumber(1), timestamp, - l1_gas_price: 50_000_000_000, // 50 gwei - fair_l2_gas_price: 250_000_000, // 0.25 gwei + fee_input: BatchFeeInput::l1_pegged( + 50_000_000_000, // 50 gwei + 250_000_000, // 0.25 gwei + ), fee_account: Address::random(), enforced_base_fee: None, first_l2_block: L2BlockEnv { @@ -119,7 +122,9 @@ pub fn get_deploy_tx(code: &[u8]) -> Transaction { gas_limit: U256::from(30000000u32), max_fee_per_gas: U256::from(250_000_000), max_priority_fee_per_gas: U256::from(0), - gas_per_pubdata_limit: U256::from(MAX_GAS_PER_PUBDATA_BYTE), + gas_per_pubdata_limit: U256::from(get_max_gas_per_pubdata_byte( + ProtocolVersionId::latest().into(), + )), }, U256::zero(), L2ChainId::from(270), diff --git a/docker/build-base/Dockerfile b/docker/build-base/Dockerfile new file mode 100644 index 000000000000..1fec4cca7e03 --- /dev/null +++ b/docker/build-base/Dockerfile @@ -0,0 +1,15 @@ +FROM debian:bookworm-slim + +RUN apt-get update && apt-get install -y curl clang openssl libssl-dev gcc g++ \ + pkg-config build-essential libclang-dev linux-libc-dev liburing-dev && \ + rm -rf /var/lib/apt/lists/* + +ENV RUSTUP_HOME=/usr/local/rustup \ + CARGO_HOME=/usr/local/cargo \ + PATH=/usr/local/cargo/bin:$PATH + +RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \ + rustup install nightly-2023-08-21 && \ + rustup default nightly-2023-08-21 + +RUN cargo install sqlx-cli --version 0.7.3 diff --git a/docker/circuit-synthesizer/Dockerfile b/docker/circuit-synthesizer/Dockerfile deleted file mode 100644 index 831fe1672239..000000000000 --- a/docker/circuit-synthesizer/Dockerfile +++ /dev/null @@ -1,29 +0,0 @@ -FROM debian:bookworm-slim as builder - -ARG DEBIAN_FRONTEND=noninteractive - -RUN apt-get update && apt-get install -y curl clang openssl libssl-dev gcc g++ \ - pkg-config build-essential libclang-dev && \ - rm -rf /var/lib/apt/lists/* - -ENV RUSTUP_HOME=/usr/local/rustup \ - CARGO_HOME=/usr/local/cargo \ - PATH=/usr/local/cargo/bin:$PATH - -RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \ - rustup install nightly-2023-08-21 && \ - rustup default nightly-2023-08-21 - -WORKDIR /usr/src/zksync -COPY . . - -RUN cargo build --release - -FROM debian:bookworm-slim - -RUN apt-get update && apt-get install -y curl openssl libpq5 ca-certificates && rm -rf /var/lib/apt/lists/* - -COPY core/bin/verification_key_generator_and_server/data/ /core/bin/verification_key_generator_and_server/data/ -COPY --from=builder /usr/src/zksync/target/release/zksync_circuit_synthesizer /usr/bin/ - -ENTRYPOINT ["zksync_circuit_synthesizer"] diff --git a/docker/contract-verifier/Dockerfile b/docker/contract-verifier/Dockerfile index 15dc7d7a3141..6941de6321f0 100644 --- a/docker/contract-verifier/Dockerfile +++ b/docker/contract-verifier/Dockerfile @@ -1,17 +1,5 @@ # syntax=docker/dockerfile:experimental -FROM debian:bookworm-slim as builder - -RUN apt-get update && apt-get install -y curl clang openssl libssl-dev gcc g++ \ - pkg-config build-essential libclang-dev && \ - rm -rf /var/lib/apt/lists/* - -ENV RUSTUP_HOME=/usr/local/rustup \ - CARGO_HOME=/usr/local/cargo \ - PATH=/usr/local/cargo/bin:$PATH - -RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \ - rustup install nightly-2023-08-21 && \ - rustup default nightly-2023-08-21 +FROM matterlabs/zksync-build-base:latest as builder WORKDIR /usr/src/zksync COPY . . @@ -20,11 +8,11 @@ RUN cargo build --release FROM debian:bookworm-slim -RUN apt-get update && apt-get install -y curl libpq5 ca-certificates wget python3 && rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get install -y curl libpq5 ca-certificates wget python3 jq && rm -rf /var/lib/apt/lists/* # install zksolc 1.3.x -RUN skip_versions="v1.3.12 v1.3.15" && \ - for VERSION in $(seq -f "v1.3.%g" 0 18); do \ +RUN skip_versions="v1.3.12 v1.3.15 v1.3.20" && \ + for VERSION in $(seq -f "v1.3.%g" 0 22); do \ if echo " $skip_versions " | grep -q -w " $VERSION "; then \ continue; \ fi; \ @@ -34,7 +22,7 @@ RUN skip_versions="v1.3.12 v1.3.15" && \ done # install zkvyper 1.3.x -RUN for VERSION in $(seq -f "v1.3.%g" 9 13); do \ +RUN for VERSION in $(seq -f "v1.3.%g" 9 16); do \ mkdir -p /etc/zkvyper-bin/$VERSION && \ wget https://github.com/matter-labs/zkvyper-bin/raw/main/linux-amd64/zkvyper-linux-amd64-musl-$VERSION -O /etc/zkvyper-bin/$VERSION/zkvyper && \ chmod +x /etc/zkvyper-bin/$VERSION/zkvyper; \ @@ -42,7 +30,7 @@ RUN for VERSION in $(seq -f "v1.3.%g" 9 13); do \ # install solc COPY docker/contract-verifier/install-all-solc.sh install-all-solc.sh -RUN sh ./install-all-solc.sh +RUN bash ./install-all-solc.sh # install vyper RUN mkdir -p /etc/vyper-bin/0.3.3 \ diff --git a/docker/contract-verifier/install-all-solc.sh b/docker/contract-verifier/install-all-solc.sh old mode 100644 new mode 100755 index 8f4d8c38a5c1..e75e2a71eade --- a/docker/contract-verifier/install-all-solc.sh +++ b/docker/contract-verifier/install-all-solc.sh @@ -1,3 +1,7 @@ +#!/bin/bash + +set -e + # Installs all solc versions from the github repo wget -O list.txt https://github.com/ethereum/solc-bin/raw/gh-pages/linux-amd64/list.txt @@ -18,3 +22,12 @@ do ls etc/solc-bin/ done + +# Download zkVM solc +list=("0.8.23-1.0.0" "0.8.22-1.0.0" "0.8.21-1.0.0" "0.8.20-1.0.0" "0.8.19-1.0.0" "0.8.18-1.0.0" "0.8.17-1.0.0" "0.8.16-1.0.0" "0.8.15-1.0.0" "0.8.14-1.0.0" "0.8.13-1.0.0" "0.8.12-1.0.0" "0.8.11-1.0.0" "0.8.10-1.0.0" "0.8.9-1.0.0" "0.8.8-1.0.0" "0.8.7-1.0.0" "0.8.6-1.0.0" "0.8.5-1.0.0" "0.8.4-1.0.0" "0.8.3-1.0.0" "0.8.2-1.0.0" "0.8.1-1.0.0" "0.8.0-1.0.0" "0.7.6-1.0.0" "0.7.5-1.0.0" "0.7.4-1.0.0" "0.7.3-1.0.0" "0.7.2-1.0.0" "0.7.1-1.0.0" "0.7.0-1.0.0" "0.6.12-1.0.0" "0.6.11-1.0.0" "0.6.10-1.0.0" "0.6.9-1.0.0" "0.6.8-1.0.0" "0.6.7-1.0.0" "0.6.6-1.0.0" "0.6.5-1.0.0" "0.6.4-1.0.0" "0.6.3-1.0.0" "0.6.2-1.0.0" "0.6.1-1.0.0" "0.6.0-1.0.0" "0.5.17-1.0.0" "0.5.16-1.0.0" "0.5.15-1.0.0" "0.5.14-1.0.0" "0.5.13-1.0.0" "0.5.12-1.0.0" "0.5.11-1.0.0" "0.5.10-1.0.0" "0.5.9-1.0.0" "0.5.8-1.0.0" "0.5.7-1.0.0" "0.5.6-1.0.0" "0.5.5-1.0.0" "0.5.4-1.0.0" "0.5.3-1.0.0" "0.5.2-1.0.0" "0.5.1-1.0.0" "0.5.0-1.0.0" "0.4.26-1.0.0" "0.4.25-1.0.0" "0.4.24-1.0.0" "0.4.23-1.0.0" "0.4.22-1.0.0" "0.4.21-1.0.0" "0.4.20-1.0.0" "0.4.19-1.0.0" "0.4.18-1.0.0" "0.4.17-1.0.0" "0.4.16-1.0.0" "0.4.15-1.0.0" "0.4.14-1.0.0" "0.4.13-1.0.0" "0.4.12-1.0.0") +for version in ${list[@]}; +do + mkdir -p etc/solc-bin/zkVM-$version/ + wget https://github.com/matter-labs/era-solidity/releases/download/$version/solc-linux-amd64-$version -O etc/solc-bin/zkVM-$version/solc + chmod +x etc/solc-bin/zkVM-$version/solc +done diff --git a/docker/cross-external-nodes-checker/Dockerfile b/docker/cross-external-nodes-checker/Dockerfile deleted file mode 100644 index 87b5d67d719d..000000000000 --- a/docker/cross-external-nodes-checker/Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -# syntax=docker/dockerfile:experimental -FROM debian:bookworm-slim as builder - -RUN apt-get update && apt-get install -y curl clang openssl libssl-dev gcc g++ \ - pkg-config build-essential libclang-dev && \ - rm -rf /var/lib/apt/lists/* - -ENV RUSTUP_HOME=/usr/local/rustup \ - CARGO_HOME=/usr/local/cargo \ - PATH=/usr/local/cargo/bin:$PATH - -RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \ - rustup install nightly-2023-08-21 && \ - rustup default nightly-2023-08-21 - -WORKDIR /usr/src/zksync -COPY . . - -RUN cargo build --release - -FROM debian:bookworm-slim - -RUN apt-get update && apt-get install -y curl ca-certificates && rm -rf /var/lib/apt/lists/* - -COPY --from=builder /usr/src/zksync/target/release/cross_external_nodes_checker /usr/bin - -ENTRYPOINT ["cross_external_nodes_checker"] diff --git a/docker/external-node/Dockerfile b/docker/external-node/Dockerfile index a1496bc43e24..02dca4cd50c6 100644 --- a/docker/external-node/Dockerfile +++ b/docker/external-node/Dockerfile @@ -1,24 +1,11 @@ # Will work locally only after prior contracts build -FROM debian:bookworm-slim as builder - -RUN apt-get update && apt-get install -y curl clang openssl libssl-dev gcc g++ \ - pkg-config build-essential libclang-dev && \ - rm -rf /var/lib/apt/lists/* - -ENV RUSTUP_HOME=/usr/local/rustup \ - CARGO_HOME=/usr/local/cargo \ - PATH=/usr/local/cargo/bin:$PATH - -RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \ - rustup install nightly-2023-08-21 && \ - rustup default nightly-2023-08-21 +FROM matterlabs/zksync-build-base:latest as builder WORKDIR /usr/src/zksync COPY . . RUN cargo build --release -RUN cargo install sqlx-cli --version 0.5.13 FROM debian:bookworm-slim @@ -29,8 +16,8 @@ COPY --from=builder /usr/src/zksync/target/release/block_reverter /usr/bin COPY --from=builder /usr/local/cargo/bin/sqlx /usr/bin COPY --from=builder /usr/src/zksync/docker/external-node/entrypoint.sh /usr/bin COPY contracts/system-contracts/bootloader/build/artifacts/ /contracts/system-contracts/bootloader/build/artifacts/ -COPY contracts/system-contracts/contracts/artifacts/ /contracts/system-contracts/contracts/artifacts/ -COPY contracts/system-contracts/contracts/precompiles/artifacts/ /contracts/system-contracts/contracts/precompiles/artifacts/ +COPY contracts/system-contracts/contracts-preprocessed/artifacts/ /contracts/system-contracts/contracts-preprocessed/artifacts/ +COPY contracts/system-contracts/contracts-preprocessed/precompiles/artifacts/ /contracts/system-contracts/contracts-preprocessed/precompiles/artifacts/ COPY contracts/system-contracts/artifacts-zk /contracts/system-contracts/artifacts-zk COPY contracts/l1-contracts/artifacts/ /contracts/l1-contracts/artifacts/ COPY contracts/l2-contracts/artifacts-zk/ /contracts/l2-contracts/artifacts-zk/ diff --git a/docker/local-node/Dockerfile b/docker/local-node/Dockerfile index 2b1d57c1a587..b6d8857a4f64 100644 --- a/docker/local-node/Dockerfile +++ b/docker/local-node/Dockerfile @@ -13,8 +13,8 @@ ENV NODE_MAJOR=18 RUN mkdir -p /etc/apt/keyrings && \ wget -c -O - https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \ echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && \ - apt-get update && apt-get install nodejs -y && \ - npm install -g yarn + apt-get update && apt-get install nodejs npm -y && \ + npm install -g yarn && npm install -g cspell && npm install -g markdown-link-check # Copy compiler (both solc and zksolc) binaries # Obtain `solc` 0.8.12. diff --git a/docker/proof-fri-compressor/Dockerfile b/docker/proof-fri-compressor/Dockerfile index e18c0c27f552..c6739dca8279 100644 --- a/docker/proof-fri-compressor/Dockerfile +++ b/docker/proof-fri-compressor/Dockerfile @@ -1,21 +1,9 @@ # Will work locally only after prior universal setup key download -FROM debian:bookworm-slim as builder +FROM matterlabs/zksync-build-base:latest as builder ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y curl clang openssl libssl-dev gcc g++ \ - pkg-config build-essential libclang-dev && \ - rm -rf /var/lib/apt/lists/* - -ENV RUSTUP_HOME=/usr/local/rustup \ - CARGO_HOME=/usr/local/cargo \ - PATH=/usr/local/cargo/bin:$PATH - -RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \ - rustup install nightly-2023-08-21 && \ - rustup default nightly-2023-08-21 - WORKDIR /usr/src/zksync COPY . . diff --git a/docker/prover-fri-gateway/Dockerfile b/docker/prover-fri-gateway/Dockerfile index 256621e8df75..f381a5902d7f 100644 --- a/docker/prover-fri-gateway/Dockerfile +++ b/docker/prover-fri-gateway/Dockerfile @@ -1,19 +1,7 @@ -FROM debian:bookworm-slim as builder +FROM matterlabs/zksync-build-base:latest as builder ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y curl clang openssl libssl-dev gcc g++ \ - pkg-config build-essential libclang-dev && \ - rm -rf /var/lib/apt/lists/* - -ENV RUSTUP_HOME=/usr/local/rustup \ - CARGO_HOME=/usr/local/cargo \ - PATH=/usr/local/cargo/bin:$PATH - -RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \ - rustup install nightly-2023-08-21 && \ - rustup default nightly-2023-08-21 - WORKDIR /usr/src/zksync COPY . . diff --git a/docker/prover-fri/Dockerfile b/docker/prover-fri/Dockerfile index 8244aea06b28..fd85801b7294 100644 --- a/docker/prover-fri/Dockerfile +++ b/docker/prover-fri/Dockerfile @@ -1,19 +1,7 @@ -FROM debian:bookworm-slim as builder +FROM matterlabs/zksync-build-base:latest as builder ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y curl clang openssl libssl-dev gcc g++ \ - pkg-config build-essential libclang-dev && \ - rm -rf /var/lib/apt/lists/* - -ENV RUSTUP_HOME=/usr/local/rustup \ - CARGO_HOME=/usr/local/cargo \ - PATH=/usr/local/cargo/bin:$PATH - -RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \ - rustup install nightly-2023-08-21 && \ - rustup default nightly-2023-08-21 - WORKDIR /usr/src/zksync COPY . . diff --git a/docker/prover-gar/Dockerfile b/docker/prover-gar/Dockerfile deleted file mode 100644 index 1e96e23bbbac..000000000000 --- a/docker/prover-gar/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -# Will work locally only after prior universal key download and Docker login to the private registry - -ARG PROVER_IMAGE=latest -FROM us-docker.pkg.dev/matterlabs-infra/matterlabs-docker/prover-v2:2.0-$PROVER_IMAGE as prover - -FROM nvidia/cuda:11.8.0-runtime-ubuntu22.04 as app - -# HACK copying to root is the only way to make Docker layer caching work for these files for some reason -COPY *.bin / -COPY setup_2\^26.key /setup_2\^26.key - -RUN apt-get update && apt-get install -y libpq5 ca-certificates openssl && rm -rf /var/lib/apt/lists/* - -COPY --from=prover contracts/system-contracts/bootloader/build/artifacts/ /contracts/system-contracts/bootloader/build/artifacts/ -COPY --from=prover contracts/system-contracts/artifacts-zk /contracts/system-contracts/artifacts-zk -COPY --from=prover contracts/l1-contracts/artifacts/ /contracts/l1-contracts/artifacts/ -COPY --from=prover contracts/l2-contracts/artifacts-zk/ /contracts/l2-contracts/artifacts-zk/ -COPY --from=prover core/bin/verification_key_generator_and_server/data/ /core/bin/verification_key_generator_and_server/data/ -COPY --from=prover /usr/bin/zksync_prover /usr/bin/ - -ENTRYPOINT ["zksync_prover"] diff --git a/docker/prover/Dockerfile b/docker/prover/Dockerfile deleted file mode 100644 index d6dc38b29873..000000000000 --- a/docker/prover/Dockerfile +++ /dev/null @@ -1,63 +0,0 @@ -# Will work locally only after prior contracts build and universal setup key download - -FROM nvidia/cuda:11.8.0-devel-ubuntu22.04 as builder - -ARG DEBIAN_FRONTEND=noninteractive - -RUN apt-get update && apt-get install -y curl jq clang openssl libssl-dev gcc g++ \ - pkg-config build-essential libclang-dev && \ - rm -rf /var/lib/apt/lists/* - -ENV RUSTUP_HOME=/usr/local/rustup \ - CARGO_HOME=/usr/local/cargo \ - PATH=/usr/local/cargo/bin:$PATH - -RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \ - rustup install nightly-2023-08-21 && \ - rustup default nightly-2023-08-21 - -WORKDIR /usr/src/zksync - -ARG ERA_BELLMAN_CUDA_RELEASE -ENV ERA_BELLMAN_CUDA_RELEASE=$ERA_BELLMAN_CUDA_RELEASE -ENV GITHUB_OWNER=matter-labs -ENV GITHUB_REPO=era-bellman-cuda - -RUN set -e; \ - if [ -z "$ERA_BELLMAN_CUDA_RELEASE" ]; then \ - ERA_BELLMAN_CUDA_RELEASE="latest"; \ - fi; \ - if [ "$ERA_BELLMAN_CUDA_RELEASE" = "latest" ]; then \ - ERA_BELLMAN_CUDA_RELEASE=$(curl --silent "https://api.github.com/repos/${GITHUB_OWNER}/${GITHUB_REPO}/releases" | jq -r '.[0].tag_name'); \ - fi; \ - source_url="https://github.com/${GITHUB_OWNER}/${GITHUB_REPO}/archive/refs/tags/${ERA_BELLMAN_CUDA_RELEASE}.tar.gz"; \ - binary_url="https://github.com/${GITHUB_OWNER}/${GITHUB_REPO}/releases/download/${ERA_BELLMAN_CUDA_RELEASE}/bellman-cuda.tar.gz"; \ - curl --silent --location "$source_url" --output bellman-cuda-source.tar.gz; \ - curl --silent --location "$binary_url" --output bellman-cuda.tar.gz; \ - mkdir -p bellman-cuda; \ - tar xvfz bellman-cuda.tar.gz -C ./bellman-cuda; \ - tar xvfz bellman-cuda-source.tar.gz -C ./bellman-cuda --strip-components=1 - -ENV BELLMAN_CUDA_DIR=/usr/src/zksync/bellman-cuda - -COPY . . - -RUN cargo build --release --features gpu - -FROM nvidia/cuda:11.8.0-runtime-ubuntu22.04 as runner - -ARG DEBIAN_FRONTEND=noninteractive - -RUN apt-get update && apt-get install -y libpq5 ca-certificates openssl && rm -rf /var/lib/apt/lists/* - -COPY contracts/system-contracts/bootloader/build/artifacts/ /contracts/system-contracts/bootloader/build/artifacts/ -COPY contracts/system-contracts/artifacts-zk /contracts/system-contracts/artifacts-zk -COPY contracts/l1-contracts/artifacts/ /contracts/l1-contracts/artifacts/ -COPY contracts/l2-contracts/artifacts-zk/ /contracts/l2-contracts/artifacts-zk/ -COPY setup_2\^26.key /etc/ - -COPY core/bin/verification_key_generator_and_server/data/ /core/bin/verification_key_generator_and_server/data/ - -COPY --from=builder /usr/src/zksync/target/release/zksync_prover /usr/bin/ - -ENTRYPOINT ["zksync_prover"] diff --git a/docker/server-v2/Dockerfile b/docker/server-v2/Dockerfile index 51048e11c167..e5d378c3b6d8 100644 --- a/docker/server-v2/Dockerfile +++ b/docker/server-v2/Dockerfile @@ -1,21 +1,10 @@ # Will work locally only after prior contracts build # syntax=docker/dockerfile:experimental -FROM debian:bookworm-slim as builder +FROM matterlabs/zksync-build-base:latest as builder WORKDIR /usr/src/zksync -COPY . . - -RUN apt-get update && apt-get install -y curl clang openssl libssl-dev gcc g++ \ - pkg-config build-essential libclang-dev linux-libc-dev liburing-dev && \ - rm -rf /var/lib/apt/lists/* -ENV RUSTUP_HOME=/usr/local/rustup \ - CARGO_HOME=/usr/local/cargo \ - PATH=/usr/local/cargo/bin:$PATH - -RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \ - rustup install nightly-2023-08-21 && \ - rustup default nightly-2023-08-21 +COPY . . RUN cargo build --release --features=rocksdb/io-uring @@ -32,14 +21,13 @@ COPY --from=builder /usr/src/zksync/target/release/zksync_server /usr/bin COPY --from=builder /usr/src/zksync/target/release/block_reverter /usr/bin COPY --from=builder /usr/src/zksync/target/release/merkle_tree_consistency_checker /usr/bin COPY contracts/system-contracts/bootloader/build/artifacts/ /contracts/system-contracts/bootloader/build/artifacts/ -COPY contracts/system-contracts/contracts/artifacts/ /contracts/system-contracts/contracts/artifacts/ -COPY contracts/system-contracts/contracts/precompiles/artifacts/ /contracts/system-contracts/contracts/precompiles/artifacts/ +COPY contracts/system-contracts/contracts-preprocessed/artifacts/ /contracts/system-contracts/contracts-preprocessed/artifacts/ +COPY contracts/system-contracts/contracts-preprocessed/precompiles/artifacts/ /contracts/system-contracts/contracts-preprocessed/precompiles/artifacts/ COPY contracts/system-contracts/artifacts-zk /contracts/system-contracts/artifacts-zk COPY contracts/l1-contracts/artifacts/ /contracts/l1-contracts/artifacts/ COPY contracts/l2-contracts/artifacts-zk/ /contracts/l2-contracts/artifacts-zk/ COPY etc/tokens/ /etc/tokens/ COPY etc/ERC20/ /etc/ERC20/ COPY etc/multivm_bootloaders/ /etc/multivm_bootloaders/ -COPY core/bin/verification_key_generator_and_server/data/ /core/bin/verification_key_generator_and_server/data/ ENTRYPOINT ["zksync_server"] diff --git a/docker/snapshots-creator/Dockerfile b/docker/snapshots-creator/Dockerfile index 897f28f87800..10eef06dfbbc 100644 --- a/docker/snapshots-creator/Dockerfile +++ b/docker/snapshots-creator/Dockerfile @@ -1,21 +1,9 @@ # syntax=docker/dockerfile:experimental -FROM debian:bookworm-slim as builder +FROM matterlabs/zksync-build-base:latest as builder WORKDIR /usr/src/zksync COPY . . -RUN apt-get update && apt-get install -y curl clang openssl libssl-dev gcc g++ \ - pkg-config build-essential libclang-dev linux-libc-dev liburing-dev && \ - rm -rf /var/lib/apt/lists/* - -ENV RUSTUP_HOME=/usr/local/rustup \ - CARGO_HOME=/usr/local/cargo \ - PATH=/usr/local/cargo/bin:$PATH - -RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \ - rustup install nightly-2023-08-21 && \ - rustup default nightly-2023-08-21 - RUN cargo build --release --bin snapshots_creator FROM debian:bookworm-slim diff --git a/docker/witness-generator/Dockerfile b/docker/witness-generator/Dockerfile index f431339d3e96..42dee7ba5d0b 100644 --- a/docker/witness-generator/Dockerfile +++ b/docker/witness-generator/Dockerfile @@ -1,19 +1,7 @@ -FROM debian:bookworm-slim as builder +FROM matterlabs/zksync-build-base:latest AS builder ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y curl clang openssl libssl-dev gcc g++ \ - pkg-config build-essential libclang-dev && \ - rm -rf /var/lib/apt/lists/* - -ENV RUSTUP_HOME=/usr/local/rustup \ - CARGO_HOME=/usr/local/cargo \ - PATH=/usr/local/cargo/bin:$PATH - -RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \ - rustup install nightly-2023-08-21 && \ - rustup default nightly-2023-08-21 - WORKDIR /usr/src/zksync COPY . . diff --git a/docker/witness-vector-generator/Dockerfile b/docker/witness-vector-generator/Dockerfile index 5861f3e51622..7d3c44f67fc9 100644 --- a/docker/witness-vector-generator/Dockerfile +++ b/docker/witness-vector-generator/Dockerfile @@ -1,19 +1,7 @@ -FROM debian:bookworm-slim as builder +FROM matterlabs/zksync-build-base:latest as builder ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y curl clang openssl libssl-dev gcc g++ \ - pkg-config build-essential libclang-dev && \ - rm -rf /var/lib/apt/lists/* - -ENV RUSTUP_HOME=/usr/local/rustup \ - CARGO_HOME=/usr/local/cargo \ - PATH=/usr/local/cargo/bin:$PATH - -RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \ - rustup install nightly-2023-08-21 && \ - rustup default nightly-2023-08-21 - WORKDIR /usr/src/zksync COPY . . diff --git a/docker/zk-environment/20.04_amd64_cuda_11_8.Dockerfile b/docker/zk-environment/20.04_amd64_cuda_11_8.Dockerfile index 9aa7a2b00679..bd77e680d5fc 100644 --- a/docker/zk-environment/20.04_amd64_cuda_11_8.Dockerfile +++ b/docker/zk-environment/20.04_amd64_cuda_11_8.Dockerfile @@ -50,10 +50,13 @@ RUN apt update; apt install -y docker-ce-cli # Configurate git to fetch submodules correctly (https://stackoverflow.com/questions/38378914/how-to-fix-git-error-rpc-failed-curl-56-gnutls) RUN git config --global http.postBuffer 1048576000 -# Install node and yarn -RUN wget -c -O - https://deb.nodesource.com/setup_18.x | bash - -RUN apt-get install -y nodejs -RUN npm install -g yarn +# Install Node and yarn +ENV NODE_MAJOR=18 +RUN mkdir -p /etc/apt/keyrings && \ + wget -c -O - https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \ + echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && \ + apt-get update && apt-get install nodejs -y && \ + npm install -g yarn # Install Rust and required cargo packages ENV RUSTUP_HOME=/usr/local/rustup \ @@ -72,7 +75,7 @@ RUN echo "deb http://packages.cloud.google.com/apt cloud-sdk main" > /etc/apt/so RUN wget -c -O - https://sh.rustup.rs | bash -s -- -y RUN rustup install nightly-2023-08-21 RUN rustup default stable -RUN cargo install --version=0.5.13 sqlx-cli +RUN cargo install --version=0.7.3 sqlx-cli RUN cargo install cargo-nextest # Copy compiler (both solc and zksolc) binaries diff --git a/docker/zk-environment/20.04_amd64_cuda_12_0.Dockerfile b/docker/zk-environment/20.04_amd64_cuda_12_0.Dockerfile index ed10b2529740..d0bb05fed16e 100644 --- a/docker/zk-environment/20.04_amd64_cuda_12_0.Dockerfile +++ b/docker/zk-environment/20.04_amd64_cuda_12_0.Dockerfile @@ -49,9 +49,12 @@ RUN apt update; apt install -y docker-ce-cli RUN git config --global http.postBuffer 1048576000 # Install node and yarn -RUN wget -c -O - https://deb.nodesource.com/setup_18.x | bash - -RUN apt-get install -y nodejs -RUN npm install -g yarn +ENV NODE_MAJOR=18 +RUN mkdir -p /etc/apt/keyrings && \ + wget -c -O - https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \ + echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && \ + apt-get update && apt-get install nodejs -y && \ + npm install -g yarn # Install Rust and required cargo packages ENV RUSTUP_HOME=/usr/local/rustup \ @@ -70,7 +73,7 @@ RUN echo "deb http://packages.cloud.google.com/apt cloud-sdk main" > /etc/apt/so RUN wget -c -O - https://sh.rustup.rs | bash -s -- -y RUN rustup install nightly-2023-08-21 RUN rustup default stable -RUN cargo install --version=0.5.13 sqlx-cli +RUN cargo install --version=0.7.3 sqlx-cli RUN cargo install cargo-nextest # Copy compiler (both solc and zksolc) binaries diff --git a/docker/zk-environment/Dockerfile b/docker/zk-environment/Dockerfile index f86aeaddb110..0c714db68e43 100644 --- a/docker/zk-environment/Dockerfile +++ b/docker/zk-environment/Dockerfile @@ -83,8 +83,8 @@ ENV NODE_MAJOR=18 RUN mkdir -p /etc/apt/keyrings && \ wget -c -O - https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \ echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && \ - apt-get update && apt-get install nodejs -y && \ - npm install -g yarn + apt-get update && apt-get install nodejs npm -y && \ + npm install -g yarn && npm install -g cspell && npm install -g markdown-link-check # Install Rust and required cargo packages ENV RUSTUP_HOME=/usr/local/rustup \ @@ -103,8 +103,9 @@ RUN echo "deb [arch=${ARCH}] http://packages.cloud.google.com/apt cloud-sdk main RUN wget -c -O - https://sh.rustup.rs | bash -s -- -y && \ rustup default stable -RUN cargo install --version=0.5.13 sqlx-cli +RUN cargo install --version=0.7.3 sqlx-cli RUN cargo install cargo-nextest +RUN cargo install cargo-spellcheck # Copy compiler (both solc and zksolc) binaries # Obtain `solc` 0.8.20. diff --git a/docs/guides/advanced/0_alternative_vm_intro.md b/docs/guides/advanced/0_alternative_vm_intro.md index bce8c48a60aa..74e70edc9537 100644 --- a/docs/guides/advanced/0_alternative_vm_intro.md +++ b/docs/guides/advanced/0_alternative_vm_intro.md @@ -2,7 +2,7 @@ ## zkEVM clarifier -[Back to ToC](../../README.md) +[Back to ToC](../../specs/README.md) The zkSync zkEVM plays a fundamentally different role in the zkStack than the EVM does in Ethereum. The EVM is used to execute code in Ethereum's state transition function. This STF needs a client to implement and run it. Ethereum has a @@ -41,16 +41,18 @@ Unlike EVM, which is stack machine, zkEVM has 16 registers. Instead of receiving receiving a _pointer_ in its first register *(*basically a packed struct with 4 elements: the memory page id, start and length of the slice to which it points to*)* to the calldata page of the parent. Similarly, a transaction can receive some other additional data within its registers at the start of the program: whether the transaction should invoke the -constructor ([more about deployments here](#contractdeployer--immutablesimulator)), whether the transaction has -`isSystem` flag, etc. The meaning of each of these flags will be expanded further in this section. +constructor +[more about deployments here](https://github.com/matter-labs/zksync-era/blob/main/docs/specs/zk_evm/system_contracts.md#contractdeployer--immutablesimulator), +whether the transaction has `isSystem` flag, etc. The meaning of each of these flags will be expanded further in this +section. _Pointers_ are separate type in the VM. It is only possible to: - Read some value within a pointer. - Shrink the pointer by reducing the slice to which pointer points to. -- Receive the pointer to the returndata/as a calldata. -- Pointers can be stored only on stack/registers to make sure that the other contracts can not read memory/returndata of - contracts they are not supposed to. +- Receive the pointer to the `returndata` as a calldata. +- Pointers can be stored only on stack/registers to make sure that the other contracts can not read `memory/returndata` + of contracts they are not supposed to. - A pointer can be converted to the u256 integer representing it, but an integer can not be converted to a pointer to prevent unallowed memory access. - It is not possible to return a pointer that points to a memory page with id smaller than the one for the current page. @@ -63,7 +65,7 @@ For each frame, the following memory areas are allocated: - _Heap_ (plays the same role as `memory` on Ethereum). - _AuxHeap_ (auxiliary heap). It has the same properties as Heap, but it is used for the compiler to encode - calldata/copy the returndata from the calls to system contracts to not interfere with the standard Solidity memory + calldata/copy the `returndata` from the calls to system contracts to not interfere with the standard Solidity memory alignment. - _Stack_. Unlike Ethereum, stack is not the primary place to get arguments for opcodes. The biggest difference between stack on zkEVM and EVM is that on zkSync stack can be accessed at any location (just like memory). While users do not @@ -160,7 +162,9 @@ result in `revert(0,0)`. Note, that currently we do not have access to the `tx_counter` within VM (i.e. for now it is possible to increment it and it will be automatically used for logs such as `event`s as well as system logs produced by `to_l1`, but we can not read it). We need to read it to publish the _user_ L2→L1 logs, so `increment_tx_counter` is always accompanied by the -corresponding call to the [SystemContext](#systemcontext) contract. +corresponding call to the +[SystemContext](https://github.com/matter-labs/zksync-era/blob/main/docs/specs/zk_evm/system_contracts.md#systemcontext) +contract. More on the difference between system and user logs can be read [here](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/Handling%20pubdata%20in%20Boojum.md). - @@ -195,11 +199,11 @@ the start of execution: to the call. Currently, two flags are supported: 0-th bit: `isConstructor` flag. This flag can only be set by system contracts and denotes whether the account should execute its constructor logic. Note, unlike Ethereum, there is no separation on constructor & deployment bytecode. More on that can be read - [here](#contractdeployer--immutablesimulator). 1-st bit: `isSystem` flag. Whether the call intends a system contracts’ - function. While most of the system contracts’ functions are relatively harmless, accessing some with calldata only may - break the invariants of Ethereum, e.g. if the system contract uses `mimic_call`: no one expects that by calling a - contract some operations may be done out of the name of the caller. This flag can be only set if the callee is in - kernel space. + [here](https://github.com/matter-labs/zksync-era/blob/main/docs/specs/zk_evm/system_contracts.md#contractdeployer--immutablesimulator). + 1-st bit: `isSystem` flag. Whether the call intends a system contracts’ function. While most of the system contracts’ + functions are relatively harmless, accessing some with calldata only may break the invariants of Ethereum, e.g. if the + system contract uses `mimic_call`: no one expects that by calling a contract some operations may be done out of the + name of the caller. This flag can be only set if the callee is in kernel space. - The rest r3..r12 registers are non-empty only if the `isSystem` flag is set. There may be arbitrary values passed, which we call `extraAbiParams`. @@ -284,7 +288,7 @@ On zkSync the bytecode hashes are stored in the following format: - The 0th byte denotes the version of the format. Currently the only version that is used is “1”. - The 1st byte is `0` for deployed contracts’ code and `1` for the contract code - [that is being constructed](#constructing-vs-non-constructing-code-hash). + [that is being constructed](https://github.com/matter-labs/zksync-era/blob/main/docs/specs/zk_evm/system_contracts.md#constructing-vs-non-constructing-code-hash). - The 2nd and 3rd bytes denote the length of the contract in 32-byte words as big-endian 2-byte number. - The next 28 bytes are the last 28 bytes of the sha256 hash of the contract’s bytecode. @@ -302,5 +306,6 @@ Note, that it does not have to consist of only correct opcodes. In case the VM e simply revert (similar to how EVM would treat them). A call to a contract with invalid bytecode can not be proven. That is why it is **essential** that no contract with -invalid bytecode is ever deployed on zkSync. It is the job of the [KnownCodesStorage](#knowncodestorage) to ensure that -all allowed bytecodes in the system are valid. +invalid bytecode is ever deployed on zkSync. It is the job of the +[KnownCodesStorage](https://github.com/matter-labs/zksync-era/blob/main/docs/specs/zk_evm/system_contracts.md#knowncodestorage) +to ensure that all allowed bytecodes in the system are valid. diff --git a/docs/guides/advanced/compression.md b/docs/guides/advanced/compression.md index de257cc4c2be..12071e79891c 100644 --- a/docs/guides/advanced/compression.md +++ b/docs/guides/advanced/compression.md @@ -31,7 +31,7 @@ Dictionary would be: 3 -> 0xC (count: 1) ``` -Note that '1' maps to '0xD', as it occurs twice, and first occurrence is earlier than first occurence of 0xB, that also +Note that '1' maps to '0xD', as it occurs twice, and first occurrence is earlier than first occurrence of 0xB, that also occurs twice. Compressed bytecode: diff --git a/docs/guides/advanced/contracts.md b/docs/guides/advanced/contracts.md index cb42a945da6c..98065a787b71 100644 --- a/docs/guides/advanced/contracts.md +++ b/docs/guides/advanced/contracts.md @@ -70,7 +70,7 @@ override getDeployTransaction(..) { } ``` -Also `ContractDeployer` adding a special prefix for all the new contract addresses. This means that contract addesses +Also `ContractDeployer` adding a special prefix for all the new contract addresses. This means that contract addresses WILL be different on `zkSync` and Ethereum (and also leaves us the possibility of adding Ethereum addresses in the future if needed). @@ -86,9 +86,9 @@ changed - so updating the same slot multiple times doesn't increase the amount o ### Account abstraction and some method calls -As `zkSync` has a built-in AccountAbstraction (more on this in a separate article) - you shouldn't depend on some of the -solidity functions (like `ecrecover` - that checks the keys, or `tx.origin`) - in all the cases, the compiler will try -to warn you. +As `zkSync` has a built-in Account Abstraction (more on this in a separate article) - you shouldn't depend on some of +the solidity functions (like `ecrecover` - that checks the keys, or `tx.origin`) - in all the cases, the compiler will +try to warn you. ## Summary diff --git a/docs/guides/advanced/deeper_overview.md b/docs/guides/advanced/deeper_overview.md index fef5e8bb6add..7fa4a009a920 100644 --- a/docs/guides/advanced/deeper_overview.md +++ b/docs/guides/advanced/deeper_overview.md @@ -69,8 +69,8 @@ pub struct SelectionGate { } ``` -Internaly the `Variable` object is `pub struct Variable(pub(crate) u64);` - so it is an index to the position within the -constraint system object. +Internally the `Variable` object is `pub struct Variable(pub(crate) u64);` - so it is an index to the position within +the constraint system object. And now let's see how we can add this gate into the system. @@ -211,7 +211,7 @@ how we were operating on regular 'Variables' above). ### CSSelectable -Implements the `Selectable` trait - that allows this struct to participage in operations like conditionally select (so +Implements the `Selectable` trait - that allows this struct to participate in operations like conditionally select (so it can be used as 'a' or 'b' in the Select gate example above). ### CSVarLengthEncodable diff --git a/docs/guides/advanced/how_l2_messaging_works.md b/docs/guides/advanced/how_l2_messaging_works.md index 85410dfbadc0..0fea2be7d502 100644 --- a/docs/guides/advanced/how_l2_messaging_works.md +++ b/docs/guides/advanced/how_l2_messaging_works.md @@ -201,13 +201,10 @@ transmitted to L1 for final verification. [log_writing_in_vm]: https://github.com/matter-labs/era-zk_evm/blob/v1.3.2/src/opcodes/execution/log.rs [log_opcode]: https://github.com/matter-labs/era-zkevm_opcode_defs/blob/v1.3.2/src/definitions/log.rs#L16 [zkevm_assembly_parse]: - https://github.com/matter-labs/zkEVM-assembly/blob/fcfeb51e45544a629d4279b3455def847dcc2505/src/assembly/instruction/log.rs#L32 + https://github.com/matter-labs/era-zkEVM-assembly/blob/v1.3.2/src/assembly/instruction/log.rs#L32 [executor_sol]: https://github.com/matter-labs/era-contracts/blob/3a4506522aaef81485d8abb96f5a6394bd2ba69e/ethereum/contracts/zksync/facets/Executor.sol#L26 [mainet_executor]: https://etherscan.io/address/0x389a081BCf20e5803288183b929F08458F1d863D - -[sepolia_tx]: -[0x18c2a113d18c53237a4056403047ff9fafbf772cb83ccd44bb5b607f8108a64c](https://sepolia.etherscan.io/tx/0x18c2a113d18c53237a4056403047ff9fafbf772cb83ccd44bb5b607f8108a64c) - +[sepolia_tx]: https://sepolia.etherscan.io/tx/0x18c2a113d18c53237a4056403047ff9fafbf772cb83ccd44bb5b607f8108a64c [mailbox_log_inclusion]: https://github.com/matter-labs/era-contracts/blob/3a4506522aaef81485d8abb96f5a6394bd2ba69e/ethereum/contracts/zksync/facets/Mailbox.sol#L54 diff --git a/docs/guides/advanced/how_transaction_works.md b/docs/guides/advanced/how_transaction_works.md index 3ee9c30a205f..83471bfd7e84 100644 --- a/docs/guides/advanced/how_transaction_works.md +++ b/docs/guides/advanced/how_transaction_works.md @@ -85,7 +85,7 @@ The transaction can have three different results in state keeper: [l1_tx]: https://github.com/matter-labs/zksync-era/blob/main/core/lib/types/src/l1/mod.rs#L183 'l1 tx' [l2_tx]: https://github.com/matter-labs/zksync-era/blob/main/core/lib/types/src/l2/mod.rs#L140 'l2 tx' [submit_tx]: - https://github.com/matter-labs/zksync-era/blob/main/core/lib/zksync_core/src/api_server/tx_sender/mod.rs#L309 + https://github.com/matter-labs/zksync-era/blob/main/core/lib/zksync_core/src/api_server/tx_sender/mod.rs#L288 'submit tx' [process_l1_batch]: https://github.com/matter-labs/zksync-era/blob/main/core/lib/zksync_core/src/state_keeper/keeper.rs#L257 diff --git a/docs/guides/advanced/prover_keys.md b/docs/guides/advanced/prover_keys.md index 8cf59067cf89..34660492bf21 100644 --- a/docs/guides/advanced/prover_keys.md +++ b/docs/guides/advanced/prover_keys.md @@ -124,4 +124,4 @@ friendly hash function (currently Poseidon2). [prover_setup_data]: https://github.com/matter-labs/zksync-era/blob/d2ca29bf20b4ec2d9ec9e327b4ba6b281d9793de/prover/vk_setup_data_generator_server_fri/src/lib.rs#L61 [verifier_computation]: - https://github.com/matter-labs/era-contracts/blob/dev/ethereum/contracts/zksync/Verifier.sol#L268 + https://github.com/matter-labs/era-contracts/blob/dev/l1-contracts/contracts/zksync/Verifier.sol#268 diff --git a/docs/guides/advanced/pubdata.md b/docs/guides/advanced/pubdata.md index 9b8fd4346c42..f0e159a8010c 100644 --- a/docs/guides/advanced/pubdata.md +++ b/docs/guides/advanced/pubdata.md @@ -22,9 +22,9 @@ executed, we then will pull the transaction input and the relevant fields, apply current state of L2. One thing to note is that in both systems some of the contract bytecode is compressed into an array of indices where -each 2 byte index corresponds to an 8 byte word in a dictionary. More on how that is done -[here](./bytecode_compression.md). Once the bytecode has been expanded, the hash can be taken and checked against the -storage writes within the `AccountCodeStorage` contract which connects an address on L2 with the 32 byte code hash: +each 2 byte index corresponds to an 8 byte word in a dictionary. More on how that is done [here](./compression.md). Once +the bytecode has been expanded, the hash can be taken and checked against the storage writes within the +`AccountCodeStorage` contract which connects an address on L2 with the 32 byte code hash: ```solidity function _storeCodeHash(address _address, bytes32 _hash) internal { @@ -79,8 +79,8 @@ The 4 main fields to look at here are: 1. Structure: `num entries as u32 || for each entry: (8 byte id, 32 bytes final value)` 3. `factoryDeps`: An array of uncompressed bytecodes 4. `l2ArbitraryLengthMessages` : L2 → L1 Messages - 1. We don’t need them all, we are just concerned with messages sent from the `Compressor/BytcodeCompressor` contract - 2. These messages will follow the compression algorithm outline [here](./bytecode_compression.md) + 1. We don’t need them all, we are just concerned with messages sent from the `Compressor/BytecodeCompressor` contract + 2. These messages will follow the compression algorithm outline [here](./compression.md) For the ids on the repeated writes, they are generated as we process the first time keys. For example: if we see `[, ]` (starting from an empty state) then we can assume that the next time a write happens to diff --git a/docs/guides/advanced/zk_intuition.md b/docs/guides/advanced/zk_intuition.md index 97b0d26920a0..e567ebf7ca82 100644 --- a/docs/guides/advanced/zk_intuition.md +++ b/docs/guides/advanced/zk_intuition.md @@ -62,7 +62,7 @@ pub fn compute_decommitter_circuit_snapshots< ... ) -> ( Vec>, - CodeDecommittmentsDeduplicatorInstanceWitness, + CodeDecommitmentsDeduplicatorInstanceWitness, ) ``` @@ -139,15 +139,13 @@ version 1.4.0. [witness_example]: https://github.com/matter-labs/era-zkevm_test_harness/tree/main/src/witness/individual_circuits/decommit_code.rs#L24 -[verifier]: https://github.com/matter-labs/era-contracts/blob/main/ethereum/contracts/zksync/Verifier.sol +[verifier]: https://github.com/matter-labs/era-contracts/blob/main/l1-contracts/contracts/zksync/Verifier.sol [bellman repo]: https://github.com/matter-labs/bellman [bellman cuda repo]: https://github.com/matter-labs/era-bellman-cuda [example ecrecover circuit]: - https://github.com/matter-labs/sync_vm/blob/683ade0bbb445f3e2ceb82dd3f4346a0c5d16a78/src/glue/ecrecover_circuit/mod.rs#L157 -[zksync core witness]: - https://github.com/matter-labs/zksync-era/blob/main/core/lib/zksync_core/src/witness_generator/mod.rs + https://github.com/matter-labs/era-sync_vm/blob/v1.3.2/src/glue/ecrecover_circuit/mod.rs#L157 [separate witness binary]: https://github.com/matter-labs/zksync-era/blob/main/prover/witness_generator/src/main.rs [zkevm_test_harness witness]: - https://github.com/matter-labs/zkevm_test_harness/blob/0c17bc7baa4e0b64634d414942ef4200d8613bbd/src/external_calls.rs#L575 -[heavy_ops_service repo]: https://github.com/matter-labs/heavy-ops-service/tree/v1.3.2 + https://github.com/matter-labs/era-zkevm_test_harness/blob/fb47657ae3b6ff6e4bb5199964d3d37212978200/src/external_calls.rs#L579 +[heavy_ops_service repo]: https://github.com/matter-labs/era-heavy-ops-service [franklin repo]: https://github.com/matter-labs/franklin-crypto diff --git a/docs/guides/architecture.md b/docs/guides/architecture.md index dbac73fa09a8..e87f4bca7e55 100644 --- a/docs/guides/architecture.md +++ b/docs/guides/architecture.md @@ -62,7 +62,6 @@ This section provides a physical map of folders & files in this repository. - `/multivm`: A wrapper over several versions of VM that have been used by the main node. - `/object_store`: Abstraction for storing blobs outside the main data store. - `/prometheus_exporter`: Prometheus data exporter. - - `/prover_utils`: Utilities related to the proof generation. - `/queued_job_processor`: An abstraction for async job processing - `/state`: A state keeper responsible for handling transaction execution and creating miniblocks and L1 batches. - `/storage`: An encapsulated database interface. diff --git a/docs/guides/development.md b/docs/guides/development.md index 955189cb3ab4..c6410bbfcbb4 100644 --- a/docs/guides/development.md +++ b/docs/guides/development.md @@ -89,6 +89,73 @@ Currently the following criteria are checked: - Other code should always be formatted via `zk fmt`. - Dummy Prover should not be staged for commit (see below for the explanation). +## Spell Checking + +In our development workflow, we utilize a spell checking process to ensure the quality and accuracy of our documentation +and code comments. This is achieved using two primary tools: `cspell` and `cargo-spellcheck`. This section outlines how +to use these tools and configure them for your needs. + +### Using the Spellcheck Command + +The spell check command `zk spellcheck` is designed to check for spelling errors in our documentation and code. To run +the spell check, use the following command: + +``` +zk spellcheck +Options: +--pattern : Specifies the glob pattern for files to check. Default is docs/**/*. +--use-cargo: Utilize cargo spellcheck. +--use-cspell: Utilize cspell. +``` + +## Link Checking + +To maintain the integrity and reliability of our documentation, we make use of a link checking process using the +`markdown-link-check` tool. This ensures that all links in our markdown files are valid and accessible. The following +section describes how to use this tool and configure it for specific needs. + +### Using the Link Check Command + +The link check command `zk linkcheck` is designed to verify the integrity of links in our markdown files. To execute the +link check, use the following command: + +``` +zk linkcheck +Options: +--config : Path to the markdown-link-check configuration file. Default is './checks-config/links.json'. +``` + +### General Rules + +**Code References in Comments**: When referring to code elements within development comments, they should be wrapped in +backticks. For example, reference a variable as `block_number`. + +**Code Blocks in Comments**: For larger blocks of pseudocode or commented-out code, use code blocks formatted as +follows: + +```` +// ``` +// let overhead_for_pubdata = { +// let numerator: U256 = overhead_for_block_gas * total_gas_limit +// + gas_per_pubdata_byte_limit * U256::from(MAX_PUBDATA_PER_BLOCK); +// let denominator = +// gas_per_pubdata_byte_limit * U256::from(MAX_PUBDATA_PER_BLOCK) + overhead_for_block_gas; +// ``` +```` + +**Language Settings**: We use the Hunspell language setting of `en_US`. + +**CSpell Usage**: For spell checking within the `docs/` directory, we use `cspell`. The configuration for this tool is +found in `cspell.json`. It's tailored to check our documentation for spelling errors. + +**Cargo-Spellcheck for Rust and Dev Comments**: For Rust code and development comments, `cargo-spellcheck` is used. Its +configuration is maintained in `era.cfg`. + +### Adding Words to the Dictionary + +To add a new word to the spell checker dictionary, navigate to `/spellcheck/era.dic` and include the word. Ensure that +the word is relevant and necessary to be included in the dictionary to maintain the integrity of our documentation. + ## Using Dummy Prover By default, the chosen prover is a "dummy" one, meaning that it doesn't actually compute proofs but rather uses mocks to diff --git a/docs/guides/external-node/prepared_configs/mainnet-config.env b/docs/guides/external-node/prepared_configs/mainnet-config.env index 67679777fbd2..546e572f6cbc 100644 --- a/docs/guides/external-node/prepared_configs/mainnet-config.env +++ b/docs/guides/external-node/prepared_configs/mainnet-config.env @@ -41,8 +41,6 @@ EN_FILTERS_LIMIT=10000 EN_SUBSCRIPTIONS_LIMIT=10000 # Interval for polling the DB for pubsub (in ms). EN_PUBSUB_POLLING_INTERVAL=200 -# Number of threads per API server. -EN_THREADS_PER_SERVER=128 # Tx nonce: how far ahead from the committed nonce can it be. # This shouldn't be larger than the value on the main node (50). EN_MAX_NONCE_AHEAD=50 diff --git a/docs/guides/external-node/prepared_configs/testnet-goerli-config-deprecated.env b/docs/guides/external-node/prepared_configs/testnet-goerli-config-deprecated.env index b2e7e43c528b..e5c0ac947df8 100644 --- a/docs/guides/external-node/prepared_configs/testnet-goerli-config-deprecated.env +++ b/docs/guides/external-node/prepared_configs/testnet-goerli-config-deprecated.env @@ -41,8 +41,6 @@ EN_FILTERS_LIMIT=10000 EN_SUBSCRIPTIONS_LIMIT=10000 # Interval for polling the DB for pubsub (in ms). EN_PUBSUB_POLLING_INTERVAL=200 -# Number of threads per API server. -EN_THREADS_PER_SERVER=128 # Tx nonce: how far ahead from the committed nonce can it be. # This shouldn't be larger than the value on the main node (50). EN_MAX_NONCE_AHEAD=50 diff --git a/docs/guides/external-node/prepared_configs/testnet-sepolia-config.env b/docs/guides/external-node/prepared_configs/testnet-sepolia-config.env index 9019b847fb47..bc1898f89be3 100644 --- a/docs/guides/external-node/prepared_configs/testnet-sepolia-config.env +++ b/docs/guides/external-node/prepared_configs/testnet-sepolia-config.env @@ -41,8 +41,6 @@ EN_FILTERS_LIMIT=10000 EN_SUBSCRIPTIONS_LIMIT=10000 # Interval for polling the DB for pubsub (in ms). EN_PUBSUB_POLLING_INTERVAL=200 -# Number of threads per API server. -EN_THREADS_PER_SERVER=128 # Tx nonce: how far ahead from the committed nonce can it be. # This shouldn't be larger than the value on the main node (50). EN_MAX_NONCE_AHEAD=50 diff --git a/docs/guides/launch.md b/docs/guides/launch.md index b463655719c6..265d88e515b1 100644 --- a/docs/guides/launch.md +++ b/docs/guides/launch.md @@ -1,6 +1,6 @@ # Running the application -This document covers common scenarios of launching zkSync applications set locally. +This document covers common scenarios for launching zkSync applications set locally. ## Prerequisites @@ -17,8 +17,9 @@ zk # installs and builds zk itself zk init ``` -If you face any other problems with the `zk init` command, go to the [Troubleshooting](#Troubleshooting) section at the -end of this file. There are solutions for some common error cases. +If you face any other problems with the `zk init` command, go to the +[Troubleshooting](https://github.com/matter-labs/zksync-era/blob/main/docs/guides/launch.md#troubleshooting) section at +the end of this file. There are solutions for some common error cases. To completely reset the dev environment: @@ -111,29 +112,6 @@ cargo run --release --bin zksync_verification_key_generator ``` -## Running the setup key generator on machine with GPU - -- uncomment `"core/bin/setup_key_generator_and_server",` from root `Cargo.toml` file. -- ensure that the setup_2^26.key in the current directory, the file can be downloaded from - - -```shell -export BELLMAN_CUDA_DIR=$PWD -# To generate setup key for specific circuit type[0 - 17], 2 below corresponds to circuit type 2. -cargo +nightly run --features gpu --release --bin zksync_setup_key_generator -- --numeric-circuit 2 -``` - -## Running the setup key generator on machine without GPU - -- uncomment `"core/bin/setup_key_generator_and_server",` from root `Cargo.toml` file. -- ensure that the setup_2^26.key in the current directory, the file can be downloaded from - - -```shell -# To generate setup key for specific circuit type[0 - 17], 2 below corresponds to circuit type 2. -cargo +nightly run --release --bin zksync_setup_key_generator -- --numeric-circuit 2 -``` - ## Generating binary verification keys for existing json verification keys ```shell diff --git a/docs/guides/repositories.md b/docs/guides/repositories.md index b2b1a92d373b..154f0bccdd5b 100644 --- a/docs/guides/repositories.md +++ b/docs/guides/repositories.md @@ -16,7 +16,7 @@ | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | | [era-compiler-tester](https://github.com/matter-labs/era-compiler-tester) | Integration testing framework for running executable tests on zkEVM | | [era-compiler-tests](https://github.com/matter-labs/era-compiler-tests) | Collection of executable tests for zkEVM | -| [era-compiler-llvm](https://github.com/matter-labs/compiler-llvm) | zkEVM fork of the LLVM framework | +| [era-compiler-llvm](https://github.com/matter-labs//era-compiler-llvm) | zkEVM fork of the LLVM framework | | [era-compiler-solidity](https://github.com/matter-labs/era-compiler-solidity) | Solidity Yul/EVMLA compiler front end | | [era-compiler-vyper](https://github.com/matter-labs/era-compiler-vyper) | Vyper LLL compiler front end | | [era-compiler-llvm-context](https://github.com/matter-labs/era-compiler-llvm-context) | LLVM IR generator logic shared by multiple front ends | @@ -46,7 +46,7 @@ | ----------------------------------------------------------------------------- | ------------------------------------------------------------------- | | [era-bellman-cuda](https://github.com/matter-labs/era-bellman-cuda) | Cuda implementations for cryptographic functions used by the prover | | [era-heavy-ops-service](https://github.com/matter-labs/era-heavy-ops-service) | Main circuit prover that requires GPU to run | -| [era-cicruit_testing](https://github.com/matter-labs/era-circuit_testing) | ?? | +| [era-circuit_testing](https://github.com/matter-labs/era-circuit_testing) | ?? | ### Tools & contract developers diff --git a/docs/guides/setup-dev.md b/docs/guides/setup-dev.md index f17e267ac53e..a833fa10f455 100644 --- a/docs/guides/setup-dev.md +++ b/docs/guides/setup-dev.md @@ -10,19 +10,19 @@ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # NVM curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash # All necessary stuff -sudo apt-get install build-essential pkg-config cmake clang lldb lld libssl-dev postgresql docker-compose +sudo apt-get install build-essential pkg-config cmake clang lldb lld libssl-dev postgresql # Docker sudo usermod -aG docker YOUR_USER ## You might need to re-connect (due to usermod change). # Node & yarn -nvm install node +nvm install 18 npm install -g yarn yarn set version 1.22.19 # SQL tools -cargo install sqlx-cli --version 0.5.13 +cargo install sqlx-cli --version 0.7.3 # Stop default postgres (as we'll use the docker one) sudo systemctl stop postgresql # Start docker. @@ -55,9 +55,9 @@ want to only have CLI tool, you need the `docker-ce` package and you can follow Installing `docker` via `snap` or from the default repository can cause troubles. -You need to install both `docker` and `docker-compose`. +You need to install both `docker` and `docker compose`. -**Note:** `docker-compose` is installed automatically with `Docker Desktop`. +**Note:** `docker compose` is installed automatically with `Docker Desktop`. **Note:** On linux you may encounter the following error when you’ll try to work with `zksync`: @@ -90,10 +90,10 @@ If logging out does not resolve the issue, restarting the computer should. `Node.js`, we suggest you to install [nvm](https://github.com/nvm-sh/nvm). It will allow you to update `Node.js` version easily in the future (by running `nvm use` in the root of the repository) 2. Install `yarn` (make sure to get version 1.22.19 - you can change the version by running `yarn set version 1.22.19`). - Instructions can be found on the [official site](https://classic.yarnpkg.com/en/docs/install/). - Check if `yarn` is installed by running `yarn -v`. If you face any problems when installing `yarn`, it might be the - case that your package manager installed the wrong package.Make sure to thoroughly follow the instructions above on - the official website. It contains a lot of troubleshooting guides in it. + Instructions can be found on the [official site](https://classic.yarnpkg.com/en/docs/install/). Check if `yarn` is + installed by running `yarn -v`. If you face any problems when installing `yarn`, it might be the case that your + package manager installed the wrong package.Make sure to thoroughly follow the instructions above on the official + website. It contains a lot of troubleshooting guides in it. ## `Axel` @@ -123,7 +123,7 @@ Make sure the version is higher than `2.17.10`. In order to compile RocksDB, you must have LLVM available. On debian-based linux it can be installed as follows: -On linux: +On debian-based linux: ```bash sudo apt-get install build-essential pkg-config cmake clang lldb lld @@ -144,7 +144,7 @@ On mac: brew install openssl ``` -On linux: +On debian-based linux: ```bash sudo apt-get install libssl-dev @@ -196,7 +196,7 @@ On mac: brew install postgresql@14 ``` -On linux: +On debian-based linux: ```bash sudo apt-get install postgresql @@ -217,17 +217,27 @@ SQLx is a Rust library we use to interact with Postgres, and its CLI is used to features of the library. ```bash -cargo install sqlx-cli --version 0.5.13 +cargo install sqlx-cli --version 0.7.3 ``` ## Solidity compiler `solc` Install the latest solidity compiler. +On mac: + ```bash brew install solidity ``` +On debian-based linux: + +```bash +sudo add-apt-repository ppa:ethereum/ethereum +sudo apt-get update +sudo apt-get install solc +``` + Alternatively, download a [precompiled version](https://github.com/ethereum/solc-bin) and add it to your PATH. ## Python diff --git a/docs/specs/README.md b/docs/specs/README.md index 724d7b923e84..34103584e547 100644 --- a/docs/specs/README.md +++ b/docs/specs/README.md @@ -5,7 +5,7 @@ 1. [L1 Contracts](./l1_smart_contracts.md) 1. [zkEVM](./zk_evm/README.md) - [VM Overview](./zk_evm/vm_overview.md) - - [VM Specificiation](./zk_evm/vm_specification/README.md) + - [VM Specification](./zk_evm/vm_specification/README.md) - [Bootloader](./zk_evm/bootloader.md) - [System Contracts](./zk_evm/system_contracts.md) - [Precompiles](./zk_evm/precompiles.md) @@ -33,4 +33,4 @@ 1. [The Hyperchain](./the_hyperchain/README.md) - [Overview](./the_hyperchain/overview.md) - [Shared Bridge](./the_hyperchain/shared_bridge.md) - - [Hyperbrdges](./the_hyperchain/hyperbridges.md) + - [Hyperbridges](./the_hyperchain/hyperbridges.md) diff --git a/docs/specs/blocks_batches.md b/docs/specs/blocks_batches.md index bd3df88539c6..ce678edf937d 100644 --- a/docs/specs/blocks_batches.md +++ b/docs/specs/blocks_batches.md @@ -142,7 +142,7 @@ on mainnet is still ongoing and most likely will end on late October / early Nov ## Blocks’ processing and consistency checks Our `SystemContext` contract allows to get information about batches and L2 blocks. Some of the information is hard to -calculate onchain. For instace, time. The timing information (for both batches and L2 blocks) are provided by the +calculate onchain. For instance, time. The timing information (for both batches and L2 blocks) are provided by the operator. In order to check that the operator provided some realistic values, certain checks are done on L1. Generally though, we try to check as much as we can on L2. diff --git a/docs/specs/data_availability/compression.md b/docs/specs/data_availability/compression.md index ef29ece4a8bb..0a0057ac9faf 100644 --- a/docs/specs/data_availability/compression.md +++ b/docs/specs/data_availability/compression.md @@ -111,15 +111,15 @@ There are two reasons for it: - A minor reason: sometimes it is less efficient in case the packing is used for very few slots (since for correct unpacking we need to provide the number of slots for each packing type). -- A fundamental reason: currently enum indeces are stored directly in the merkle tree & have very strict order of +- A fundamental reason: currently enum indices are stored directly in the merkle tree & have very strict order of incrementing enforced by the circuits and (they are given in order by pairs `(address, key)`), which are generally not accessible from pubdata. All this means that we are not allowed to change the order of “first writes” above, so indexes for them are directly recoverable from their order, and so we can not permute them. If we were to reorder keys without supplying the new -enumeration indeces for them, the state would be unrecoverable. Always supplying the new enum index may add additional 5 +enumeration indices for them, the state would be unrecoverable. Always supplying the new enum index may add additional 5 bytes for each key, which might negate the compression benefits in a lot of cases. Even if the compression will still be beneficial, the added complexity may not be worth it. -That being said, we _could_ rearange those for _repeated_ writes, but for now we stick to the same value compression +That being said, we _could_ rearrange those for _repeated_ writes, but for now we stick to the same value compression format for simplicity. diff --git a/docs/specs/data_availability/reconstruction.md b/docs/specs/data_availability/reconstruction.md index 4b86b4325a22..a97f22298e01 100644 --- a/docs/specs/data_availability/reconstruction.md +++ b/docs/specs/data_availability/reconstruction.md @@ -1,4 +1,4 @@ -# L2 State Recosntruction Tool +# L2 State Reconstruction Tool Given that we post all data to L1, there is a tool, created by the [Equilibrium Team](https://equilibrium.co/) that solely uses L1 pubdata for reconstructing the state and verifying that the state root on L1 can be created using diff --git a/docs/specs/l1_l2_communication/l1_to_l2.md b/docs/specs/l1_l2_communication/l1_to_l2.md index 12a20292ef64..ed1605a039a6 100644 --- a/docs/specs/l1_l2_communication/l1_to_l2.md +++ b/docs/specs/l1_l2_communication/l1_to_l2.md @@ -108,7 +108,7 @@ In a very rare event when the team needs to revert the batch with the upgrade on [reset](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/contracts/ethereum/contracts/zksync/facets/Executor.sol#L412). Note, however, that we do not “remember” that certain batches had a version before the upgrade, i.e. if the reverted -batches will have to be reexecuted, the upgrade transaction must still be present there, even if some of the deleted +batches will have to be re-executed, the upgrade transaction must still be present there, even if some of the deleted batches were committed before the upgrade and thus didn’t contain the transaction. ### Execute diff --git a/docs/specs/l1_smart_contracts.md b/docs/specs/l1_smart_contracts.md index 3bcd6a1ac4fe..b5b0a484559c 100644 --- a/docs/specs/l1_smart_contracts.md +++ b/docs/specs/l1_smart_contracts.md @@ -23,7 +23,7 @@ implementation that is inspired by the [mudgen reference implementation](https:/ external functions, only the fallback that delegates a call to one of the facets (target/implementation contract). So even an upgrade system is a separate facet that can be replaced. -One of the differences from the reference implementation is access freezability. Each of the facets has an associated +One of the differences from the reference implementation is access freezable. Each of the facets has an associated parameter that indicates if it is possible to freeze access to the facet. Privileged actors can freeze the **diamond** (not a specific facet!) and all facets with the marker `isFreezable` should be inaccessible until the governor or admin unfreezes the diamond. Note that it is a very dangerous thing since the diamond proxy can freeze the upgrade system and diff --git a/docs/specs/overview.md b/docs/specs/overview.md index 2ac887090915..0f87d91c5c7a 100644 --- a/docs/specs/overview.md +++ b/docs/specs/overview.md @@ -8,9 +8,8 @@ A user submits their transaction to the sequencer. The job of the sequencer is t using the zkEVM, and to provide a soft confirmation to the user that their transaction was executed. If the user chooses they can force the sequencer to include their transaction by submitting it via L1. After the sequencer executes the block, it sends it over to the prover, who creates a cryptographic proof of the block's execution. This proof is then -sent to the L1 contract alongside the necessary data. On the L1 a -[smart contract](./zkEVM/high_level/l1_smart_contracts.md) verifies that the proof is valid and all the data has been -submitted, and the rollup's state is also updated in the contract. +sent to the L1 contract alongside the necessary data. On the L1 a [smart contract](./l1_smart_contracts.md) verifies +that the proof is valid and all the data has been submitted, and the rollup's state is also updated in the contract. ![Components](./img/L2_Components.png) diff --git a/docs/specs/prover/boojum_function_check_if_satisfied.md b/docs/specs/prover/boojum_function_check_if_satisfied.md index 31b3a88a59d6..48fa095637d6 100644 --- a/docs/specs/prover/boojum_function_check_if_satisfied.md +++ b/docs/specs/prover/boojum_function_check_if_satisfied.md @@ -12,7 +12,7 @@ variables circuit columns that are under PLONK copy-permutation constraints (so in programming languages), and the witness ephemeral values that can be used to prove certain constraints, for example by providing an inverse if the variable must be non-zero. -![Check_if_satisfied.png](./img/boojum_function_check_if_satisfied/check_if_satisfied.png) +![Check_if_satisfied.png](./img/boojum_function_check_if_satisfied/Check_if_satisfied.png) Next we prepare a view. Instead of working with all of the columns at once, it can be helpful to work with only a subset. @@ -70,7 +70,7 @@ we iterate over each gate_type_id and evaluator. ![Check_if_satisfied(9).png](<./img/boojum_function_check_if_satisfied/Check_if_satisfied(9).png>) If gate_type_id is a LookupFormalGate, we don’t need to do anything in this loop because it is handled by the lookup -table. For all other cases, we need to check the evaluator’s total_quotient_terms_over_all_repititions is non-zero. +table. For all other cases, we need to check the evaluator’s total_quotient_terms_over_all_repetitions is non-zero. ![Check_if_satisfied(11).png](<./img/boojum_function_check_if_satisfied/Check_if_satisfied(11).png>) diff --git a/docs/specs/prover/boojum_gadgets.md b/docs/specs/prover/boojum_gadgets.md index 666422e53f45..eb6e9ce719b6 100644 --- a/docs/specs/prover/boojum_gadgets.md +++ b/docs/specs/prover/boojum_gadgets.md @@ -86,7 +86,7 @@ pub struct Variable(pub(crate) u64); ``` which is represented in the current Field. Variable is quite diverse, and to have "good" alignment and size we manually -do encoding management to be able to represent it as both copiable variable or witness. +do encoding management to be able to represent it as both copyable variable or witness. The implementation of this circuit type itself is similar. We can also divide them into classes as main and dependent: Such type like U8-U512 decoding inside functions to Num for using them in logical operations. As mentioned above, the @@ -120,7 +120,7 @@ As you see, you can allocate both with and without witnesses. ## Hash function -In gadgets we have a lot of hast implementation: +In gadgets we have a lot of hash implementation: - blake2s - keccak256 @@ -151,7 +151,7 @@ And here is the main functions: ```rust fn push(&mut self, value: Element) { - // increment lenght + // increment length // head - hash(head, value) // witness.push_back(value.witness) } diff --git a/docs/specs/prover/circuit_testing.md b/docs/specs/prover/circuit_testing.md index 16f1e7b8209f..159d908642ff 100644 --- a/docs/specs/prover/circuit_testing.md +++ b/docs/specs/prover/circuit_testing.md @@ -27,9 +27,9 @@ constraint system. Next, we define a helper function: To help run the test, we have a helper function called configure that returns a builder. The builder knows all of the gates and gate placement strategy, which will be useful for setting up the constraint system. -![Contest(6).png](<./img/img/circuit_testing/Contest(6).png>) +![Contest(6).png](<./img/circuit_testing/Contest(6).png>) -The constaint system is almost ready! We still need to add the lookup tables for common boolean functions: +The constraint system is almost ready! We still need to add the lookup tables for common boolean functions: ![Contest(7).png](<./img/circuit_testing/Contest(7).png>) @@ -49,7 +49,7 @@ We have to use special integer types because we are working in a finite field. The constants here are specific to the curve used, and are described in detail by code comments in the ecrecover_precompile_inner_routine. -Finally we can call the ecrecover_precompile_innner_routine: +Finally we can call the ecrecover_precompile_inner_routine: ![Contest(11).png](<./img/circuit_testing/Contest(11).png>) diff --git a/docs/specs/prover/circuits/README.md b/docs/specs/prover/circuits/README.md index fbec506d8f91..f0da38ab3aeb 100644 --- a/docs/specs/prover/circuits/README.md +++ b/docs/specs/prover/circuits/README.md @@ -1,7 +1,7 @@ # Circuits - [Overview](./overview.md) -- [Code decommiter](./code_decommitter.md) +- [Code decommitter](./code_decommitter.md) - [Demux log queue](./demux_log_queue.md) - [ECRecover](./ecrecover.md) - [Keccak round function](./keccak_round_function.md) diff --git a/docs/specs/prover/circuits/code_decommitter.md b/docs/specs/prover/circuits/code_decommitter.md index 91ff102afcb2..2e5b9609de10 100644 --- a/docs/specs/prover/circuits/code_decommitter.md +++ b/docs/specs/prover/circuits/code_decommitter.md @@ -23,12 +23,12 @@ pub struct CodeDecommitterOutputData { ```rust pub struct CodeDecommitterFSMInputOutput { - pub internal_fsm: CodeDecommittmentFSM, - pub decommittment_requests_queue_state: QueueState, + pub internal_fsm: CodeDecommitmentFSM, + pub decommitment_requests_queue_state: QueueState, pub memory_queue_state: QueueState, } -pub struct CodeDecommittmentFSM { +pub struct CodeDecommitmentFSM { pub sha256_inner_state: [UInt32; 8], // 8 uint32 words of internal sha256 state pub hash_to_compare_against: UInt256, pub current_index: UInt32, @@ -64,7 +64,7 @@ let mut structured_input = CodeDecommitterCycleInputOutput::alloc_ignoring_outputs(cs, closed_form_input.clone()); ``` -We chose what `memory_queue` state and `deccomitments_queue` state to continue to work with. +We chose what `memory_queue` state and `decommitments_queue` state to continue to work with. ```rust let requests_queue_state = QueueState::conditionally_select( @@ -75,7 +75,7 @@ let requests_queue_state = QueueState::conditionally_select( .sorted_requests_queue_initial_state, &structured_input .hidden_fsm_input - .decommittment_requests_queue_state, + .decommitment_requests_queue_state, ); let memory_queue_state = QueueState::conditionally_select( @@ -89,7 +89,7 @@ let memory_queue_state = QueueState::conditionally_select( We do the same with inner FSM part. ```rust -let initial_state = CodeDecommittmentFSM::conditionally_select( +let initial_state = CodeDecommitmentFSM::conditionally_select( cs, structured_input.start_flag, &starting_fsm_state, diff --git a/docs/specs/prover/circuits/demux_log_queue.md b/docs/specs/prover/circuits/demux_log_queue.md index 27bc596bfcf2..f84c8d1ea1ed 100644 --- a/docs/specs/prover/circuits/demux_log_queue.md +++ b/docs/specs/prover/circuits/demux_log_queue.md @@ -60,7 +60,7 @@ structured_input .enforce_trivial_head(cs); ``` -So long as `tail` is some equivalent of the merkel tree root and `head` is an equivalent of the current node hash, we +So long as `tail` is some equivalent of the merkle tree root and `head` is an equivalent of the current node hash, we provide some path witness when we pop elements and require that we properly end up in the root. So we must prove that element of head is zero: diff --git a/docs/specs/prover/circuits/log_sorter.md b/docs/specs/prover/circuits/log_sorter.md index 05294b6f63c4..87edeb2057c0 100644 --- a/docs/specs/prover/circuits/log_sorter.md +++ b/docs/specs/prover/circuits/log_sorter.md @@ -197,14 +197,14 @@ Additional checks for length. We should always check whether the sorted queue an length. ```rust -let unsorted_queue_lenght = Num::from_variable(unsorted_queue.length.get_variable()); -let intermediate_sorted_queue_lenght = +let unsorted_queue_length = Num::from_variable(unsorted_queue.length.get_variable()); +let intermediate_sorted_queue_length = Num::from_variable(intermediate_sorted_queue.length.get_variable()); Num::enforce_equal( cs, - &unsorted_queue_lenght, - &intermediate_sorted_queue_lenght, + &unsorted_queue_length, + &intermediate_sorted_queue_length, ); ``` @@ -266,7 +266,7 @@ values_are_equal.conditionally_enforce_true(cs, should_enforce); let this_item_is_non_trivial_rollback = Boolean::multi_and(cs, &[sorted_item.rollback, should_pop]); let negate_previous_item_rollback = previous_item.rollback.negated(cs); -let prevous_item_is_non_trivial_write = Boolean::multi_and( +let previous_item_is_non_trivial_write = Boolean::multi_and( cs, &[negate_previous_item_rollback, negate_previous_is_trivial], ); @@ -274,7 +274,7 @@ let is_sequential_rollback = Boolean::multi_and( cs, &[ this_item_is_non_trivial_rollback, - prevous_item_is_non_trivial_write, + previous_item_is_non_trivial_write, ], ); same_log.conditionally_enforce_true(cs, is_sequential_rollback); diff --git a/docs/specs/prover/circuits/main_vm.md b/docs/specs/prover/circuits/main_vm.md index cc18f7b56610..048ed9ea3ca9 100644 --- a/docs/specs/prover/circuits/main_vm.md +++ b/docs/specs/prover/circuits/main_vm.md @@ -40,8 +40,8 @@ pub struct VmLocalState { pub callstack: Callstack, pub memory_queue_state: [Num; FULL_SPONGE_QUEUE_STATE_WIDTH], pub memory_queue_length: UInt32, - pub code_decommittment_queue_state: [Num; FULL_SPONGE_QUEUE_STATE_WIDTH], - pub code_decommittment_queue_length: UInt32, + pub code_decommitment_queue_state: [Num; FULL_SPONGE_QUEUE_STATE_WIDTH], + pub code_decommitment_queue_length: UInt32, pub context_composite_u128: [UInt32; 4], } ``` @@ -120,7 +120,7 @@ for _cycle_idx in 0..limit { The VM runs in cycles. For each cycle, 1. Start in a prestate - perform all common operations for every opcode, namely deal with exceptions, resources, edge - cases like end of execution, select opcods, compute common values. Within the zkEVM framework, numerous entities + cases like end of execution, select opcodes, compute common values. Within the zkEVM framework, numerous entities identified as "opcodes" in the EVM paradigm are elegantly manifested as mere function calls. This modification is rooted in the succinct observation that, from the perspective of an external caller, an inlined function (analogous to an opcode) is inherently indistinguishable from an internal function call. @@ -185,7 +185,7 @@ pub struct StateDiffsAccumulator { // other meta parameters of VM pub new_tx_number: Option<(Boolean, UInt32)>, pub new_ergs_per_pubdata: Option<(Boolean, UInt32)>, - // memory bouds + // memory bounds pub new_heap_bounds: Vec<(Boolean, UInt32)>, pub new_aux_heap_bounds: Vec<(Boolean, UInt32)>, // u128 special register, one from context, another from call/ret @@ -194,7 +194,7 @@ pub struct StateDiffsAccumulator { pub callstacks: Vec<(Boolean, Callstack)>, // memory page counter pub memory_page_counters: Option>, - // decommittment queue + // decommitment queue pub decommitment_queue_candidates: Option<( Boolean, UInt32, @@ -271,8 +271,8 @@ let memory_queue_final_tail = QueueTailState::conditionally_select( ```rust let decommitment_queue_current_tail = QueueTailState { - tail: final_state.code_decommittment_queue_state, - length: final_state.code_decommittment_queue_length, + tail: final_state.code_decommitment_queue_state, + length: final_state.code_decommitment_queue_length, }; let decommitment_queue_final_tail = QueueTailState::conditionally_select( cs, diff --git a/docs/specs/prover/circuits/overview.md b/docs/specs/prover/circuits/overview.md index 73b164230e55..4e0a8ea19b41 100644 --- a/docs/specs/prover/circuits/overview.md +++ b/docs/specs/prover/circuits/overview.md @@ -38,7 +38,7 @@ That’s how we can make our prover structure more optimized and flexible. For now, we have 13 base layer circuits: - [MainVM](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/Main%20Vm.md) -- [CodeDecommittmentsSorter](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/SortDecommitments.md) +- [CodeDecommitmentsSorter](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/SortDecommitments.md) - [CodeDecommitter](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/CodeDecommitter.md) - [LogDemuxer](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/DemuxLogQueue.md) - [KeccakRoundFunction](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/KeccakRoundFunction.md) diff --git a/docs/specs/prover/circuits/sha256_round_function.md b/docs/specs/prover/circuits/sha256_round_function.md index 055d45a50fd7..dbc8de485053 100644 --- a/docs/specs/prover/circuits/sha256_round_function.md +++ b/docs/specs/prover/circuits/sha256_round_function.md @@ -127,7 +127,7 @@ Form the final state (depending on flag we choose between states): ); structured_input.hidden_fsm_output.internal_fsm = final_state; - structured_input.hidden_fsm_output.log_queue_state = final_requets_state; + structured_input.hidden_fsm_output.log_queue_state = final_request_state; structured_input.hidden_fsm_output.memory_queue_state = final_memory_state; ``` @@ -166,7 +166,7 @@ progress: ```rust let input_queue_is_empty = precompile_calls_queue.is_empty(cs); -let can_finish_immediatelly = +let can_finish_immediately = Boolean::multi_and(cs, &[state.read_precompile_call, input_queue_is_empty]); ``` @@ -334,7 +334,7 @@ let no_rounds_left = state.precompile_call_params.num_rounds.is_zero(cs); let write_result = Boolean::multi_and(cs, &[state.read_words_for_round, no_rounds_left]); let mut write_word = zero_u256; -// some endianess magic +// some endianness magic for (dst, src) in write_word .inner .iter_mut() diff --git a/docs/specs/prover/circuits/sort_decommitments.md b/docs/specs/prover/circuits/sort_decommitments.md index 8fd4ea11b281..622f91054c4b 100644 --- a/docs/specs/prover/circuits/sort_decommitments.md +++ b/docs/specs/prover/circuits/sort_decommitments.md @@ -5,7 +5,7 @@ ### [Input](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/sort_decommittment_requests/input.rs#L62) ```rust -pub struct CodeDecommittmentsDeduplicatorInputData { +pub struct CodeDecommitmentsDeduplicatorInputData { pub initial_queue_state: QueueState, pub sorted_queue_initial_state: QueueState, } @@ -14,7 +14,7 @@ pub struct CodeDecommittmentsDeduplicatorInputData { ### [Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/sort_decommittment_requests/input.rs#L81) ```rust -pub struct CodeDecommittmentsDeduplicatorOutputData { +pub struct CodeDecommitmentsDeduplicatorOutputData { pub final_queue_state: QueueState, } ``` @@ -22,7 +22,7 @@ pub struct CodeDecommittmentsDeduplicatorOutputData { ### [FSM Input and FSM Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/sort_decommittment_requests/input.rs#L26) ```rust -pub struct CodeDecommittmentsDeduplicatorFSMInputOutput { +pub struct CodeDecommitmentsDeduplicatorFSMInputOutput { pub initial_queue_state: QueueState, pub sorted_queue_state: QueueState, pub final_queue_state: QueueState, @@ -39,10 +39,10 @@ pub struct CodeDecommittmentsDeduplicatorFSMInputOutput { ## Main circuit logic This circuit handles the sorting and deduplication of code cancellation requests. Before starting, during the pre-start -phase, the first decommiter queue is generated. To decommiter a code, the input will receive the hash root of the code, -the length of the code, the code hash of the opcode, the number of opcodes and the code of the page. Next, it sorts the -queue and, in the process, identifies and removes identical requests, serving as a filtering mechanism in case the same -contract is called several times. +phase, the first decommitter queue is generated. To decommitter a code, the input will receive the hash root of the +code, the length of the code, the code hash of the opcode, the number of opcodes and the code of the page. Next, it +sorts the queue and, in the process, identifies and removes identical requests, serving as a filtering mechanism in case +the same contract is called several times. The detailed explanation of sorting and deduplicating can be found [here](https://github.com/code-423n4/2023-10-zksync/blob/c3ff020df5d11fe91209bd99d7fb0ec1272dc387/docs/Circuits%20Section/Circuits/Sorting.md). @@ -52,13 +52,13 @@ The detailed explanation of sorting and deduplicating can be found The circuit begins with allocating input part of the PI. ```rust -let CodeDecommittmentsDeduplicatorInstanceWitness { +let CodeDecommitmentsDeduplicatorInstanceWitness { closed_form_input, initial_queue_witness, sorted_queue_witness, } = witness; -let mut structured_input = CodeDecommittmentsDeduplicatorInputOutput::alloc_ignoring_outputs( +let mut structured_input = CodeDecommitmentsDeduplicatorInputOutput::alloc_ignoring_outputs( cs, closed_form_input.clone(), ); diff --git a/docs/specs/prover/circuits/storage_application.md b/docs/specs/prover/circuits/storage_application.md index 862f0c262b53..05f013de888f 100644 --- a/docs/specs/prover/circuits/storage_application.md +++ b/docs/specs/prover/circuits/storage_application.md @@ -133,7 +133,7 @@ state_diff_data.derived_key = UInt8::parallel_select( ... ``` -Finally, we compute a new merkel path. +Finally, we compute a new Merkle path. ```rust let mut current_hash = blake2s(cs, &leaf_bytes); diff --git a/docs/specs/prover/circuits/storage_sorter.md b/docs/specs/prover/circuits/storage_sorter.md index 3a6757af5c5e..d7f82cd9acbe 100644 --- a/docs/specs/prover/circuits/storage_sorter.md +++ b/docs/specs/prover/circuits/storage_sorter.md @@ -273,9 +273,9 @@ new_lhs.iter().zip(new_rhs).for_each(|(l, r)| { Now we update PI output parts and compute a commitment. Then we allocate it as public variables. ```rust -let input_committment = +let input_commitment = commit_variable_length_encodable_item(cs, &compact_form, round_function); -for el in input_committment.iter() { +for el in input_commitment.iter() { let gate = PublicInputGate::new(el.get_variable()); gate.add_to_cs(cs); } diff --git a/docs/specs/prover/overview.md b/docs/specs/prover/overview.md index 2a1a6f89bdcb..a7f814a458a8 100644 --- a/docs/specs/prover/overview.md +++ b/docs/specs/prover/overview.md @@ -1,7 +1,7 @@ # Intro to zkSync’s ZK This page is specific to our cryptography. For a general introduction, please read: -[https://docs.zksync.io/userdocs/intro/#introduction](https://docs.zksync.io/userdocs/intro/#introduction) +[https://docs.zksync.io/build/developer-reference/rollups.html](https://docs.zksync.io/build/developer-reference/rollups.html) As a ZK rollup, we want everything to be verified by cryptography and secured by Ethereum. The power of ZK allows for transaction compression, reducing fees for users while inheriting the same security. @@ -57,7 +57,7 @@ is described in more detail in The process of turning code into constraints is called arithmetization. Our arithmetization is based on a variation of “Plonk”. The details are abstracted away from the circuits, but if you’d like to learn more, read about Plonk in -[Vitalik’s blog](https://vitalik.ca/general/2019/09/22/plonk.html) or the +[Vitalik’s blog](https://vitalik.eth.limo/general/2019/09/22/plonk.html) or the [Plonky2 paper](https://github.com/mir-protocol/plonky2/blob/main/plonky2/plonky2.pdf). More details of our proving system can be found in the [Redshift Paper](https://eprint.iacr.org/2019/1400.pdf). diff --git a/docs/specs/the_hyperchain/overview.md b/docs/specs/the_hyperchain/overview.md index 13f27acba944..f31c4da99f1c 100644 --- a/docs/specs/the_hyperchain/overview.md +++ b/docs/specs/the_hyperchain/overview.md @@ -1,6 +1,6 @@ # Overview -ZK Stack roll chains will be launched on L1 into a [shared bridge](./the_hyperchain/shared_bridge.md). The shared bridge -will create an ecosystem of chains, with shared standards, upgrades, and free flow of assets. This free flow of assets -will be enabled by [hyperbridges](./the_hyperchain/hyperbridges.md). Hyperbridges are trustless and cheap bridges -between hyperchains, allowing cross-chain function calls. +ZK Stack roll chains will be launched on L1 into a [shared bridge](./shared_bridge.md). The shared bridge will create an +ecosystem of chains, with shared standards, upgrades, and free flow of assets. This free flow of assets will be enabled +by [hyperbridges](./hyperbridges.md). Hyperbridges are trustless and cheap bridges between hyperchains, allowing +cross-chain function calls. diff --git a/docs/specs/the_hyperchain/shared_bridge.md b/docs/specs/the_hyperchain/shared_bridge.md index a57c1ff7dd7b..72b4970dd356 100644 --- a/docs/specs/the_hyperchain/shared_bridge.md +++ b/docs/specs/the_hyperchain/shared_bridge.md @@ -119,8 +119,8 @@ be able to leverage them when available). - Some assets have to be natively supported (ETH, WETH) and it also makes sense to support some generally accepted token standards (ERC20 tokens), as this makes it easy to bridge those tokens (and ensures a single version of them exists on - the hyperchain). These cannonical asset contracts are deployed from L1 by a bridge shared by all hyperchains. This is - where assets are locked on L1. These bridges use the Bridgehub to communicate with all hyperchains. Currently, these + the hyperchain). These canonical asset contracts are deployed from L1 by a bridge shared by all hyperchains. This is + where assets are locked on L1. These bridges use the BridgeHub to communicate with all hyperchains. Currently, these bridges are the `WETH` and `ERC20` bridges. - The pair on L2 is deployed from L1. The hash of the factory dependencies is stored on L1, and when a hyperchain diff --git a/docs/specs/zk_evm/bootloader.md b/docs/specs/zk_evm/bootloader.md index bdadd1d3fce1..ec7f8378151d 100644 --- a/docs/specs/zk_evm/bootloader.md +++ b/docs/specs/zk_evm/bootloader.md @@ -76,7 +76,7 @@ supported: transactions. The L1 contract ensures that the hash did indeed match the [hashes of the priority transactions on L1](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/contracts/ethereum/contracts/zksync/facets/Executor.sol#L282). -You can also read more on L1->L2 transactions and upgrade transacitons +You can also read more on L1->L2 transactions and upgrade transactions [here](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/Handling%20L1%E2%86%92L2%20ops%20on%20zkSync.md). However, as already stated, the bootloader’s memory is not deterministic and the operator is free to put anything it @@ -129,7 +129,7 @@ Once read, these slots can be used for temporary data. - `[7283..40050]` – slots used for compressed bytecodes each in the following format: - 32 bytecode hash - 32 zeroes (but then it will be modified by the bootloader to contain 28 zeroes and then the 4-byte selector of the - `publishCompressedBytecode` function of the `BytecodeCompresor`) + `publishCompressedBytecode` function of the `BytecodeCompressor`) - The calldata to the bytecode compressor (without the selector). - `[40051..40052]` – slots where the hash and the number of current priority ops is stored. More on it in the priority operations @@ -152,9 +152,9 @@ entries. These will not be published to L1, but will be used to verify the corre worst-case number of bytes that may be needed for this scratch space is if all the pubdata consists of repeated writes (i.e. we’ll need only 4 bytes to include key) that turn into 0 (i.e. they’ll need only 1 byte to describe it). However, each of these writes in the uncompressed form will be represented as 272 byte state diff entry and so we get the number -of diffs is `120k / 5 = 24k`. This means that they will have accoomdate `24k * 272 = 6528000` bytes of calldata for the +of diffs is `120k / 5 = 24k`. This means that they will have accommodate `24k * 272 = 6528000` bytes of calldata for the uncompressed state diffs. Adding 120k on top leaves us with roughly `6650000` bytes needed for calldata. `207813` slots -are needed to accomodate this amount of data. We round up to `208000` slots to give space for constant-size factors for +are needed to accommodate this amount of data. We round up to `208000` slots to give space for constant-size factors for ABI-encoding, like offsets, lengths, etc. In theory though much more calldata could be used (if for instance 1 byte is used for enum index). It is the @@ -298,8 +298,9 @@ L1->L2 transactions are transactions that were initiated on L1. We assume that ` transactions. It also has its L1 pubdata price as well as ergsPrice set on L1. Most of the steps from the execution of L2 transactions are omitted and we set `tx.origin` to the `from`, and -`ergsPrice` to the one provided by transaction. After that, we use [mimicCall](#zksync-specific-opcodes) to provide the -operation itself from the name of the sender account. +`ergsPrice` to the one provided by transaction. After that, we use +[mimicCall](https://github.com/matter-labs/zksync-era/blob/main/docs/guides/advanced/0_alternative_vm_intro.md#zkevm-specific-opcodes) +to provide the operation itself from the name of the sender account. Note, that for L1→L2 transactions, `reserved0` field denotes the amount of ETH that should be minted on L2 as a result of this transaction. `reserved1` is the refund receiver address, i.e. the address that would receive the refund for the diff --git a/docs/specs/zk_evm/fee_model.md b/docs/specs/zk_evm/fee_model.md index 2298529595a1..a75d45a737b9 100644 --- a/docs/specs/zk_evm/fee_model.md +++ b/docs/specs/zk_evm/fee_model.md @@ -478,7 +478,7 @@ Note, that the computational overhead is proportional to the `tx.gasLimit` and t pay is proportional to the L1 gas price (recall the formula of `B_O`). We can roughly express the transaction overhead from computation as `tx.gasLimit * L1_GAS_PRICE * C` where `C` is just some constant. Note, that since a transaction typically contains some storage writes, and its -`tx.gasLimit = gasSpentOnCompute + pubdataPublished * gasPricePerPubdata`, `tx.gasLimit` is roughly proprtional to +`tx.gasLimit = gasSpentOnCompute + pubdataPublished * gasPricePerPubdata`, `tx.gasLimit` is roughly proportional to `gasPricePerPubdata` and so it is also proportional to `L1_GAS_PRICE`. This means that formula `tx.gasLimit * L1_GAS_PRICE * C` becomes _quadratic_ to the `L1_GAS_PRICE`. diff --git a/docs/specs/zk_evm/precompiles.md b/docs/specs/zk_evm/precompiles.md index f1f812c68e1c..4874bcdf9404 100644 --- a/docs/specs/zk_evm/precompiles.md +++ b/docs/specs/zk_evm/precompiles.md @@ -167,7 +167,7 @@ function montgomeryMul(multiplicand, multiplier) -> ret { ```solidity /// @notice Computes the Montgomery modular inverse skipping the Montgomery reduction step. -/// @dev The Montgomery reduction step is skept because a modification in the binary extended Euclidean algorithm is used to compute the modular inverse. +/// @dev The Montgomery reduction step is skipped because a modification in the binary extended Euclidean algorithm is used to compute the modular inverse. /// @dev See the function `binaryExtendedEuclideanAlgorithm` for further details. /// @param a The field element in Montgomery form to compute the modular inverse of. /// @return invmod The result of the Montgomery modular inverse (in Montgomery form). diff --git a/docs/specs/zk_evm/system_contracts.md b/docs/specs/zk_evm/system_contracts.md index f0e1f182de9c..393c38db6c40 100644 --- a/docs/specs/zk_evm/system_contracts.md +++ b/docs/specs/zk_evm/system_contracts.md @@ -122,7 +122,8 @@ Whenever anyone wants to do a non-zero value call, they need to call `MsgValueSi - Pass `value` and whether the call should be marked with `isSystem` in the first extra abi params. - Pass the address of the callee in the second extraAbiParam. -More information on the extraAbiParams can be read [here](#flags-for-calls). +More information on the extraAbiParams can be read +[here](../../guides/advanced/0_alternative_vm_intro.md#flags-for-calls). ## KnownCodeStorage @@ -145,7 +146,7 @@ It is the responsibility of the [ContractDeployer](#contractdeployer--immutables those code hashes that are known. The KnownCodesStorage contract is also responsible for ensuring that all the “known” bytecode hashes are also -[valid](#bytecode-validity). +[valid](../../guides/advanced/0_alternative_vm_intro.md#bytecode-validity). ## ContractDeployer & ImmutableSimulator @@ -204,7 +205,8 @@ On Ethereum, the constructor is only part of the initCode that gets executed dur returns the deployment code of the contract. On zkSync, there is no separation between deployed code and constructor code. The constructor is always a part of the deployment code of the contract. In order to protect it from being called, the compiler-generated contracts invoke constructor only if the `isConstructor` flag provided (it is only available for -the system contracts). You can read more about flags [here](#flags-for-calls). +the system contracts). You can read more about flags +[here](../../guides/advanced/0_alternative_vm_intro.md#flags-for-calls). After execution, the constructor must return an array of: @@ -226,7 +228,8 @@ address. Whenever a contract needs to access a value of some immutable, they call the `ImmutableSimulator.getImmutable(getCodeAddress(), index)`. Note that on zkSync it is possible to get the current -execution address (you can read more about `getCodeAddress()` [here](#zksync-specific-opcodes). +execution address you can read more about `getCodeAddress()` +[here](https://github.com/matter-labs/zksync-era/blob/main/docs/guides/advanced/0_alternative_vm_intro.md#zkevm-specific-opcodes). ### **Return value of the deployment methods** diff --git a/docs/specs/zk_evm/vm_overview.md b/docs/specs/zk_evm/vm_overview.md index a664352c54ef..51d0e74cbf1e 100644 --- a/docs/specs/zk_evm/vm_overview.md +++ b/docs/specs/zk_evm/vm_overview.md @@ -15,14 +15,13 @@ The zkEVM has a lot of special features compared to the EVM that are needed for precompiles etc. These functions are either built into the zkEVM, or there are special [system contracts](./system_contracts.md) for them. The system contracts are deployed at predefined addresses, they are called by the Bootloader, and they have special permissions compared to normal user contracts. These are not to be -confused with the [precompiles](./precompiles.md), which are also predeloyed contracts with special support from the +confused with the [precompiles](./precompiles.md), which are also pre-deployed contracts with special support from the zkEVM, but these contract do not have special permissions and are called by the users and not the Bootloader. The zkEVM also has user-facing features. For the best possible UX the ZK Stack supports native -[account abstraction](./zkEVM/high_level/account_abstraction.md). This means users can fully customize how they pay the -fees needed to execute their transactions. +[account abstraction](./account_abstraction.md). This means users can fully customize how they pay the fees needed to +execute their transactions. All transactions need to pay fees. The requirements to run a rollup are different than the ones needed to run Ethereum, -so the ZK Stack has a different [fee model](./zkEVM/high_level/fee_model/fee_model.md). The fee model is designed to -consider all the components that are needed to run the rollup: data and proof execution costs on L1, sequencer costs, -and prover costs. +so the ZK Stack has a different [fee model](./fee_model.md). The fee model is designed to consider all the components +that are needed to run the rollup: data and proof execution costs on L1, sequencer costs, and prover costs. diff --git a/docs/specs/zk_evm/vm_specification/compiler/instructions/evm/block.md b/docs/specs/zk_evm/vm_specification/compiler/instructions/evm/block.md index 61fe1479b4b0..228a80d48518 100644 --- a/docs/specs/zk_evm/vm_specification/compiler/instructions/evm/block.md +++ b/docs/specs/zk_evm/vm_specification/compiler/instructions/evm/block.md @@ -14,7 +14,7 @@ On how the System Contract is called, see is common for Yul and EVMLA representations. The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) +[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/llvm_runtime.rs) runtime function. ## [COINBASE](https://www.evm.codes/#41?fork=shanghai) @@ -22,7 +22,7 @@ runtime function. ### System Contract This information is requested a System Contract called -[SystemContext](.https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/contracts/SystemContext.sol). +[SystemContext](https://github.com/matter-labs/era-contracts/blob/main/system-contracts/contracts/SystemContext.sol). On how the System Contract is called, see [this section](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/VM%20Section/How%20compiler%20works/system_contracts.md#environmental-data-storage). @@ -33,7 +33,7 @@ On how the System Contract is called, see is common for Yul and EVMLA representations. The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) +[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/llvm_runtime.rs) runtime function. ## [TIMESTAMP](https://www.evm.codes/#42?fork=shanghai) @@ -52,7 +52,7 @@ On how the System Contract is called, see is common for Yul and EVMLA representations. The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) +[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/llvm_runtime.rs#L137) runtime function. ## [NUMBER](https://www.evm.codes/#43?fork=shanghai) @@ -71,7 +71,7 @@ On how the System Contract is called, see is common for Yul and EVMLA representations. The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) +[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/llvm_runtime.rs#L137) runtime function. ## [PREVRANDAO](https://www.evm.codes/#44?fork=shanghai) | [DIFFICULTY](https://www.evm.codes/#44?fork=grayGlacier) @@ -90,7 +90,7 @@ On how the System Contract is called, see is common for Yul and EVMLA representations. The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) +[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/llvm_runtime.rs#L137) runtime function. ## [GASLIMIT](https://www.evm.codes/#45?fork=shanghai) @@ -109,7 +109,7 @@ On how the System Contract is called, see is common for Yul and EVMLA representations. The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) +[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/llvm_runtime.rs#L137) runtime function. ## [CHAINID](https://www.evm.codes/#46?fork=shanghai) @@ -128,7 +128,7 @@ On how the System Contract is called, see is common for Yul and EVMLA representations. The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) +[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/llvm_runtime.rs#L137) runtime function. ## [SELFBALANCE](https://www.evm.codes/#47?fork=shanghai) @@ -155,5 +155,5 @@ On how the System Contract is called, see is common for Yul and EVMLA representations. The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) +[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/llvm_runtime.rs#L137) runtime function. diff --git a/docs/specs/zk_evm/vm_specification/compiler/instructions/evm/environment.md b/docs/specs/zk_evm/vm_specification/compiler/instructions/evm/environment.md index 117a68cbb91b..56be086cc7a1 100644 --- a/docs/specs/zk_evm/vm_specification/compiler/instructions/evm/environment.md +++ b/docs/specs/zk_evm/vm_specification/compiler/instructions/evm/environment.md @@ -23,7 +23,7 @@ On how the System Contract is called, see is common for Yul and EVMLA representations. The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) +[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/llvm_runtime.rs) runtime function. ## [ORIGIN](https://www.evm.codes/#32?fork=shanghai) @@ -42,7 +42,7 @@ On how the System Contract is called, see is common for Yul and EVMLA representations. The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) +[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/llvm_runtime.rs#L137) runtime function. ## [CALLER](https://www.evm.codes/#33?fork=shanghai) @@ -186,7 +186,7 @@ On how the System Contract is called, see is common for Yul and EVMLA representations. The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) +[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/llvm_runtime.rs#L137) runtime function. ## [EXTCODESIZE](https://www.evm.codes/#3b?fork=shanghai) @@ -205,7 +205,7 @@ On how the System Contract is called, see is common for Yul and EVMLA representations. The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) +[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/llvm_runtime.rs#L137) runtime function. ## [EXTCODECOPY](https://www.evm.codes/#3c?fork=shanghai) @@ -290,5 +290,5 @@ On how the System Contract is called, see is common for Yul and EVMLA representations. The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) +[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/llvm_runtime.rs#L137) runtime function. diff --git a/docs/specs/zk_evm/vm_specification/compiler/instructions/extensions/call.md b/docs/specs/zk_evm/vm_specification/compiler/instructions/extensions/call.md index 9833205e20ba..20033e8500aa 100644 --- a/docs/specs/zk_evm/vm_specification/compiler/instructions/extensions/call.md +++ b/docs/specs/zk_evm/vm_specification/compiler/instructions/extensions/call.md @@ -32,8 +32,8 @@ manipulations, since one can not easily load pointer value into Solidity’s var | system_mimic_call_byref(to, ACTIVE_PTR, implicit r3, r4, r5 = who to mimic) | who_to_call | 0xFFF8 | 0 | 0 | who_to_mimic | value_to_put_into_r3 | value_to_put_into_r4 | WILL mess up the registers and WILL use r1-r4 for our standard ABI convention and r5 for the extra who_to_mimic argument | any in the code; mimic call in the bytecode | Runtime *{i256, i1} \_\_mimiccall(*i8 addrspace(3), i256, i256, \*{i256, i1}) | Same as one above, but takes ABI data from ACTIVE_PTR | | raw_far_call | who_to_call | 0xFFF7 | 0 | 0 | abi_data (CAN be with “to system = true”) | output_offset | output_length | Same as for EVM call | call | static | delegate (the call type is preserved) | | It’s very similar to “system_call” described below, but for the cases when we only need to have to_system = true set in ABI (responsibility of the user, NOT the compiler), but we do not actually need to pass anything through r3 and r4 (so we can save on setting them or zeroing them, whatever) | | raw_far_call_byref | who_to_call | 0xFFF6 | 0 | 0 | 0xFFFF to prevent optimizing out by Yul | output_offset | output_length | Same as for EVM call | call | static | delegate (the call type is preserved) | | Same as one above, but takes ABI data from ACTIVE_PTR | -| system_call | who_to_call | 0xFFF5 | value_to_put_into_r3 (only for call with 7 arguments) | value_to_put_into_r4 | abi_data (MUST have “to system” set) | value_to_put_into_r5 | value_to_put_into_r6 | Same as for EVM call | call | static | delegate (the call type is preserved) | to call system contracts, like MSG_VALUE_SIMUALTOR. We may need 4 different formal definitions for cases when we would want to have integer/ptr in r3 and r4 | | -| system_call_byref | who_to_call | 0xFFF4 | value_to_put_into_r3 (only for call with 7 arguments) | value_to_put_into_r4 | 0xFFFF to prevent optimizing out by Yul | value_to_put_into_r5 | value_to_put_into_r6 | Same as for EVM call | call | static | delegate (the call type is preserved) | to call system contracts, like MSG_VALUE_SIMUALTOR. We may need 4 different formal definitions for cases when we would want to have integer/ptr in r3 and r4 | Same as one above, but takes ABI data from ACTIVE_PTR | +| system_call | who_to_call | 0xFFF5 | value_to_put_into_r3 (only for call with 7 arguments) | value_to_put_into_r4 | abi_data (MUST have “to system” set) | value_to_put_into_r5 | value_to_put_into_r6 | Same as for EVM call | call | static | delegate (the call type is preserved) | to call system contracts, like MSG_VALUE_SIMULATOR. We may need 4 different formal definitions for cases when we would want to have integer/ptr in r3 and r4 | | +| system_call_byref | who_to_call | 0xFFF4 | value_to_put_into_r3 (only for call with 7 arguments) | value_to_put_into_r4 | 0xFFFF to prevent optimizing out by Yul | value_to_put_into_r5 | value_to_put_into_r6 | Same as for EVM call | call | static | delegate (the call type is preserved) | to call system contracts, like MSG_VALUE_SIMULATOR. We may need 4 different formal definitions for cases when we would want to have integer/ptr in r3 and r4 | Same as one above, but takes ABI data from ACTIVE_PTR | | set_context_u128 | 0 | 0xFFF3 | value | 0 | 0xFFFF to prevent optimizing out by Yul | 0 | 0 | - | call | | | | set_pubdata_price | in0 | 0xFFF2 | 0 | 0 | 0xFFFF to prevent optimizing out by Yul | 0 | 0 | - | call | context.set_ergs_per_pubdata in0 in assembly | | | increment_tx_counter | 0 | 0xFFF1 | 0 | 0 | 0xFFFF to prevent optimizing out by Yul | 0 | 0 | - | call | context.inc_tx_num in assembly | | diff --git a/docs/specs/zk_evm/vm_specification/compiler/overview.md b/docs/specs/zk_evm/vm_specification/compiler/overview.md index ec949c297f3d..62652e9447c5 100644 --- a/docs/specs/zk_evm/vm_specification/compiler/overview.md +++ b/docs/specs/zk_evm/vm_specification/compiler/overview.md @@ -38,87 +38,88 @@ The table below describes the scheme of translation Yul and EVMLA to EraVM bytec At the moment it does not explain much of the LLVM IR and assembly aspects, but mainly focus on the EVM-equivalence for the sake of assisting the upcoming audit. -| Yul name | EVMLA name | Descriptive keywords | Input/output | System contract usage | Front end notes | -| ---------------------- | ----------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -| add | ADD | arithmetic, binary | Stack: 2 inputs, 1 output | - | - | -| sub | SUB | arithmetic, binary | Stack: 2 inputs, 1 output | - | - | -| mul | MUL | arithmetic, binary | Stack: 2 inputs, 1 output | - | - | -| div | DIV | arithmetic, binary | Stack: 2 inputs, 1 output | - | x / 0. Division by 0 returns 0. | -| sdiv | SDIV | arithmetic, binary, signed | Stack: 2 inputs, 1 output | - | x / 0. Division by 0 returns 0. -(2^255) / (-1). In case of overflow the first operand is returned. | -| mod | MOD | arithmetic, binary | Stack: 2 inputs, 1 output | - | x % 0. Remainder of division by 0 returns 0. | -| smod | SMOD | arithmetic, binary, signed | Stack: 2 inputs, 1 output | - | x % 0. Remainder of division by 0 returns 0. | -| exp | EXP | arithmetic, binary | Stack: 2 inputs, 1 output | - | Unfolds into the binary exponentiation algorithm. | -| lt | LT | logical, binary | Stack: 2 inputs, 1 output | - | - | -| slt | SLT | logical, binary, signed | Stack: 2 inputs, 1 output | - | - | -| gt | GT | logical, binary | Stack: 2 inputs, 1 output | - | - | -| sgt | SGT | logical, binary, signed | Stack: 2 inputs, 1 output | - | - | -| eq | EQ | logical, binary | Stack: 2 inputs, 1 output | - | - | -| iszero | ISZERO | logical, unary | Stack: 1 input, 1 output | - | - | -| or | OR | bitwise, binary | Stack: 2 inputs, 1 output | - | - | -| xor | XOR | bitwise, binary | Stack: 2 inputs, 1 output | - | - | -| and | AND | bitwise, binary | Stack: 2 inputs, 1 output | - | - | -| not | NOT | bitwise, unary | Stack: 1 input, 1 output | - | - | -| shl | SHL | bitwise, binary | Stack: 2 inputs, 1 output | - | x << N, N > 255. Shifting by more than a word size is a UB in LLVM. This case is checked explicitly and zero is returned. | -| shr | SHR | bitwise, binary | Stack: 2 inputs, 1 output | - | x >> N, N > 255. Shifting by more than a word size is a UB in LLVM. This case is checked explicitly and zero is returned. | -| sar | SAR | bitwise, binary, signed | Stack: 2 inputs, 1 output | - | x >> N, N > 255. Shifting by more than a word size is a UB in LLVM. This case is checked explicitly and zero or minus one is returned, depending on the sign bit. | -| signextend | SIGNEXTEND | bitwise, binary | Stack: 2 inputs, 1 output | - | See the LLVM runtime section below. | -| byte | BYTE | bitwise, binary | Stack: 2 inputs, 1 output | - | - | -| addmod | ADDMOD | modular, ternary | Stack: 3 inputs, 1 output | - | - | -| mulmod | MULMOD | modular, ternary | Stack: 3 inputs, 1 output | - | - | -| - | PUSH | stack | Stack: 1 output | - | - | -| - | PUSH{1..32} | stack | Stack: 1 output | - | - | -| - | PUSHSIZE | stack | Stack: 1 output | - | Pushes 0. | -| - | PUSH [tag] | stack | Stack: 1 output (compile time) | - | - | -| - | PUSH data | stack | Stack: 1 output | - | Unfolded into several cells if the length is more than 32 bytes. | -| - | Tag | stack | - | - | - | -| pop | POP | stack | Stack: 1 input | - | - | -| - | DUP{1..16} | stack | Stack: 1 output | - | - | -| - | SWAP{1..16} | stack | Stack: 1 swap | - | - | -| - | JUMP | stack | Stack: 1 input (compile time) | - | Expects a compile-time known tag and generates an unconditional jump to the statically known block of LLVM IR. | -| - | JUMPI | stack | Stack: 2 inputs (1 in compile time) | - | Expects a compile-time known tag and generates a conditional jump to the statically known block of LLVM IR. | -| - | JUMPDEST | stack | - | - | Unused by the static analyzer and totally discarded. | -| mload` | MLOAD | heap | Stack: 1 input. Heap: read 32 bytes. Stack: 1 output | - | - | -| mstore | MSTORE | heap | Stack: 2 inputs. Heap: write 32 bytes | - | - | -| mstore8 | MSTORE8 | heap | Stack: 2 inputs. Heap: write 1 byte | - | - | -| msize | MSIZE | heap, context | Context: 1 request. Stack: 1 output | - | - | -| memoryguard | | heap | Stack: 1 output | - | - | -| sload | SLOAD | storage | Stack: 1 input. Storage: read 1 slot. Stack: 1 output | - | - | -| sstore | SSTORE | storage | Stack: 2 inputs. Storage: write 1 slot | - | - | -| loadimmutable | PUSHIMMUTABLE | immutable, heap | Stack: 1 input (compile time). Heap: read 32 bytes (deploy code). System contracts: 1 request (runtime code) | ImmutableSimulator | - | -| setimmutable | ASSIGNIMMUTABLE | immutable, heap | Stack: 3 inputs (1 in compile time). Heap: write 32 bytes (deploy code) | ImmutableSimulator | No-op in the runtime code. | -| log0 | LOG0 | event | Stack: 2 inputs. Heap: read N bytes. VM: write 1 event (0 topics, N bytes) | - | - | -| log1 | LOG1 | event | Stack: 3 inputs. Heap: read N bytes. VM: write 1 event (1 topics, N bytes) | - | - | -| log2 | LOG2 | event | Stack: 4 inputs. Heap: read N bytes. VM: write 1 event (2 topics, N bytes) | - | - | -| log3 | LOG3 | event | Stack: 5 inputs. Heap: read N bytes. VM: write 1 event (3 topics, N bytes) | - | - | -| log4 | LOG4 | event | Stack: 6 inputs. Heap: read N bytes. VM: write 1 event (4 topics, N bytes) | - | - | -| calldataload | CALLDATALOAD | calldata | Stack: 1 input. Calldata: read 32 bytes. Stack: 1 output | - | 0 in deploy code. | -| calldatacopy | CALLDATACOPY | calldata, heap | Stack: 3 inputs. Calldata: read N bytes. Heap: write N bytes | - | Generated by solc in the runtime code only. Copies 0 in deploy code. | -| calldatasize | CALLDATASIZE | calldata | Stack: 1 output | - | 0 in deploy code. | -| codecopy | CODECOPY | calldata | Stack: 3 inputs. Calldata: read N bytes. Heap: write N bytes | - | Generated by solc in the deploy code only, but is treated as CALLDATACOPY, since the constructor arguments are calldata in zkSync 2.0. Compile time error in Yul runtime code. Copies 0 in EVMLA runtime code. | -| codesize | CODESIZE | calldata | Stack: 1 output | - | - | -| returndatacopy | RETURNDATACOPY | return data, heap | Stack: 3 inputs. Return data: read N bytes. Heap: write N bytes | - | - | -| returndatasize | RETURNDATASIZE | return data | Stack: 1 output | - | - | -| keccak256 | KECCAK256 | SHA3 | hash | Heap: read N bytes. System contracts: 1 request. Stack: 1 output | Keccak256 | Calls a system contract which may revert if the input is too long. In this case the error is bubbled-up and the calling contract also reverts. | -| call | CALL | call | Stack: 7 inputs, 1 output. Heap: read N bytes, write M bytes | MsgValueSimulator | - | -| staticcall | STATICCALL | call | Stack: 6 inputs, 1 output. Heap: read N bytes, write M bytes | Ecrecover, SHA256 | - | -| delegatecall | DELEGATECALL | call | Stack: 6 inputs, 1 output. Heap: read N bytes, write M bytes | - | - | -| linkersymbol | PUSHLIB | library | Stack: 1 output | - | - | -| - | PUSHDEPLOYADDRESS | library | Context: 1 request. Stack: 1 output | - | - | -| create | CREATE | create | | ContractDeployer, MsgValueSimulator | - | -| create2 | CREATE2 | create | | ContractDeployer, MsgValueSimulator | - | -| datasize | PUSH #[$] | create | Stack: 1 output | - | - | -| dataoffset | PUSH [$] | create | Stack: 1 output | - | - | -| datacopy | CODECOPY | create, heap | Stack: 3 inputs. Heap: write 32 bytes | - | - | -| return | RETURN | return, positive | Stack: 2 inputs | - | In the deploy code the auxiliary heap is used to avoid conflicts with memory allocated by the Yul generator. | -| stop | STOP | return, positive | - | - | - | -| revert | REVERT | return, negative | Stack: 2 inputs | - | - | -| invalid | INVALID | return, negative | - | - | - | -| address | ADDRESS | context, transaction | Context: 1 request. Stack: 1 output | - | - | -| caller | CALLER | context, transaction | Context: 1 request. Stack: 1 output | - | - | -| gas | GAS | context, transaction | Context: 1 request. Stack: 1 output | - | - | -| chainid | CHAINID | context, transaction | System contracts: 1 request. Stack: 1 output | ContractContext | - | -| gasprice | GASPRICE | context, transaction | System contracts: 1 request. Stack: 1 output | ContractContext | - | -| origin | ORIGIN | context, transaction | System contracts: 1 request. Stack: 1 output | ContractContext | - | + +| Yul name | EVMLA name | Descriptive keywords | Input/output | System contract usage | Front end notes | +|------------------|-----------------|------------------------------|----------------------------------------------------|--------------------------|----------------------------------------------------------------------------------------------------------| +| add | ADD | arithmetic, binary | Stack: 2 inputs, 1 output | - | - | +| sub | SUB | arithmetic, binary | Stack: 2 inputs, 1 output | - | - | +| mul | MUL | arithmetic, binary | Stack: 2 inputs, 1 output | - | - | +| div | DIV | arithmetic, binary | Stack: 2 inputs, 1 output | - | x / 0. Division by 0 returns 0. | +| sdiv | SDIV | arithmetic, binary, signed | Stack: 2 inputs, 1 output | - | x / 0. Division by 0 returns 0. -(2^255) / (-1). In case of overflow the first operand is returned. | +| mod | MOD | arithmetic, binary | Stack: 2 inputs, 1 output | - | x % 0. Remainder of division by 0 returns 0. | +| smod | SMOD | arithmetic, binary, signed | Stack: 2 inputs, 1 output | - | x % 0. Remainder of division by 0 returns 0. | +| exp | EXP | arithmetic, binary | Stack: 2 inputs, 1 output | - | Unfolds into the binary exponentiation algorithm. | +| lt | LT | logical, binary | Stack: 2 inputs, 1 output | - | - | +| slt | SLT | logical, binary, signed | Stack: 2 inputs, 1 output | - | - | +| gt | GT | logical, binary | Stack: 2 inputs, 1 output | - | - | +| sgt | SGT | logical, binary, signed | Stack: 2 inputs, 1 output | - | - | +| eq | EQ | logical, binary | Stack: 2 inputs, 1 output | - | - | +| iszero | ISZERO | logical, unary | Stack: 1 input, 1 output | - | - | +| or | OR | bitwise, binary | Stack: 2 inputs, 1 output | - | - | +| xor | XOR | bitwise, binary | Stack: 2 inputs, 1 output | - | - | +| and | AND | bitwise, binary | Stack: 2 inputs, 1 output | - | - | +| not | NOT | bitwise, unary | Stack: 1 input, 1 output | - | - | +| shl | SHL | bitwise, binary | Stack: 2 inputs, 1 output | - | x << N, N > 255. Shifting by more than a word size is a UB in LLVM. This case is checked explicitly and zero is returned. | +| shr | SHR | bitwise, binary | Stack: 2 inputs, 1 output | - | x >> N, N > 255. Shifting by more than a word size is a UB in LLVM. This case is checked explicitly and zero is returned. | +| sar | SAR | bitwise, binary, signed | Stack: 2 inputs, 1 output | - | x >> N, N > 255. Shifting by more than a word size is a UB in LLVM. This case is checked explicitly and zero or minus one is returned, depending on the sign bit. | +| signextend | SIGNEXTEND | bitwise, binary | Stack: 2 inputs, 1 output | - | See the LLVM runtime section below. | +| byte | BYTE | bitwise, binary | Stack: 2 inputs, 1 output | - | - | +| addmod | ADDMOD | modular, ternary | Stack: 3 inputs, 1 output | - | - | +| mulmod | MULMOD | modular, ternary | Stack: 3 inputs, 1 output | - | - | +| - | PUSH | stack | Stack: 1 output | - | - | +| - | PUSH{1..32} | stack | Stack: 1 output | - | - | +| - | PUSHSIZE | stack | Stack: 1 output | - | Pushes 0. | +| - | PUSH [tag] | stack | Stack: 1 output (compile time) | - | - | +| - | PUSH data | stack | Stack: 1 output | - | Unfolded into several cells if the length is more than 32 bytes. | +| - | Tag | stack | - | - | - | +| pop | POP | stack | Stack: 1 input | - | - | +| - | DUP{1..16} | stack | Stack: 1 output | - | - | +| - | SWAP{1..16} | stack | Stack: 1 swap | - | - | +| - | JUMP | stack | Stack: 1 input (compile time) | - | Expects a compile-time known tag and generates an unconditional jump to the statically known block of LLVM IR. | +| - | JUMPI | stack | Stack: 2 inputs (1 in compile time) | - | Expects a compile-time known tag and generates a conditional jump to the statically known block of LLVM IR. | +| - | JUMPDEST | stack | - | - | Unused by the static analyzer and totally discarded. | +| mload` | MLOAD | heap | Stack: 1 input. Heap: read 32 bytes. Stack: 1 output | - | - | +| mstore | MSTORE | heap | Stack: 2 inputs. Heap: write 32 bytes | - | - | +| mstore8 | MSTORE8 | heap | Stack: 2 inputs. Heap: write 1 byte | - | - | +| msize | MSIZE | heap, context | Context: 1 request. Stack: 1 output | - | - | +| memoryguard | | heap | Stack: 1 output | - | - | +| sload | SLOAD | storage | Stack: 1 input. Storage: read 1 slot. Stack: 1 output | - | - | +| sstore | SSTORE | storage | Stack: 2 inputs. Storage: write 1 slot | - | - | +| loadimmutable | PUSHIMMUTABLE | immutable, heap | Stack: 1 input (compile time). Heap: read 32 bytes (deploy code). System contracts: 1 request (runtime code) | ImmutableSimulator | - | +| setimmutable | ASSIGNIMMUTABLE | immutable, heap | Stack: 3 inputs (1 in compile time). Heap: write 32 bytes (deploy code) | ImmutableSimulator | No-op in the runtime code. | +| log0 | LOG0 | event | Stack: 2 inputs. Heap: read N bytes. VM: write 1 event (0 topics, N bytes) | - | - | +| log1 | LOG1 | event | Stack: 3 inputs. Heap: read N bytes. VM: write 1 event (1 topics, N bytes) | - | - | +| log2 | LOG2 | event | Stack: 4 inputs. Heap: read N bytes. VM: write 1 event (2 topics, N bytes) | - | - | +| log3 | LOG3 | event | Stack: 5 inputs. Heap: read N bytes. VM: write 1 event (3 topics, N bytes) | - | - | +| log4 | LOG4 | event | Stack: 6 inputs. Heap: read N bytes. VM: write 1 event (4 topics, N bytes) | - | - | +| calldataload | CALLDATALOAD | calldata | Stack: 1 input. Calldata: read 32 bytes. Stack: 1 output | - | 0 in deploy code. | +| calldatacopy | CALLDATACOPY | calldata, heap | Stack: 3 inputs. Calldata: read N bytes. Heap: write N bytes | - | Generated by solc in the runtime code only. Copies 0 in deploy code. | +| calldatasize | CALLDATASIZE | calldata | Stack: 1 output | - | 0 in deploy code. | +| codecopy | CODECOPY | calldata | Stack: 3 inputs. Calldata: read N bytes. Heap: write N bytes | - | Generated by solc in the deploy code only, but is treated as CALLDATACOPY, since the constructor arguments are calldata in zkSync 2.0. Compile time error in Yul runtime code. Copies 0 in EVMLA runtime code. | +| codesize | CODESIZE | calldata | Stack: 1 output | - | - | +| returndatacopy | RETURNDATACOPY | return data, heap | Stack: 3 inputs. Return data: read N bytes. Heap: write N bytes | - | - | +| returndatasize | RETURNDATASIZE | return data | Stack: 1 output | - | - | +| keccak256 | KECCAK256 | SHA3 | hash | Heap: read N bytes. System contracts: 1 request. Stack: 1 output | Keccak256 Calls a system contract which may revert if the input is too long. In this case the error is bubbled-up and the calling contract also reverts. | +| call | CALL | call | Stack: 7 inputs, 1 output. Heap: read N bytes, write M bytes | MsgValueSimulator | - | +| staticcall | STATICCALL | call | Stack: 6 inputs, 1 output. Heap: read N bytes, write M bytes | Ecrecover, SHA256 | - | +| delegatecall | DELEGATECALL | call | Stack: 6 inputs, 1 output. Heap: read N bytes, write M bytes | - | - | +| linkersymbol | PUSHLIB | library | Stack: 1 output | - | - | +| - | PUSHDEPLOYADDRESS | library | Context: 1 request. Stack: 1 output | - | - | +| create | CREATE | create | - | ContractDeployer, MsgValueSimulator | - | +| create2 | CREATE2 | create | - | ContractDeployer, MsgValueSimulator | - | +| datasize | PUSH #[$] | create | Stack: 1 output | - | - | +| dataoffset | PUSH [$] | create | Stack: 1 output | - | - | +| datacopy | CODECOPY | create, heap | Stack: 3 inputs. Heap: write 32 bytes | - | - | +| return | RETURN | return, positive | Stack: 2 inputs | - | In the deploy code the auxiliary heap is used to avoid conflicts with memory allocated by the Yul generator. | +| stop | STOP | return, positive | - | - | - | +| revert | REVERT | return, negative | Stack: 2 inputs | - | - | +| invalid | INVALID | return, negative | - | - | - | +| address | ADDRESS | context, transaction | Context: 1 request. Stack: 1 output | - | - | +| caller | CALLER | context, transaction | Context: 1 request. Stack: 1 output | - | - | +| gas | GAS | context, transaction | Context: 1 request. Stack: 1 output | - | - | +| chainid | CHAINID | context, transaction | System contracts: 1 request. Stack: 1 output | ContractContext | - | +| gasprice | GASPRICE | context, transaction | System contracts: 1 request. Stack: 1 output | ContractContext | - | +| origin | ORIGIN | context, transaction | System contracts: 1 request. Stack: 1 output | ContractContext | - | | | callvalue | CALLVALUE | context, transaction | Context: 1 request. Stack: 1 output | - | - | | blockhash | BLOCKHASH | context, block | Stack: 1 input. System contracts: 1 request. Stack: 1 output | ContractContext | - | | gaslimit | GASLIMIT | context, block | System contracts: 1 request. Stack: 1 output | ContractContext | - | diff --git a/docs/specs/zk_evm/vm_specification/compiler/system_contracts.md b/docs/specs/zk_evm/vm_specification/compiler/system_contracts.md index 96f370f986b2..ca93cb6eb315 100644 --- a/docs/specs/zk_evm/vm_specification/compiler/system_contracts.md +++ b/docs/specs/zk_evm/vm_specification/compiler/system_contracts.md @@ -38,7 +38,7 @@ Steps to handle such instructions: 6. Return the value as the result of the original instruction. For reference, see -[the LLVM IR codegen source code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs). +[the LLVM IR codegen source code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/llvm_runtime.rs). ### KECCAK256 Hash Function diff --git a/etc/commitment_tests/zksync_testharness_test.json b/etc/commitment_tests/zksync_testharness_test.json index 6f5730144a02..da4f5503878d 100644 --- a/etc/commitment_tests/zksync_testharness_test.json +++ b/etc/commitment_tests/zksync_testharness_test.json @@ -67,8 +67,8 @@ "pass_through_hash": "0x1c695ec7d7944f720a2c0fc6b5651cbd3178967407bc4df579a15985652350e9", "meta_params_bytes": "000100037723960c07cda7251089daffbdd567476a7e31971ff801568a3856e8e8010006699c833b654b365f0e3ce866c394626d5e40461a6868809d452738606f", "meta_params_hash": "0x57404e50342edcd09180fb27fa49634676f71a3ce1a76e9b3edf6185bf164082", - "auxiliary_bytes": "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "auxiliary_hash": "0x7c613c82ec911cf56dd6241854dd87bd538e0201f4ff0735f56a1a013db6466a", - "commitment_hash": "0xea55acb8903f82e4cfedd2041ce2db2f3b77741b6e35bc90a4f0a11e9526bfc2" + "auxiliary_bytes": "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "auxiliary_hash": "0xc80c4621670dfbae60a5878a224bf9515d566e341eacc6339b5256899cd70b77", + "commitment_hash": "0x35ec1c1af30b41260459f0fef16248b8702d443fb027f9b483c2a71791c136db" } } diff --git a/etc/contracts-test-data/contracts/complex-upgrade/complex-upgrade.sol b/etc/contracts-test-data/contracts/complex-upgrade/complex-upgrade.sol index 83321ec47271..e65f51d56522 100644 --- a/etc/contracts-test-data/contracts/complex-upgrade/complex-upgrade.sol +++ b/etc/contracts-test-data/contracts/complex-upgrade/complex-upgrade.sol @@ -11,18 +11,24 @@ import "./msg-sender.sol"; contract ComplexUpgrade { constructor() {} - function mimicCall( - address _address, - address _whoToMimic, - bytes memory _calldata - ) internal { + struct MimicCallInfo { + address to; + address whoToMimic; + bytes data; + } + + function _mimicCall(MimicCallInfo memory info) internal { address callAddr = MIMIC_CALL_CALL_ADDRESS; + bytes memory data = info.data; + address to = info.to; + address whoToMimic = info.whoToMimic; + uint32 dataStart; uint32 dataLength; assembly { - dataStart := add(_calldata, 0x20) - dataLength := mload(_calldata) + dataStart := add(data, 0x20) + dataLength := mload(data) } uint256 farCallAbi = SystemContractsCaller.getFarCallABI( @@ -39,7 +45,7 @@ contract ComplexUpgrade { ); assembly { - let success := call(_address, callAddr, 0, farCallAbi, _whoToMimic, 0, 0) + let success := call(to, callAddr, 0, farCallAbi, whoToMimic, 0, 0) if iszero(success) { returndatacopy(0, 0, returndatasize()) @@ -48,6 +54,14 @@ contract ComplexUpgrade { } } + function mimicCalls( + MimicCallInfo[] memory info + ) public { + for (uint256 i = 0; i < info.length; i++) { + _mimicCall(info[i]); + } + } + // This function is used to imitate some complex upgrade logic function someComplexUpgrade( address _address1, @@ -86,6 +100,13 @@ contract ComplexUpgrade { MsgSenderTest.testMsgSender.selector, toMimic ); - mimicCall(address(msgSenderTest), toMimic, _mimicCallCalldata); + + MimicCallInfo memory info = MimicCallInfo({ + to: address(msgSenderTest), + whoToMimic: toMimic, + data: _mimicCallCalldata + }); + + _mimicCall(info); } } diff --git a/etc/contracts-test-data/contracts/precompiles/precompiles.sol b/etc/contracts-test-data/contracts/precompiles/precompiles.sol new file mode 100644 index 000000000000..d9e23c46a6fa --- /dev/null +++ b/etc/contracts-test-data/contracts/precompiles/precompiles.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.0; + +contract Precompiles { + function doKeccak(uint256 iters) public pure returns (uint256) { + uint256 sum = 0; + for (uint256 i = 0; i < iters; i += 1) { + sum += uint(keccak256(abi.encode(i))) % 256; + } + return sum; + } + + function doSha256(uint256 iters) public pure returns (uint256) { + uint256 sum = 0; + for (uint256 i = 0; i < iters; i += 1) { + sum += uint(sha256(abi.encode(i))) % 256; + } + return sum; + } +} diff --git a/etc/env/base/api.toml b/etc/env/base/api.toml index 186e2cfb2b0e..1c5d906603fb 100644 --- a/etc/env/base/api.toml +++ b/etc/env/base/api.toml @@ -17,6 +17,7 @@ pubsub_polling_interval=200 threads_per_server=128 max_nonce_ahead=50 gas_price_scale_factor=1.2 +l1_to_l2_transactions_compatibility_mode=true request_timeout=10 account_pks=[ "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", diff --git a/etc/env/base/chain.toml b/etc/env/base/chain.toml index db9d87107c41..181c7cc86321 100644 --- a/etc/env/base/chain.toml +++ b/etc/env/base/chain.toml @@ -45,8 +45,37 @@ reject_tx_at_eth_params_percentage=0.95 # it takes more percentage of the max block gas capacity than this value. reject_tx_at_gas_percentage=0.95 -# The price the operator spends on 1 gas of computation in wei. -fair_l2_gas_price=250000000 +# The minimal acceptable L2 gas price, i.e. the price that should include the cost of computation/proving as well +# as potentially premium for congestion. +minimal_l2_gas_price=100000000 + +# The constant that represents the possibility that a batch can be sealed because of overuse of computation resources. +# It has range from 0 to 1. If it is 0, the compute will not depend on the cost for closing the batch. +# If it is 1, the gas limit per batch will have to cover the entire cost of closing the batch. +compute_overhead_part=0.0 + +# The constant that represents the possibility that a batch can be sealed because of overuse of pubdata. +# It has range from 0 to 1. If it is 0, the pubdata will not depend on the cost for closing the batch. +# If it is 1, the pubdata limit per batch will have to cover the entire cost of closing the batch. +pubdata_overhead_part=1.0 + +# The constant amount of L1 gas that is used as the overhead for the batch. It includes the price for batch verification, etc. +batch_overhead_l1_gas=800000 + +# The maximum amount of gas that can be used by the batch. This value is derived from the circuits limitation per batch. +max_gas_per_batch=200000000 + +# The maximum amount of pubdata that can be used by the batch. Note that if the calldata is used as pubdata, this variable should not exceed 128kb. +max_pubdata_per_batch=100000 + +# The version of the fee model to use. +# - `V1`, the first model that was used in zkSync Era. In this fee model, the pubdata price must be pegged to the L1 gas price. +# Also, the fair L2 gas price is expected to only include the proving/computation price for the operator and not the costs that come from +# processing the batch on L1. +# - `V2`, the second model that was used in zkSync Era. There the pubdata price might be independent from the L1 gas price. Also, +# The fair L2 gas price is expected to both the proving/computation price for the operator and the costs that come from +# processing the batch on L1. +fee_model_version="V1" # Max number of computational gas that validation step is allowed to take. validation_computational_gas_limit=300000 diff --git a/etc/env/base/circuit_synthesizer.toml b/etc/env/base/circuit_synthesizer.toml deleted file mode 100644 index 970520025b6b..000000000000 --- a/etc/env/base/circuit_synthesizer.toml +++ /dev/null @@ -1,10 +0,0 @@ -[circuit_synthesizer] -generation_timeout_in_secs=3000 -max_attempts=3 -gpu_prover_queue_timeout_in_secs=600 -prover_instance_wait_timeout_in_secs=200 -prover_instance_poll_time_in_milli_secs=250 -prometheus_listener_port=3314 -prometheus_pushgateway_url="http://127.0.0.1:9091" -prometheus_push_interval_ms=100 -prover_group_id=100 diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index 0a3b535f3bc3..bfc9b82aa715 100644 --- a/etc/env/base/contracts.toml +++ b/etc/env/base/contracts.toml @@ -38,10 +38,10 @@ L1_WETH_TOKEN_ADDR="0x5E6D086F5eC079ADFF4FB3774CDf3e8D6a34F7E9" L2_WETH_BRIDGE_ADDR="0x5E6D086F5eC079ADFF4FB3774CDf3e8D6a34F7E9" L2_WETH_TOKEN_IMPL_ADDR="0x5E6D086F5eC079ADFF4FB3774CDf3e8D6a34F7E9" L2_WETH_TOKEN_PROXY_ADDR="0x5E6D086F5eC079ADFF4FB3774CDf3e8D6a34F7E9" -FRI_RECURSION_LEAF_LEVEL_VK_HASH ="0x14628525c227822148e718ca1138acfc6d25e759e19452455d89f7f610c3dcb8" +FRI_RECURSION_LEAF_LEVEL_VK_HASH ="0x062362cb3eaf1f631406cbe19bf2a2c5d0d9ea69d069309a6003addae9f387be" FRI_RECURSION_NODE_LEVEL_VK_HASH ="0x5a3ef282b21e12fe1f4438e5bb158fc5060b160559c5158c6389d62d9fe3d080" -FRI_RECURSION_SCHEDULER_LEVEL_VK_HASH ="0x61ed1ea338680a9f83945b300a4a4778dd76d74a015b43a3e9b7fedba914a3d0" -SNARK_WRAPPER_VK_HASH = "0x750d8e21be7555a6841472a5cacd24c75a7ceb34261aea61e72bb7423a7d30fc" +FRI_RECURSION_SCHEDULER_LEVEL_VK_HASH ="0xf12256f7ba1ab223ba82abb19c8366c6677596897f9e5a82016977113e52ed5d" +SNARK_WRAPPER_VK_HASH = "0x8574e152c41dc39a2ecab984545e1cf21cb3ec250b919018a8053f2fa270784f" # Prover that should be used at genesis. 'fri' or 'snark' PROVER_AT_GENESIS="fri" diff --git a/etc/env/base/fri_prover.toml b/etc/env/base/fri_prover.toml index e714f66ed99c..94af27417ae0 100644 --- a/etc/env/base/fri_prover.toml +++ b/etc/env/base/fri_prover.toml @@ -9,5 +9,6 @@ setup_load_mode="FromDisk" specialized_group_id=100 witness_vector_generator_thread_count=5 queue_capacity=10 -witness_vector_receiver_port=4000 +witness_vector_receiver_port=3316 +zone_read_url="http://metadata.google.internal/computeMetadata/v1/instance/zone" shall_save_to_public_bucket=true diff --git a/etc/env/base/private.toml b/etc/env/base/private.toml index 60d5bfb2d9c8..0a6ff7eeb2d1 100644 --- a/etc/env/base/private.toml +++ b/etc/env/base/private.toml @@ -11,6 +11,14 @@ operator_private_key="0x27593fea79697e947890ecbecce7901b0008345e5d7259710d0dd5e5 # Derived from the `OPERATOR_PRIVATE_KEY`. operator_commit_eth_addr="0xde03a0B5963f75f1C8485B355fF6D30f3093BDE7" +[consensus] +config_path = "etc/env/consensus_config.json" +# generated with zksync_consensus_tools/src/bin/keys.rs +# node:public:ed25519:ee717abba6aec5baae5e09d457bd2ffc2f121b576cf4170ce15a68163ce4c868 +node_key="node:secret:ed25519:b6666c3be2703e15028bbebd220d2678fde7431038641f36c52f02849595a8ab" +# validator:public:bn254:8b0ff0ad1a250e64b0209277148ccee3b64534d8fa60cf25ba0bcc8b65d4d89309cdae79197c2db873d351401093fa0542a5a2071c1a247f2e1abe56d08cbabb +validator_key="validator:secret:bn254:038ec13f4dca210c9d3525204422f0584e1653a5684bff47f98316d9e64b6746" + [misc] # Private key for the fee seller account fee_account_private_key="0x27593fea79697e947890ecbecce7901b0008345e5d7259710d0dd5e500d040be" diff --git a/etc/env/base/prover.toml b/etc/env/base/prover.toml deleted file mode 100644 index 3504b41343f2..000000000000 --- a/etc/env/base/prover.toml +++ /dev/null @@ -1,74 +0,0 @@ -[prover.non_gpu] -prometheus_port=3313 -initial_setup_key_path="./../../../keys/setup/setup_2^22.key" -key_download_url="https://storage.googleapis.com/matterlabs-setup-keys-us/setup-keys/setup_2^22.key" -generation_timeout_in_secs=2700 -number_of_threads=22 -max_attempts=1 -polling_duration_in_millis=750 -setup_keys_path="/usr/src/setup-keys" -number_of_setup_slots=2 -assembly_receiver_port=17791 -assembly_receiver_poll_time_in_millis=250 -assembly_queue_capacity=1 -specialized_prover_group_id=0 - -[prover.two_gpu_forty_gb_mem] -prometheus_port=3313 -initial_setup_key_path="./../../../keys/setup/setup_2^26.key" -key_download_url="https://storage.googleapis.com/matterlabs-setup-keys-us/setup-keys/setup_2^26.key" -generation_timeout_in_secs=2700 -number_of_threads=5 -max_attempts=1 -polling_duration_in_millis=750 -setup_keys_path="/usr/src/setup-keys" -number_of_setup_slots=5 -assembly_receiver_port=17791 -assembly_receiver_poll_time_in_millis=250 -assembly_queue_capacity=3 -specialized_prover_group_id=1 - -[prover.one_gpu_eighty_gb_mem] -prometheus_port=3313 -initial_setup_key_path="./../../../keys/setup/setup_2^26.key" -key_download_url="https://storage.googleapis.com/matterlabs-setup-keys-us/setup-keys/setup_2^26.key" -generation_timeout_in_secs=2700 -number_of_threads=5 -max_attempts=1 -polling_duration_in_millis=750 -setup_keys_path="/usr/src/setup-keys" -number_of_setup_slots=5 -assembly_receiver_port=17791 -assembly_receiver_poll_time_in_millis=250 -assembly_queue_capacity=3 -specialized_prover_group_id=2 - -[prover.two_gpu_eighty_gb_mem] -prometheus_port=3313 -initial_setup_key_path="./../../../keys/setup/setup_2^26.key" -key_download_url="https://storage.googleapis.com/matterlabs-setup-keys-us/setup-keys/setup_2^26.key" -generation_timeout_in_secs=2700 -number_of_threads=9 -max_attempts=1 -polling_duration_in_millis=750 -setup_keys_path="/usr/src/setup-keys" -number_of_setup_slots=11 -assembly_receiver_port=17791 -assembly_receiver_poll_time_in_millis=250 -assembly_queue_capacity=4 -specialized_prover_group_id=3 - -[prover.four_gpu_eighty_gb_mem] -prometheus_port=3313 -initial_setup_key_path="./../../../keys/setup/setup_2^26.key" -key_download_url="https://storage.googleapis.com/matterlabs-setup-keys-us/setup-keys/setup_2^26.key" -generation_timeout_in_secs=2700 -number_of_threads=18 -max_attempts=1 -polling_duration_in_millis=750 -setup_keys_path="/usr/src/setup-keys" -number_of_setup_slots=18 -assembly_receiver_port=17791 -assembly_receiver_poll_time_in_millis=250 -assembly_queue_capacity=20 -specialized_prover_group_id=4 diff --git a/etc/env/base/prover_group.toml b/etc/env/base/prover_group.toml deleted file mode 100644 index 7372a407f3b8..000000000000 --- a/etc/env/base/prover_group.toml +++ /dev/null @@ -1,17 +0,0 @@ -[prover_group] -group_0_circuit_ids="0,18" -group_1_circuit_ids="1,4" -group_2_circuit_ids="2,5" -group_3_circuit_ids="6,7" -group_4_circuit_ids="8,9" -group_5_circuit_ids="10,11" -group_6_circuit_ids="12,13" -group_7_circuit_ids="14,15" -group_8_circuit_ids="16,17" -group_9_circuit_ids="3" -group_100_circuit_ids="" -region_read_url="http://metadata.google.internal/computeMetadata/v1/instance/attributes/cluster-location" -region_override="us-central-1" -zone_read_url="http://metadata.google.internal/computeMetadata/v1/instance/zone" -zone_override="us-central-1-b" -synthesizer_per_gpu="10" diff --git a/etc/env/base/rust.toml b/etc/env/base/rust.toml index 4c0ebb6ed052..8eef7700067a 100644 --- a/etc/env/base/rust.toml +++ b/etc/env/base/rust.toml @@ -5,9 +5,11 @@ # `RUST_LOG` environment variable for `env_logger` # Here we use TOML multiline strings: newlines will be trimmed. RUST_LOG="""\ +zksync_consensus_bft=info,\ +zksync_consensus_network=info,\ +zksync_consensus_storage=info,\ zksync_core=debug,\ zksync_server=debug,\ -zksync_prover=debug,\ zksync_contract_verifier=debug,\ zksync_dal=info,\ zksync_eth_client=info,\ @@ -22,13 +24,9 @@ zksync_mempool=debug,\ loadnext=info,\ vm=info,\ block_sizes_test=info,\ -zksync_verification_key_generator_and_server=info,\ zksync_object_store=info,\ -setup_key_generator_and_server=info,\ -zksync_circuit_synthesizer=info,\ en_playground=info,\ zksync_external_node=info,\ -cross_nodes_checker=debug,\ zksync_witness_generator=info,\ zksync_prover_fri=info,\ zksync_witness_vector_generator=info,\ diff --git a/etc/env/consensus_config.json b/etc/env/consensus_config.json new file mode 100644 index 000000000000..4dc62be73249 --- /dev/null +++ b/etc/env/consensus_config.json @@ -0,0 +1,13 @@ +{ + "server_addr": "127.0.0.1:3054", + "public_addr": "127.0.0.1:3054", + "validators": [ + "validator:public:bn254:8b0ff0ad1a250e64b0209277148ccee3b64534d8fa60cf25ba0bcc8b65d4d89309cdae79197c2db873d351401093fa0542a5a2071c1a247f2e1abe56d08cbabb" + ], + "max_payload_size": 5000000, + "gossip_static_outbound": [], + "gossip_static_inbound": [ + "node:public:ed25519:147bb71be895846e1d6f5b1c6a8be53848b82bdafcf66e9dfe6ca65581076a1d" + ], + "gossip_dynamic_inbound_limit": 0 +} diff --git a/etc/env/en_consensus_config.json b/etc/env/en_consensus_config.json new file mode 100644 index 000000000000..29ec0ca1e9a8 --- /dev/null +++ b/etc/env/en_consensus_config.json @@ -0,0 +1,16 @@ +{ + "server_addr": "127.0.0.1:3055", + "public_addr": "127.0.0.1:3055", + "validators": [ + "validator:public:bn254:8b0ff0ad1a250e64b0209277148ccee3b64534d8fa60cf25ba0bcc8b65d4d89309cdae79197c2db873d351401093fa0542a5a2071c1a247f2e1abe56d08cbabb" + ], + "max_payload_size": 5000000, + "gossip_static_outbound": [ + { + "key": "node:public:ed25519:ee717abba6aec5baae5e09d457bd2ffc2f121b576cf4170ce15a68163ce4c868", + "addr": "127.0.0.1:3054" + } + ], + "gossip_static_inbound": [], + "gossip_dynamic_inbound_limit": 0 +} diff --git a/etc/env/ext-node-docker.toml b/etc/env/ext-node-docker.toml index b14a35ffef19..129b41a41816 100644 --- a/etc/env/ext-node-docker.toml +++ b/etc/env/ext-node-docker.toml @@ -1,4 +1,8 @@ database_url = "postgres://postgres@postgres/zksync_local_ext_node" +# Optional variable. If set, "zk db setup" will recreate "database_url" db by +# cloning "template_database_url" db instead of creating an empty db. +# "template_database_url" is not used by EN itself. +template_database_url = "postgres://postgres@postgres/zksync_local" test_database_url = "postgres://postgres@host:5433/zksync_local_test_ext_node" database_pool_size = 50 zksync_action="dont_ask" @@ -32,11 +36,23 @@ api_namespaces = ["eth", "web3", "net", "pubsub", "zks", "en", "debug"] bootloader_hash="0x0100038581be3d0e201b3cc45d151ef5cc59eb3a0f146ad44f0f72abf00b594c" default_aa_hash="0x0100038dc66b69be75ec31653c64cb931678299b9b659472772b2550b703f41c" +# Should be the same as chain.state_keeper.fee_account_addr. +operator_addr="0xde03a0B5963f75f1C8485B355fF6D30f3093BDE7" + +[en.consensus] +config_path="etc/env/en_consensus_config.json" +# generated with zksync_consensus_tools/src/bin/keys.rs +# node:public:ed25519:147bb71be895846e1d6f5b1c6a8be53848b82bdafcf66e9dfe6ca65581076a1d +node_key="node:secret:ed25519:d56de77c738326c305c64c25bffe1cc94ea7c639cf71ca3ff94229df27f167ac" + [rust] # `RUST_LOG` environment variable for `env_logger` # Here we use TOML multiline strings: newlines will be trimmed. log="""\ warn,\ +zksync_consensus_bft=info,\ +zksync_consensus_network=info,\ +zksync_consensus_storage=info,\ zksync_core=debug,\ zksync_dal=info,\ zksync_eth_client=info,\ @@ -48,7 +64,6 @@ zksync_types=info,\ loadnext=info,\ vm=info,\ zksync_external_node=info,\ -cross_nodes_checker=debug,\ """ # `RUST_BACKTRACE` variable diff --git a/etc/env/ext-node.toml b/etc/env/ext-node.toml index 61f74a87ce00..58298a5501bd 100644 --- a/etc/env/ext-node.toml +++ b/etc/env/ext-node.toml @@ -2,8 +2,12 @@ # All the variables must be provided explicitly. # This is on purpose: if EN will accidentally depend on the main node env, it may cause problems. -test_database_url = "postgres://postgres@localhost:5433/zksync_local_test_ext_node" database_url = "postgres://postgres@localhost/zksync_local_ext_node" +# Optional variable. If set, "zk db setup" will recreate "database_url" db by +# cloning "template_database_url" db instead of creating an empty db. +# "template_database_url" is not used by EN itself. +template_database_url="postgres://postgres@localhost/zksync_local" +test_database_url = "postgres://postgres@localhost:5433/zksync_local_test_ext_node" database_pool_size = 50 zksync_action="dont_ask" @@ -32,11 +36,23 @@ api_namespaces = ["eth", "web3", "net", "pubsub", "zks", "en", "debug"] bootloader_hash="0x0100038581be3d0e201b3cc45d151ef5cc59eb3a0f146ad44f0f72abf00b594c" default_aa_hash="0x0100038dc66b69be75ec31653c64cb931678299b9b659472772b2550b703f41c" +# Should be the same as chain.state_keeper.fee_account_addr. +operator_addr="0xde03a0B5963f75f1C8485B355fF6D30f3093BDE7" + +[en.consensus] +config_path="etc/env/en_consensus_config.json" +# generated with zksync_consensus_tools/src/bin/keys.rs +# node:public:ed25519:147bb71be895846e1d6f5b1c6a8be53848b82bdafcf66e9dfe6ca65581076a1d +node_key="node:secret:ed25519:d56de77c738326c305c64c25bffe1cc94ea7c639cf71ca3ff94229df27f167ac" + [rust] # `RUST_LOG` environment variable for `env_logger` # Here we use TOML multiline strings: newlines will be trimmed. log="""\ warn,\ +zksync_consensus_bft=info,\ +zksync_consensus_network=info,\ +zksync_consensus_storage=info,\ zksync_core=debug,\ zksync_dal=info,\ zksync_eth_client=info,\ @@ -48,7 +64,6 @@ zksync_types=info,\ loadnext=info,\ vm=info,\ zksync_external_node=info,\ -cross_nodes_checker=debug,\ """ # `RUST_BACKTRACE` variable diff --git a/etc/multivm_bootloaders/vm_1_4_1/fee_estimate.yul/fee_estimate.yul.zbin b/etc/multivm_bootloaders/vm_1_4_1/fee_estimate.yul/fee_estimate.yul.zbin new file mode 100644 index 000000000000..a020cd118c7a Binary files /dev/null and b/etc/multivm_bootloaders/vm_1_4_1/fee_estimate.yul/fee_estimate.yul.zbin differ diff --git a/etc/multivm_bootloaders/vm_1_4_1/gas_test.yul/gas_test.yul.zbin b/etc/multivm_bootloaders/vm_1_4_1/gas_test.yul/gas_test.yul.zbin new file mode 100644 index 000000000000..ad090f3d214f Binary files /dev/null and b/etc/multivm_bootloaders/vm_1_4_1/gas_test.yul/gas_test.yul.zbin differ diff --git a/etc/multivm_bootloaders/vm_1_4_1/playground_batch.yul/playground_batch.yul.zbin b/etc/multivm_bootloaders/vm_1_4_1/playground_batch.yul/playground_batch.yul.zbin new file mode 100644 index 000000000000..fc5bd1542439 Binary files /dev/null and b/etc/multivm_bootloaders/vm_1_4_1/playground_batch.yul/playground_batch.yul.zbin differ diff --git a/etc/multivm_bootloaders/vm_1_4_1/proved_batch.yul/proved_batch.yul.zbin b/etc/multivm_bootloaders/vm_1_4_1/proved_batch.yul/proved_batch.yul.zbin new file mode 100644 index 000000000000..1ad3bd50502a Binary files /dev/null and b/etc/multivm_bootloaders/vm_1_4_1/proved_batch.yul/proved_batch.yul.zbin differ diff --git a/etc/multivm_bootloaders/vm_remove_allowlist/commit b/etc/multivm_bootloaders/vm_remove_allowlist/commit new file mode 100644 index 000000000000..e7f169487fa5 --- /dev/null +++ b/etc/multivm_bootloaders/vm_remove_allowlist/commit @@ -0,0 +1 @@ +fa45ef1d2b04c640395ec1f34f76ef03f8d19849 diff --git a/etc/multivm_bootloaders/vm_remove_allowlist/fee_estimate.yul/fee_estimate.yul.zbin b/etc/multivm_bootloaders/vm_remove_allowlist/fee_estimate.yul/fee_estimate.yul.zbin new file mode 100644 index 000000000000..278974358990 Binary files /dev/null and b/etc/multivm_bootloaders/vm_remove_allowlist/fee_estimate.yul/fee_estimate.yul.zbin differ diff --git a/etc/multivm_bootloaders/vm_remove_allowlist/gas_test.yul/gas_test.yul.zbin b/etc/multivm_bootloaders/vm_remove_allowlist/gas_test.yul/gas_test.yul.zbin new file mode 100644 index 000000000000..16aff9b48048 Binary files /dev/null and b/etc/multivm_bootloaders/vm_remove_allowlist/gas_test.yul/gas_test.yul.zbin differ diff --git a/etc/multivm_bootloaders/vm_remove_allowlist/playground_batch.yul/playground_batch.yul.zbin b/etc/multivm_bootloaders/vm_remove_allowlist/playground_batch.yul/playground_batch.yul.zbin new file mode 100644 index 000000000000..9c529d213c49 Binary files /dev/null and b/etc/multivm_bootloaders/vm_remove_allowlist/playground_batch.yul/playground_batch.yul.zbin differ diff --git a/etc/multivm_bootloaders/vm_remove_allowlist/proved_batch.yul/proved_batch.yul.zbin b/etc/multivm_bootloaders/vm_remove_allowlist/proved_batch.yul/proved_batch.yul.zbin new file mode 100644 index 000000000000..c10074923e9b Binary files /dev/null and b/etc/multivm_bootloaders/vm_remove_allowlist/proved_batch.yul/proved_batch.yul.zbin differ diff --git a/etc/upgrades/1702392522-allowlist-removal/common.json b/etc/upgrades/1702392522-allowlist-removal/common.json new file mode 100644 index 000000000000..fd31e51c7414 --- /dev/null +++ b/etc/upgrades/1702392522-allowlist-removal/common.json @@ -0,0 +1,5 @@ +{ + "name": "allowlist-removal", + "creationTimestamp": 1702392522, + "protocolVersion": "19" +} \ No newline at end of file diff --git a/etc/upgrades/1702392522-allowlist-removal/mainnet2/facetCuts.json b/etc/upgrades/1702392522-allowlist-removal/mainnet2/facetCuts.json new file mode 100644 index 000000000000..d8d40f875a74 --- /dev/null +++ b/etc/upgrades/1702392522-allowlist-removal/mainnet2/facetCuts.json @@ -0,0 +1,165 @@ +[ + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x0e18b681", + "0xe58bb639", + "0xa9f6d941", + "0x27ae4c16", + "0x4dd18bf5", + "0xf235757f", + "0x1cc5d103", + "0xbe6f11cf", + "0x4623c91d", + "0x17338945" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0xcdffacc6", + "0x52ef6b2c", + "0xadfca15e", + "0x7a0ed627", + "0xa7cd63b7", + "0x79823c9a", + "0x4fc07d75", + "0xd86970d8", + "0xfd791f3c", + "0xe5355c75", + "0x9d1b5a81", + "0x7b30c8da", + "0x8665b150", + "0x631f4bac", + "0x0ec6b0b7", + "0x33ce93fe", + "0xdb1f0bf9", + "0xb8c2f66f", + "0xef3f0bae", + "0xfe26699e", + "0x39607382", + "0xaf6a2dcd", + "0xa1954fc5", + "0x46657fe9", + "0x18e3a941", + "0x29b98c67", + "0xbd7c5412", + "0xc3bbd2d7", + "0xe81e0ba1", + "0xfacd743b", + "0x9cd939e4", + "0x56142d7a", + "0xb22dd78e", + "0x74f4d30d" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x6c0960f9", + "0xb473318e", + "0x042901c7", + "0x263b7f8e", + "0xe4948f43", + "0xeb672419" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x701f58c5", + "0xc3d93e7c", + "0x7f61885c", + "0x97c09d34" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0xAeA49FCEbe3A93ADaE67FF668C0ac87799537967", + "selectors": [ + "0x0e18b681", + "0xe58bb639", + "0xa9f6d941", + "0x27ae4c16", + "0x4dd18bf5", + "0xf235757f", + "0x1cc5d103", + "0xbe6f11cf", + "0x4623c91d", + "0x17338945" + ], + "action": 0, + "isFreezable": false + }, + { + "facet": "0x5edb1756c0A0F933EB87f9d69DfA1db3167547a7", + "selectors": [ + "0xcdffacc6", + "0x52ef6b2c", + "0xadfca15e", + "0x7a0ed627", + "0x79823c9a", + "0x4fc07d75", + "0xd86970d8", + "0xfd791f3c", + "0xe5355c75", + "0x9d1b5a81", + "0x7b30c8da", + "0x8665b150", + "0x631f4bac", + "0x0ec6b0b7", + "0x33ce93fe", + "0xdb1f0bf9", + "0xb8c2f66f", + "0xef3f0bae", + "0xfe26699e", + "0x39607382", + "0xaf6a2dcd", + "0xa1954fc5", + "0x46657fe9", + "0x18e3a941", + "0x29b98c67", + "0xbd7c5412", + "0xc3bbd2d7", + "0xe81e0ba1", + "0xfacd743b", + "0x9cd939e4", + "0x56142d7a", + "0xb22dd78e", + "0x74f4d30d" + ], + "action": 0, + "isFreezable": false + }, + { + "facet": "0x2FbF76bAE617cE41AdB9021907F02e2bF187BB58", + "selectors": [ + "0x6c0960f9", + "0xb473318e", + "0x042901c7", + "0x263b7f8e", + "0xe4948f43", + "0xeb672419" + ], + "action": 0, + "isFreezable": true + }, + { + "facet": "0xc40e5BE1a6D18DdB14268D32dc6075FCf72fF16d", + "selectors": [ + "0x701f58c5", + "0xc3d93e7c", + "0x7f61885c", + "0x97c09d34" + ], + "action": 0, + "isFreezable": true + } +] \ No newline at end of file diff --git a/etc/upgrades/1702392522-allowlist-removal/mainnet2/facets.json b/etc/upgrades/1702392522-allowlist-removal/mainnet2/facets.json new file mode 100644 index 000000000000..04ad16f9ce2a --- /dev/null +++ b/etc/upgrades/1702392522-allowlist-removal/mainnet2/facets.json @@ -0,0 +1,18 @@ +{ + "ExecutorFacet": { + "address": "0xc40e5BE1a6D18DdB14268D32dc6075FCf72fF16d", + "txHash": "0x8af0682204aaefc413cddee5ab9c6103c8d5e1efb466efb82848caf186dc0ab8" + }, + "AdminFacet": { + "address": "0xAeA49FCEbe3A93ADaE67FF668C0ac87799537967", + "txHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "GettersFacet": { + "address": "0x5edb1756c0A0F933EB87f9d69DfA1db3167547a7", + "txHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "MailboxFacet": { + "address": "0x2FbF76bAE617cE41AdB9021907F02e2bF187BB58", + "txHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } +} \ No newline at end of file diff --git a/etc/upgrades/1702392522-allowlist-removal/mainnet2/l2Upgrade.json b/etc/upgrades/1702392522-allowlist-removal/mainnet2/l2Upgrade.json new file mode 100644 index 000000000000..a52f61deaf7d --- /dev/null +++ b/etc/upgrades/1702392522-allowlist-removal/mainnet2/l2Upgrade.json @@ -0,0 +1,323 @@ +{ + "systemContracts": [ + { + "name": "EmptyContract", + "bytecodeHashes": [ + "0x01000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d06" + ], + "address": "0x0000000000000000000000000000000000000000" + }, + { + "name": "Ecrecover", + "bytecodeHashes": [ + "0x0100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d12" + ], + "address": "0x0000000000000000000000000000000000000001" + }, + { + "name": "SHA256", + "bytecodeHashes": [ + "0x010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b0131" + ], + "address": "0x0000000000000000000000000000000000000002" + }, + { + "name": "EcAdd", + "bytecodeHashes": [ + "0x0100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef" + ], + "address": "0x0000000000000000000000000000000000000006" + }, + { + "name": "EcMul", + "bytecodeHashes": [ + "0x010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb2" + ], + "address": "0x0000000000000000000000000000000000000007" + }, + { + "name": "EmptyContract", + "bytecodeHashes": [ + "0x01000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d06" + ], + "address": "0x0000000000000000000000000000000000008001" + }, + { + "name": "AccountCodeStorage", + "bytecodeHashes": [ + "0x01000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e0655" + ], + "address": "0x0000000000000000000000000000000000008002" + }, + { + "name": "NonceHolder", + "bytecodeHashes": [ + "0x010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e223" + ], + "address": "0x0000000000000000000000000000000000008003" + }, + { + "name": "KnownCodesStorage", + "bytecodeHashes": [ + "0x0100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a2" + ], + "address": "0x0000000000000000000000000000000000008004" + }, + { + "name": "ImmutableSimulator", + "bytecodeHashes": [ + "0x0100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf84" + ], + "address": "0x0000000000000000000000000000000000008005" + }, + { + "name": "ContractDeployer", + "bytecodeHashes": [ + "0x0100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a" + ], + "address": "0x0000000000000000000000000000000000008006" + }, + { + "name": "L1Messenger", + "bytecodeHashes": [ + "0x0100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b" + ], + "address": "0x0000000000000000000000000000000000008008" + }, + { + "name": "MsgValueSimulator", + "bytecodeHashes": [ + "0x01000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f00" + ], + "address": "0x0000000000000000000000000000000000008009" + }, + { + "name": "L2EthToken", + "bytecodeHashes": [ + "0x01000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0" + ], + "address": "0x000000000000000000000000000000000000800a" + }, + { + "name": "SystemContext", + "bytecodeHashes": [ + "0x01000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da" + ], + "address": "0x000000000000000000000000000000000000800b" + }, + { + "name": "BootloaderUtilities", + "bytecodeHashes": [ + "0x010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe" + ], + "address": "0x000000000000000000000000000000000000800c" + }, + { + "name": "EventWriter", + "bytecodeHashes": [ + "0x0100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6" + ], + "address": "0x000000000000000000000000000000000000800d" + }, + { + "name": "Compressor", + "bytecodeHashes": [ + "0x010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0" + ], + "address": "0x000000000000000000000000000000000000800e" + }, + { + "name": "ComplexUpgrader", + "bytecodeHashes": [ + "0x01000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050" + ], + "address": "0x000000000000000000000000000000000000800f" + }, + { + "name": "Keccak256", + "bytecodeHashes": [ + "0x01000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f1300" + ], + "address": "0x0000000000000000000000000000000000008010" + } + ], + "defaultAA": { + "name": "DefaultAccount", + "bytecodeHashes": [ + "0x0100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8" + ] + }, + "bootloader": { + "name": "Bootloader", + "bytecodeHashes": [ + "0x01000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d0" + ] + }, + "forcedDeployments": [ + { + "bytecodeHash": "0x01000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d06", + "newAddress": "0x0000000000000000000000000000000000000000", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d12", + "newAddress": "0x0000000000000000000000000000000000000001", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b0131", + "newAddress": "0x0000000000000000000000000000000000000002", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef", + "newAddress": "0x0000000000000000000000000000000000000006", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb2", + "newAddress": "0x0000000000000000000000000000000000000007", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d06", + "newAddress": "0x0000000000000000000000000000000000008001", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e0655", + "newAddress": "0x0000000000000000000000000000000000008002", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e223", + "newAddress": "0x0000000000000000000000000000000000008003", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a2", + "newAddress": "0x0000000000000000000000000000000000008004", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf84", + "newAddress": "0x0000000000000000000000000000000000008005", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a", + "newAddress": "0x0000000000000000000000000000000000008006", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b", + "newAddress": "0x0000000000000000000000000000000000008008", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f00", + "newAddress": "0x0000000000000000000000000000000000008009", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0", + "newAddress": "0x000000000000000000000000000000000000800a", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da", + "newAddress": "0x000000000000000000000000000000000000800b", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe", + "newAddress": "0x000000000000000000000000000000000000800c", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6", + "newAddress": "0x000000000000000000000000000000000000800d", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0", + "newAddress": "0x000000000000000000000000000000000000800e", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050", + "newAddress": "0x000000000000000000000000000000000000800f", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f1300", + "newAddress": "0x0000000000000000000000000000000000008010", + "value": 0, + "input": "0x", + "callConstructor": false + } + ], + "forcedDeploymentCalldata": "0xe9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", + "calldata": "0xe9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", + "tx": { + "txType": 254, + "from": "0x0000000000000000000000000000000000008007", + "to": "0x0000000000000000000000000000000000008006", + "gasLimit": 72000000, + "gasPerPubdataByteLimit": 800, + "maxFeePerGas": 0, + "maxPriorityFeePerGas": 0, + "paymaster": 0, + "nonce": "19", + "value": 0, + "reserved": [ + 0, + 0, + 0, + 0 + ], + "data": "0xe9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", + "signature": "0x", + "factoryDeps": [], + "paymasterInput": "0x", + "reservedDynamic": "0x" + } +} \ No newline at end of file diff --git a/etc/upgrades/1702392522-allowlist-removal/mainnet2/transactions.json b/etc/upgrades/1702392522-allowlist-removal/mainnet2/transactions.json new file mode 100644 index 000000000000..063587e2f0b0 --- /dev/null +++ b/etc/upgrades/1702392522-allowlist-removal/mainnet2/transactions.json @@ -0,0 +1,230 @@ +{ + "proposeUpgradeTx": { + "l2ProtocolUpgradeTx": { + "txType": 254, + "from": "0x0000000000000000000000000000000000008007", + "to": "0x0000000000000000000000000000000000008006", + "gasLimit": 72000000, + "gasPerPubdataByteLimit": 800, + "maxFeePerGas": 0, + "maxPriorityFeePerGas": 0, + "paymaster": 0, + "nonce": "19", + "value": 0, + "reserved": [ + 0, + 0, + 0, + 0 + ], + "data": "0xe9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", + "signature": "0x", + "factoryDeps": [], + "paymasterInput": "0x", + "reservedDynamic": "0x" + }, + "bootloaderHash": "0x01000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d0", + "defaultAccountHash": "0x0100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8", + "verifier": "0x0000000000000000000000000000000000000000", + "verifierParams": { + "recursionNodeLevelVkHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "recursionLeafLevelVkHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "recursionCircuitsSetVksHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "l1ContractsUpgradeCalldata": "0x", + "postUpgradeCalldata": "0x", + "upgradeTimestamp": { + "type": "BigNumber", + "hex": "0x6581a1e0" + }, + "factoryDeps": [], + "newProtocolVersion": "19", + "newAllowList": "0x0000000000000000000000000000000000000000" + }, + "l1upgradeCalldata": "0x1ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000168001000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d00100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016c0000000000000000000000000000000000000000000000000000000006581a1e00000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000001460000000000000000000000000000000000000000000000000000000000000148000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000011c4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "upgradeAddress": "0x75dE2E1ABB12Bc54A5aB04b2761AFc083Be54dC5", + "protocolVersion": "19", + "upgradeTimestamp": "1702994400", + "scheduleTransparentOperation": "0x2c431917000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000032400084c286cf3e17e7b677ea9583e60a000324000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000002b44a9f6d9410000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000075de2e1abb12bc54a5ab04b2761afc083be54dc500000000000000000000000000000000000000000000000000000000000013e00000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000007c000000000000000000000000000000000000000000000000000000000000009200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c2000000000000000000000000000000000000000000000000000000000000010e000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d00000000000000000000000000000000000000000000000000000000173389450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000022cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed62700000000000000000000000000000000000000000000000000000000a7cd63b70000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb6724190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d3400000000000000000000000000000000000000000000000000000000000000000000000000000000aea49fcebe3a93adae67ff668c0ac87799537967000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d0000000000000000000000000000000000000000000000000000000017338945000000000000000000000000000000000000000000000000000000000000000000000000000000005edb1756c0a0f933eb87f9d69dfa1db3167547a70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000021cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed6270000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d000000000000000000000000000000000000000000000000000000000000000000000000000000002fbf76bae617ce41adb9021907f02e2bf187bb5800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb67241900000000000000000000000000000000000000000000000000000000000000000000000000000000c40e5be1a6d18ddb14268d32dc6075fcf72ff16d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017041ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000168001000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d00100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016c0000000000000000000000000000000000000000000000000000000006581a1e00000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000001460000000000000000000000000000000000000000000000000000000000000148000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000011c4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "executeOperation": "0x74da756b00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000032400084c286cf3e17e7b677ea9583e60a000324000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000002b44a9f6d9410000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000075de2e1abb12bc54a5ab04b2761afc083be54dc500000000000000000000000000000000000000000000000000000000000013e00000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000007c000000000000000000000000000000000000000000000000000000000000009200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c2000000000000000000000000000000000000000000000000000000000000010e000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d00000000000000000000000000000000000000000000000000000000173389450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000022cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed62700000000000000000000000000000000000000000000000000000000a7cd63b70000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb6724190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d3400000000000000000000000000000000000000000000000000000000000000000000000000000000aea49fcebe3a93adae67ff668c0ac87799537967000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d0000000000000000000000000000000000000000000000000000000017338945000000000000000000000000000000000000000000000000000000000000000000000000000000005edb1756c0a0f933eb87f9d69dfa1db3167547a70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000021cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed6270000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d000000000000000000000000000000000000000000000000000000000000000000000000000000002fbf76bae617ce41adb9021907f02e2bf187bb5800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb67241900000000000000000000000000000000000000000000000000000000000000000000000000000000c40e5be1a6d18ddb14268d32dc6075fcf72ff16d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017041ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000168001000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d00100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016c0000000000000000000000000000000000000000000000000000000006581a1e00000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000001460000000000000000000000000000000000000000000000000000000000000148000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000011c4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "governanceOperation": { + "calls": [ + { + "target": "0x32400084c286cf3e17e7b677ea9583e60a000324", + "value": 0, + "data": "0xa9f6d9410000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000075de2e1abb12bc54a5ab04b2761afc083be54dc500000000000000000000000000000000000000000000000000000000000013e00000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000007c000000000000000000000000000000000000000000000000000000000000009200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c2000000000000000000000000000000000000000000000000000000000000010e000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d00000000000000000000000000000000000000000000000000000000173389450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000022cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed62700000000000000000000000000000000000000000000000000000000a7cd63b70000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb6724190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d3400000000000000000000000000000000000000000000000000000000000000000000000000000000aea49fcebe3a93adae67ff668c0ac87799537967000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d0000000000000000000000000000000000000000000000000000000017338945000000000000000000000000000000000000000000000000000000000000000000000000000000005edb1756c0a0f933eb87f9d69dfa1db3167547a70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000021cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed6270000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d000000000000000000000000000000000000000000000000000000000000000000000000000000002fbf76bae617ce41adb9021907f02e2bf187bb5800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb67241900000000000000000000000000000000000000000000000000000000000000000000000000000000c40e5be1a6d18ddb14268d32dc6075fcf72ff16d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017041ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000168001000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d00100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016c0000000000000000000000000000000000000000000000000000000006581a1e00000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000001460000000000000000000000000000000000000000000000000000000000000148000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000011c4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + ], + "predecessor": "0x0000000000000000000000000000000000000000000000000000000000000000", + "salt": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "transparentUpgrade": { + "facetCuts": [ + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x0e18b681", + "0xe58bb639", + "0xa9f6d941", + "0x27ae4c16", + "0x4dd18bf5", + "0xf235757f", + "0x1cc5d103", + "0xbe6f11cf", + "0x4623c91d", + "0x17338945" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0xcdffacc6", + "0x52ef6b2c", + "0xadfca15e", + "0x7a0ed627", + "0xa7cd63b7", + "0x79823c9a", + "0x4fc07d75", + "0xd86970d8", + "0xfd791f3c", + "0xe5355c75", + "0x9d1b5a81", + "0x7b30c8da", + "0x8665b150", + "0x631f4bac", + "0x0ec6b0b7", + "0x33ce93fe", + "0xdb1f0bf9", + "0xb8c2f66f", + "0xef3f0bae", + "0xfe26699e", + "0x39607382", + "0xaf6a2dcd", + "0xa1954fc5", + "0x46657fe9", + "0x18e3a941", + "0x29b98c67", + "0xbd7c5412", + "0xc3bbd2d7", + "0xe81e0ba1", + "0xfacd743b", + "0x9cd939e4", + "0x56142d7a", + "0xb22dd78e", + "0x74f4d30d" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x6c0960f9", + "0xb473318e", + "0x042901c7", + "0x263b7f8e", + "0xe4948f43", + "0xeb672419" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x701f58c5", + "0xc3d93e7c", + "0x7f61885c", + "0x97c09d34" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0xAeA49FCEbe3A93ADaE67FF668C0ac87799537967", + "selectors": [ + "0x0e18b681", + "0xe58bb639", + "0xa9f6d941", + "0x27ae4c16", + "0x4dd18bf5", + "0xf235757f", + "0x1cc5d103", + "0xbe6f11cf", + "0x4623c91d", + "0x17338945" + ], + "action": 0, + "isFreezable": false + }, + { + "facet": "0x5edb1756c0A0F933EB87f9d69DfA1db3167547a7", + "selectors": [ + "0xcdffacc6", + "0x52ef6b2c", + "0xadfca15e", + "0x7a0ed627", + "0x79823c9a", + "0x4fc07d75", + "0xd86970d8", + "0xfd791f3c", + "0xe5355c75", + "0x9d1b5a81", + "0x7b30c8da", + "0x8665b150", + "0x631f4bac", + "0x0ec6b0b7", + "0x33ce93fe", + "0xdb1f0bf9", + "0xb8c2f66f", + "0xef3f0bae", + "0xfe26699e", + "0x39607382", + "0xaf6a2dcd", + "0xa1954fc5", + "0x46657fe9", + "0x18e3a941", + "0x29b98c67", + "0xbd7c5412", + "0xc3bbd2d7", + "0xe81e0ba1", + "0xfacd743b", + "0x9cd939e4", + "0x56142d7a", + "0xb22dd78e", + "0x74f4d30d" + ], + "action": 0, + "isFreezable": false + }, + { + "facet": "0x2FbF76bAE617cE41AdB9021907F02e2bF187BB58", + "selectors": [ + "0x6c0960f9", + "0xb473318e", + "0x042901c7", + "0x263b7f8e", + "0xe4948f43", + "0xeb672419" + ], + "action": 0, + "isFreezable": true + }, + { + "facet": "0xc40e5BE1a6D18DdB14268D32dc6075FCf72fF16d", + "selectors": [ + "0x701f58c5", + "0xc3d93e7c", + "0x7f61885c", + "0x97c09d34" + ], + "action": 0, + "isFreezable": true + } + ], + "initAddress": "0x75dE2E1ABB12Bc54A5aB04b2761AFc083Be54dC5", + "initCalldata": "0x1ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000168001000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d00100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016c0000000000000000000000000000000000000000000000000000000006581a1e00000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000001460000000000000000000000000000000000000000000000000000000000000148000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000011c4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } +} \ No newline at end of file diff --git a/etc/upgrades/1702392522-allowlist-removal/stage2/facetCuts.json b/etc/upgrades/1702392522-allowlist-removal/stage2/facetCuts.json new file mode 100644 index 000000000000..0a0eb824ab2a --- /dev/null +++ b/etc/upgrades/1702392522-allowlist-removal/stage2/facetCuts.json @@ -0,0 +1,165 @@ +[ + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x0e18b681", + "0xe58bb639", + "0xa9f6d941", + "0x27ae4c16", + "0x4dd18bf5", + "0xf235757f", + "0x1cc5d103", + "0xbe6f11cf", + "0x4623c91d", + "0x17338945" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0xcdffacc6", + "0x52ef6b2c", + "0xadfca15e", + "0x7a0ed627", + "0xa7cd63b7", + "0x79823c9a", + "0x4fc07d75", + "0xd86970d8", + "0xfd791f3c", + "0xe5355c75", + "0x9d1b5a81", + "0x7b30c8da", + "0x8665b150", + "0x631f4bac", + "0x0ec6b0b7", + "0x33ce93fe", + "0xdb1f0bf9", + "0xb8c2f66f", + "0xef3f0bae", + "0xfe26699e", + "0x39607382", + "0xaf6a2dcd", + "0xa1954fc5", + "0x46657fe9", + "0x18e3a941", + "0x29b98c67", + "0xbd7c5412", + "0xc3bbd2d7", + "0xe81e0ba1", + "0xfacd743b", + "0x9cd939e4", + "0x56142d7a", + "0xb22dd78e", + "0x74f4d30d" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x6c0960f9", + "0xb473318e", + "0x042901c7", + "0x263b7f8e", + "0xe4948f43", + "0xeb672419" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x701f58c5", + "0xc3d93e7c", + "0x7f61885c", + "0x97c09d34" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0xAeA49FCEbe3A93ADaE67FF668C0ac87799537967", + "selectors": [ + "0x0e18b681", + "0xe58bb639", + "0xa9f6d941", + "0x27ae4c16", + "0x4dd18bf5", + "0xf235757f", + "0x1cc5d103", + "0xbe6f11cf", + "0x4623c91d", + "0x17338945" + ], + "action": 0, + "isFreezable": false + }, + { + "facet": "0x5edb1756c0A0F933EB87f9d69DfA1db3167547a7", + "selectors": [ + "0xcdffacc6", + "0x52ef6b2c", + "0xadfca15e", + "0x7a0ed627", + "0x79823c9a", + "0x4fc07d75", + "0xd86970d8", + "0xfd791f3c", + "0xe5355c75", + "0x9d1b5a81", + "0x7b30c8da", + "0x8665b150", + "0x631f4bac", + "0x0ec6b0b7", + "0x33ce93fe", + "0xdb1f0bf9", + "0xb8c2f66f", + "0xef3f0bae", + "0xfe26699e", + "0x39607382", + "0xaf6a2dcd", + "0xa1954fc5", + "0x46657fe9", + "0x18e3a941", + "0x29b98c67", + "0xbd7c5412", + "0xc3bbd2d7", + "0xe81e0ba1", + "0xfacd743b", + "0x9cd939e4", + "0x56142d7a", + "0xb22dd78e", + "0x74f4d30d" + ], + "action": 0, + "isFreezable": false + }, + { + "facet": "0x2FbF76bAE617cE41AdB9021907F02e2bF187BB58", + "selectors": [ + "0x6c0960f9", + "0xb473318e", + "0x042901c7", + "0x263b7f8e", + "0xe4948f43", + "0xeb672419" + ], + "action": 0, + "isFreezable": true + }, + { + "facet": "0x801F3729fBB5859d94b867f813a22D85487BCa2d", + "selectors": [ + "0x701f58c5", + "0xc3d93e7c", + "0x7f61885c", + "0x97c09d34" + ], + "action": 0, + "isFreezable": true + } +] \ No newline at end of file diff --git a/etc/upgrades/1702392522-allowlist-removal/stage2/facets.json b/etc/upgrades/1702392522-allowlist-removal/stage2/facets.json new file mode 100644 index 000000000000..e764752637bd --- /dev/null +++ b/etc/upgrades/1702392522-allowlist-removal/stage2/facets.json @@ -0,0 +1,18 @@ +{ + "ExecutorFacet": { + "address": "0x801F3729fBB5859d94b867f813a22D85487BCa2d", + "txHash": "0x64dd4de966f38edd59afa205c93b77fcbf1b2591d0bafb95436c63cafd71587a" + }, + "AdminFacet": { + "address": "0xAeA49FCEbe3A93ADaE67FF668C0ac87799537967", + "txHash": "0xe6cd37936d0260972a23212253ea670417e8e515c52171a6e8623e9fb910c927" + }, + "GettersFacet": { + "address": "0x5edb1756c0A0F933EB87f9d69DfA1db3167547a7", + "txHash": "0x466fc08747c85e597602c3b4a98c61498417cbf3af10ca5404920f3244229c50" + }, + "MailboxFacet": { + "address": "0x2FbF76bAE617cE41AdB9021907F02e2bF187BB58", + "txHash": "0xabd2bbe0947fbf14d480c0469a5012bacc9189575f95bd656a94250f7660d571" + } +} \ No newline at end of file diff --git a/etc/upgrades/1702392522-allowlist-removal/stage2/l2Upgrade.json b/etc/upgrades/1702392522-allowlist-removal/stage2/l2Upgrade.json new file mode 100644 index 000000000000..a52f61deaf7d --- /dev/null +++ b/etc/upgrades/1702392522-allowlist-removal/stage2/l2Upgrade.json @@ -0,0 +1,323 @@ +{ + "systemContracts": [ + { + "name": "EmptyContract", + "bytecodeHashes": [ + "0x01000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d06" + ], + "address": "0x0000000000000000000000000000000000000000" + }, + { + "name": "Ecrecover", + "bytecodeHashes": [ + "0x0100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d12" + ], + "address": "0x0000000000000000000000000000000000000001" + }, + { + "name": "SHA256", + "bytecodeHashes": [ + "0x010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b0131" + ], + "address": "0x0000000000000000000000000000000000000002" + }, + { + "name": "EcAdd", + "bytecodeHashes": [ + "0x0100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef" + ], + "address": "0x0000000000000000000000000000000000000006" + }, + { + "name": "EcMul", + "bytecodeHashes": [ + "0x010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb2" + ], + "address": "0x0000000000000000000000000000000000000007" + }, + { + "name": "EmptyContract", + "bytecodeHashes": [ + "0x01000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d06" + ], + "address": "0x0000000000000000000000000000000000008001" + }, + { + "name": "AccountCodeStorage", + "bytecodeHashes": [ + "0x01000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e0655" + ], + "address": "0x0000000000000000000000000000000000008002" + }, + { + "name": "NonceHolder", + "bytecodeHashes": [ + "0x010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e223" + ], + "address": "0x0000000000000000000000000000000000008003" + }, + { + "name": "KnownCodesStorage", + "bytecodeHashes": [ + "0x0100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a2" + ], + "address": "0x0000000000000000000000000000000000008004" + }, + { + "name": "ImmutableSimulator", + "bytecodeHashes": [ + "0x0100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf84" + ], + "address": "0x0000000000000000000000000000000000008005" + }, + { + "name": "ContractDeployer", + "bytecodeHashes": [ + "0x0100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a" + ], + "address": "0x0000000000000000000000000000000000008006" + }, + { + "name": "L1Messenger", + "bytecodeHashes": [ + "0x0100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b" + ], + "address": "0x0000000000000000000000000000000000008008" + }, + { + "name": "MsgValueSimulator", + "bytecodeHashes": [ + "0x01000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f00" + ], + "address": "0x0000000000000000000000000000000000008009" + }, + { + "name": "L2EthToken", + "bytecodeHashes": [ + "0x01000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0" + ], + "address": "0x000000000000000000000000000000000000800a" + }, + { + "name": "SystemContext", + "bytecodeHashes": [ + "0x01000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da" + ], + "address": "0x000000000000000000000000000000000000800b" + }, + { + "name": "BootloaderUtilities", + "bytecodeHashes": [ + "0x010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe" + ], + "address": "0x000000000000000000000000000000000000800c" + }, + { + "name": "EventWriter", + "bytecodeHashes": [ + "0x0100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6" + ], + "address": "0x000000000000000000000000000000000000800d" + }, + { + "name": "Compressor", + "bytecodeHashes": [ + "0x010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0" + ], + "address": "0x000000000000000000000000000000000000800e" + }, + { + "name": "ComplexUpgrader", + "bytecodeHashes": [ + "0x01000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050" + ], + "address": "0x000000000000000000000000000000000000800f" + }, + { + "name": "Keccak256", + "bytecodeHashes": [ + "0x01000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f1300" + ], + "address": "0x0000000000000000000000000000000000008010" + } + ], + "defaultAA": { + "name": "DefaultAccount", + "bytecodeHashes": [ + "0x0100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8" + ] + }, + "bootloader": { + "name": "Bootloader", + "bytecodeHashes": [ + "0x01000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d0" + ] + }, + "forcedDeployments": [ + { + "bytecodeHash": "0x01000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d06", + "newAddress": "0x0000000000000000000000000000000000000000", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d12", + "newAddress": "0x0000000000000000000000000000000000000001", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b0131", + "newAddress": "0x0000000000000000000000000000000000000002", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef", + "newAddress": "0x0000000000000000000000000000000000000006", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb2", + "newAddress": "0x0000000000000000000000000000000000000007", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d06", + "newAddress": "0x0000000000000000000000000000000000008001", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e0655", + "newAddress": "0x0000000000000000000000000000000000008002", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e223", + "newAddress": "0x0000000000000000000000000000000000008003", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a2", + "newAddress": "0x0000000000000000000000000000000000008004", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf84", + "newAddress": "0x0000000000000000000000000000000000008005", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a", + "newAddress": "0x0000000000000000000000000000000000008006", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b", + "newAddress": "0x0000000000000000000000000000000000008008", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f00", + "newAddress": "0x0000000000000000000000000000000000008009", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0", + "newAddress": "0x000000000000000000000000000000000000800a", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da", + "newAddress": "0x000000000000000000000000000000000000800b", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe", + "newAddress": "0x000000000000000000000000000000000000800c", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6", + "newAddress": "0x000000000000000000000000000000000000800d", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0", + "newAddress": "0x000000000000000000000000000000000000800e", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050", + "newAddress": "0x000000000000000000000000000000000000800f", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f1300", + "newAddress": "0x0000000000000000000000000000000000008010", + "value": 0, + "input": "0x", + "callConstructor": false + } + ], + "forcedDeploymentCalldata": "0xe9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", + "calldata": "0xe9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", + "tx": { + "txType": 254, + "from": "0x0000000000000000000000000000000000008007", + "to": "0x0000000000000000000000000000000000008006", + "gasLimit": 72000000, + "gasPerPubdataByteLimit": 800, + "maxFeePerGas": 0, + "maxPriorityFeePerGas": 0, + "paymaster": 0, + "nonce": "19", + "value": 0, + "reserved": [ + 0, + 0, + 0, + 0 + ], + "data": "0xe9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", + "signature": "0x", + "factoryDeps": [], + "paymasterInput": "0x", + "reservedDynamic": "0x" + } +} \ No newline at end of file diff --git a/etc/upgrades/1702392522-allowlist-removal/stage2/transactions.json b/etc/upgrades/1702392522-allowlist-removal/stage2/transactions.json new file mode 100644 index 000000000000..857677c91aad --- /dev/null +++ b/etc/upgrades/1702392522-allowlist-removal/stage2/transactions.json @@ -0,0 +1,230 @@ +{ + "proposeUpgradeTx": { + "l2ProtocolUpgradeTx": { + "txType": 254, + "from": "0x0000000000000000000000000000000000008007", + "to": "0x0000000000000000000000000000000000008006", + "gasLimit": 72000000, + "gasPerPubdataByteLimit": 800, + "maxFeePerGas": 0, + "maxPriorityFeePerGas": 0, + "paymaster": 0, + "nonce": "19", + "value": 0, + "reserved": [ + 0, + 0, + 0, + 0 + ], + "data": "0xe9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", + "signature": "0x", + "factoryDeps": [], + "paymasterInput": "0x", + "reservedDynamic": "0x" + }, + "bootloaderHash": "0x01000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d0", + "defaultAccountHash": "0x0100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8", + "verifier": "0x0000000000000000000000000000000000000000", + "verifierParams": { + "recursionNodeLevelVkHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "recursionLeafLevelVkHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "recursionCircuitsSetVksHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "l1ContractsUpgradeCalldata": "0x", + "postUpgradeCalldata": "0x", + "upgradeTimestamp": { + "type": "BigNumber", + "hex": "0x6579de20" + }, + "factoryDeps": [], + "newProtocolVersion": "19", + "newAllowList": "0x0000000000000000000000000000000000000000" + }, + "l1upgradeCalldata": "0x1ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000168001000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d00100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016c0000000000000000000000000000000000000000000000000000000006579de200000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000001460000000000000000000000000000000000000000000000000000000000000148000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000011c4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "upgradeAddress": "0x75dE2E1ABB12Bc54A5aB04b2761AFc083Be54dC5", + "protocolVersion": "19", + "upgradeTimestamp": "1702485536", + "scheduleTransparentOperation": "0x2c43191700000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000006d6e010a2680e2e5a3b097ce411528b36d880ef6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000002b44a9f6d9410000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000075de2e1abb12bc54a5ab04b2761afc083be54dc500000000000000000000000000000000000000000000000000000000000013e00000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000007c000000000000000000000000000000000000000000000000000000000000009200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c2000000000000000000000000000000000000000000000000000000000000010e000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d00000000000000000000000000000000000000000000000000000000173389450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000022cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed62700000000000000000000000000000000000000000000000000000000a7cd63b70000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb6724190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d3400000000000000000000000000000000000000000000000000000000000000000000000000000000aea49fcebe3a93adae67ff668c0ac87799537967000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d0000000000000000000000000000000000000000000000000000000017338945000000000000000000000000000000000000000000000000000000000000000000000000000000005edb1756c0a0f933eb87f9d69dfa1db3167547a70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000021cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed6270000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d000000000000000000000000000000000000000000000000000000000000000000000000000000002fbf76bae617ce41adb9021907f02e2bf187bb5800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb67241900000000000000000000000000000000000000000000000000000000000000000000000000000000801f3729fbb5859d94b867f813a22d85487bca2d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017041ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000168001000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d00100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016c0000000000000000000000000000000000000000000000000000000006579de200000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000001460000000000000000000000000000000000000000000000000000000000000148000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000011c4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "executeOperation": "0x74da756b0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000006d6e010a2680e2e5a3b097ce411528b36d880ef6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000002b44a9f6d9410000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000075de2e1abb12bc54a5ab04b2761afc083be54dc500000000000000000000000000000000000000000000000000000000000013e00000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000007c000000000000000000000000000000000000000000000000000000000000009200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c2000000000000000000000000000000000000000000000000000000000000010e000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d00000000000000000000000000000000000000000000000000000000173389450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000022cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed62700000000000000000000000000000000000000000000000000000000a7cd63b70000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb6724190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d3400000000000000000000000000000000000000000000000000000000000000000000000000000000aea49fcebe3a93adae67ff668c0ac87799537967000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d0000000000000000000000000000000000000000000000000000000017338945000000000000000000000000000000000000000000000000000000000000000000000000000000005edb1756c0a0f933eb87f9d69dfa1db3167547a70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000021cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed6270000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d000000000000000000000000000000000000000000000000000000000000000000000000000000002fbf76bae617ce41adb9021907f02e2bf187bb5800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb67241900000000000000000000000000000000000000000000000000000000000000000000000000000000801f3729fbb5859d94b867f813a22d85487bca2d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017041ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000168001000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d00100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016c0000000000000000000000000000000000000000000000000000000006579de200000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000001460000000000000000000000000000000000000000000000000000000000000148000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000011c4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "governanceOperation": { + "calls": [ + { + "target": "0x6d6e010A2680E2E5a3b097ce411528b36d880EF6", + "value": 0, + "data": "0xa9f6d9410000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000075de2e1abb12bc54a5ab04b2761afc083be54dc500000000000000000000000000000000000000000000000000000000000013e00000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000007c000000000000000000000000000000000000000000000000000000000000009200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c2000000000000000000000000000000000000000000000000000000000000010e000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d00000000000000000000000000000000000000000000000000000000173389450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000022cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed62700000000000000000000000000000000000000000000000000000000a7cd63b70000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb6724190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d3400000000000000000000000000000000000000000000000000000000000000000000000000000000aea49fcebe3a93adae67ff668c0ac87799537967000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d0000000000000000000000000000000000000000000000000000000017338945000000000000000000000000000000000000000000000000000000000000000000000000000000005edb1756c0a0f933eb87f9d69dfa1db3167547a70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000021cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed6270000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d000000000000000000000000000000000000000000000000000000000000000000000000000000002fbf76bae617ce41adb9021907f02e2bf187bb5800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb67241900000000000000000000000000000000000000000000000000000000000000000000000000000000801f3729fbb5859d94b867f813a22d85487bca2d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017041ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000168001000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d00100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016c0000000000000000000000000000000000000000000000000000000006579de200000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000001460000000000000000000000000000000000000000000000000000000000000148000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000011c4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + ], + "predecessor": "0x0000000000000000000000000000000000000000000000000000000000000000", + "salt": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "transparentUpgrade": { + "facetCuts": [ + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x0e18b681", + "0xe58bb639", + "0xa9f6d941", + "0x27ae4c16", + "0x4dd18bf5", + "0xf235757f", + "0x1cc5d103", + "0xbe6f11cf", + "0x4623c91d", + "0x17338945" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0xcdffacc6", + "0x52ef6b2c", + "0xadfca15e", + "0x7a0ed627", + "0xa7cd63b7", + "0x79823c9a", + "0x4fc07d75", + "0xd86970d8", + "0xfd791f3c", + "0xe5355c75", + "0x9d1b5a81", + "0x7b30c8da", + "0x8665b150", + "0x631f4bac", + "0x0ec6b0b7", + "0x33ce93fe", + "0xdb1f0bf9", + "0xb8c2f66f", + "0xef3f0bae", + "0xfe26699e", + "0x39607382", + "0xaf6a2dcd", + "0xa1954fc5", + "0x46657fe9", + "0x18e3a941", + "0x29b98c67", + "0xbd7c5412", + "0xc3bbd2d7", + "0xe81e0ba1", + "0xfacd743b", + "0x9cd939e4", + "0x56142d7a", + "0xb22dd78e", + "0x74f4d30d" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x6c0960f9", + "0xb473318e", + "0x042901c7", + "0x263b7f8e", + "0xe4948f43", + "0xeb672419" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x701f58c5", + "0xc3d93e7c", + "0x7f61885c", + "0x97c09d34" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0xAeA49FCEbe3A93ADaE67FF668C0ac87799537967", + "selectors": [ + "0x0e18b681", + "0xe58bb639", + "0xa9f6d941", + "0x27ae4c16", + "0x4dd18bf5", + "0xf235757f", + "0x1cc5d103", + "0xbe6f11cf", + "0x4623c91d", + "0x17338945" + ], + "action": 0, + "isFreezable": false + }, + { + "facet": "0x5edb1756c0A0F933EB87f9d69DfA1db3167547a7", + "selectors": [ + "0xcdffacc6", + "0x52ef6b2c", + "0xadfca15e", + "0x7a0ed627", + "0x79823c9a", + "0x4fc07d75", + "0xd86970d8", + "0xfd791f3c", + "0xe5355c75", + "0x9d1b5a81", + "0x7b30c8da", + "0x8665b150", + "0x631f4bac", + "0x0ec6b0b7", + "0x33ce93fe", + "0xdb1f0bf9", + "0xb8c2f66f", + "0xef3f0bae", + "0xfe26699e", + "0x39607382", + "0xaf6a2dcd", + "0xa1954fc5", + "0x46657fe9", + "0x18e3a941", + "0x29b98c67", + "0xbd7c5412", + "0xc3bbd2d7", + "0xe81e0ba1", + "0xfacd743b", + "0x9cd939e4", + "0x56142d7a", + "0xb22dd78e", + "0x74f4d30d" + ], + "action": 0, + "isFreezable": false + }, + { + "facet": "0x2FbF76bAE617cE41AdB9021907F02e2bF187BB58", + "selectors": [ + "0x6c0960f9", + "0xb473318e", + "0x042901c7", + "0x263b7f8e", + "0xe4948f43", + "0xeb672419" + ], + "action": 0, + "isFreezable": true + }, + { + "facet": "0x801F3729fBB5859d94b867f813a22D85487BCa2d", + "selectors": [ + "0x701f58c5", + "0xc3d93e7c", + "0x7f61885c", + "0x97c09d34" + ], + "action": 0, + "isFreezable": true + } + ], + "initAddress": "0x75dE2E1ABB12Bc54A5aB04b2761AFc083Be54dC5", + "initCalldata": "0x1ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000168001000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d00100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016c0000000000000000000000000000000000000000000000000000000006579de200000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000001460000000000000000000000000000000000000000000000000000000000000148000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000011c4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } +} \ No newline at end of file diff --git a/etc/upgrades/1702392522-allowlist-removal/testnet-sepolia/facetCuts.json b/etc/upgrades/1702392522-allowlist-removal/testnet-sepolia/facetCuts.json new file mode 100644 index 000000000000..0a0eb824ab2a --- /dev/null +++ b/etc/upgrades/1702392522-allowlist-removal/testnet-sepolia/facetCuts.json @@ -0,0 +1,165 @@ +[ + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x0e18b681", + "0xe58bb639", + "0xa9f6d941", + "0x27ae4c16", + "0x4dd18bf5", + "0xf235757f", + "0x1cc5d103", + "0xbe6f11cf", + "0x4623c91d", + "0x17338945" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0xcdffacc6", + "0x52ef6b2c", + "0xadfca15e", + "0x7a0ed627", + "0xa7cd63b7", + "0x79823c9a", + "0x4fc07d75", + "0xd86970d8", + "0xfd791f3c", + "0xe5355c75", + "0x9d1b5a81", + "0x7b30c8da", + "0x8665b150", + "0x631f4bac", + "0x0ec6b0b7", + "0x33ce93fe", + "0xdb1f0bf9", + "0xb8c2f66f", + "0xef3f0bae", + "0xfe26699e", + "0x39607382", + "0xaf6a2dcd", + "0xa1954fc5", + "0x46657fe9", + "0x18e3a941", + "0x29b98c67", + "0xbd7c5412", + "0xc3bbd2d7", + "0xe81e0ba1", + "0xfacd743b", + "0x9cd939e4", + "0x56142d7a", + "0xb22dd78e", + "0x74f4d30d" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x6c0960f9", + "0xb473318e", + "0x042901c7", + "0x263b7f8e", + "0xe4948f43", + "0xeb672419" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x701f58c5", + "0xc3d93e7c", + "0x7f61885c", + "0x97c09d34" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0xAeA49FCEbe3A93ADaE67FF668C0ac87799537967", + "selectors": [ + "0x0e18b681", + "0xe58bb639", + "0xa9f6d941", + "0x27ae4c16", + "0x4dd18bf5", + "0xf235757f", + "0x1cc5d103", + "0xbe6f11cf", + "0x4623c91d", + "0x17338945" + ], + "action": 0, + "isFreezable": false + }, + { + "facet": "0x5edb1756c0A0F933EB87f9d69DfA1db3167547a7", + "selectors": [ + "0xcdffacc6", + "0x52ef6b2c", + "0xadfca15e", + "0x7a0ed627", + "0x79823c9a", + "0x4fc07d75", + "0xd86970d8", + "0xfd791f3c", + "0xe5355c75", + "0x9d1b5a81", + "0x7b30c8da", + "0x8665b150", + "0x631f4bac", + "0x0ec6b0b7", + "0x33ce93fe", + "0xdb1f0bf9", + "0xb8c2f66f", + "0xef3f0bae", + "0xfe26699e", + "0x39607382", + "0xaf6a2dcd", + "0xa1954fc5", + "0x46657fe9", + "0x18e3a941", + "0x29b98c67", + "0xbd7c5412", + "0xc3bbd2d7", + "0xe81e0ba1", + "0xfacd743b", + "0x9cd939e4", + "0x56142d7a", + "0xb22dd78e", + "0x74f4d30d" + ], + "action": 0, + "isFreezable": false + }, + { + "facet": "0x2FbF76bAE617cE41AdB9021907F02e2bF187BB58", + "selectors": [ + "0x6c0960f9", + "0xb473318e", + "0x042901c7", + "0x263b7f8e", + "0xe4948f43", + "0xeb672419" + ], + "action": 0, + "isFreezable": true + }, + { + "facet": "0x801F3729fBB5859d94b867f813a22D85487BCa2d", + "selectors": [ + "0x701f58c5", + "0xc3d93e7c", + "0x7f61885c", + "0x97c09d34" + ], + "action": 0, + "isFreezable": true + } +] \ No newline at end of file diff --git a/etc/upgrades/1702392522-allowlist-removal/testnet-sepolia/facets.json b/etc/upgrades/1702392522-allowlist-removal/testnet-sepolia/facets.json new file mode 100644 index 000000000000..01b5611554c5 --- /dev/null +++ b/etc/upgrades/1702392522-allowlist-removal/testnet-sepolia/facets.json @@ -0,0 +1,18 @@ +{ + "ExecutorFacet": { + "address": "0x801F3729fBB5859d94b867f813a22D85487BCa2d", + "txHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "AdminFacet": { + "address": "0xAeA49FCEbe3A93ADaE67FF668C0ac87799537967", + "txHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "GettersFacet": { + "address": "0x5edb1756c0A0F933EB87f9d69DfA1db3167547a7", + "txHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "MailboxFacet": { + "address": "0x2FbF76bAE617cE41AdB9021907F02e2bF187BB58", + "txHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } +} \ No newline at end of file diff --git a/etc/upgrades/1702392522-allowlist-removal/testnet-sepolia/l2Upgrade.json b/etc/upgrades/1702392522-allowlist-removal/testnet-sepolia/l2Upgrade.json new file mode 100644 index 000000000000..a52f61deaf7d --- /dev/null +++ b/etc/upgrades/1702392522-allowlist-removal/testnet-sepolia/l2Upgrade.json @@ -0,0 +1,323 @@ +{ + "systemContracts": [ + { + "name": "EmptyContract", + "bytecodeHashes": [ + "0x01000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d06" + ], + "address": "0x0000000000000000000000000000000000000000" + }, + { + "name": "Ecrecover", + "bytecodeHashes": [ + "0x0100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d12" + ], + "address": "0x0000000000000000000000000000000000000001" + }, + { + "name": "SHA256", + "bytecodeHashes": [ + "0x010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b0131" + ], + "address": "0x0000000000000000000000000000000000000002" + }, + { + "name": "EcAdd", + "bytecodeHashes": [ + "0x0100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef" + ], + "address": "0x0000000000000000000000000000000000000006" + }, + { + "name": "EcMul", + "bytecodeHashes": [ + "0x010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb2" + ], + "address": "0x0000000000000000000000000000000000000007" + }, + { + "name": "EmptyContract", + "bytecodeHashes": [ + "0x01000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d06" + ], + "address": "0x0000000000000000000000000000000000008001" + }, + { + "name": "AccountCodeStorage", + "bytecodeHashes": [ + "0x01000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e0655" + ], + "address": "0x0000000000000000000000000000000000008002" + }, + { + "name": "NonceHolder", + "bytecodeHashes": [ + "0x010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e223" + ], + "address": "0x0000000000000000000000000000000000008003" + }, + { + "name": "KnownCodesStorage", + "bytecodeHashes": [ + "0x0100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a2" + ], + "address": "0x0000000000000000000000000000000000008004" + }, + { + "name": "ImmutableSimulator", + "bytecodeHashes": [ + "0x0100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf84" + ], + "address": "0x0000000000000000000000000000000000008005" + }, + { + "name": "ContractDeployer", + "bytecodeHashes": [ + "0x0100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a" + ], + "address": "0x0000000000000000000000000000000000008006" + }, + { + "name": "L1Messenger", + "bytecodeHashes": [ + "0x0100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b" + ], + "address": "0x0000000000000000000000000000000000008008" + }, + { + "name": "MsgValueSimulator", + "bytecodeHashes": [ + "0x01000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f00" + ], + "address": "0x0000000000000000000000000000000000008009" + }, + { + "name": "L2EthToken", + "bytecodeHashes": [ + "0x01000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0" + ], + "address": "0x000000000000000000000000000000000000800a" + }, + { + "name": "SystemContext", + "bytecodeHashes": [ + "0x01000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da" + ], + "address": "0x000000000000000000000000000000000000800b" + }, + { + "name": "BootloaderUtilities", + "bytecodeHashes": [ + "0x010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe" + ], + "address": "0x000000000000000000000000000000000000800c" + }, + { + "name": "EventWriter", + "bytecodeHashes": [ + "0x0100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6" + ], + "address": "0x000000000000000000000000000000000000800d" + }, + { + "name": "Compressor", + "bytecodeHashes": [ + "0x010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0" + ], + "address": "0x000000000000000000000000000000000000800e" + }, + { + "name": "ComplexUpgrader", + "bytecodeHashes": [ + "0x01000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050" + ], + "address": "0x000000000000000000000000000000000000800f" + }, + { + "name": "Keccak256", + "bytecodeHashes": [ + "0x01000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f1300" + ], + "address": "0x0000000000000000000000000000000000008010" + } + ], + "defaultAA": { + "name": "DefaultAccount", + "bytecodeHashes": [ + "0x0100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8" + ] + }, + "bootloader": { + "name": "Bootloader", + "bytecodeHashes": [ + "0x01000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d0" + ] + }, + "forcedDeployments": [ + { + "bytecodeHash": "0x01000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d06", + "newAddress": "0x0000000000000000000000000000000000000000", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d12", + "newAddress": "0x0000000000000000000000000000000000000001", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b0131", + "newAddress": "0x0000000000000000000000000000000000000002", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef", + "newAddress": "0x0000000000000000000000000000000000000006", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb2", + "newAddress": "0x0000000000000000000000000000000000000007", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d06", + "newAddress": "0x0000000000000000000000000000000000008001", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e0655", + "newAddress": "0x0000000000000000000000000000000000008002", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e223", + "newAddress": "0x0000000000000000000000000000000000008003", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a2", + "newAddress": "0x0000000000000000000000000000000000008004", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf84", + "newAddress": "0x0000000000000000000000000000000000008005", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a", + "newAddress": "0x0000000000000000000000000000000000008006", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b", + "newAddress": "0x0000000000000000000000000000000000008008", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f00", + "newAddress": "0x0000000000000000000000000000000000008009", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0", + "newAddress": "0x000000000000000000000000000000000000800a", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da", + "newAddress": "0x000000000000000000000000000000000000800b", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe", + "newAddress": "0x000000000000000000000000000000000000800c", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6", + "newAddress": "0x000000000000000000000000000000000000800d", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0", + "newAddress": "0x000000000000000000000000000000000000800e", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050", + "newAddress": "0x000000000000000000000000000000000000800f", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f1300", + "newAddress": "0x0000000000000000000000000000000000008010", + "value": 0, + "input": "0x", + "callConstructor": false + } + ], + "forcedDeploymentCalldata": "0xe9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", + "calldata": "0xe9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", + "tx": { + "txType": 254, + "from": "0x0000000000000000000000000000000000008007", + "to": "0x0000000000000000000000000000000000008006", + "gasLimit": 72000000, + "gasPerPubdataByteLimit": 800, + "maxFeePerGas": 0, + "maxPriorityFeePerGas": 0, + "paymaster": 0, + "nonce": "19", + "value": 0, + "reserved": [ + 0, + 0, + 0, + 0 + ], + "data": "0xe9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", + "signature": "0x", + "factoryDeps": [], + "paymasterInput": "0x", + "reservedDynamic": "0x" + } +} \ No newline at end of file diff --git a/etc/upgrades/1702392522-allowlist-removal/testnet-sepolia/transactions.json b/etc/upgrades/1702392522-allowlist-removal/testnet-sepolia/transactions.json new file mode 100644 index 000000000000..236e338d264d --- /dev/null +++ b/etc/upgrades/1702392522-allowlist-removal/testnet-sepolia/transactions.json @@ -0,0 +1,230 @@ +{ + "proposeUpgradeTx": { + "l2ProtocolUpgradeTx": { + "txType": 254, + "from": "0x0000000000000000000000000000000000008007", + "to": "0x0000000000000000000000000000000000008006", + "gasLimit": 72000000, + "gasPerPubdataByteLimit": 800, + "maxFeePerGas": 0, + "maxPriorityFeePerGas": 0, + "paymaster": 0, + "nonce": "19", + "value": 0, + "reserved": [ + 0, + 0, + 0, + 0 + ], + "data": "0xe9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", + "signature": "0x", + "factoryDeps": [], + "paymasterInput": "0x", + "reservedDynamic": "0x" + }, + "bootloaderHash": "0x01000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d0", + "defaultAccountHash": "0x0100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8", + "verifier": "0x0000000000000000000000000000000000000000", + "verifierParams": { + "recursionNodeLevelVkHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "recursionLeafLevelVkHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "recursionCircuitsSetVksHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "l1ContractsUpgradeCalldata": "0x", + "postUpgradeCalldata": "0x", + "upgradeTimestamp": { + "type": "BigNumber", + "hex": "0x657c4cc8" + }, + "factoryDeps": [], + "newProtocolVersion": "19", + "newAllowList": "0x0000000000000000000000000000000000000000" + }, + "l1upgradeCalldata": "0x1ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000168001000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d00100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000657c4cc80000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000001460000000000000000000000000000000000000000000000000000000000000148000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000011c4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "upgradeAddress": "0x75dE2E1ABB12Bc54A5aB04b2761AFc083Be54dC5", + "protocolVersion": "19", + "upgradeTimestamp": "1702644936", + "scheduleTransparentOperation": "0x2c43191700000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000009a6de0f62aa270a8bcb1e2610078650d539b1ef9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000002b44a9f6d9410000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000075de2e1abb12bc54a5ab04b2761afc083be54dc500000000000000000000000000000000000000000000000000000000000013e00000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000007c000000000000000000000000000000000000000000000000000000000000009200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c2000000000000000000000000000000000000000000000000000000000000010e000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d00000000000000000000000000000000000000000000000000000000173389450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000022cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed62700000000000000000000000000000000000000000000000000000000a7cd63b70000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb6724190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d3400000000000000000000000000000000000000000000000000000000000000000000000000000000aea49fcebe3a93adae67ff668c0ac87799537967000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d0000000000000000000000000000000000000000000000000000000017338945000000000000000000000000000000000000000000000000000000000000000000000000000000005edb1756c0a0f933eb87f9d69dfa1db3167547a70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000021cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed6270000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d000000000000000000000000000000000000000000000000000000000000000000000000000000002fbf76bae617ce41adb9021907f02e2bf187bb5800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb67241900000000000000000000000000000000000000000000000000000000000000000000000000000000801f3729fbb5859d94b867f813a22d85487bca2d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017041ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000168001000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d00100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000657c4cc80000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000001460000000000000000000000000000000000000000000000000000000000000148000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000011c4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "executeOperation": "0x74da756b0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000009a6de0f62aa270a8bcb1e2610078650d539b1ef9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000002b44a9f6d9410000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000075de2e1abb12bc54a5ab04b2761afc083be54dc500000000000000000000000000000000000000000000000000000000000013e00000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000007c000000000000000000000000000000000000000000000000000000000000009200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c2000000000000000000000000000000000000000000000000000000000000010e000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d00000000000000000000000000000000000000000000000000000000173389450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000022cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed62700000000000000000000000000000000000000000000000000000000a7cd63b70000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb6724190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d3400000000000000000000000000000000000000000000000000000000000000000000000000000000aea49fcebe3a93adae67ff668c0ac87799537967000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d0000000000000000000000000000000000000000000000000000000017338945000000000000000000000000000000000000000000000000000000000000000000000000000000005edb1756c0a0f933eb87f9d69dfa1db3167547a70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000021cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed6270000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d000000000000000000000000000000000000000000000000000000000000000000000000000000002fbf76bae617ce41adb9021907f02e2bf187bb5800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb67241900000000000000000000000000000000000000000000000000000000000000000000000000000000801f3729fbb5859d94b867f813a22d85487bca2d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017041ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000168001000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d00100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000657c4cc80000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000001460000000000000000000000000000000000000000000000000000000000000148000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000011c4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "governanceOperation": { + "calls": [ + { + "target": "0x9a6de0f62aa270a8bcb1e2610078650d539b1ef9", + "value": 0, + "data": "0xa9f6d9410000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000075de2e1abb12bc54a5ab04b2761afc083be54dc500000000000000000000000000000000000000000000000000000000000013e00000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000007c000000000000000000000000000000000000000000000000000000000000009200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c2000000000000000000000000000000000000000000000000000000000000010e000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d00000000000000000000000000000000000000000000000000000000173389450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000022cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed62700000000000000000000000000000000000000000000000000000000a7cd63b70000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb6724190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d3400000000000000000000000000000000000000000000000000000000000000000000000000000000aea49fcebe3a93adae67ff668c0ac87799537967000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d0000000000000000000000000000000000000000000000000000000017338945000000000000000000000000000000000000000000000000000000000000000000000000000000005edb1756c0a0f933eb87f9d69dfa1db3167547a70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000021cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed6270000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d000000000000000000000000000000000000000000000000000000000000000000000000000000002fbf76bae617ce41adb9021907f02e2bf187bb5800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb67241900000000000000000000000000000000000000000000000000000000000000000000000000000000801f3729fbb5859d94b867f813a22d85487bca2d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017041ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000168001000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d00100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000657c4cc80000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000001460000000000000000000000000000000000000000000000000000000000000148000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000011c4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + ], + "predecessor": "0x0000000000000000000000000000000000000000000000000000000000000000", + "salt": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "transparentUpgrade": { + "facetCuts": [ + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x0e18b681", + "0xe58bb639", + "0xa9f6d941", + "0x27ae4c16", + "0x4dd18bf5", + "0xf235757f", + "0x1cc5d103", + "0xbe6f11cf", + "0x4623c91d", + "0x17338945" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0xcdffacc6", + "0x52ef6b2c", + "0xadfca15e", + "0x7a0ed627", + "0xa7cd63b7", + "0x79823c9a", + "0x4fc07d75", + "0xd86970d8", + "0xfd791f3c", + "0xe5355c75", + "0x9d1b5a81", + "0x7b30c8da", + "0x8665b150", + "0x631f4bac", + "0x0ec6b0b7", + "0x33ce93fe", + "0xdb1f0bf9", + "0xb8c2f66f", + "0xef3f0bae", + "0xfe26699e", + "0x39607382", + "0xaf6a2dcd", + "0xa1954fc5", + "0x46657fe9", + "0x18e3a941", + "0x29b98c67", + "0xbd7c5412", + "0xc3bbd2d7", + "0xe81e0ba1", + "0xfacd743b", + "0x9cd939e4", + "0x56142d7a", + "0xb22dd78e", + "0x74f4d30d" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x6c0960f9", + "0xb473318e", + "0x042901c7", + "0x263b7f8e", + "0xe4948f43", + "0xeb672419" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x701f58c5", + "0xc3d93e7c", + "0x7f61885c", + "0x97c09d34" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0xAeA49FCEbe3A93ADaE67FF668C0ac87799537967", + "selectors": [ + "0x0e18b681", + "0xe58bb639", + "0xa9f6d941", + "0x27ae4c16", + "0x4dd18bf5", + "0xf235757f", + "0x1cc5d103", + "0xbe6f11cf", + "0x4623c91d", + "0x17338945" + ], + "action": 0, + "isFreezable": false + }, + { + "facet": "0x5edb1756c0A0F933EB87f9d69DfA1db3167547a7", + "selectors": [ + "0xcdffacc6", + "0x52ef6b2c", + "0xadfca15e", + "0x7a0ed627", + "0x79823c9a", + "0x4fc07d75", + "0xd86970d8", + "0xfd791f3c", + "0xe5355c75", + "0x9d1b5a81", + "0x7b30c8da", + "0x8665b150", + "0x631f4bac", + "0x0ec6b0b7", + "0x33ce93fe", + "0xdb1f0bf9", + "0xb8c2f66f", + "0xef3f0bae", + "0xfe26699e", + "0x39607382", + "0xaf6a2dcd", + "0xa1954fc5", + "0x46657fe9", + "0x18e3a941", + "0x29b98c67", + "0xbd7c5412", + "0xc3bbd2d7", + "0xe81e0ba1", + "0xfacd743b", + "0x9cd939e4", + "0x56142d7a", + "0xb22dd78e", + "0x74f4d30d" + ], + "action": 0, + "isFreezable": false + }, + { + "facet": "0x2FbF76bAE617cE41AdB9021907F02e2bF187BB58", + "selectors": [ + "0x6c0960f9", + "0xb473318e", + "0x042901c7", + "0x263b7f8e", + "0xe4948f43", + "0xeb672419" + ], + "action": 0, + "isFreezable": true + }, + { + "facet": "0x801F3729fBB5859d94b867f813a22D85487BCa2d", + "selectors": [ + "0x701f58c5", + "0xc3d93e7c", + "0x7f61885c", + "0x97c09d34" + ], + "action": 0, + "isFreezable": true + } + ], + "initAddress": "0x75dE2E1ABB12Bc54A5aB04b2761AFc083Be54dC5", + "initCalldata": "0x1ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000168001000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d00100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000657c4cc80000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000001460000000000000000000000000000000000000000000000000000000000000148000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000011c4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } +} \ No newline at end of file diff --git a/etc/upgrades/1702392522-allowlist-removal/testnet2/facetCuts.json b/etc/upgrades/1702392522-allowlist-removal/testnet2/facetCuts.json new file mode 100644 index 000000000000..0a0eb824ab2a --- /dev/null +++ b/etc/upgrades/1702392522-allowlist-removal/testnet2/facetCuts.json @@ -0,0 +1,165 @@ +[ + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x0e18b681", + "0xe58bb639", + "0xa9f6d941", + "0x27ae4c16", + "0x4dd18bf5", + "0xf235757f", + "0x1cc5d103", + "0xbe6f11cf", + "0x4623c91d", + "0x17338945" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0xcdffacc6", + "0x52ef6b2c", + "0xadfca15e", + "0x7a0ed627", + "0xa7cd63b7", + "0x79823c9a", + "0x4fc07d75", + "0xd86970d8", + "0xfd791f3c", + "0xe5355c75", + "0x9d1b5a81", + "0x7b30c8da", + "0x8665b150", + "0x631f4bac", + "0x0ec6b0b7", + "0x33ce93fe", + "0xdb1f0bf9", + "0xb8c2f66f", + "0xef3f0bae", + "0xfe26699e", + "0x39607382", + "0xaf6a2dcd", + "0xa1954fc5", + "0x46657fe9", + "0x18e3a941", + "0x29b98c67", + "0xbd7c5412", + "0xc3bbd2d7", + "0xe81e0ba1", + "0xfacd743b", + "0x9cd939e4", + "0x56142d7a", + "0xb22dd78e", + "0x74f4d30d" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x6c0960f9", + "0xb473318e", + "0x042901c7", + "0x263b7f8e", + "0xe4948f43", + "0xeb672419" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x701f58c5", + "0xc3d93e7c", + "0x7f61885c", + "0x97c09d34" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0xAeA49FCEbe3A93ADaE67FF668C0ac87799537967", + "selectors": [ + "0x0e18b681", + "0xe58bb639", + "0xa9f6d941", + "0x27ae4c16", + "0x4dd18bf5", + "0xf235757f", + "0x1cc5d103", + "0xbe6f11cf", + "0x4623c91d", + "0x17338945" + ], + "action": 0, + "isFreezable": false + }, + { + "facet": "0x5edb1756c0A0F933EB87f9d69DfA1db3167547a7", + "selectors": [ + "0xcdffacc6", + "0x52ef6b2c", + "0xadfca15e", + "0x7a0ed627", + "0x79823c9a", + "0x4fc07d75", + "0xd86970d8", + "0xfd791f3c", + "0xe5355c75", + "0x9d1b5a81", + "0x7b30c8da", + "0x8665b150", + "0x631f4bac", + "0x0ec6b0b7", + "0x33ce93fe", + "0xdb1f0bf9", + "0xb8c2f66f", + "0xef3f0bae", + "0xfe26699e", + "0x39607382", + "0xaf6a2dcd", + "0xa1954fc5", + "0x46657fe9", + "0x18e3a941", + "0x29b98c67", + "0xbd7c5412", + "0xc3bbd2d7", + "0xe81e0ba1", + "0xfacd743b", + "0x9cd939e4", + "0x56142d7a", + "0xb22dd78e", + "0x74f4d30d" + ], + "action": 0, + "isFreezable": false + }, + { + "facet": "0x2FbF76bAE617cE41AdB9021907F02e2bF187BB58", + "selectors": [ + "0x6c0960f9", + "0xb473318e", + "0x042901c7", + "0x263b7f8e", + "0xe4948f43", + "0xeb672419" + ], + "action": 0, + "isFreezable": true + }, + { + "facet": "0x801F3729fBB5859d94b867f813a22D85487BCa2d", + "selectors": [ + "0x701f58c5", + "0xc3d93e7c", + "0x7f61885c", + "0x97c09d34" + ], + "action": 0, + "isFreezable": true + } +] \ No newline at end of file diff --git a/etc/upgrades/1702392522-allowlist-removal/testnet2/facets.json b/etc/upgrades/1702392522-allowlist-removal/testnet2/facets.json new file mode 100644 index 000000000000..32b71aa87dc6 --- /dev/null +++ b/etc/upgrades/1702392522-allowlist-removal/testnet2/facets.json @@ -0,0 +1,18 @@ +{ + "ExecutorFacet": { + "address": "0x801F3729fBB5859d94b867f813a22D85487BCa2d", + "txHash": "0x4d006c6fbfa654f7f7128f17bd906d3b8c26b9f9e7e96b745ef0ace70e79e5fb" + }, + "AdminFacet": { + "address": "0xAeA49FCEbe3A93ADaE67FF668C0ac87799537967", + "txHash": "0x4c672bc51d6350edd0870e523402049bc586c7d5979392caaf1bee263153483f" + }, + "GettersFacet": { + "address": "0x5edb1756c0A0F933EB87f9d69DfA1db3167547a7", + "txHash": "0xfdb47829a2fc0c6c6019558f9c50d68d8764d14a02c44a1135ae04ae538cf6ef" + }, + "MailboxFacet": { + "address": "0x2FbF76bAE617cE41AdB9021907F02e2bF187BB58", + "txHash": "0xcc4ceaeef395946e91aa282920b20a3e3df53ef2ecf6833649473e35ba487fde" + } +} \ No newline at end of file diff --git a/etc/upgrades/1702392522-allowlist-removal/testnet2/l2Upgrade.json b/etc/upgrades/1702392522-allowlist-removal/testnet2/l2Upgrade.json new file mode 100644 index 000000000000..a52f61deaf7d --- /dev/null +++ b/etc/upgrades/1702392522-allowlist-removal/testnet2/l2Upgrade.json @@ -0,0 +1,323 @@ +{ + "systemContracts": [ + { + "name": "EmptyContract", + "bytecodeHashes": [ + "0x01000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d06" + ], + "address": "0x0000000000000000000000000000000000000000" + }, + { + "name": "Ecrecover", + "bytecodeHashes": [ + "0x0100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d12" + ], + "address": "0x0000000000000000000000000000000000000001" + }, + { + "name": "SHA256", + "bytecodeHashes": [ + "0x010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b0131" + ], + "address": "0x0000000000000000000000000000000000000002" + }, + { + "name": "EcAdd", + "bytecodeHashes": [ + "0x0100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef" + ], + "address": "0x0000000000000000000000000000000000000006" + }, + { + "name": "EcMul", + "bytecodeHashes": [ + "0x010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb2" + ], + "address": "0x0000000000000000000000000000000000000007" + }, + { + "name": "EmptyContract", + "bytecodeHashes": [ + "0x01000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d06" + ], + "address": "0x0000000000000000000000000000000000008001" + }, + { + "name": "AccountCodeStorage", + "bytecodeHashes": [ + "0x01000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e0655" + ], + "address": "0x0000000000000000000000000000000000008002" + }, + { + "name": "NonceHolder", + "bytecodeHashes": [ + "0x010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e223" + ], + "address": "0x0000000000000000000000000000000000008003" + }, + { + "name": "KnownCodesStorage", + "bytecodeHashes": [ + "0x0100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a2" + ], + "address": "0x0000000000000000000000000000000000008004" + }, + { + "name": "ImmutableSimulator", + "bytecodeHashes": [ + "0x0100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf84" + ], + "address": "0x0000000000000000000000000000000000008005" + }, + { + "name": "ContractDeployer", + "bytecodeHashes": [ + "0x0100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a" + ], + "address": "0x0000000000000000000000000000000000008006" + }, + { + "name": "L1Messenger", + "bytecodeHashes": [ + "0x0100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b" + ], + "address": "0x0000000000000000000000000000000000008008" + }, + { + "name": "MsgValueSimulator", + "bytecodeHashes": [ + "0x01000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f00" + ], + "address": "0x0000000000000000000000000000000000008009" + }, + { + "name": "L2EthToken", + "bytecodeHashes": [ + "0x01000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0" + ], + "address": "0x000000000000000000000000000000000000800a" + }, + { + "name": "SystemContext", + "bytecodeHashes": [ + "0x01000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da" + ], + "address": "0x000000000000000000000000000000000000800b" + }, + { + "name": "BootloaderUtilities", + "bytecodeHashes": [ + "0x010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe" + ], + "address": "0x000000000000000000000000000000000000800c" + }, + { + "name": "EventWriter", + "bytecodeHashes": [ + "0x0100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6" + ], + "address": "0x000000000000000000000000000000000000800d" + }, + { + "name": "Compressor", + "bytecodeHashes": [ + "0x010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0" + ], + "address": "0x000000000000000000000000000000000000800e" + }, + { + "name": "ComplexUpgrader", + "bytecodeHashes": [ + "0x01000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050" + ], + "address": "0x000000000000000000000000000000000000800f" + }, + { + "name": "Keccak256", + "bytecodeHashes": [ + "0x01000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f1300" + ], + "address": "0x0000000000000000000000000000000000008010" + } + ], + "defaultAA": { + "name": "DefaultAccount", + "bytecodeHashes": [ + "0x0100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8" + ] + }, + "bootloader": { + "name": "Bootloader", + "bytecodeHashes": [ + "0x01000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d0" + ] + }, + "forcedDeployments": [ + { + "bytecodeHash": "0x01000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d06", + "newAddress": "0x0000000000000000000000000000000000000000", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d12", + "newAddress": "0x0000000000000000000000000000000000000001", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b0131", + "newAddress": "0x0000000000000000000000000000000000000002", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef", + "newAddress": "0x0000000000000000000000000000000000000006", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb2", + "newAddress": "0x0000000000000000000000000000000000000007", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d06", + "newAddress": "0x0000000000000000000000000000000000008001", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e0655", + "newAddress": "0x0000000000000000000000000000000000008002", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e223", + "newAddress": "0x0000000000000000000000000000000000008003", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a2", + "newAddress": "0x0000000000000000000000000000000000008004", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf84", + "newAddress": "0x0000000000000000000000000000000000008005", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a", + "newAddress": "0x0000000000000000000000000000000000008006", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b", + "newAddress": "0x0000000000000000000000000000000000008008", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f00", + "newAddress": "0x0000000000000000000000000000000000008009", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0", + "newAddress": "0x000000000000000000000000000000000000800a", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da", + "newAddress": "0x000000000000000000000000000000000000800b", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe", + "newAddress": "0x000000000000000000000000000000000000800c", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6", + "newAddress": "0x000000000000000000000000000000000000800d", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0", + "newAddress": "0x000000000000000000000000000000000000800e", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050", + "newAddress": "0x000000000000000000000000000000000000800f", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f1300", + "newAddress": "0x0000000000000000000000000000000000008010", + "value": 0, + "input": "0x", + "callConstructor": false + } + ], + "forcedDeploymentCalldata": "0xe9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", + "calldata": "0xe9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", + "tx": { + "txType": 254, + "from": "0x0000000000000000000000000000000000008007", + "to": "0x0000000000000000000000000000000000008006", + "gasLimit": 72000000, + "gasPerPubdataByteLimit": 800, + "maxFeePerGas": 0, + "maxPriorityFeePerGas": 0, + "paymaster": 0, + "nonce": "19", + "value": 0, + "reserved": [ + 0, + 0, + 0, + 0 + ], + "data": "0xe9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", + "signature": "0x", + "factoryDeps": [], + "paymasterInput": "0x", + "reservedDynamic": "0x" + } +} \ No newline at end of file diff --git a/etc/upgrades/1702392522-allowlist-removal/testnet2/transactions.json b/etc/upgrades/1702392522-allowlist-removal/testnet2/transactions.json new file mode 100644 index 000000000000..9f5285fb949b --- /dev/null +++ b/etc/upgrades/1702392522-allowlist-removal/testnet2/transactions.json @@ -0,0 +1,230 @@ +{ + "proposeUpgradeTx": { + "l2ProtocolUpgradeTx": { + "txType": 254, + "from": "0x0000000000000000000000000000000000008007", + "to": "0x0000000000000000000000000000000000008006", + "gasLimit": 72000000, + "gasPerPubdataByteLimit": 800, + "maxFeePerGas": 0, + "maxPriorityFeePerGas": 0, + "paymaster": 0, + "nonce": "19", + "value": 0, + "reserved": [ + 0, + 0, + 0, + 0 + ], + "data": "0xe9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", + "signature": "0x", + "factoryDeps": [], + "paymasterInput": "0x", + "reservedDynamic": "0x" + }, + "bootloaderHash": "0x01000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d0", + "defaultAccountHash": "0x0100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8", + "verifier": "0x0000000000000000000000000000000000000000", + "verifierParams": { + "recursionNodeLevelVkHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "recursionLeafLevelVkHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "recursionCircuitsSetVksHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "l1ContractsUpgradeCalldata": "0x", + "postUpgradeCalldata": "0x", + "upgradeTimestamp": { + "type": "BigNumber", + "hex": "0x657c378c" + }, + "factoryDeps": [], + "newProtocolVersion": "19", + "newAllowList": "0x0000000000000000000000000000000000000000" + }, + "l1upgradeCalldata": "0x1ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000168001000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d00100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000657c378c0000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000001460000000000000000000000000000000000000000000000000000000000000148000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000011c4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "upgradeAddress": "0x75dE2E1ABB12Bc54A5aB04b2761AFc083Be54dC5", + "protocolVersion": "19", + "upgradeTimestamp": "1702639500", + "scheduleTransparentOperation": "0x2c43191700000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000001908e2bf4a88f91e4ef0dc72f02b8ea36bea2319000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000002b44a9f6d9410000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000075de2e1abb12bc54a5ab04b2761afc083be54dc500000000000000000000000000000000000000000000000000000000000013e00000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000007c000000000000000000000000000000000000000000000000000000000000009200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c2000000000000000000000000000000000000000000000000000000000000010e000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d00000000000000000000000000000000000000000000000000000000173389450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000022cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed62700000000000000000000000000000000000000000000000000000000a7cd63b70000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb6724190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d3400000000000000000000000000000000000000000000000000000000000000000000000000000000aea49fcebe3a93adae67ff668c0ac87799537967000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d0000000000000000000000000000000000000000000000000000000017338945000000000000000000000000000000000000000000000000000000000000000000000000000000005edb1756c0a0f933eb87f9d69dfa1db3167547a70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000021cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed6270000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d000000000000000000000000000000000000000000000000000000000000000000000000000000002fbf76bae617ce41adb9021907f02e2bf187bb5800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb67241900000000000000000000000000000000000000000000000000000000000000000000000000000000801f3729fbb5859d94b867f813a22d85487bca2d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017041ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000168001000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d00100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000657c378c0000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000001460000000000000000000000000000000000000000000000000000000000000148000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000011c4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "executeOperation": "0x74da756b0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000001908e2bf4a88f91e4ef0dc72f02b8ea36bea2319000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000002b44a9f6d9410000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000075de2e1abb12bc54a5ab04b2761afc083be54dc500000000000000000000000000000000000000000000000000000000000013e00000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000007c000000000000000000000000000000000000000000000000000000000000009200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c2000000000000000000000000000000000000000000000000000000000000010e000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d00000000000000000000000000000000000000000000000000000000173389450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000022cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed62700000000000000000000000000000000000000000000000000000000a7cd63b70000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb6724190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d3400000000000000000000000000000000000000000000000000000000000000000000000000000000aea49fcebe3a93adae67ff668c0ac87799537967000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d0000000000000000000000000000000000000000000000000000000017338945000000000000000000000000000000000000000000000000000000000000000000000000000000005edb1756c0a0f933eb87f9d69dfa1db3167547a70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000021cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed6270000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d000000000000000000000000000000000000000000000000000000000000000000000000000000002fbf76bae617ce41adb9021907f02e2bf187bb5800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb67241900000000000000000000000000000000000000000000000000000000000000000000000000000000801f3729fbb5859d94b867f813a22d85487bca2d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017041ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000168001000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d00100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000657c378c0000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000001460000000000000000000000000000000000000000000000000000000000000148000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000011c4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "governanceOperation": { + "calls": [ + { + "target": "0x1908e2BF4a88F91E4eF0DC72f02b8Ea36BEa2319", + "value": 0, + "data": "0xa9f6d9410000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000075de2e1abb12bc54a5ab04b2761afc083be54dc500000000000000000000000000000000000000000000000000000000000013e00000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000007c000000000000000000000000000000000000000000000000000000000000009200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c2000000000000000000000000000000000000000000000000000000000000010e000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d00000000000000000000000000000000000000000000000000000000173389450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000022cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed62700000000000000000000000000000000000000000000000000000000a7cd63b70000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb6724190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d3400000000000000000000000000000000000000000000000000000000000000000000000000000000aea49fcebe3a93adae67ff668c0ac87799537967000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d0000000000000000000000000000000000000000000000000000000017338945000000000000000000000000000000000000000000000000000000000000000000000000000000005edb1756c0a0f933eb87f9d69dfa1db3167547a70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000021cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed6270000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d000000000000000000000000000000000000000000000000000000000000000000000000000000002fbf76bae617ce41adb9021907f02e2bf187bb5800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb67241900000000000000000000000000000000000000000000000000000000000000000000000000000000801f3729fbb5859d94b867f813a22d85487bca2d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017041ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000168001000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d00100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000657c378c0000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000001460000000000000000000000000000000000000000000000000000000000000148000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000011c4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + ], + "predecessor": "0x0000000000000000000000000000000000000000000000000000000000000000", + "salt": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "transparentUpgrade": { + "facetCuts": [ + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x0e18b681", + "0xe58bb639", + "0xa9f6d941", + "0x27ae4c16", + "0x4dd18bf5", + "0xf235757f", + "0x1cc5d103", + "0xbe6f11cf", + "0x4623c91d", + "0x17338945" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0xcdffacc6", + "0x52ef6b2c", + "0xadfca15e", + "0x7a0ed627", + "0xa7cd63b7", + "0x79823c9a", + "0x4fc07d75", + "0xd86970d8", + "0xfd791f3c", + "0xe5355c75", + "0x9d1b5a81", + "0x7b30c8da", + "0x8665b150", + "0x631f4bac", + "0x0ec6b0b7", + "0x33ce93fe", + "0xdb1f0bf9", + "0xb8c2f66f", + "0xef3f0bae", + "0xfe26699e", + "0x39607382", + "0xaf6a2dcd", + "0xa1954fc5", + "0x46657fe9", + "0x18e3a941", + "0x29b98c67", + "0xbd7c5412", + "0xc3bbd2d7", + "0xe81e0ba1", + "0xfacd743b", + "0x9cd939e4", + "0x56142d7a", + "0xb22dd78e", + "0x74f4d30d" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x6c0960f9", + "0xb473318e", + "0x042901c7", + "0x263b7f8e", + "0xe4948f43", + "0xeb672419" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x701f58c5", + "0xc3d93e7c", + "0x7f61885c", + "0x97c09d34" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0xAeA49FCEbe3A93ADaE67FF668C0ac87799537967", + "selectors": [ + "0x0e18b681", + "0xe58bb639", + "0xa9f6d941", + "0x27ae4c16", + "0x4dd18bf5", + "0xf235757f", + "0x1cc5d103", + "0xbe6f11cf", + "0x4623c91d", + "0x17338945" + ], + "action": 0, + "isFreezable": false + }, + { + "facet": "0x5edb1756c0A0F933EB87f9d69DfA1db3167547a7", + "selectors": [ + "0xcdffacc6", + "0x52ef6b2c", + "0xadfca15e", + "0x7a0ed627", + "0x79823c9a", + "0x4fc07d75", + "0xd86970d8", + "0xfd791f3c", + "0xe5355c75", + "0x9d1b5a81", + "0x7b30c8da", + "0x8665b150", + "0x631f4bac", + "0x0ec6b0b7", + "0x33ce93fe", + "0xdb1f0bf9", + "0xb8c2f66f", + "0xef3f0bae", + "0xfe26699e", + "0x39607382", + "0xaf6a2dcd", + "0xa1954fc5", + "0x46657fe9", + "0x18e3a941", + "0x29b98c67", + "0xbd7c5412", + "0xc3bbd2d7", + "0xe81e0ba1", + "0xfacd743b", + "0x9cd939e4", + "0x56142d7a", + "0xb22dd78e", + "0x74f4d30d" + ], + "action": 0, + "isFreezable": false + }, + { + "facet": "0x2FbF76bAE617cE41AdB9021907F02e2bF187BB58", + "selectors": [ + "0x6c0960f9", + "0xb473318e", + "0x042901c7", + "0x263b7f8e", + "0xe4948f43", + "0xeb672419" + ], + "action": 0, + "isFreezable": true + }, + { + "facet": "0x801F3729fBB5859d94b867f813a22D85487BCa2d", + "selectors": [ + "0x701f58c5", + "0xc3d93e7c", + "0x7f61885c", + "0x97c09d34" + ], + "action": 0, + "isFreezable": true + } + ], + "initAddress": "0x75dE2E1ABB12Bc54A5aB04b2761AFc083Be54dC5", + "initCalldata": "0x1ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000168001000831ba7021800f5d9103772fcc7463ed7e764a2a3624cacca6b3826172d00100055bf7f1bc4237c2be24252fb6737cc235194139e544933c1dbf25c24ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000657c378c0000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000001460000000000000000000000000000000000000000000000000000000000000148000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000011c4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007c0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f40000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010c001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001147fcb33fbc266df8067be8b51d68ad9362a6204de5a6b2279c613d1200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000179d3c90b59acbc8fbda5ba2389cc80dfa840840e5183d44ea3c9b013100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100008f337dc5cc92411071569be5cd4bfd755adf20021c8a0e316c4834c4ef00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000d941fe2d54aa725915db7d63795e02ced38fa2709d736631e30792ccb200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000007f845e3f2ab16646632231e4fee11627449b45067fa0e7c76ba114d0600000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000075c32c6af70ed4fd798a3fca41f2984e7440e2d2937858d700637e065500000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e52e563c15152eb655ea2d1b633c1409b61afa74065d05e93107a7e22300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d4be0212415ae3920fbd92c2547f5419ac8da07bb7e29488472a434a200000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003d467f114197fad7d1e6bb58867710524d5c8d200558a213f5429cbf8400000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100055578bdf1a737843d2278c672bfa9be2c17183a7e9b00052845aa5d240a00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028debc3f96ddf2c6630fb28ac7b4ae198ad453fdc08df2e81e6d2a4aa0b00000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063d13c3fdbd042669053befb649f89c1dd0de3d7a0542486e89b6a7f0000000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000101dbb3209311751d4f335ac6909943e19a1c3d26cdd27db01adb509db0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181e472c23b9b5e9b971dec1971183ab06fb5932ea469ee207cc4a668da000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c95cdffb79ed99ad5fb842d3bab4084e2d49028df8ee3f7c2d543f7ebe000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100001752ddb6f7d76adaf32594816c0bda5b9c17d6fd86e90a06acba2e4cb6000000000000000000000000000000000000000000000000000000000000800d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001670943abd41e5b14499ae7bd0b99406a7d3cc406d9251c138d87f573c0000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000055de10df9214a2628ab870a3bc2154a6e7f8c0479a7bad15c875aec050000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000021e3954694ddb9479f31cabe797467b4ea3b92ab64fd81e9b5e53f130000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } +} \ No newline at end of file diff --git a/etc/upgrades/1705556759-fee-model-and-1.4.1/common.json b/etc/upgrades/1705556759-fee-model-and-1.4.1/common.json new file mode 100644 index 000000000000..a8b657906bea --- /dev/null +++ b/etc/upgrades/1705556759-fee-model-and-1.4.1/common.json @@ -0,0 +1,5 @@ +{ + "name": "fee-model-and-1.4.1", + "creationTimestamp": 1705556759, + "protocolVersion": "20" +} \ No newline at end of file diff --git a/etc/upgrades/1705556759-fee-model-and-1.4.1/stage2/crypto.json b/etc/upgrades/1705556759-fee-model-and-1.4.1/stage2/crypto.json new file mode 100644 index 000000000000..83cbf12094e6 --- /dev/null +++ b/etc/upgrades/1705556759-fee-model-and-1.4.1/stage2/crypto.json @@ -0,0 +1,11 @@ +{ + "verifier": { + "address": "0x3390051435eCB25a9610A1cF17d1BA0a228A0560", + "txHash": "0x2c3b8915e8ebc617cc13e462df334f4197d48b19b302538a519f55acbda285cb" + }, + "keys": { + "recursionNodeLevelVkHash": "0x5a3ef282b21e12fe1f4438e5bb158fc5060b160559c5158c6389d62d9fe3d080", + "recursionLeafLevelVkHash": "0x062362cb3eaf1f631406cbe19bf2a2c5d0d9ea69d069309a6003addae9f387be", + "recursionCircuitsSetVksHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } +} \ No newline at end of file diff --git a/etc/upgrades/1705556759-fee-model-and-1.4.1/stage2/facetCuts.json b/etc/upgrades/1705556759-fee-model-and-1.4.1/stage2/facetCuts.json new file mode 100644 index 000000000000..67a756036524 --- /dev/null +++ b/etc/upgrades/1705556759-fee-model-and-1.4.1/stage2/facetCuts.json @@ -0,0 +1,165 @@ +[ + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x0e18b681", + "0xe58bb639", + "0xa9f6d941", + "0x27ae4c16", + "0x4dd18bf5", + "0xf235757f", + "0x1cc5d103", + "0xbe6f11cf", + "0x4623c91d", + "0x17338945" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0xcdffacc6", + "0x52ef6b2c", + "0xadfca15e", + "0x7a0ed627", + "0x79823c9a", + "0x4fc07d75", + "0xd86970d8", + "0xfd791f3c", + "0xe5355c75", + "0x9d1b5a81", + "0x7b30c8da", + "0x8665b150", + "0x631f4bac", + "0x0ec6b0b7", + "0x33ce93fe", + "0xdb1f0bf9", + "0xb8c2f66f", + "0xef3f0bae", + "0xfe26699e", + "0x39607382", + "0xaf6a2dcd", + "0xa1954fc5", + "0x46657fe9", + "0x18e3a941", + "0x29b98c67", + "0xbd7c5412", + "0xc3bbd2d7", + "0xe81e0ba1", + "0xfacd743b", + "0x9cd939e4", + "0x56142d7a", + "0xb22dd78e", + "0x74f4d30d" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x6c0960f9", + "0xb473318e", + "0x042901c7", + "0x263b7f8e", + "0xe4948f43", + "0xeb672419" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x701f58c5", + "0xc3d93e7c", + "0x7f61885c", + "0x97c09d34" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0xE6426c725cB507168369c10284390E59d91eC821", + "selectors": [ + "0x0e18b681", + "0xe58bb639", + "0x64bf8d66", + "0xa9f6d941", + "0x27ae4c16", + "0x4dd18bf5", + "0xf235757f", + "0x1cc5d103", + "0xbe6f11cf", + "0x4623c91d", + "0x17338945" + ], + "action": 0, + "isFreezable": false + }, + { + "facet": "0xc4a5e861df9DD9495f8Dba1c260913d1A9b8Ec2B", + "selectors": [ + "0xcdffacc6", + "0x52ef6b2c", + "0xadfca15e", + "0x7a0ed627", + "0x79823c9a", + "0x4fc07d75", + "0xd86970d8", + "0xfd791f3c", + "0xe5355c75", + "0x9d1b5a81", + "0x7b30c8da", + "0x8665b150", + "0x631f4bac", + "0x0ec6b0b7", + "0x33ce93fe", + "0xdb1f0bf9", + "0xb8c2f66f", + "0xef3f0bae", + "0xfe26699e", + "0x39607382", + "0xaf6a2dcd", + "0xa1954fc5", + "0x46657fe9", + "0x18e3a941", + "0x29b98c67", + "0xbd7c5412", + "0xc3bbd2d7", + "0xe81e0ba1", + "0xfacd743b", + "0x9cd939e4", + "0x56142d7a", + "0xb22dd78e", + "0x74f4d30d" + ], + "action": 0, + "isFreezable": false + }, + { + "facet": "0x0f58Fd6c9Ed966e09C1dFFBc8E6FF600ec65f6eB", + "selectors": [ + "0x6c0960f9", + "0xb473318e", + "0x042901c7", + "0x263b7f8e", + "0xe4948f43", + "0xeb672419" + ], + "action": 0, + "isFreezable": true + }, + { + "facet": "0x5b86821c1B4B55deF404c9551EC2d2Cc0aE70f5C", + "selectors": [ + "0x701f58c5", + "0xc3d93e7c", + "0x7f61885c", + "0x97c09d34" + ], + "action": 0, + "isFreezable": true + } +] \ No newline at end of file diff --git a/etc/upgrades/1705556759-fee-model-and-1.4.1/stage2/facets.json b/etc/upgrades/1705556759-fee-model-and-1.4.1/stage2/facets.json new file mode 100644 index 000000000000..b9f6acbb6fae --- /dev/null +++ b/etc/upgrades/1705556759-fee-model-and-1.4.1/stage2/facets.json @@ -0,0 +1,18 @@ +{ + "ExecutorFacet": { + "address": "0x5b86821c1B4B55deF404c9551EC2d2Cc0aE70f5C", + "txHash": "0x27598585a0471d1d95358bb93ade96fc4729d4531b08daf47f6d09e1fa3a82a2" + }, + "AdminFacet": { + "address": "0xE6426c725cB507168369c10284390E59d91eC821", + "txHash": "0x016a39f72fdd7245ebfbc07581823756d11b0638c27f32b1bc07794928b0abbb" + }, + "GettersFacet": { + "address": "0xc4a5e861df9DD9495f8Dba1c260913d1A9b8Ec2B", + "txHash": "0xbfa6c2995d7cc5c4502a3966f6c6c133dd5b45b15bd117acf2ca8413639da671" + }, + "MailboxFacet": { + "address": "0x0f58Fd6c9Ed966e09C1dFFBc8E6FF600ec65f6eB", + "txHash": "0xce16a8f2d210ee4b57159ca3f2a760af0c249234193fcf983a5a3050b29c8a5d" + } +} \ No newline at end of file diff --git a/etc/upgrades/1705556759-fee-model-and-1.4.1/stage2/l2Upgrade.json b/etc/upgrades/1705556759-fee-model-and-1.4.1/stage2/l2Upgrade.json new file mode 100644 index 000000000000..918c93b00049 --- /dev/null +++ b/etc/upgrades/1705556759-fee-model-and-1.4.1/stage2/l2Upgrade.json @@ -0,0 +1,225 @@ +{ + "systemContracts": [ + { + "name": "AccountCodeStorage", + "bytecodeHashes": [ + "0x01000075bc9de2129f5d58efa04515bbf24610645546eab19192d7f94a23f83e" + ], + "address": "0x0000000000000000000000000000000000008002" + }, + { + "name": "NonceHolder", + "bytecodeHashes": [ + "0x010000e5eef000fb93f3b7f746149d0f467fe99e0f628aa76520b18321eeb7b3" + ], + "address": "0x0000000000000000000000000000000000008003" + }, + { + "name": "KnownCodesStorage", + "bytecodeHashes": [ + "0x0100007d88348c8092dd260d3ba1b90da3d693c5d416b7078b2faca348e2f3a8" + ], + "address": "0x0000000000000000000000000000000000008004" + }, + { + "name": "ImmutableSimulator", + "bytecodeHashes": [ + "0x0100003ddb0142c77e7e36c37910cd90b07e48bb952168e66c79519953d32d57" + ], + "address": "0x0000000000000000000000000000000000008005" + }, + { + "name": "ContractDeployer", + "bytecodeHashes": [ + "0x01000555b2471aa863b7da5360cc0d2459a8aa5ad9feb6ad8ea5666aee0b5f4c" + ], + "address": "0x0000000000000000000000000000000000008006" + }, + { + "name": "L1Messenger", + "bytecodeHashes": [ + "0x0100028d5519113834685985178f33d36dd855e0b0835e2dad3892ddc3244d80" + ], + "address": "0x0000000000000000000000000000000000008008" + }, + { + "name": "MsgValueSimulator", + "bytecodeHashes": [ + "0x01000063cb83b923ab1e67bb7944c6493286ba7c1c5614c0cb17155c5eef82d9" + ], + "address": "0x0000000000000000000000000000000000008009" + }, + { + "name": "L2EthToken", + "bytecodeHashes": [ + "0x010001014336cee5c792682bf2c2079807e643c491d879c07de9dea482a78e39" + ], + "address": "0x000000000000000000000000000000000000800a" + }, + { + "name": "SystemContext", + "bytecodeHashes": [ + "0x01000181b1c963c230c8521d78a0a650cf7c1879cc6b38e9315035c5596cd914" + ], + "address": "0x000000000000000000000000000000000000800b" + }, + { + "name": "BootloaderUtilities", + "bytecodeHashes": [ + "0x010007c96884dfd5de1a2e02616564c057e67c423d31c589df25bf25b08dd3d6" + ], + "address": "0x000000000000000000000000000000000000800c" + }, + { + "name": "Compressor", + "bytecodeHashes": [ + "0x01000167b75441cbdf3edc039678e2e57bb28d87ca3b76c88ba153be0e65f366" + ], + "address": "0x000000000000000000000000000000000000800e" + }, + { + "name": "ComplexUpgrader", + "bytecodeHashes": [ + "0x010000553156325702c61297c4ebe6171f7d64845d548311e0fe88792cd86841" + ], + "address": "0x000000000000000000000000000000000000800f" + }, + { + "name": "Keccak256", + "bytecodeHashes": [ + "0x0100000fb004b644efe76e9ef3ba89dfa3eaac946e3fa19f8a046ed27465eeef" + ], + "address": "0x0000000000000000000000000000000000008010" + } + ], + "defaultAA": { + "name": "DefaultAccount", + "bytecodeHashes": [ + "0x0100055b7a8be90522251be8be1a186464d056462973502ac8a0437c85e4d2a9" + ] + }, + "bootloader": { + "name": "Bootloader", + "bytecodeHashes": [ + "0x010007ed0e328b940e241f7666a6303b7ffd4e3fd7e8c154d6e7556befe6cd6d" + ] + }, + "forcedDeployments": [ + { + "bytecodeHash": "0x01000075bc9de2129f5d58efa04515bbf24610645546eab19192d7f94a23f83e", + "newAddress": "0x0000000000000000000000000000000000008002", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010000e5eef000fb93f3b7f746149d0f467fe99e0f628aa76520b18321eeb7b3", + "newAddress": "0x0000000000000000000000000000000000008003", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100007d88348c8092dd260d3ba1b90da3d693c5d416b7078b2faca348e2f3a8", + "newAddress": "0x0000000000000000000000000000000000008004", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100003ddb0142c77e7e36c37910cd90b07e48bb952168e66c79519953d32d57", + "newAddress": "0x0000000000000000000000000000000000008005", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000555b2471aa863b7da5360cc0d2459a8aa5ad9feb6ad8ea5666aee0b5f4c", + "newAddress": "0x0000000000000000000000000000000000008006", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100028d5519113834685985178f33d36dd855e0b0835e2dad3892ddc3244d80", + "newAddress": "0x0000000000000000000000000000000000008008", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000063cb83b923ab1e67bb7944c6493286ba7c1c5614c0cb17155c5eef82d9", + "newAddress": "0x0000000000000000000000000000000000008009", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010001014336cee5c792682bf2c2079807e643c491d879c07de9dea482a78e39", + "newAddress": "0x000000000000000000000000000000000000800a", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000181b1c963c230c8521d78a0a650cf7c1879cc6b38e9315035c5596cd914", + "newAddress": "0x000000000000000000000000000000000000800b", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010007c96884dfd5de1a2e02616564c057e67c423d31c589df25bf25b08dd3d6", + "newAddress": "0x000000000000000000000000000000000000800c", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x01000167b75441cbdf3edc039678e2e57bb28d87ca3b76c88ba153be0e65f366", + "newAddress": "0x000000000000000000000000000000000000800e", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x010000553156325702c61297c4ebe6171f7d64845d548311e0fe88792cd86841", + "newAddress": "0x000000000000000000000000000000000000800f", + "value": 0, + "input": "0x", + "callConstructor": false + }, + { + "bytecodeHash": "0x0100000fb004b644efe76e9ef3ba89dfa3eaac946e3fa19f8a046ed27465eeef", + "newAddress": "0x0000000000000000000000000000000000008010", + "value": 0, + "input": "0x", + "callConstructor": false + } + ], + "forcedDeploymentCalldata": "0xe9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000062000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000860000000000000000000000000000000000000000000000000000000000000092000000000000000000000000000000000000000000000000000000000000009e00000000000000000000000000000000000000000000000000000000000000aa001000075bc9de2129f5d58efa04515bbf24610645546eab19192d7f94a23f83e00000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e5eef000fb93f3b7f746149d0f467fe99e0f628aa76520b18321eeb7b300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d88348c8092dd260d3ba1b90da3d693c5d416b7078b2faca348e2f3a800000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003ddb0142c77e7e36c37910cd90b07e48bb952168e66c79519953d32d5700000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000555b2471aa863b7da5360cc0d2459a8aa5ad9feb6ad8ea5666aee0b5f4c00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028d5519113834685985178f33d36dd855e0b0835e2dad3892ddc3244d8000000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063cb83b923ab1e67bb7944c6493286ba7c1c5614c0cb17155c5eef82d900000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001014336cee5c792682bf2c2079807e643c491d879c07de9dea482a78e39000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181b1c963c230c8521d78a0a650cf7c1879cc6b38e9315035c5596cd914000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c96884dfd5de1a2e02616564c057e67c423d31c589df25bf25b08dd3d6000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000167b75441cbdf3edc039678e2e57bb28d87ca3b76c88ba153be0e65f366000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000553156325702c61297c4ebe6171f7d64845d548311e0fe88792cd86841000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100000fb004b644efe76e9ef3ba89dfa3eaac946e3fa19f8a046ed27465eeef00000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", + "calldata": "0xe9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000062000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000860000000000000000000000000000000000000000000000000000000000000092000000000000000000000000000000000000000000000000000000000000009e00000000000000000000000000000000000000000000000000000000000000aa001000075bc9de2129f5d58efa04515bbf24610645546eab19192d7f94a23f83e00000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e5eef000fb93f3b7f746149d0f467fe99e0f628aa76520b18321eeb7b300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d88348c8092dd260d3ba1b90da3d693c5d416b7078b2faca348e2f3a800000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003ddb0142c77e7e36c37910cd90b07e48bb952168e66c79519953d32d5700000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000555b2471aa863b7da5360cc0d2459a8aa5ad9feb6ad8ea5666aee0b5f4c00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028d5519113834685985178f33d36dd855e0b0835e2dad3892ddc3244d8000000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063cb83b923ab1e67bb7944c6493286ba7c1c5614c0cb17155c5eef82d900000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001014336cee5c792682bf2c2079807e643c491d879c07de9dea482a78e39000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181b1c963c230c8521d78a0a650cf7c1879cc6b38e9315035c5596cd914000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c96884dfd5de1a2e02616564c057e67c423d31c589df25bf25b08dd3d6000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000167b75441cbdf3edc039678e2e57bb28d87ca3b76c88ba153be0e65f366000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000553156325702c61297c4ebe6171f7d64845d548311e0fe88792cd86841000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100000fb004b644efe76e9ef3ba89dfa3eaac946e3fa19f8a046ed27465eeef00000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", + "tx": { + "txType": 254, + "from": "0x0000000000000000000000000000000000008007", + "to": "0x0000000000000000000000000000000000008006", + "gasLimit": 72000000, + "gasPerPubdataByteLimit": 800, + "maxFeePerGas": 0, + "maxPriorityFeePerGas": 0, + "paymaster": 0, + "nonce": "20", + "value": 0, + "reserved": [ + 0, + 0, + 0, + 0 + ], + "data": "0xe9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000062000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000860000000000000000000000000000000000000000000000000000000000000092000000000000000000000000000000000000000000000000000000000000009e00000000000000000000000000000000000000000000000000000000000000aa001000075bc9de2129f5d58efa04515bbf24610645546eab19192d7f94a23f83e00000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e5eef000fb93f3b7f746149d0f467fe99e0f628aa76520b18321eeb7b300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d88348c8092dd260d3ba1b90da3d693c5d416b7078b2faca348e2f3a800000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003ddb0142c77e7e36c37910cd90b07e48bb952168e66c79519953d32d5700000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000555b2471aa863b7da5360cc0d2459a8aa5ad9feb6ad8ea5666aee0b5f4c00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028d5519113834685985178f33d36dd855e0b0835e2dad3892ddc3244d8000000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063cb83b923ab1e67bb7944c6493286ba7c1c5614c0cb17155c5eef82d900000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001014336cee5c792682bf2c2079807e643c491d879c07de9dea482a78e39000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181b1c963c230c8521d78a0a650cf7c1879cc6b38e9315035c5596cd914000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c96884dfd5de1a2e02616564c057e67c423d31c589df25bf25b08dd3d6000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000167b75441cbdf3edc039678e2e57bb28d87ca3b76c88ba153be0e65f366000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000553156325702c61297c4ebe6171f7d64845d548311e0fe88792cd86841000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100000fb004b644efe76e9ef3ba89dfa3eaac946e3fa19f8a046ed27465eeef00000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", + "signature": "0x", + "factoryDeps": [], + "paymasterInput": "0x", + "reservedDynamic": "0x" + } +} \ No newline at end of file diff --git a/etc/upgrades/1705556759-fee-model-and-1.4.1/stage2/transactions.json b/etc/upgrades/1705556759-fee-model-and-1.4.1/stage2/transactions.json new file mode 100644 index 000000000000..c393a5820558 --- /dev/null +++ b/etc/upgrades/1705556759-fee-model-and-1.4.1/stage2/transactions.json @@ -0,0 +1,230 @@ +{ + "proposeUpgradeTx": { + "l2ProtocolUpgradeTx": { + "txType": 254, + "from": "0x0000000000000000000000000000000000008007", + "to": "0x0000000000000000000000000000000000008006", + "gasLimit": 72000000, + "gasPerPubdataByteLimit": 800, + "maxFeePerGas": 0, + "maxPriorityFeePerGas": 0, + "paymaster": 0, + "nonce": "20", + "value": 0, + "reserved": [ + 0, + 0, + 0, + 0 + ], + "data": "0xe9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000062000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000860000000000000000000000000000000000000000000000000000000000000092000000000000000000000000000000000000000000000000000000000000009e00000000000000000000000000000000000000000000000000000000000000aa001000075bc9de2129f5d58efa04515bbf24610645546eab19192d7f94a23f83e00000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e5eef000fb93f3b7f746149d0f467fe99e0f628aa76520b18321eeb7b300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d88348c8092dd260d3ba1b90da3d693c5d416b7078b2faca348e2f3a800000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003ddb0142c77e7e36c37910cd90b07e48bb952168e66c79519953d32d5700000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000555b2471aa863b7da5360cc0d2459a8aa5ad9feb6ad8ea5666aee0b5f4c00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028d5519113834685985178f33d36dd855e0b0835e2dad3892ddc3244d8000000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063cb83b923ab1e67bb7944c6493286ba7c1c5614c0cb17155c5eef82d900000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001014336cee5c792682bf2c2079807e643c491d879c07de9dea482a78e39000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181b1c963c230c8521d78a0a650cf7c1879cc6b38e9315035c5596cd914000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c96884dfd5de1a2e02616564c057e67c423d31c589df25bf25b08dd3d6000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000167b75441cbdf3edc039678e2e57bb28d87ca3b76c88ba153be0e65f366000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000553156325702c61297c4ebe6171f7d64845d548311e0fe88792cd86841000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100000fb004b644efe76e9ef3ba89dfa3eaac946e3fa19f8a046ed27465eeef00000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000", + "signature": "0x", + "factoryDeps": [], + "paymasterInput": "0x", + "reservedDynamic": "0x" + }, + "bootloaderHash": "0x010007ed0e328b940e241f7666a6303b7ffd4e3fd7e8c154d6e7556befe6cd6d", + "defaultAccountHash": "0x0100055b7a8be90522251be8be1a186464d056462973502ac8a0437c85e4d2a9", + "verifier": "0x3390051435eCB25a9610A1cF17d1BA0a228A0560", + "verifierParams": { + "recursionNodeLevelVkHash": "0x5a3ef282b21e12fe1f4438e5bb158fc5060b160559c5158c6389d62d9fe3d080", + "recursionLeafLevelVkHash": "0x062362cb3eaf1f631406cbe19bf2a2c5d0d9ea69d069309a6003addae9f387be", + "recursionCircuitsSetVksHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "l1ContractsUpgradeCalldata": "0x", + "postUpgradeCalldata": "0x", + "upgradeTimestamp": { + "type": "BigNumber", + "hex": "0x65aa4820" + }, + "factoryDeps": [], + "newProtocolVersion": "20", + "newAllowList": "0x0000000000000000000000000000000000000000" + }, + "l1upgradeCalldata": "0x1ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000001060010007ed0e328b940e241f7666a6303b7ffd4e3fd7e8c154d6e7556befe6cd6d0100055b7a8be90522251be8be1a186464d056462973502ac8a0437c85e4d2a90000000000000000000000003390051435ecb25a9610a1cf17d1ba0a228a05605a3ef282b21e12fe1f4438e5bb158fc5060b160559c5158c6389d62d9fe3d080062362cb3eaf1f631406cbe19bf2a2c5d0d9ea69d069309a6003addae9f387be0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000108000000000000000000000000000000000000000000000000000000000000010a00000000000000000000000000000000000000000000000000000000065aa48200000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000e400000000000000000000000000000000000000000000000000000000000000e600000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000ea00000000000000000000000000000000000000000000000000000000000000ba4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000062000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000860000000000000000000000000000000000000000000000000000000000000092000000000000000000000000000000000000000000000000000000000000009e00000000000000000000000000000000000000000000000000000000000000aa001000075bc9de2129f5d58efa04515bbf24610645546eab19192d7f94a23f83e00000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e5eef000fb93f3b7f746149d0f467fe99e0f628aa76520b18321eeb7b300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d88348c8092dd260d3ba1b90da3d693c5d416b7078b2faca348e2f3a800000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003ddb0142c77e7e36c37910cd90b07e48bb952168e66c79519953d32d5700000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000555b2471aa863b7da5360cc0d2459a8aa5ad9feb6ad8ea5666aee0b5f4c00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028d5519113834685985178f33d36dd855e0b0835e2dad3892ddc3244d8000000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063cb83b923ab1e67bb7944c6493286ba7c1c5614c0cb17155c5eef82d900000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001014336cee5c792682bf2c2079807e643c491d879c07de9dea482a78e39000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181b1c963c230c8521d78a0a650cf7c1879cc6b38e9315035c5596cd914000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c96884dfd5de1a2e02616564c057e67c423d31c589df25bf25b08dd3d6000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000167b75441cbdf3edc039678e2e57bb28d87ca3b76c88ba153be0e65f366000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000553156325702c61297c4ebe6171f7d64845d548311e0fe88792cd86841000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100000fb004b644efe76e9ef3ba89dfa3eaac946e3fa19f8a046ed27465eeef00000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "upgradeAddress": "0x38283BE1B217873DDacb599e727669E88c8f36C7", + "protocolVersion": "20", + "upgradeTimestamp": "1705658400", + "scheduleTransparentOperation": "0x2c43191700000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000006d6e010a2680e2e5a3b097ce411528b36d880ef6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000002524a9f6d9410000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000038283be1b217873ddacb599e727669e88c8f36c700000000000000000000000000000000000000000000000000000000000013e00000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000007a000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a200000000000000000000000000000000000000000000000000000000000000c2000000000000000000000000000000000000000000000000000000000000010e000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d00000000000000000000000000000000000000000000000000000000173389450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000021cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed6270000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb6724190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d3400000000000000000000000000000000000000000000000000000000000000000000000000000000e6426c725cb507168369c10284390e59d91ec821000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000b0e18b68100000000000000000000000000000000000000000000000000000000e58bb6390000000000000000000000000000000000000000000000000000000064bf8d6600000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d000000000000000000000000000000000000000000000000000000001733894500000000000000000000000000000000000000000000000000000000000000000000000000000000c4a5e861df9dd9495f8dba1c260913d1a9b8ec2b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000021cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed6270000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d000000000000000000000000000000000000000000000000000000000000000000000000000000000f58fd6c9ed966e09c1dffbc8e6ff600ec65f6eb00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb672419000000000000000000000000000000000000000000000000000000000000000000000000000000005b86821c1b4b55def404c9551ec2d2cc0ae70f5c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e41ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000001060010007ed0e328b940e241f7666a6303b7ffd4e3fd7e8c154d6e7556befe6cd6d0100055b7a8be90522251be8be1a186464d056462973502ac8a0437c85e4d2a90000000000000000000000003390051435ecb25a9610a1cf17d1ba0a228a05605a3ef282b21e12fe1f4438e5bb158fc5060b160559c5158c6389d62d9fe3d080062362cb3eaf1f631406cbe19bf2a2c5d0d9ea69d069309a6003addae9f387be0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000108000000000000000000000000000000000000000000000000000000000000010a00000000000000000000000000000000000000000000000000000000065aa48200000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000e400000000000000000000000000000000000000000000000000000000000000e600000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000ea00000000000000000000000000000000000000000000000000000000000000ba4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000062000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000860000000000000000000000000000000000000000000000000000000000000092000000000000000000000000000000000000000000000000000000000000009e00000000000000000000000000000000000000000000000000000000000000aa001000075bc9de2129f5d58efa04515bbf24610645546eab19192d7f94a23f83e00000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e5eef000fb93f3b7f746149d0f467fe99e0f628aa76520b18321eeb7b300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d88348c8092dd260d3ba1b90da3d693c5d416b7078b2faca348e2f3a800000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003ddb0142c77e7e36c37910cd90b07e48bb952168e66c79519953d32d5700000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000555b2471aa863b7da5360cc0d2459a8aa5ad9feb6ad8ea5666aee0b5f4c00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028d5519113834685985178f33d36dd855e0b0835e2dad3892ddc3244d8000000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063cb83b923ab1e67bb7944c6493286ba7c1c5614c0cb17155c5eef82d900000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001014336cee5c792682bf2c2079807e643c491d879c07de9dea482a78e39000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181b1c963c230c8521d78a0a650cf7c1879cc6b38e9315035c5596cd914000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c96884dfd5de1a2e02616564c057e67c423d31c589df25bf25b08dd3d6000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000167b75441cbdf3edc039678e2e57bb28d87ca3b76c88ba153be0e65f366000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000553156325702c61297c4ebe6171f7d64845d548311e0fe88792cd86841000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100000fb004b644efe76e9ef3ba89dfa3eaac946e3fa19f8a046ed27465eeef00000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "executeOperation": "0x74da756b0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000006d6e010a2680e2e5a3b097ce411528b36d880ef6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000002524a9f6d9410000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000038283be1b217873ddacb599e727669e88c8f36c700000000000000000000000000000000000000000000000000000000000013e00000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000007a000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a200000000000000000000000000000000000000000000000000000000000000c2000000000000000000000000000000000000000000000000000000000000010e000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d00000000000000000000000000000000000000000000000000000000173389450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000021cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed6270000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb6724190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d3400000000000000000000000000000000000000000000000000000000000000000000000000000000e6426c725cb507168369c10284390e59d91ec821000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000b0e18b68100000000000000000000000000000000000000000000000000000000e58bb6390000000000000000000000000000000000000000000000000000000064bf8d6600000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d000000000000000000000000000000000000000000000000000000001733894500000000000000000000000000000000000000000000000000000000000000000000000000000000c4a5e861df9dd9495f8dba1c260913d1a9b8ec2b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000021cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed6270000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d000000000000000000000000000000000000000000000000000000000000000000000000000000000f58fd6c9ed966e09c1dffbc8e6ff600ec65f6eb00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb672419000000000000000000000000000000000000000000000000000000000000000000000000000000005b86821c1b4b55def404c9551ec2d2cc0ae70f5c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e41ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000001060010007ed0e328b940e241f7666a6303b7ffd4e3fd7e8c154d6e7556befe6cd6d0100055b7a8be90522251be8be1a186464d056462973502ac8a0437c85e4d2a90000000000000000000000003390051435ecb25a9610a1cf17d1ba0a228a05605a3ef282b21e12fe1f4438e5bb158fc5060b160559c5158c6389d62d9fe3d080062362cb3eaf1f631406cbe19bf2a2c5d0d9ea69d069309a6003addae9f387be0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000108000000000000000000000000000000000000000000000000000000000000010a00000000000000000000000000000000000000000000000000000000065aa48200000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000e400000000000000000000000000000000000000000000000000000000000000e600000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000ea00000000000000000000000000000000000000000000000000000000000000ba4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000062000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000860000000000000000000000000000000000000000000000000000000000000092000000000000000000000000000000000000000000000000000000000000009e00000000000000000000000000000000000000000000000000000000000000aa001000075bc9de2129f5d58efa04515bbf24610645546eab19192d7f94a23f83e00000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e5eef000fb93f3b7f746149d0f467fe99e0f628aa76520b18321eeb7b300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d88348c8092dd260d3ba1b90da3d693c5d416b7078b2faca348e2f3a800000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003ddb0142c77e7e36c37910cd90b07e48bb952168e66c79519953d32d5700000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000555b2471aa863b7da5360cc0d2459a8aa5ad9feb6ad8ea5666aee0b5f4c00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028d5519113834685985178f33d36dd855e0b0835e2dad3892ddc3244d8000000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063cb83b923ab1e67bb7944c6493286ba7c1c5614c0cb17155c5eef82d900000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001014336cee5c792682bf2c2079807e643c491d879c07de9dea482a78e39000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181b1c963c230c8521d78a0a650cf7c1879cc6b38e9315035c5596cd914000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c96884dfd5de1a2e02616564c057e67c423d31c589df25bf25b08dd3d6000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000167b75441cbdf3edc039678e2e57bb28d87ca3b76c88ba153be0e65f366000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000553156325702c61297c4ebe6171f7d64845d548311e0fe88792cd86841000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100000fb004b644efe76e9ef3ba89dfa3eaac946e3fa19f8a046ed27465eeef00000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "governanceOperation": { + "calls": [ + { + "target": "0x6d6e010A2680E2E5a3b097ce411528b36d880EF6", + "value": 0, + "data": "0xa9f6d9410000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000038283be1b217873ddacb599e727669e88c8f36c700000000000000000000000000000000000000000000000000000000000013e00000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000007a000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a200000000000000000000000000000000000000000000000000000000000000c2000000000000000000000000000000000000000000000000000000000000010e000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a0e18b68100000000000000000000000000000000000000000000000000000000e58bb63900000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d00000000000000000000000000000000000000000000000000000000173389450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000021cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed6270000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb6724190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d3400000000000000000000000000000000000000000000000000000000000000000000000000000000e6426c725cb507168369c10284390e59d91ec821000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000b0e18b68100000000000000000000000000000000000000000000000000000000e58bb6390000000000000000000000000000000000000000000000000000000064bf8d6600000000000000000000000000000000000000000000000000000000a9f6d9410000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004dd18bf500000000000000000000000000000000000000000000000000000000f235757f000000000000000000000000000000000000000000000000000000001cc5d10300000000000000000000000000000000000000000000000000000000be6f11cf000000000000000000000000000000000000000000000000000000004623c91d000000000000000000000000000000000000000000000000000000001733894500000000000000000000000000000000000000000000000000000000000000000000000000000000c4a5e861df9dd9495f8dba1c260913d1a9b8ec2b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000021cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed6270000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000004fc07d7500000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000e5355c75000000000000000000000000000000000000000000000000000000009d1b5a81000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008665b15000000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000033ce93fe00000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000fe26699e000000000000000000000000000000000000000000000000000000003960738200000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000a1954fc50000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000018e3a9410000000000000000000000000000000000000000000000000000000029b98c6700000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000facd743b000000000000000000000000000000000000000000000000000000009cd939e40000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000b22dd78e0000000000000000000000000000000000000000000000000000000074f4d30d000000000000000000000000000000000000000000000000000000000000000000000000000000000f58fd6c9ed966e09c1dffbc8e6ff600ec65f6eb00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000042901c700000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb672419000000000000000000000000000000000000000000000000000000000000000000000000000000005b86821c1b4b55def404c9551ec2d2cc0ae70f5c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004701f58c500000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e41ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000001060010007ed0e328b940e241f7666a6303b7ffd4e3fd7e8c154d6e7556befe6cd6d0100055b7a8be90522251be8be1a186464d056462973502ac8a0437c85e4d2a90000000000000000000000003390051435ecb25a9610a1cf17d1ba0a228a05605a3ef282b21e12fe1f4438e5bb158fc5060b160559c5158c6389d62d9fe3d080062362cb3eaf1f631406cbe19bf2a2c5d0d9ea69d069309a6003addae9f387be0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000108000000000000000000000000000000000000000000000000000000000000010a00000000000000000000000000000000000000000000000000000000065aa48200000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000e400000000000000000000000000000000000000000000000000000000000000e600000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000ea00000000000000000000000000000000000000000000000000000000000000ba4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000062000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000860000000000000000000000000000000000000000000000000000000000000092000000000000000000000000000000000000000000000000000000000000009e00000000000000000000000000000000000000000000000000000000000000aa001000075bc9de2129f5d58efa04515bbf24610645546eab19192d7f94a23f83e00000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e5eef000fb93f3b7f746149d0f467fe99e0f628aa76520b18321eeb7b300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d88348c8092dd260d3ba1b90da3d693c5d416b7078b2faca348e2f3a800000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003ddb0142c77e7e36c37910cd90b07e48bb952168e66c79519953d32d5700000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000555b2471aa863b7da5360cc0d2459a8aa5ad9feb6ad8ea5666aee0b5f4c00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028d5519113834685985178f33d36dd855e0b0835e2dad3892ddc3244d8000000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063cb83b923ab1e67bb7944c6493286ba7c1c5614c0cb17155c5eef82d900000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001014336cee5c792682bf2c2079807e643c491d879c07de9dea482a78e39000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181b1c963c230c8521d78a0a650cf7c1879cc6b38e9315035c5596cd914000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c96884dfd5de1a2e02616564c057e67c423d31c589df25bf25b08dd3d6000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000167b75441cbdf3edc039678e2e57bb28d87ca3b76c88ba153be0e65f366000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000553156325702c61297c4ebe6171f7d64845d548311e0fe88792cd86841000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100000fb004b644efe76e9ef3ba89dfa3eaac946e3fa19f8a046ed27465eeef00000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + ], + "predecessor": "0x0000000000000000000000000000000000000000000000000000000000000000", + "salt": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "transparentUpgrade": { + "facetCuts": [ + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x0e18b681", + "0xe58bb639", + "0xa9f6d941", + "0x27ae4c16", + "0x4dd18bf5", + "0xf235757f", + "0x1cc5d103", + "0xbe6f11cf", + "0x4623c91d", + "0x17338945" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0xcdffacc6", + "0x52ef6b2c", + "0xadfca15e", + "0x7a0ed627", + "0x79823c9a", + "0x4fc07d75", + "0xd86970d8", + "0xfd791f3c", + "0xe5355c75", + "0x9d1b5a81", + "0x7b30c8da", + "0x8665b150", + "0x631f4bac", + "0x0ec6b0b7", + "0x33ce93fe", + "0xdb1f0bf9", + "0xb8c2f66f", + "0xef3f0bae", + "0xfe26699e", + "0x39607382", + "0xaf6a2dcd", + "0xa1954fc5", + "0x46657fe9", + "0x18e3a941", + "0x29b98c67", + "0xbd7c5412", + "0xc3bbd2d7", + "0xe81e0ba1", + "0xfacd743b", + "0x9cd939e4", + "0x56142d7a", + "0xb22dd78e", + "0x74f4d30d" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x6c0960f9", + "0xb473318e", + "0x042901c7", + "0x263b7f8e", + "0xe4948f43", + "0xeb672419" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0x0000000000000000000000000000000000000000", + "selectors": [ + "0x701f58c5", + "0xc3d93e7c", + "0x7f61885c", + "0x97c09d34" + ], + "action": 2, + "isFreezable": false + }, + { + "facet": "0xE6426c725cB507168369c10284390E59d91eC821", + "selectors": [ + "0x0e18b681", + "0xe58bb639", + "0x64bf8d66", + "0xa9f6d941", + "0x27ae4c16", + "0x4dd18bf5", + "0xf235757f", + "0x1cc5d103", + "0xbe6f11cf", + "0x4623c91d", + "0x17338945" + ], + "action": 0, + "isFreezable": false + }, + { + "facet": "0xc4a5e861df9DD9495f8Dba1c260913d1A9b8Ec2B", + "selectors": [ + "0xcdffacc6", + "0x52ef6b2c", + "0xadfca15e", + "0x7a0ed627", + "0x79823c9a", + "0x4fc07d75", + "0xd86970d8", + "0xfd791f3c", + "0xe5355c75", + "0x9d1b5a81", + "0x7b30c8da", + "0x8665b150", + "0x631f4bac", + "0x0ec6b0b7", + "0x33ce93fe", + "0xdb1f0bf9", + "0xb8c2f66f", + "0xef3f0bae", + "0xfe26699e", + "0x39607382", + "0xaf6a2dcd", + "0xa1954fc5", + "0x46657fe9", + "0x18e3a941", + "0x29b98c67", + "0xbd7c5412", + "0xc3bbd2d7", + "0xe81e0ba1", + "0xfacd743b", + "0x9cd939e4", + "0x56142d7a", + "0xb22dd78e", + "0x74f4d30d" + ], + "action": 0, + "isFreezable": false + }, + { + "facet": "0x0f58Fd6c9Ed966e09C1dFFBc8E6FF600ec65f6eB", + "selectors": [ + "0x6c0960f9", + "0xb473318e", + "0x042901c7", + "0x263b7f8e", + "0xe4948f43", + "0xeb672419" + ], + "action": 0, + "isFreezable": true + }, + { + "facet": "0x5b86821c1B4B55deF404c9551EC2d2Cc0aE70f5C", + "selectors": [ + "0x701f58c5", + "0xc3d93e7c", + "0x7f61885c", + "0x97c09d34" + ], + "action": 0, + "isFreezable": true + } + ], + "initAddress": "0x38283BE1B217873DDacb599e727669E88c8f36C7", + "initCalldata": "0x1ed824a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000001060010007ed0e328b940e241f7666a6303b7ffd4e3fd7e8c154d6e7556befe6cd6d0100055b7a8be90522251be8be1a186464d056462973502ac8a0437c85e4d2a90000000000000000000000003390051435ecb25a9610a1cf17d1ba0a228a05605a3ef282b21e12fe1f4438e5bb158fc5060b160559c5158c6389d62d9fe3d080062362cb3eaf1f631406cbe19bf2a2c5d0d9ea69d069309a6003addae9f387be0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000108000000000000000000000000000000000000000000000000000000000000010a00000000000000000000000000000000000000000000000000000000065aa48200000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000008007000000000000000000000000000000000000000000000000000000000000800600000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000e400000000000000000000000000000000000000000000000000000000000000e600000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000ea00000000000000000000000000000000000000000000000000000000000000ba4e9f18c170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000062000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000860000000000000000000000000000000000000000000000000000000000000092000000000000000000000000000000000000000000000000000000000000009e00000000000000000000000000000000000000000000000000000000000000aa001000075bc9de2129f5d58efa04515bbf24610645546eab19192d7f94a23f83e00000000000000000000000000000000000000000000000000000000000080020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000e5eef000fb93f3b7f746149d0f467fe99e0f628aa76520b18321eeb7b300000000000000000000000000000000000000000000000000000000000080030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100007d88348c8092dd260d3ba1b90da3d693c5d416b7078b2faca348e2f3a800000000000000000000000000000000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100003ddb0142c77e7e36c37910cd90b07e48bb952168e66c79519953d32d5700000000000000000000000000000000000000000000000000000000000080050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000555b2471aa863b7da5360cc0d2459a8aa5ad9feb6ad8ea5666aee0b5f4c00000000000000000000000000000000000000000000000000000000000080060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100028d5519113834685985178f33d36dd855e0b0835e2dad3892ddc3244d8000000000000000000000000000000000000000000000000000000000000080080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000063cb83b923ab1e67bb7944c6493286ba7c1c5614c0cb17155c5eef82d900000000000000000000000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010001014336cee5c792682bf2c2079807e643c491d879c07de9dea482a78e39000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000181b1c963c230c8521d78a0a650cf7c1879cc6b38e9315035c5596cd914000000000000000000000000000000000000000000000000000000000000800b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010007c96884dfd5de1a2e02616564c057e67c423d31c589df25bf25b08dd3d6000000000000000000000000000000000000000000000000000000000000800c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001000167b75441cbdf3edc039678e2e57bb28d87ca3b76c88ba153be0e65f366000000000000000000000000000000000000000000000000000000000000800e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000010000553156325702c61297c4ebe6171f7d64845d548311e0fe88792cd86841000000000000000000000000000000000000000000000000000000000000800f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000100000fb004b644efe76e9ef3ba89dfa3eaac946e3fa19f8a046ed27465eeef00000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } +} \ No newline at end of file diff --git a/flake.lock b/flake.lock index 3b683c15c855..44c9f48b2913 100644 --- a/flake.lock +++ b/flake.lock @@ -7,16 +7,16 @@ }, "stable": { "locked": { - "lastModified": 1683478192, - "narHash": "sha256-7f7RR71w0jRABDgBwjq3vE1yY3nrVJyXk8hDzu5kl1E=", + "lastModified": 1705331948, + "narHash": "sha256-qjQXfvrAT1/RKDFAMdl8Hw3m4tLVvMCc8fMqzJv0pP4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c568239bcc990050b7aedadb7387832440ad8fb1", + "rev": "b8dd8be3c790215716e7c12b247f45ca525867e2", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-22.11", + "ref": "nixos-23.11", "repo": "nixpkgs", "type": "github" } diff --git a/flake.nix b/flake.nix index e4fe935907e7..d34ecd551abc 100644 --- a/flake.nix +++ b/flake.nix @@ -1,40 +1,43 @@ { - description = "zkSync development shell"; - inputs = { - stable.url = "github:NixOS/nixpkgs/nixos-22.11"; - }; - outputs = {self, stable}: { - packages.x86_64-linux.default = - with import stable { system = "x86_64-linux"; }; - pkgs.mkShell { - name = "zkSync"; - src = ./.; - buildInputs = [ - docker-compose - nodejs - yarn - axel - libclang - openssl - pkg-config - postgresql - python3 - solc - ]; + description = "zkSync development shell"; + inputs = { + stable.url = "github:NixOS/nixpkgs/nixos-23.11"; + }; + outputs = { self, stable }: { + formatter.x86_64-linux = stable.legacyPackages.x86_64-linux.nixpkgs-fmt; + devShells.x86_64-linux.default = + with import stable { system = "x86_64-linux"; }; + pkgs.mkShell.override { stdenv = pkgs.stdenvAdapters.useMoldLinker pkgs.gccStdenv; } { + name = "zkSync"; + src = ./.; + buildInputs = [ + docker-compose + nodejs + yarn + axel + libclang + openssl + pkg-config + postgresql + python3 + solc + sqlx-cli + rustup + ]; - # for RocksDB and other Rust bindgen libraries - LIBCLANG_PATH = lib.makeLibraryPath [ libclang.lib ]; - BINDGEN_EXTRA_CLANG_ARGS = ''-I"${libclang.lib}/lib/clang/${libclang.version}/include"''; + # for RocksDB and other Rust bindgen libraries + LIBCLANG_PATH = lib.makeLibraryPath [ libclang.lib ]; + BINDGEN_EXTRA_CLANG_ARGS = ''-I"${libclang.lib}/lib/clang/${builtins.elemAt (builtins.splitVersion libclang.version) 0}/include"''; - shellHook = '' - export ZKSYNC_HOME=$PWD - export PATH=$ZKSYNC_HOME/bin:$PATH - ''; + shellHook = '' + export ZKSYNC_HOME=$PWD + export PATH=$ZKSYNC_HOME/bin:$PATH + ''; - # hardhat solc requires ld-linux - # Nixos has to fake it with nix-ld - NIX_LD_LIBRARY_PATH = lib.makeLibraryPath []; - NIX_LD = builtins.readFile "${stdenv.cc}/nix-support/dynamic-linker"; - }; - }; + # hardhat solc requires ld-linux + # Nixos has to fake it with nix-ld + NIX_LD_LIBRARY_PATH = lib.makeLibraryPath []; + NIX_LD = builtins.readFile "${stdenv.cc}/nix-support/dynamic-linker"; + }; + }; } diff --git a/infrastructure/protocol-upgrade/src/crypto/crypto.ts b/infrastructure/protocol-upgrade/src/crypto/crypto.ts index df7aa6bd44b5..1f87b215ab69 100644 --- a/infrastructure/protocol-upgrade/src/crypto/crypto.ts +++ b/infrastructure/protocol-upgrade/src/crypto/crypto.ts @@ -1,6 +1,6 @@ import { getCryptoFileName, getUpgradePath, VerifierParams } from '../utils'; import fs from 'fs'; -import { BytesLike } from 'ethers'; +import { BytesLike, ethers } from 'ethers'; import { Command } from 'commander'; import { deployVerifier } from './deployer'; @@ -12,8 +12,7 @@ function saveVerificationKeys( ) { recursionNodeLevelVkHash = recursionNodeLevelVkHash ?? process.env.CONTRACTS_FRI_RECURSION_NODE_LEVEL_VK_HASH; recursionLeafLevelVkHash = recursionLeafLevelVkHash ?? process.env.CONTRACTS_FRI_RECURSION_LEAF_LEVEL_VK_HASH; - recursionCircuitsSetVksHash = - recursionCircuitsSetVksHash ?? process.env.CONTRACTS_FRI_RECURSION_SCHEDULER_LEVEL_VK_HASH; + recursionCircuitsSetVksHash = recursionCircuitsSetVksHash ?? ethers.constants.HashZero; const verificationParams: VerifierParams = { recursionNodeLevelVkHash, recursionLeafLevelVkHash, diff --git a/infrastructure/protocol-upgrade/src/l1upgrade/facets.ts b/infrastructure/protocol-upgrade/src/l1upgrade/facets.ts index 95364215da38..4f89ec477a7b 100644 --- a/infrastructure/protocol-upgrade/src/l1upgrade/facets.ts +++ b/infrastructure/protocol-upgrade/src/l1upgrade/facets.ts @@ -143,7 +143,7 @@ export const command = new Command('facets').description('Deploy facets and gene command .command('deploy-all') - .description('Deploy all facets') + .description('Deploy all facets and generate facet cuts') .option('--private-key ') .option('--l1rpc ') .option('--gas-price ') diff --git a/infrastructure/protocol-upgrade/src/transaction.ts b/infrastructure/protocol-upgrade/src/transaction.ts index e147a02c740c..2735f21c8351 100644 --- a/infrastructure/protocol-upgrade/src/transaction.ts +++ b/infrastructure/protocol-upgrade/src/transaction.ts @@ -523,6 +523,11 @@ command .option('--zksync-address ') .option('--use-new-governance') .action(async (options) => { + if (!options.useNewGovernance) { + // TODO(X): remove old governance functionality from the protocol upgrade tool + throw new Error('Old governance is not supported anymore'); + } + let diamondUpgradeProposalId = options.diamondUpgradeProposalId; if (!diamondUpgradeProposalId && !options.useNewGovernance) { diamondUpgradeProposalId = await getNewDiamondUpgradeProposalId(options.l1rpc, options.zksyncAddress); @@ -550,6 +555,11 @@ command .option('--l1rpc ') .option('--new-governance ') .action(async (options) => { + if (!options.newGovernance) { + // TODO(X): remove old governance functionality from the protocol upgrade tool + throw new Error('Old governance is not supported anymore'); + } + await proposeUpgrade( options.privateKey, options.l1rpc, @@ -571,6 +581,11 @@ command .option('--l1rpc ') .option('--new-governance ') .action(async (options) => { + if (!options.newGovernance) { + // TODO(X): remove old governance functionality from the protocol upgrade tool + throw new Error('Old governance is not supported anymore'); + } + await executeUpgrade( options.privateKey, options.l1rpc, @@ -593,6 +608,11 @@ command .option('--execute') .option('--new-governance ') .action(async (options) => { + if (!options.newGovernance) { + // TODO(X): remove old governance functionality from the protocol upgrade tool + throw new Error('Old governance is not supported anymore'); + } + await cancelUpgrade( options.privateKey, options.l1rpc, diff --git a/infrastructure/zk/package.json b/infrastructure/zk/package.json index 7e2f70d82cba..11a05a760239 100644 --- a/infrastructure/zk/package.json +++ b/infrastructure/zk/package.json @@ -31,6 +31,9 @@ "@types/pg": "^8.10.3", "@types/tabtab": "^3.0.1", "hardhat": "=2.16.0", - "typescript": "^4.3.5" + "typescript": "^4.3.5", + "cspell": "^8.3.2", + "sql-formatter": "^13.1.0", + "markdown-link-check": "^3.11.2" } } diff --git a/infrastructure/zk/src/clean.ts b/infrastructure/zk/src/clean.ts index 117635111840..96c68d5908be 100644 --- a/infrastructure/zk/src/clean.ts +++ b/infrastructure/zk/src/clean.ts @@ -27,6 +27,7 @@ export const command = new Command('clean') const env = process.env.ZKSYNC_ENV; clean(`etc/env/${env}.env`); clean('etc/env/.init.env'); + clean('etc/env/.current'); } if (cmd.all || cmd.artifacts) { diff --git a/infrastructure/zk/src/config.ts b/infrastructure/zk/src/config.ts index d7b0a96dcd17..6d2b722c0d25 100644 --- a/infrastructure/zk/src/config.ts +++ b/infrastructure/zk/src/config.ts @@ -16,12 +16,9 @@ const CONFIG_FILES = [ 'misc.toml', 'object_store.toml', 'nfs.toml', - 'prover.toml', 'rust.toml', 'private.toml', 'witness_generator.toml', - 'circuit_synthesizer.toml', - 'prover_group.toml', 'house_keeper.toml', 'fri_prover.toml', 'fri_witness_generator.toml', diff --git a/infrastructure/zk/src/contract.ts b/infrastructure/zk/src/contract.ts index 4d0ec52ec6d3..fec4eba4963c 100644 --- a/infrastructure/zk/src/contract.ts +++ b/infrastructure/zk/src/contract.ts @@ -51,15 +51,6 @@ export async function initializeGovernance(args: any[] = []) { await utils.spawn(`${baseCommandL1} initialize-governance ${args.join(' ')} | tee initializeGovernance.log`); } -export async function initializeL1AllowList(args: any[] = []) { - await utils.confirmAction(); - - const isLocalSetup = process.env.ZKSYNC_LOCAL_SETUP; - const baseCommandL1 = isLocalSetup ? `yarn --cwd /contracts/l1-contracts` : `yarn l1-contracts`; - - await utils.spawn(`${baseCommandL1} initialize-allow-list ${args.join(' ')} | tee initializeL1AllowList.log`); -} - export async function initializeWethToken(args: any[] = []) { await utils.confirmAction(); @@ -171,8 +162,4 @@ command command.command('deploy [deploy-opts...]').allowUnknownOption(true).description('deploy contracts').action(deployL1); command.command('build').description('build contracts').action(build); command.command('initialize-validator').description('initialize validator').action(initializeValidator); -command - .command('initialize-l1-allow-list-contract') - .description('initialize L1 allow list contract') - .action(initializeL1AllowList); command.command('verify').description('verify L1 contracts').action(verifyL1Contracts); diff --git a/infrastructure/zk/src/database.ts b/infrastructure/zk/src/database.ts index 721ff734730a..f78486fcbecd 100644 --- a/infrastructure/zk/src/database.ts +++ b/infrastructure/zk/src/database.ts @@ -53,10 +53,21 @@ export async function setup() { // Remote database, we can't show the contents. console.log(`WARNING! Using prod db!`); } - await utils.spawn('cargo sqlx database create'); - await utils.spawn('cargo sqlx migrate run'); - if (process.env.DATABASE_URL!.startsWith(localDbUrl)) { - await utils.spawn('cargo sqlx prepare --check -- --tests || cargo sqlx prepare -- --tests'); + if (process.env.TEMPLATE_DATABASE_URL !== undefined) { + // Dump and restore from template database (simulate backup) + console.log(`Template DB URL provided. Creating a DB via dump from ${process.env.TEMPLATE_DATABASE_URL}`); + await utils.spawn('cargo sqlx database drop -y'); + await utils.spawn('cargo sqlx database create'); + await utils.spawn( + `pg_dump ${process.env.TEMPLATE_DATABASE_URL} -F c | pg_restore -d ${process.env.DATABASE_URL}` + ); + } else { + // Create an empty database. + await utils.spawn('cargo sqlx database create'); + await utils.spawn('cargo sqlx migrate run'); + if (process.env.DATABASE_URL!.startsWith(localDbUrl)) { + await utils.spawn('cargo sqlx prepare --check -- --tests || cargo sqlx prepare -- --tests'); + } } process.chdir(process.env.ZKSYNC_HOME as string); diff --git a/infrastructure/zk/src/docker.ts b/infrastructure/zk/src/docker.ts index 0139811eff52..143a41bd154f 100644 --- a/infrastructure/zk/src/docker.ts +++ b/infrastructure/zk/src/docker.ts @@ -1,11 +1,9 @@ import { Command } from 'commander'; import * as utils from './utils'; -import * as contract from './contract'; const IMAGES = [ 'server-v2', 'external-node', - 'cross-external-nodes-checker', 'contract-verifier', 'prover-v2', 'geth', @@ -20,12 +18,17 @@ const IMAGES = [ 'proof-fri-compressor', 'snapshots-creator' ]; + +const DOCKER_REGISTRIES = ['us-docker.pkg.dev/matterlabs-infra/matterlabs-docker', 'matterlabs']; + const UNIX_TIMESTAMP = Date.now(); async function dockerCommand( command: 'push' | 'build', image: string, + platform: string = '', customTag?: string, + buildExtraArgs: string = '', dockerOrg: string = 'matterlabs' ) { // Generating all tags for containers. We need 2 tags here: SHA and SHA+TS @@ -37,8 +40,8 @@ async function dockerCommand( // We want an alternative flow for Rust image if (image == 'rust') { - await dockerCommand(command, 'server-v2', customTag, dockerOrg); - await dockerCommand(command, 'prover', customTag, dockerOrg); + await dockerCommand(command, 'server-v2', platform, customTag, dockerOrg); + await dockerCommand(command, 'prover', platform, customTag, dockerOrg); return; } if (!IMAGES.includes(image)) { @@ -54,10 +57,7 @@ async function dockerCommand( // Main build\push flow switch (command) { case 'build': - await _build(image, tagList, dockerOrg); - break; - case 'push': - await _push(image, tagList); + await _build(image, tagList, dockerOrg, platform, buildExtraArgs); break; default: console.log(`Unknown command for docker ${command}.`); @@ -69,7 +69,6 @@ function defaultTagList(image: string, imageTagSha: string, imageTagShaTS: strin const tagList = [ 'server-v2', 'external-node', - 'cross-external-nodes-checker', 'prover', 'contract-verifier', 'prover-v2', @@ -88,72 +87,54 @@ function defaultTagList(image: string, imageTagSha: string, imageTagShaTS: strin return tagList; } -async function _build(image: string, tagList: string[], dockerOrg: string) { - if (image === 'server-v2' || image === 'external-node' || image === 'prover') { - await contract.build(); - } +async function _build(image: string, tagList: string[], dockerOrg: string, platform: string, extraArgs: string = '') { let tagsToBuild = ''; - // generate list of tags for image - we want 3 tags (latest, SHA, SHA+TimeStamp) for listed components and only "latest" for everything else - tagsToBuild = tagList.map((tag) => `-t ${dockerOrg}/${image}:${tag}`).join(' '); + for (const tag of tagList) { + for (const registry of DOCKER_REGISTRIES) { + if (platform != '') { + let platformSuffix = platform.replace('/', '-'); + tagsToBuild = tagsToBuild + `-t ${registry}/${image}:${tag}-${platformSuffix} `; + } else { + tagsToBuild = tagsToBuild + `-t ${registry}/${image}:${tag} `; + } + } + } - // Conditionally add build argument if image is prover-v2 let buildArgs = ''; + if (platform != '') { + buildArgs += `--platform=${platform} `; + } if (image === 'prover-v2') { const eraBellmanCudaRelease = process.env.ERA_BELLMAN_CUDA_RELEASE; - buildArgs += `--build-arg ERA_BELLMAN_CUDA_RELEASE=${eraBellmanCudaRelease}`; + buildArgs += `--build-arg ERA_BELLMAN_CUDA_RELEASE=${eraBellmanCudaRelease} `; } if (image === 'prover-gpu-fri') { const cudaArch = process.env.CUDA_ARCH; - buildArgs += `--build-arg CUDA_ARCH='${cudaArch}'`; + buildArgs += `--build-arg CUDA_ARCH='${cudaArch}' `; } + buildArgs += extraArgs; - // HACK - // For prover-v2 which is not a prover, but should be built from the prover dockerfile. So here we go. - const imagePath = image == 'prover-v2' ? 'prover' : image; + const imagePath = image === 'prover-v2' ? 'prover' : image; const buildCommand = - `DOCKER_BUILDKIT=1 docker build ${tagsToBuild}` + + `DOCKER_BUILDKIT=1 docker buildx build ${tagsToBuild}` + (buildArgs ? ` ${buildArgs}` : '') + ` -f ./docker/${imagePath}/Dockerfile .`; await utils.spawn(buildCommand); } -async function _push(image: string, tagList: string[]) { - // For development purposes, we want to use `2.0` tags for 2.0 images, just to not interfere with 1.x - - for (const tag of tagList) { - await utils.spawn(`docker push matterlabs/${image}:${tag}`); - await utils.spawn( - `docker tag matterlabs/${image}:${tag} us-docker.pkg.dev/matterlabs-infra/matterlabs-docker/${image}:${tag}` - ); - await utils.spawn(`docker push us-docker.pkg.dev/matterlabs-infra/matterlabs-docker/${image}:${tag}`); - - if (image == 'circuit-synthesizer') { - await utils.spawn( - `docker tag us-docker.pkg.dev/matterlabs-infra/matterlabs-docker/${image}:${tag} asia-docker.pkg.dev/matterlabs-infra/matterlabs-docker/${image}:${tag}` - ); - await utils.spawn( - `docker tag us-docker.pkg.dev/matterlabs-infra/matterlabs-docker/${image}:${tag} europe-docker.pkg.dev/matterlabs-infra/matterlabs-docker/${image}:${tag}` - ); - await utils.spawn(`docker push asia-docker.pkg.dev/matterlabs-infra/matterlabs-docker/${image}:${tag}`); - await utils.spawn(`docker push europe-docker.pkg.dev/matterlabs-infra/matterlabs-docker/${image}:${tag}`); - } - } -} - export async function build(image: string, cmd: Command) { - await dockerCommand('build', image, cmd.customTag); + await dockerCommand('build', image, cmd.platform, cmd.customTag); } export async function customBuildForHyperchain(image: string, dockerOrg: string) { - await dockerCommand('build', image, '', dockerOrg); + await dockerCommand('build', image, 'linux/amd64', dockerOrg); } export async function push(image: string, cmd: Command) { - await dockerCommand('build', image, cmd.customTag); - await dockerCommand('push', image, cmd.customTag); + await dockerCommand('build', image, cmd.platform, cmd.customTag, '--push'); } export async function restart(container: string) { @@ -169,12 +150,13 @@ export const command = new Command('docker').description('docker management'); command .command('build ') .option('--custom-tag ', 'Custom tag for image') + .option('--platform ', 'Docker platform') .description('build docker image') .action(build); command .command('push ') .option('--custom-tag ', 'Custom tag for image') - .description('build and push docker image') + .option('--platform ', 'Docker platform') .action(push); command.command('pull').description('pull all containers').action(pull); command.command('restart ').description('restart container in docker-compose.yml').action(restart); diff --git a/infrastructure/zk/src/format_sql.ts b/infrastructure/zk/src/format_sql.ts index 2465ec20ba24..1e2bd2261c54 100644 --- a/infrastructure/zk/src/format_sql.ts +++ b/infrastructure/zk/src/format_sql.ts @@ -34,7 +34,7 @@ function formatQuery(query: string) { return formattedQuery; } -function extractQueryFromRustString(query: string): string { +function extractQueryFromRustString(query: string, isRaw: boolean): string { query = query.trim(); if (query.endsWith(',')) { query = query.slice(0, query.length - 1); @@ -46,9 +46,10 @@ function extractQueryFromRustString(query: string): string { query = query.slice(3, query.length - 2); } - //getting rid of all "\" characters, both from escapes and line breaks - query = query.replace(/\\/g, ''); - + // Get rid of all "\" characters, both from escapes and line breaks. + if (!isRaw) { + query = query.replace(/\\(.|\n)/g, '$1'); + } return query; } @@ -63,9 +64,9 @@ function addIndent(query: string, indent: number) { .join('\n'); } -function formatRustStringQuery(query: string) { +function formatRustStringQuery(query: string, isRaw: boolean) { const baseIndent = query.search(/\S/); - const rawQuery = extractQueryFromRustString(query); + const rawQuery = extractQueryFromRustString(query, isRaw); const formattedQuery = formatQuery(rawQuery); const reconstructedRustString = embedTextInsideRustString(formattedQuery); @@ -81,7 +82,7 @@ function formatOneLineQuery(line: string): string { const queryEnd = isRawString ? line.indexOf('"#') + 2 : line.slice(1).search(/(^|[^\\])"/) + 3; const suffix = line.slice(queryEnd); const query = line.slice(0, queryEnd); - let formattedQuery = formatRustStringQuery(query); + let formattedQuery = formatRustStringQuery(query, isRawString); formattedQuery = addIndent(formattedQuery, baseIndent); return prefix + '\n' + formattedQuery + '\n' + suffix; @@ -124,7 +125,7 @@ async function formatFile(filePath: string, check: boolean) { } if (isInsideQuery) { - const queryNotEmpty = builtQuery || line.trim().length > 1; + const queryNotEmpty = builtQuery !== '' || line.trim().length > 1; const rawStringQueryEnded = line.endsWith('"#,') || line.endsWith('"#'); const regularStringQueryEnded = (line.endsWith('",') || line.endsWith('"')) && queryNotEmpty; builtQuery += line + '\n'; @@ -135,7 +136,7 @@ async function formatFile(filePath: string, check: boolean) { ) { isInsideQuery = false; let endedWithComma = builtQuery.trimEnd().endsWith(','); - modifiedFile += formatRustStringQuery(builtQuery).trimEnd(); + modifiedFile += formatRustStringQuery(builtQuery, isRawString).trimEnd(); modifiedFile += endedWithComma ? ',' : ''; modifiedFile += '\n'; } diff --git a/infrastructure/zk/src/hyperchain_wizard.ts b/infrastructure/zk/src/hyperchain_wizard.ts index 73e3f69d7a10..467304752dcd 100644 --- a/infrastructure/zk/src/hyperchain_wizard.ts +++ b/infrastructure/zk/src/hyperchain_wizard.ts @@ -43,9 +43,6 @@ export interface BasePromptOptions { skip?: ((state: object) => boolean | Promise) | boolean; } -// PLA:681 -let isLocalhost = false; - // An init command that allows configuring and spinning up a new hyperchain network. async function initHyperchain() { await announced('Initializing hyperchain creation', setupConfiguration()); @@ -72,15 +69,6 @@ async function initHyperchain() { await init(initArgs); - // if we used matterlabs/geth network, we need custom ENV file for hyperchain compose parts - // This breaks `zk status prover` command, but neccessary for working in isolated docker-network - // TODO: Think about better implementation - // PLA:681 - if (isLocalhost) { - wrapEnvModify('ETH_CLIENT_WEB3_URL', 'http://geth:8545'); - wrapEnvModify('DATABASE_URL', 'postgres://postgres:notsecurepassword@postgres:5432/zksync_local'); - } - env.mergeInitToEnv(); console.log(announce(`\nYour hyperchain configuration is available at ${process.env.ENV_FILE}\n`)); @@ -262,8 +250,6 @@ async function setHyperchainMetadata() { feeReceiverAddress = keyResults.feeReceiver; } } else { - // PLA:681 - isLocalhost = true; l1Rpc = 'http://localhost:8545'; l1Id = 9; databaseUrl = 'postgres://postgres:notsecurepassword@localhost:5432/zksync_local'; @@ -619,6 +605,9 @@ type L1Token = { export function getTokens(network: string): L1Token[] { const configPath = `${process.env.ZKSYNC_HOME}/etc/tokens/${network}.json`; + if (!fs.existsSync(configPath)) { + return []; + } try { return JSON.parse( fs.readFileSync(configPath, { @@ -785,7 +774,7 @@ async function configDemoHyperchain(cmd: Command) { const deployerPrivateKey = process.env.DEPLOYER_PRIVATE_KEY; const governorPrivateKey = process.env.GOVERNOR_PRIVATE_KEY; const deployL2Weth = Boolean(process.env.DEPLOY_L2_WETH || false); - const deployTestTokens = Boolean(process.env.DEPLOY_TEST_TOKENS || false); + const deployTestTokens = Boolean(process.env.DEPLOY_TEST_TOKENS || true); const initArgs: InitArgs = { skipSubmodulesCheckout: false, diff --git a/infrastructure/zk/src/index.ts b/infrastructure/zk/src/index.ts index 5d65df824d71..f0c838adcd35 100644 --- a/infrastructure/zk/src/index.ts +++ b/infrastructure/zk/src/index.ts @@ -22,6 +22,8 @@ import { command as db } from './database'; import { command as verifyUpgrade } from './verify-upgrade'; import { proverCommand } from './prover_setup'; import { command as status } from './status'; +import { command as spellcheck } from './spellcheck'; +import { command as linkcheck } from './linkcheck'; import * as env from './env'; const COMMANDS = [ @@ -48,6 +50,8 @@ const COMMANDS = [ proverCommand, env.command, status, + spellcheck, + linkcheck, completion(program as Command) ]; diff --git a/infrastructure/zk/src/init.ts b/infrastructure/zk/src/init.ts index a04111395a74..b42de59a475c 100644 --- a/infrastructure/zk/src/init.ts +++ b/infrastructure/zk/src/init.ts @@ -46,7 +46,6 @@ export async function init(initArgs: InitArgs = DEFAULT_ARGS) { await announced('Running server genesis setup', server.genesisFromSources()); await announced('Deploying L1 contracts', contract.redeployL1(governorPrivateKeyArgs)); await announced('Initializing validator', contract.initializeValidator(governorPrivateKeyArgs)); - await announced('Initialize L1 allow list', contract.initializeL1AllowList(governorPrivateKeyArgs)); await announced( 'Deploying L2 contracts', contract.deployL2( @@ -59,13 +58,7 @@ export async function init(initArgs: InitArgs = DEFAULT_ARGS) { if (deployerL2ContractInput.includeL2WETH) { await announced('Initializing L2 WETH token', contract.initializeWethToken(governorPrivateKeyArgs)); } - await announced( - 'Initializing governance', - contract.initializeGovernance([ - ...governorPrivateKeyArgs, - !deployerL2ContractInput.includeL2WETH ? ['--skip-weth-bridge'] : [] - ]) - ); + await announced('Initializing governance', contract.initializeGovernance(governorPrivateKeyArgs)); } // A smaller version of `init` that "resets" the localhost environment, for which `init` was already called before. @@ -83,7 +76,6 @@ export async function reinit() { await announced('Reloading env', env.reload()); await announced('Running server genesis setup', server.genesisFromSources()); await announced('Deploying L1 contracts', contract.redeployL1([])); - await announced('Initializing L1 Allow list', contract.initializeL1AllowList()); await announced('Deploying L2 contracts', contract.deployL2([], true, true)); await announced('Initializing L2 WETH token', contract.initializeWethToken()); await announced('Initializing governance', contract.initializeGovernance()); @@ -97,9 +89,9 @@ export async function lightweightInit() { await announced('Deploying L1 verifier', contract.deployVerifier([])); await announced('Reloading env', env.reload()); await announced('Running server genesis setup', server.genesisFromBinary()); + await announced('Deploying localhost ERC20 tokens', run.deployERC20('dev', '', '', '', [])); await announced('Deploying L1 contracts', contract.redeployL1([])); await announced('Initializing validator', contract.initializeValidator()); - await announced('Initializing L1 Allow list', contract.initializeL1AllowList()); await announced('Deploying L2 contracts', contract.deployL2([], true, false)); await announced('Initializing governance', contract.initializeGovernance()); } diff --git a/infrastructure/zk/src/linkcheck.ts b/infrastructure/zk/src/linkcheck.ts new file mode 100644 index 000000000000..08db322d079e --- /dev/null +++ b/infrastructure/zk/src/linkcheck.ts @@ -0,0 +1,25 @@ +import { Command } from 'commander'; +import * as utils from './utils'; + +export async function runMarkdownLinkCheck(configPath: string) { + // Command line usage for markdown-link-check suggests using find and xargs for + // recursive checks. See: `https://github.com/tcort/markdown-link-check?tab=readme-ov-file#check-links-from-a-local-markdown-folder-recursive` + const findCommand = `find . -name "*.md" ! -path "*/node_modules/*" ! -path "*/target/release/*" ! -path "*/build/*" ! -path "*/contracts/*" -print0`; + const markdownLinkCheckCommand = `xargs -0 -n1 markdown-link-check --config ${configPath}`; + const fullCommand = `${findCommand} | ${markdownLinkCheckCommand}`; + + try { + await utils.spawn(fullCommand); + console.log('Markdown link check completed successfully'); + } catch (error) { + console.error('Error occurred during markdown link checking:', error); + process.exit(1); + } +} + +export const command = new Command('linkcheck') + .option('--config ', 'Path to configuration file', './checks-config/links.json') + .description('Run markdown link check on specified files') + .action((cmd) => { + runMarkdownLinkCheck(cmd.config); + }); diff --git a/infrastructure/zk/src/lint.ts b/infrastructure/zk/src/lint.ts index fc83655b48fc..4b7ed461dc48 100644 --- a/infrastructure/zk/src/lint.ts +++ b/infrastructure/zk/src/lint.ts @@ -30,12 +30,12 @@ async function lintContracts(check: boolean = false) { async function clippy() { process.chdir(process.env.ZKSYNC_HOME!); - await utils.spawn('cargo clippy --tests -- -D warnings'); + await utils.spawn('cargo clippy --tests --locked -- -D warnings -D unstable_features'); } async function proverClippy() { process.chdir(process.env.ZKSYNC_HOME! + '/prover'); - await utils.spawn('cargo clippy --tests -- -D warnings -A incomplete_features'); + await utils.spawn('cargo clippy --tests --locked -- -D warnings -A incomplete_features'); } const ARGS = [...EXTENSIONS, 'rust', 'prover', 'contracts']; diff --git a/infrastructure/zk/src/run/run.ts b/infrastructure/zk/src/run/run.ts index e4132e64b204..a8044e75b1ec 100644 --- a/infrastructure/zk/src/run/run.ts +++ b/infrastructure/zk/src/run/run.ts @@ -56,7 +56,7 @@ export async function tokenInfo(address: string) { // installs all dependencies export async function yarn() { - await utils.spawn('yarn'); + await utils.spawn('yarn install --frozen-lockfile'); } export async function deployTestkit(genesisRoot: string) { @@ -113,12 +113,6 @@ export async function readVariable(address: string, contractName: string, variab ); } -export async function cross_en_checker() { - let logLevel = 'RUST_LOG=cross_external_nodes_checker=debug'; - let suffix = 'cargo run --release --bin cross_external_nodes_checker'; - await utils.spawn(`${logLevel} ${suffix}`); -} - export async function snapshots_creator() { process.chdir(`${process.env.ZKSYNC_HOME}`); let logLevel = 'RUST_LOG=snapshots_creator=debug'; @@ -127,7 +121,7 @@ export async function snapshots_creator() { export const command = new Command('run').description('run miscellaneous applications').addCommand(dataRestore.command); command.command('test-accounts').description('print ethereum test accounts').action(testAccounts); -command.command('yarn').description('install all JS dependencies').action(yarn); +command.command('yarn install --frozen-lockfile').description('install all JS dependencies').action(yarn); command.command('cat-logs [exit_code]').description('print server and prover logs').action(catLogs); command @@ -194,107 +188,3 @@ command }); command.command('snapshots-creator').action(snapshots_creator); - -command - .command('cross-en-checker') - .description('run the cross external nodes checker. See Checker Readme the default run mode and configuration.') - .option( - '--mode ', - '`Rpc` to run only the RPC checker; `PubSub` to run only the PubSub checker; `All` to run both.' - ) - .option( - '--env ', - `Provide the env the checker will test in to use the default urls for that env. 'Local', 'Stage, 'Testnet', or 'Mainnet'` - ) - .option('--main_node_http_url ', 'Manually provide the HTTP URL of the main node') - .option('--instances_http_urls ', 'Manually provide the HTTP URLs of the instances to check') - .option('--main_node_ws_url ', 'Manually provide the WS URL of the main node') - .option('--instances_ws_urls ', 'Manually provide the WS URLs of the instances to check') - .option( - '--rpc_mode ', - 'The mode to run the RPC checker in. `Triggered` to run once; `Continuous` to run forever.' - ) - .option( - '--start_miniblock ', - 'Check all miniblocks starting from this. If not set, then check from genesis. Inclusive.' - ) - .option( - '--finish_miniblock ', - 'For Triggered mode. If not set, then check all available miniblocks. Inclusive.' - ) - .option( - '--max_transactions_to_check ', - 'The maximum number of transactions to be checked at random in each miniblock.' - ) - .option( - '--instance_poll_period ', - 'For RPC mode. In seconds, how often to poll the instance node for new miniblocks.' - ) - .option( - '--subscription_duration ', - 'For PubSub mode. Time in seconds for a subscription to be active. If not set, then the subscription will run forever.' - ) - .action(async (cmd: Command) => { - interface Environment { - httpMain: string; - httpInstances: string; - wsMain: string; - wsInstances: string; - } - - const nodeUrls: Record = { - Local: { - httpMain: 'http://127.0.0.1:3050', - httpInstances: 'http://127.0.0.1:3060', - wsMain: 'ws://127.0.0.1:3051', - wsInstances: 'ws://127.0.0.1:3061' - }, - Stage: { - httpMain: 'https://z2-dev-api.zksync.dev:443', - httpInstances: 'https://external-node-dev.zksync.dev:443', - wsMain: 'wss://z2-dev-api.zksync.dev:443/ws', - wsInstances: 'wss://external-node-dev.zksync.dev:443/ws' - }, - Testnet: { - httpMain: 'https://zksync2-testnet.zksync.dev:443', - httpInstances: 'https://external-node-testnet.zksync.dev:443', - wsMain: 'wss://zksync2-testnet.zksync.dev:443/ws', - wsInstances: 'wss://external-node-testnet.zksync.dev:443/ws' - }, - Mainnet: { - httpMain: 'https://zksync2-mainnet.zksync.io:443', - httpInstances: 'https://external-node-mainnet.zksync.dev:443', - wsMain: 'wss://zksync2-mainnet.zksync.io:443/ws', - wsInstances: 'wss://external-node-mainnet.zksync.dev:443/ws' - } - }; - - if (cmd.env && nodeUrls[cmd.env]) { - process.env.CHECKER_MAIN_NODE_HTTP_URL = nodeUrls[cmd.env].httpMain; - process.env.CHECKER_INSTANCES_HTTP_URLS = nodeUrls[cmd.env].httpInstances; - process.env.CHECKER_MAIN_NODE_WS_URL = nodeUrls[cmd.env].wsMain; - process.env.CHECKER_INSTANCES_WS_URLS = nodeUrls[cmd.env].wsInstances; - } - - const envVarMap = { - mode: 'CHECKER_MODE', - rpc_mode: 'CHECKER_RPC_MODE', - main_node_http_url: 'CHECKER_MAIN_NODE_HTTP_URL', - instances_http_urls: 'CHECKER_INSTANCES_HTTP_URLS', - main_node_ws_url: 'CHECKER_MAIN_NODE_WS_URL', - instances_ws_urls: 'CHECKER_INSTANCES_WS_URLS', - start_miniblock: 'CHECKER_START_MINIBLOCK', - finish_miniblock: 'CHECKER_FINISH_MINIBLOCK', - max_transactions_to_check: 'CHECKER_MAX_TRANSACTIONS_TO_CHECK', - instance_poll_period: 'CHECKER_INSTANCE_POLL_PERIOD', - subscription_duration: 'CHECKER_SUBSCRIPTION_DURATION' - }; - - for (const [cmdOption, envVar] of Object.entries(envVarMap)) { - if (cmd[cmdOption]) { - process.env[envVar] = cmd[cmdOption]; - } - } - - await cross_en_checker(); - }); diff --git a/infrastructure/zk/src/server.ts b/infrastructure/zk/src/server.ts index e7ae689057f9..52b3e66c7449 100644 --- a/infrastructure/zk/src/server.ts +++ b/infrastructure/zk/src/server.ts @@ -25,7 +25,7 @@ export async function server(rebuildTree: boolean, uring: boolean, components?: await utils.spawn(`cargo run --bin zksync_server --release ${options}`); } -export async function externalNode(reinit: boolean = false) { +export async function externalNode(reinit: boolean = false, enableConsensus: boolean = false) { if (process.env.ZKSYNC_ENV != 'ext-node') { console.warn(`WARNING: using ${process.env.ZKSYNC_ENV} environment for external node`); console.warn('If this is a mistake, set $ZKSYNC_ENV to "ext-node" or other environment'); @@ -45,7 +45,11 @@ export async function externalNode(reinit: boolean = false) { clean(path.dirname(process.env.EN_MERKLE_TREE_PATH!)); } - await utils.spawn('cargo run --release --bin zksync_external_node'); + let options = ''; + if (enableConsensus) { + options += ' --enable-consensus'; + } + await utils.spawn(`cargo run --release --bin zksync_external_node -- ${options}`); } async function create_genesis(cmd: string) { @@ -135,6 +139,7 @@ export const serverCommand = new Command('server') export const enCommand = new Command('external-node') .description('start zksync external node') .option('--reinit', 'reset postgres and rocksdb before starting') + .option('--enable-consensus', 'enables consensus component') .action(async (cmd: Command) => { - await externalNode(cmd.reinit); + await externalNode(cmd.reinit, cmd.enableConsensus); }); diff --git a/infrastructure/zk/src/spellcheck.ts b/infrastructure/zk/src/spellcheck.ts new file mode 100644 index 000000000000..4f6553e2c654 --- /dev/null +++ b/infrastructure/zk/src/spellcheck.ts @@ -0,0 +1,44 @@ +import { Command } from 'commander'; +import * as utils from './utils'; + +export async function runSpellCheck(pattern: string, useCargo: boolean, useCSpell: boolean) { + // Default commands for cSpell and cargo spellcheck + const cSpellCommand = `cspell "${pattern}" --config=./checks-config/cspell.json`; + const cargoCommand = `cargo spellcheck --cfg=./checks-config/era.cfg --code 1`; + // Necessary to run cargo spellcheck in the prover directory explicitly as + // it is not included in the root cargo.toml file + const cargoCommandForProver = `cargo spellcheck --cfg=../checks-config/era.cfg --code 1`; + + try { + let results = []; + + // Run cspell over all **/*.md files + if (useCSpell || (!useCargo && !useCSpell)) { + results.push(await utils.spawn(cSpellCommand)); + } + + // Run cargo spellcheck in core and prover directories + if (useCargo || (!useCargo && !useCSpell)) { + results.push(await utils.spawn(cargoCommand)); + results.push(await utils.spawn('cd prover && ' + cargoCommandForProver)); + } + + // Check results and exit with error code if any command failed + if (results.some((code) => code !== 0)) { + console.error('Spell check failed'); + process.exit(1); + } + } catch (error) { + console.error('Error occurred during spell checking:', error); + process.exit(1); + } +} + +export const command = new Command('spellcheck') + .option('--pattern ', 'Glob pattern for files to check', '**/*.md') + .option('--use-cargo', 'Use cargo spellcheck') + .option('--use-cspell', 'Use cspell') + .description('Run spell check on specified files') + .action((cmd) => { + runSpellCheck(cmd.pattern, cmd.useCargo, cmd.useCSpell); + }); diff --git a/infrastructure/zk/src/status.ts b/infrastructure/zk/src/status.ts index 0763355248dc..3727dc383a1c 100644 --- a/infrastructure/zk/src/status.ts +++ b/infrastructure/zk/src/status.ts @@ -176,7 +176,7 @@ const greenStart = '\x1b[32m'; const resetColor = '\x1b[0m'; export async function statusProver() { - console.log('==== FRI Prover status ===='); + console.log('==== FRI Prover Status ===='); pool = new Pool({ connectionString: process.env.DATABASE_URL }); @@ -184,20 +184,21 @@ export async function statusProver() { console.log(`${redStart}Can only show status for FRI provers.${resetColor}`); return; } + // Fetch the first and most recent sealed batch numbers const stateKeeperStatus = (await queryAndReturnRows('select min(number), max(number) from l1_batches'))[0]; console.log(`State keeper: First batch: ${stateKeeperStatus['min']}, recent batch: ${stateKeeperStatus['max']}`); - const [blockCommited, blockVerified] = await getL1ValidatorStatus(); - console.log(`L1 state: block verified: ${blockVerified}, block committed: ${blockCommited}`); + const [blockCommitted, blockVerified] = await getL1ValidatorStatus(); + console.log(`L1 state: block verified: ${blockVerified}, block committed: ${blockCommitted}`); - assert(blockCommited >= 0); - assert(blockCommited <= stateKeeperStatus['max']); + assert(blockCommitted >= 0); + assert(blockCommitted <= stateKeeperStatus['max']); - if (blockCommited < stateKeeperStatus['max']) { + const ethSenderLag = stateKeeperStatus['max'] - blockCommitted; + if (ethSenderLag > 0) { console.log( - `${redStart}Eth sender is behind - block commited ${blockCommited} is smaller than most recent state keeper batch ${stateKeeperStatus['max']}.${resetColor}` + `${redStart}Eth sender is ${ethSenderLag} behind. Last block committed: ${blockCommitted}. Most recent sealed state keeper batch: ${stateKeeperStatus['max']}.${resetColor}` ); - return; } await compareVerificationKeys(); await compareVerificationParams(); diff --git a/infrastructure/zk/src/test/test.ts b/infrastructure/zk/src/test/test.ts index 7bcdd813514b..b5c7f28f5d03 100644 --- a/infrastructure/zk/src/test/test.ts +++ b/infrastructure/zk/src/test/test.ts @@ -12,7 +12,7 @@ export async function l1Contracts() { export async function prover() { process.chdir(process.env.ZKSYNC_HOME! + '/prover'); - await utils.spawn('cargo test --release --workspace'); + await utils.spawn('cargo test --release --workspace --locked'); } export async function js() { diff --git a/infrastructure/zk/src/up.ts b/infrastructure/zk/src/up.ts index de0ef41cf8c7..5cfed342669c 100644 --- a/infrastructure/zk/src/up.ts +++ b/infrastructure/zk/src/up.ts @@ -44,7 +44,7 @@ export async function up(composeFile?: string) { export const command = new Command('up') .description('start development containers') - .option('--docker-file', 'path to a custom docker file') + .option('--docker-file ', 'path to a custom docker file') .action(async (cmd) => { await up(cmd.dockerFile); }); diff --git a/infrastructure/zk/src/utils.ts b/infrastructure/zk/src/utils.ts index 47f843fa3bad..777eec2a2141 100644 --- a/infrastructure/zk/src/utils.ts +++ b/infrastructure/zk/src/utils.ts @@ -22,7 +22,8 @@ const IGNORED_DIRS = [ 'binaryen', 'system-contracts', 'artifacts-zk', - 'cache-zk' + 'cache-zk', + 'contracts/l1-contracts/lib' ]; const IGNORED_FILES = ['KeysWithPlonkVerifier.sol', 'TokenInit.sol', '.tslintrc.js']; diff --git a/prover/CHANGELOG.md b/prover/CHANGELOG.md index d574826f6305..90033112e96e 100644 --- a/prover/CHANGELOG.md +++ b/prover/CHANGELOG.md @@ -1,5 +1,46 @@ # Changelog +## [11.0.0](https://github.com/matter-labs/zksync-era/compare/prover-v10.1.0...prover-v11.0.0) (2024-01-29) + + +### ⚠ BREAKING CHANGES + +* **vm:** fee model updates + 1.4.1 ([#791](https://github.com/matter-labs/zksync-era/issues/791)) + +### Features + +* **api:** Make Web3 API server work with pruned data ([#838](https://github.com/matter-labs/zksync-era/issues/838)) ([0b7cd0b](https://github.com/matter-labs/zksync-era/commit/0b7cd0b50ead2406915528becad2fac8b7e48f85)) +* consensus component config for main node and external node ([#881](https://github.com/matter-labs/zksync-era/issues/881)) ([1aed8de](https://github.com/matter-labs/zksync-era/commit/1aed8de0f1651686bf9e9f8aa7dc9ba15625cc42)) +* **en:** Restore state keeper storage from snapshot ([#885](https://github.com/matter-labs/zksync-era/issues/885)) ([a9553b5](https://github.com/matter-labs/zksync-era/commit/a9553b537a857a6f6a755cd700da4c096c1f80f0)) +* fee model updates + 1.4.1 stage upgrade ([#897](https://github.com/matter-labs/zksync-era/issues/897)) ([fa48c13](https://github.com/matter-labs/zksync-era/commit/fa48c13da0cfa20117f68c51c243ee3738184408)) +* protobuf-generated json configs for the main node (BFT-371) ([#458](https://github.com/matter-labs/zksync-era/issues/458)) ([f938314](https://github.com/matter-labs/zksync-era/commit/f9383143b4f1f0c18af658980bae8ec93b6b588f)) +* Remove zkevm_test_harness public reexport from zksync_types ([#929](https://github.com/matter-labs/zksync-era/issues/929)) ([dd1a35e](https://github.com/matter-labs/zksync-era/commit/dd1a35eec006b40db66da73e6fa3d8963efb7d60)) +* **state-keeper:** circuits seal criterion ([#729](https://github.com/matter-labs/zksync-era/issues/729)) ([c4a86bb](https://github.com/matter-labs/zksync-era/commit/c4a86bbbc5697b5391a517299bbd7a5e882a7314)) +* **vm:** fee model updates + 1.4.1 ([#791](https://github.com/matter-labs/zksync-era/issues/791)) ([3564aff](https://github.com/matter-labs/zksync-era/commit/3564affbb246c87d668ea2ec74809384bc9d621f)) + + +### Bug Fixes + +* address issue with spellchecker not checking against prover workspace ([#855](https://github.com/matter-labs/zksync-era/issues/855)) ([4f55926](https://github.com/matter-labs/zksync-era/commit/4f55926f48aaec3f43322594626148af0a0358dd)) +* addresses broken links in preparation for ci link check ([#869](https://github.com/matter-labs/zksync-era/issues/869)) ([a78d03c](https://github.com/matter-labs/zksync-era/commit/a78d03cc53d0097f6be892de65a2c35bd7f1baa3)) +* **prover:** Update shivini ([#915](https://github.com/matter-labs/zksync-era/issues/915)) ([f141a00](https://github.com/matter-labs/zksync-era/commit/f141a00cd25ae5e5d2a054aa4ecda544a2abbbd7)) +* **witness-generator:** Update era-zkevm_test_harness ([#912](https://github.com/matter-labs/zksync-era/issues/912)) ([c03c2e3](https://github.com/matter-labs/zksync-era/commit/c03c2e3df71b5737cbdae889c8330511345c52c2)) +* **witness-generator:** Update zkevm_test_harness ([#930](https://github.com/matter-labs/zksync-era/issues/930)) ([16fdcff](https://github.com/matter-labs/zksync-era/commit/16fdcffc67274f30a4a254c26b8969f4928918bc)) + +## [10.1.0](https://github.com/matter-labs/zksync-era/compare/prover-v10.0.2...prover-v10.1.0) (2024-01-05) + + +### Features + +* **prover:** Remove circuit-synthesizer ([#801](https://github.com/matter-labs/zksync-era/issues/801)) ([1426b1b](https://github.com/matter-labs/zksync-era/commit/1426b1ba3c8b700e0531087b781ced0756c12e3c)) +* **prover:** Remove old prover ([#810](https://github.com/matter-labs/zksync-era/issues/810)) ([8be1925](https://github.com/matter-labs/zksync-era/commit/8be1925b18dcbf268eb03b8ea5f07adfd5330876)) + + +### Bug Fixes + +* **prover:** increase DB polling interval for witness vector generators ([#697](https://github.com/matter-labs/zksync-era/issues/697)) ([94579cc](https://github.com/matter-labs/zksync-era/commit/94579cc524514cb867843336cd9787db1b6b99d3)) +* **prover:** Remove prover-utils from core ([#819](https://github.com/matter-labs/zksync-era/issues/819)) ([2ceb911](https://github.com/matter-labs/zksync-era/commit/2ceb9114659f4c4583c87b1bbc8ee230eb1c44db)) + ## [10.0.2](https://github.com/matter-labs/zksync-era/compare/prover-v10.0.1...prover-v10.0.2) (2023-12-21) diff --git a/prover/Cargo.lock b/prover/Cargo.lock index ab02881990f0..9363db75dbed 100644 --- a/prover/Cargo.lock +++ b/prover/Cargo.lock @@ -28,67 +28,25 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aes" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" -dependencies = [ - "aes-soft", - "aesni", - "cipher", -] - -[[package]] -name = "aes-ctr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7729c3cde54d67063be556aeac75a81330d802f0259500ca40cb52967f975763" -dependencies = [ - "aes-soft", - "aesni", - "cipher", - "ctr", -] - -[[package]] -name = "aes-soft" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" -dependencies = [ - "cipher", - "opaque-debug", -] - -[[package]] -name = "aesni" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" -dependencies = [ - "cipher", - "opaque-debug", -] - [[package]] name = "ahash" version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" dependencies = [ - "getrandom 0.2.11", + "getrandom", "once_cell", "version_check", ] [[package]] name = "ahash" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" dependencies = [ "cfg-if 1.0.0", + "getrandom", "once_cell", "version_check", "zerocopy", @@ -103,6 +61,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -141,21 +105,9 @@ checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" - -[[package]] -name = "api" -version = "0.1.0" -source = "git+https://github.com/matter-labs/era-heavy-ops-service.git?branch=v1.3.3#ac6a3af6415dc12c9ae2932fa5ad906939023d82" -dependencies = [ - "bellman_ce 0.3.2 (git+https://github.com/matter-labs/bellman?branch=dev)", - "cfg-if 1.0.0", - "gpu-prover", - "num_cpus", - "serde", -] +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" [[package]] name = "arr_macro" @@ -174,7 +126,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0609c78bd572f4edc74310dfb63a01f5609d53fa8b4dd7c4d98aef3b3e8d72d1" dependencies = [ "proc-macro-hack", - "quote 1.0.33", + "quote 1.0.35", "syn 1.0.109", ] @@ -222,31 +174,41 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] name = "atoi" -version = "0.4.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" dependencies = [ "num-traits", ] +[[package]] +name = "atomic-write-file" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436" +dependencies = [ + "nix", + "rand 0.8.5", +] + [[package]] name = "atty" version = "0.2.14" @@ -258,33 +220,12 @@ dependencies = [ "winapi", ] -[[package]] -name = "autocfg" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" -dependencies = [ - "autocfg 1.1.0", -] - [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "backon" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c1a6197b2120bb2185a267f6515038558b019e92b832bb0320e96d66268dcf9" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "pin-project", - "tokio", -] - [[package]] name = "backtrace" version = "0.3.69" @@ -306,6 +247,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.13.1" @@ -314,9 +261,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.5" +version = "0.21.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "c79fed4cdb43e993fcdadc7e58a09fd0e3e649c4436fa11da71c9f1f3ee7feb9" [[package]] name = "base64ct" @@ -342,7 +289,7 @@ dependencies = [ "byteorder", "cfg-if 1.0.0", "crossbeam 0.7.3", - "futures 0.3.29", + "futures 0.3.30", "hex", "lazy_static", "num_cpus", @@ -365,7 +312,7 @@ dependencies = [ "byteorder", "cfg-if 1.0.0", "crossbeam 0.7.3", - "futures 0.3.29", + "futures 0.3.30", "hex", "lazy_static", "num_cpus", @@ -378,11 +325,11 @@ dependencies = [ [[package]] name = "bigdecimal" -version = "0.2.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1e50562e37200edf7c6c43e54a08e64a5553bfb59d9c297d5572512aa517256" +checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" dependencies = [ - "num-bigint 0.3.3", + "num-bigint 0.4.4", "num-integer", "num-traits", "serde", @@ -397,29 +344,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bindgen" -version = "0.59.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" -dependencies = [ - "bitflags 1.3.2", - "cexpr", - "clang-sys", - "clap 2.34.0", - "env_logger 0.9.3", - "lazy_static", - "lazycell", - "log", - "peeking_take_while", - "proc-macro2 1.0.69", - "quote 1.0.33", - "regex", - "rustc-hash", - "shlex", - "which", -] - [[package]] name = "bindgen" version = "0.65.1" @@ -433,12 +357,12 @@ dependencies = [ "lazycell", "peeking_take_while", "prettyplease", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "regex", "rustc-hash", "shlex", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -455,12 +379,12 @@ dependencies = [ "log", "peeking_take_while", "prettyplease", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "regex", "rustc-hash", "shlex", - "syn 2.0.39", + "syn 2.0.48", "which", ] @@ -493,17 +417,8 @@ name = "bitflags" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" - -[[package]] -name = "bitvec" -version = "0.20.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7774144344a4faa177370406a7ff5f1da24303817368584c6206c8303eb07848" dependencies = [ - "funty 1.1.0", - "radium 0.6.2", - "tap", - "wyz 0.2.0", + "serde", ] [[package]] @@ -512,10 +427,10 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ - "funty 2.0.0", - "radium 0.7.0", + "funty", + "radium", "tap", - "wyz 0.5.1", + "wyz", ] [[package]] @@ -524,7 +439,7 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" dependencies = [ - "crypto-mac 0.8.0", + "crypto-mac", "digest 0.9.0", "opaque-debug", ] @@ -607,16 +522,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-modes" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a0e8073e8baa88212fb5823574c02ebccb395136ba9a164ab89379ec6072f0" -dependencies = [ - "block-padding", - "cipher", -] - [[package]] name = "block-padding" version = "0.2.1" @@ -638,18 +543,18 @@ dependencies = [ [[package]] name = "boojum" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-boojum?branch=main#84754b066959c8fdfb77edf730fc13ed87404907" +source = "git+https://github.com/matter-labs/era-boojum?branch=main#93b5e0f0dbff0a9b606d9025e207c8405c141bd9" dependencies = [ "arrayvec 0.7.4", "bincode", "blake2 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", "const_format", "convert_case 0.6.0", - "crossbeam 0.8.2", - "crypto-bigint 0.5.4", + "crossbeam 0.8.4", + "crypto-bigint 0.5.5", "cs_derive 0.1.0 (git+https://github.com/matter-labs/era-boojum?branch=main)", "derivative", - "ethereum-types 0.14.1", + "ethereum-types", "firestorm", "itertools 0.10.5", "lazy_static", @@ -670,16 +575,40 @@ dependencies = [ [[package]] name = "boojum-cuda" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-boojum-cuda?branch=main#6731d9a8d0c439a4fa3cde14b494c9eca642bb2e" +source = "git+https://github.com/matter-labs/era-boojum-cuda?branch=main#9df96d38a608b1aa78cd824d54112cd17b0d2537" dependencies = [ "boojum", "cmake", "cudart", "cudart-sys", - "itertools 0.11.0", + "itertools 0.12.0", "lazy_static", ] +[[package]] +name = "borsh" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f58b559fd6448c6e2fd0adb5720cd98a2506594cafa4737ff98c396f3e82f667" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aadb5b6ccbd078890f6d7003694e33816e6b784358f18e15e7e6d9f065a57cd" +dependencies = [ + "once_cell", + "proc-macro-crate 3.0.0", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", + "syn_derive", +] + [[package]] name = "bumpalo" version = "3.14.0" @@ -692,6 +621,28 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" +[[package]] +name = "bytecheck" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61" +dependencies = [ + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 1.0.109", +] + [[package]] name = "bytecount" version = "0.6.7" @@ -732,9 +683,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12024c4645c97566567129c204f65d5815a8c9aecf30fcbe682b2fe034996d36" +checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d" dependencies = [ "serde", ] @@ -760,10 +711,11 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.84" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f8e7c90afad890484a21653d08b6e209ae34770fb5ee298f9c699fcc1e5c856" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ + "jobserver", "libc", ] @@ -788,6 +740,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "chrono" version = "0.4.31" @@ -800,7 +758,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -831,26 +789,31 @@ dependencies = [ ] [[package]] -name = "cipher" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +name = "circuit_definitions" +version = "0.1.0" +source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.0#de2ecad62ac8c12777e576dca20311ad8ec770d1" dependencies = [ - "generic-array", + "crossbeam 0.8.4", + "derivative", + "seq-macro", + "serde", + "snark_wrapper", + "zk_evm 1.4.0", + "zkevm_circuits 1.4.0", ] [[package]] name = "circuit_definitions" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.0#d2e3670e0c5115b7cc7cc24e6d3dbdd17a214aad" +source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1#badf56d613b77c25f79b684c161eab7d1e385176" dependencies = [ - "crossbeam 0.8.2", + "crossbeam 0.8.4", "derivative", "seq-macro", "serde", "snark_wrapper", - "zk_evm 1.4.0", - "zkevm_circuits", + "zk_evm 1.4.1", + "zkevm_circuits 1.4.1", ] [[package]] @@ -863,9 +826,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" dependencies = [ "glob", "libc", @@ -889,18 +852,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.8" +version = "4.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" +checksum = "33e92c5c1a78c62968ec57dbc2440366a2d6e5a23faf829970ff1585dc6b18e2" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.4.8" +version = "4.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" +checksum = "f4323769dc8a61e2c39ad7dc26f6f2800524691a44d74fe3d1071a5c24db6370" dependencies = [ "anstyle", "clap_lex", @@ -912,15 +875,6 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "cmake" version = "0.1.50" @@ -930,22 +884,6 @@ dependencies = [ "cc", ] -[[package]] -name = "codegen" -version = "0.1.0" -source = "git+https://github.com/matter-labs/solidity_plonk_verifier.git?branch=dev#82f96b7156551087f1c9bfe4f0ea68845b6debfc" -dependencies = [ - "ethereum-types 0.14.1", - "franklin-crypto 0.0.5 (git+https://github.com/matter-labs/franklin-crypto?branch=dev)", - "handlebars", - "hex", - "paste", - "rescue_poseidon 0.4.1 (git+https://github.com/matter-labs/rescue-poseidon)", - "serde", - "serde_derive", - "serde_json", -] - [[package]] name = "codegen" version = "0.2.0" @@ -965,6 +903,11 @@ dependencies = [ "memchr", ] +[[package]] +name = "compile-fmt" +version = "0.1.0" +source = "git+https://github.com/slowli/compile-fmt.git?rev=c6a41c846c9a6f70cdba4b44c9f3922242ffcf12#c6a41c846c9a6f70cdba4b44c9f3922242ffcf12" + [[package]] name = "const-decoder" version = "0.3.0" @@ -973,9 +916,9 @@ checksum = "5241cd7938b1b415942e943ea96f615953d500b50347b505b0b507080bad5a6f" [[package]] name = "const-oid" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const_format" @@ -992,8 +935,8 @@ version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "unicode-xid 0.2.4", ] @@ -1020,9 +963,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -1030,33 +973,42 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "crc" -version = "2.1.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" dependencies = [ "crc-catalog", ] [[package]] name = "crc-catalog" -version = "1.1.1" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crc32fast" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if 1.0.0", +] [[package]] name = "criterion" @@ -1067,7 +1019,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.4.8", + "clap 4.4.14", "criterion-plot", "is-terminal", "itertools 0.10.5", @@ -1110,16 +1062,15 @@ dependencies = [ [[package]] name = "crossbeam" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" dependencies = [ - "cfg-if 1.0.0", - "crossbeam-channel 0.5.8", - "crossbeam-deque 0.8.3", - "crossbeam-epoch 0.9.15", - "crossbeam-queue 0.3.8", - "crossbeam-utils 0.8.16", + "crossbeam-channel 0.5.11", + "crossbeam-deque 0.8.5", + "crossbeam-epoch 0.9.18", + "crossbeam-queue 0.3.11", + "crossbeam-utils 0.8.19", ] [[package]] @@ -1134,12 +1085,11 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" dependencies = [ - "cfg-if 1.0.0", - "crossbeam-utils 0.8.16", + "crossbeam-utils 0.8.19", ] [[package]] @@ -1155,13 +1105,12 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if 1.0.0", - "crossbeam-epoch 0.9.15", - "crossbeam-utils 0.8.16", + "crossbeam-epoch 0.9.18", + "crossbeam-utils 0.8.19", ] [[package]] @@ -1170,26 +1119,22 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" dependencies = [ - "autocfg 1.1.0", + "autocfg", "cfg-if 0.1.10", "crossbeam-utils 0.7.2", "lazy_static", "maybe-uninit", - "memoffset 0.5.6", + "memoffset", "scopeguard", ] [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg 1.1.0", - "cfg-if 1.0.0", - "crossbeam-utils 0.8.16", - "memoffset 0.9.0", - "scopeguard", + "crossbeam-utils 0.8.19", ] [[package]] @@ -1205,12 +1150,11 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" dependencies = [ - "cfg-if 1.0.0", - "crossbeam-utils 0.8.16", + "crossbeam-utils 0.8.19", ] [[package]] @@ -1219,19 +1163,16 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ - "autocfg 1.1.0", + "autocfg", "cfg-if 0.1.10", "lazy_static", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if 1.0.0", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crunchy" @@ -1253,12 +1194,14 @@ dependencies = [ [[package]] name = "crypto-bigint" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28f85c3514d2a6e64160359b45a3918c3b4178bcbf4ae5d03ab2d02e521c479a" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ + "generic-array", "rand_core 0.6.4", "subtle", + "zeroize", ] [[package]] @@ -1281,24 +1224,14 @@ dependencies = [ "subtle", ] -[[package]] -name = "crypto-mac" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "cs_derive" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-boojum?branch=main#84754b066959c8fdfb77edf730fc13ed87404907" +source = "git+https://github.com/matter-labs/era-boojum?branch=main#93b5e0f0dbff0a9b606d9025e207c8405c141bd9" dependencies = [ "proc-macro-error", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "syn 1.0.109", ] @@ -1308,50 +1241,72 @@ version = "0.1.0" source = "git+https://github.com/matter-labs/era-sync_vm.git?branch=v1.3.3#ed8ab8984cae05d00d9d62196753c8d40df47c7d" dependencies = [ "proc-macro-error", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "serde", "syn 1.0.109", ] -[[package]] -name = "ctr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" -dependencies = [ - "cipher", -] - [[package]] name = "ctrlc" -version = "3.4.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf" +checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b" dependencies = [ "nix", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "cudart" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-cuda?branch=main#492f2afad93ad156ac0cfb69e6efbfc03a7a2652" +source = "git+https://github.com/matter-labs/era-cuda?branch=main#59a4e62e5264d01e84f4ac9d85541bc3e661e9f0" dependencies = [ "bitflags 2.4.1", "criterion", "cudart-sys", + "paste", ] [[package]] name = "cudart-sys" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-cuda?branch=main#492f2afad93ad156ac0cfb69e6efbfc03a7a2652" +source = "git+https://github.com/matter-labs/era-cuda?branch=main#59a4e62e5264d01e84f4ac9d85541bc3e661e9f0" dependencies = [ "bindgen 0.69.1", "serde_json", ] +[[package]] +name = "curl" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22" +dependencies = [ + "curl-sys", + "libc", + "openssl-probe", + "openssl-sys", + "schannel", + "socket2 0.4.10", + "winapi", +] + +[[package]] +name = "curl-sys" +version = "0.4.70+curl-8.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c0333d8849afe78a4c8102a429a446bfdd055832af071945520e835ae2d841e" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", + "windows-sys 0.48.0", +] + [[package]] name = "curve25519-dalek" version = "4.1.1" @@ -1375,9 +1330,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -1398,8 +1353,8 @@ checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "strsim 0.10.0", "syn 1.0.109", ] @@ -1411,7 +1366,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core", - "quote 1.0.33", + "quote 1.0.35", "syn 1.0.109", ] @@ -1422,10 +1377,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if 1.0.0", - "hashbrown 0.14.2", + "hashbrown 0.14.3", "lock_api", "once_cell", - "parking_lot_core 0.9.9", + "parking_lot_core", ] [[package]] @@ -1461,9 +1416,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", "serde", @@ -1475,8 +1430,8 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "syn 1.0.109", ] @@ -1487,8 +1442,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "convert_case 0.4.0", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "rustc_version", "syn 1.0.109", ] @@ -1509,39 +1464,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", + "const-oid", "crypto-common", "subtle", ] [[package]] -name = "dirs" -version = "4.0.0" +name = "dotenvy" +version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" -dependencies = [ - "dirs-sys", -] +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "dotenv" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" - -[[package]] -name = "dtoa" -version = "1.0.9" +name = "dtoa" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" @@ -1552,11 +1488,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" dependencies = [ "der 0.6.1", - "elliptic-curve", - "rfc6979", + "elliptic-curve 0.12.3", + "rfc6979 0.3.1", "signature 1.6.4", ] +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der 0.7.8", + "digest 0.10.7", + "elliptic-curve 0.13.8", + "rfc6979 0.4.0", + "signature 2.2.0", + "spki 0.7.3", +] + [[package]] name = "ed25519" version = "2.2.3" @@ -1597,25 +1547,44 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" dependencies = [ - "base16ct", + "base16ct 0.1.1", "crypto-bigint 0.4.9", "der 0.6.1", "digest 0.10.7", - "ff", + "ff 0.12.1", "generic-array", - "group", + "group 0.12.1", "pkcs8 0.9.0", "rand_core 0.6.4", - "sec1", + "sec1 0.3.0", + "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct 0.2.0", + "crypto-bigint 0.5.5", + "digest 0.10.7", + "ff 0.13.0", + "generic-array", + "group 0.13.0", + "pkcs8 0.10.2", + "rand_core 0.6.4", + "sec1 0.7.3", "subtle", "zeroize", ] [[package]] name = "elsa" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714f766f3556b44e7e4776ad133fcc3445a489517c25c704ace411bb14790194" +checksum = "d98e71ae4df57d214182a2e5cb90230c0192c6ddfcaa05c36453d46a54713e10" dependencies = [ "stable_deref_trait", ] @@ -1648,11 +1617,7 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" dependencies = [ - "humantime", - "is-terminal", "log", - "regex", - "termcolor", ] [[package]] @@ -1672,12 +1637,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.6" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -1689,13 +1654,24 @@ dependencies = [ "version_check", ] +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if 1.0.0", + "home", + "windows-sys 0.48.0", +] + [[package]] name = "ethabi" version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" dependencies = [ - "ethereum-types 0.14.1", + "ethereum-types", "hex", "once_cell", "regex", @@ -1706,19 +1682,6 @@ dependencies = [ "uint", ] -[[package]] -name = "ethbloom" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb684ac8fa8f6c5759f788862bb22ec6fe3cb392f6bfd08e3c64b603661e3f8" -dependencies = [ - "crunchy", - "fixed-hash 0.7.0", - "impl-rlp", - "impl-serde 0.3.2", - "tiny-keccak 2.0.2", -] - [[package]] name = "ethbloom" version = "0.13.0" @@ -1726,37 +1689,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" dependencies = [ "crunchy", - "fixed-hash 0.8.0", + "fixed-hash", "impl-rlp", - "impl-serde 0.4.0", + "impl-serde", "tiny-keccak 2.0.2", ] -[[package]] -name = "ethereum-types" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05136f7057fe789f06e6d41d07b34e6f70d8c86e5693b60f97aaa6553553bdaf" -dependencies = [ - "ethbloom 0.11.1", - "fixed-hash 0.7.0", - "impl-rlp", - "impl-serde 0.3.2", - "primitive-types 0.10.1", - "uint", -] - [[package]] name = "ethereum-types" version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" dependencies = [ - "ethbloom 0.13.0", - "fixed-hash 0.8.0", + "ethbloom", + "fixed-hash", "impl-rlp", - "impl-serde 0.4.0", - "primitive-types 0.12.2", + "impl-serde", + "primitive-types", "uint", ] @@ -1766,15 +1715,6 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - [[package]] name = "fastrand" version = "2.0.1" @@ -1791,6 +1731,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "ff_ce" version = "0.14.3" @@ -1813,8 +1763,8 @@ dependencies = [ "num-bigint 0.4.4", "num-integer", "num-traits", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "serde", "syn 1.0.109", ] @@ -1849,18 +1799,6 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c5f6c2c942da57e2aaaa84b8a521489486f14e75e7fa91dab70aba913975f98" -[[package]] -name = "fixed-hash" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" -dependencies = [ - "byteorder", - "rand 0.8.5", - "rustc-hex", - "static_assertions", -] - [[package]] name = "fixed-hash" version = "0.8.0" @@ -1879,6 +1817,27 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "futures-core", + "futures-sink", + "spin 0.9.8", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1902,9 +1861,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -1942,7 +1901,7 @@ dependencies = [ [[package]] name = "franklin-crypto" version = "0.0.5" -source = "git+https://github.com/matter-labs/franklin-crypto?branch=snark_wrapper#a9e29acd73245bd3b670b62b4d481ece06d43803" +source = "git+https://github.com/matter-labs/franklin-crypto?branch=snark_wrapper#2546c63b91b59bdb0ad342d26f03fb57477550b2" dependencies = [ "arr_macro", "bellman_ce 0.3.2 (git+https://github.com/matter-labs/bellman?branch=snark-wrapper)", @@ -1977,12 +1936,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -[[package]] -name = "funty" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" - [[package]] name = "funty" version = "2.0.0" @@ -1997,9 +1950,9 @@ checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" [[package]] name = "futures" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -2012,9 +1965,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -2022,15 +1975,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -2040,54 +1993,43 @@ dependencies = [ [[package]] name = "futures-intrusive" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604f7a68fbf8103337523b1fadc8ade7361ee3f112f7c680ad179651616aed5" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" dependencies = [ "futures-core", "lock_api", - "parking_lot 0.11.2", + "parking_lot", ] [[package]] name = "futures-io" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" - -[[package]] -name = "futures-locks" -version = "0.7.1" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" -dependencies = [ - "futures-channel", - "futures-task", - "tokio", -] +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] name = "futures-sink" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-timer" @@ -2097,9 +2039,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures 0.1.31", "futures-channel", @@ -2122,35 +2064,25 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "gimli" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "glob" @@ -2165,7 +2097,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1087f1fbd2dd3f58c17c7574ddd99cd61cbbbc2c4dc81114b8687209b196cb" dependencies = [ "async-trait", - "base64 0.21.5", + "base64 0.21.6", "google-cloud-metadata", "google-cloud-token", "home", @@ -2199,7 +2131,7 @@ checksum = "ac04b29849ebdeb9fb008988cc1c4d1f0c9d121b4c7f1ddeb8061df124580e93" dependencies = [ "async-stream", "async-trait", - "base64 0.21.5", + "base64 0.21.6", "bytes", "futures-util", "google-cloud-auth", @@ -2211,7 +2143,7 @@ dependencies = [ "pkcs8 0.10.2", "regex", "reqwest", - "ring 0.17.5", + "ring 0.17.7", "serde", "serde_json", "sha2 0.10.8", @@ -2224,58 +2156,40 @@ dependencies = [ [[package]] name = "google-cloud-token" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcd62eb34e3de2f085bcc33a09c3e17c4f65650f36d53eb328b00d63bcb536a" +checksum = "8f49c12ba8b21d128a2ce8585955246977fbce4415f680ebf9199b6f9d6d725f" dependencies = [ "async-trait", ] [[package]] -name = "gpu-ffi" -version = "0.1.0" -source = "git+https://github.com/matter-labs/era-heavy-ops-service.git?branch=v1.3.3#ac6a3af6415dc12c9ae2932fa5ad906939023d82" -dependencies = [ - "bindgen 0.59.2", - "crossbeam 0.8.2", - "derivative", - "futures 0.3.29", - "futures-locks", - "num_cpus", -] - -[[package]] -name = "gpu-prover" -version = "0.1.0" -source = "git+https://github.com/matter-labs/era-heavy-ops-service.git?branch=v1.3.3#ac6a3af6415dc12c9ae2932fa5ad906939023d82" +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ - "bit-vec", - "cfg-if 1.0.0", - "crossbeam 0.8.2", - "franklin-crypto 0.0.5 (git+https://github.com/matter-labs/franklin-crypto?branch=dev)", - "gpu-ffi", - "itertools 0.11.0", - "num_cpus", - "rand 0.4.6", - "serde", + "ff 0.12.1", + "rand_core 0.6.4", + "subtle", ] [[package]] name = "group" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ - "ff", + "ff 0.13.0", "rand_core 0.6.4", "subtle", ] [[package]] name = "h2" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", @@ -2283,7 +2197,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -2296,57 +2210,41 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" -[[package]] -name = "handlebars" -version = "4.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faa67bab9ff362228eb3d00bd024a4965d8231bbb7921167f0cfa66c6626b225" -dependencies = [ - "log", - "pest", - "pest_derive", - "serde", - "serde_json", - "thiserror", -] - [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ "ahash 0.7.7", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.7", ] [[package]] name = "hashbrown" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash 0.8.7", + "allocator-api2", +] [[package]] name = "hashlink" -version = "0.7.0" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.11.2", + "hashbrown 0.14.3", ] [[package]] @@ -2355,7 +2253,7 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" dependencies = [ - "base64 0.21.5", + "base64 0.21.6", "bytes", "headers-core", "http", @@ -2414,21 +2312,11 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hkdf" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" -dependencies = [ - "hmac 0.12.1", -] - -[[package]] -name = "hmac" -version = "0.10.1" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ - "crypto-mac 0.10.1", - "digest 0.9.0", + "hmac", ] [[package]] @@ -2442,11 +2330,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.5" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -2462,9 +2350,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f95b9abcae896730d42b78e09c155ed4ddf82c07b4de772c64aee5b2d8b7c150" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -2473,9 +2361,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -2502,9 +2390,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", @@ -2517,7 +2405,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2 0.5.5", "tokio", "tower-service", "tracing", @@ -2553,9 +2441,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.58" +version = "0.1.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2591,12 +2479,13 @@ dependencies = [ ] [[package]] -name = "impl-codec" -version = "0.5.1" +name = "idna" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161ebdfec3c8e3b52bf61c4f3550a1eea4f9579d10dc1b936f3171ebdcd6c443" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ - "parity-scale-codec 2.3.1", + "unicode-bidi", + "unicode-normalization", ] [[package]] @@ -2605,7 +2494,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" dependencies = [ - "parity-scale-codec 3.6.5", + "parity-scale-codec", ] [[package]] @@ -2617,15 +2506,6 @@ dependencies = [ "rlp", ] -[[package]] -name = "impl-serde" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" -dependencies = [ - "serde", -] - [[package]] name = "impl-serde" version = "0.4.0" @@ -2641,8 +2521,8 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "syn 1.0.109", ] @@ -2652,7 +2532,7 @@ version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ - "autocfg 1.1.0", + "autocfg", "hashbrown 0.12.3", ] @@ -2663,16 +2543,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.2", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if 1.0.0", + "hashbrown 0.14.3", ] [[package]] @@ -2683,19 +2554,22 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "ipnetwork" -version = "0.17.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c3eaab3ac0ede60ffa41add21970a7df7d91772c03383aac6c2c3d53cc716b" +checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" +dependencies = [ + "serde", +] [[package]] name = "is-terminal" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" dependencies = [ "hermit-abi 0.3.3", "rustix", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -2716,17 +2590,35 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +dependencies = [ + "either", +] + [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "jobserver" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] [[package]] name = "js-sys" -version = "0.3.65" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" dependencies = [ "wasm-bindgen", ] @@ -2737,7 +2629,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" dependencies = [ - "futures 0.3.29", + "futures 0.3.30", "futures-executor", "futures-util", "log", @@ -2752,7 +2644,7 @@ version = "8.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" dependencies = [ - "base64 0.21.5", + "base64 0.21.6", "pem", "ring 0.16.20", "serde", @@ -2767,18 +2659,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" dependencies = [ "cfg-if 1.0.0", - "ecdsa", - "elliptic-curve", + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", "sha2 0.10.8", ] [[package]] -name = "keccak" -version = "0.1.4" +name = "k256" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" dependencies = [ - "cpufeatures", + "cfg-if 1.0.0", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "once_cell", + "sha2 0.10.8", + "signature 2.2.0", +] + +[[package]] +name = "keccak" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", ] [[package]] @@ -2786,6 +2692,9 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] [[package]] name = "lazycell" @@ -2795,18 +2704,18 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "libloading" -version = "0.7.4" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" dependencies = [ "cfg-if 1.0.0", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -2815,17 +2724,6 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" -[[package]] -name = "libredox" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" -dependencies = [ - "bitflags 2.4.1", - "libc", - "redox_syscall 0.4.1", -] - [[package]] name = "librocksdb-sys" version = "0.11.0+8.1.1" @@ -2840,42 +2738,54 @@ dependencies = [ "libz-sys", ] +[[package]] +name = "libsqlite3-sys" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "libz-sys" -version = "1.1.12" +version = "1.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" +checksum = "295c17e837573c8c821dbaeb3cceb3d745ad082f7572191409e69cbc1b3fd050" dependencies = [ "cc", + "libc", "pkg-config", "vcpkg", ] [[package]] name = "linkme" -version = "0.3.17" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ed2ee9464ff9707af8e9ad834cffa4802f072caad90639c583dd3c62e6e608" +checksum = "8b53ad6a33de58864705954edb5ad5d571a010f9e296865ed43dc72a5621b430" dependencies = [ "linkme-impl", ] [[package]] name = "linkme-impl" -version = "0.3.17" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba125974b109d512fccbc6c0244e7580143e460895dfd6ea7f8bbb692fd94396" +checksum = "04e542a18c94a9b6fcc7adb090fa3ba6b79ee220a16404f325672729f32a66ff" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] name = "linux-raw-sys" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "local-ip-address" @@ -2886,7 +2796,7 @@ dependencies = [ "libc", "neli", "thiserror", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2895,7 +2805,7 @@ version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ - "autocfg 1.1.0", + "autocfg", "scopeguard", ] @@ -2922,10 +2832,10 @@ checksum = "dc487311295e0002e452025d6b580b77bb17286de87b57138f3b5db711cded68" dependencies = [ "beef", "fnv", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "regex-syntax 0.6.29", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -2939,9 +2849,9 @@ dependencies = [ [[package]] name = "mach2" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8" +checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" dependencies = [ "libc", ] @@ -2979,9 +2889,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "memoffset" @@ -2989,16 +2899,7 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" dependencies = [ - "autocfg 1.1.0", -] - -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg 1.1.0", + "autocfg", ] [[package]] @@ -3007,18 +2908,18 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fde3af1a009ed76a778cb84fdef9e7dbbdf5775ae3e4cc1f434a6a307f6f76c5" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.7", "metrics-macros", "portable-atomic", ] [[package]] name = "metrics-exporter-prometheus" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a4964177ddfdab1e3a2b37aec7cf320e14169abb0ed73999f558136409178d5" +checksum = "1d4fa7ce7c4862db464a37b0b31d89bca874562f034bd7993895572783d02950" dependencies = [ - "base64 0.21.5", + "base64 0.21.6", "hyper", "indexmap 1.9.3", "ipnet", @@ -3032,13 +2933,13 @@ dependencies = [ [[package]] name = "metrics-macros" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddece26afd34c31585c74a4db0630c376df271c285d682d1e55012197830b6df" +checksum = "38b4faf00617defe497754acde3024865bc143d44a86799b24e191ecff91354f" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -3047,8 +2948,8 @@ version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4de2ed6e491ed114b40b732e4d1659a9d53992ebd87490c44a6ffe23739d973e" dependencies = [ - "crossbeam-epoch 0.9.15", - "crossbeam-utils 0.8.16", + "crossbeam-epoch 0.9.18", + "crossbeam-utils 0.8.19", "hashbrown 0.13.1", "metrics", "num_cpus", @@ -3074,9 +2975,9 @@ version = "5.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -3097,12 +2998,12 @@ dependencies = [ [[package]] name = "mini-moka" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e0b72e7c9042467008b10279fc732326bd605459ae03bda88825909dd19b56" +checksum = "c325dfab65f261f386debee8b0969da215b3fa0037e74c8a1234db7ba986d803" dependencies = [ - "crossbeam-channel 0.5.8", - "crossbeam-utils 0.8.16", + "crossbeam-channel 0.5.11", + "crossbeam-utils 0.8.19", "dashmap", "skeptic", "smallvec", @@ -3127,13 +3028,13 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "wasi", + "windows-sys 0.48.0", ] [[package]] @@ -3156,6 +3057,10 @@ dependencies = [ "zk_evm 1.3.1", "zk_evm 1.3.3 (git+https://github.com/matter-labs/era-zk_evm.git?tag=v1.3.3-rc2)", "zk_evm 1.4.0", + "zk_evm 1.4.1", + "zkevm_test_harness 1.3.3", + "zkevm_test_harness 1.4.0", + "zkevm_test_harness 1.4.1", "zksync_contracts", "zksync_state", "zksync_system_constants", @@ -3200,8 +3105,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c168194d373b1e134786274020dae7fc5513d565ea2ebb9bc9ff17ffb69106d4" dependencies = [ "either", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "serde", "syn 1.0.109", ] @@ -3243,20 +3148,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "num" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f" -dependencies = [ - "num-bigint 0.3.3", - "num-complex 0.3.1", - "num-integer", - "num-iter", - "num-rational 0.3.2", - "num-traits", -] - [[package]] name = "num" version = "0.4.1" @@ -3264,10 +3155,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" dependencies = [ "num-bigint 0.4.4", - "num-complex 0.4.4", + "num-complex", "num-integer", "num-iter", - "num-rational 0.4.1", + "num-rational", "num-traits", ] @@ -3277,10 +3168,9 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" dependencies = [ - "autocfg 1.1.0", + "autocfg", "num-integer", "num-traits", - "serde", ] [[package]] @@ -3289,20 +3179,27 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ - "autocfg 1.1.0", + "autocfg", "num-integer", "num-traits", "serde", ] [[package]] -name = "num-complex" -version = "0.3.1" +name = "num-bigint-dig" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", "num-traits", - "serde", + "rand 0.8.5", + "smallvec", + "zeroize", ] [[package]] @@ -3312,6 +3209,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" dependencies = [ "num-traits", + "serde", ] [[package]] @@ -3331,8 +3229,8 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "syn 1.0.109", ] @@ -3342,7 +3240,7 @@ version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ - "autocfg 1.1.0", + "autocfg", "num-traits", ] @@ -3352,7 +3250,7 @@ version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" dependencies = [ - "autocfg 1.1.0", + "autocfg", "num-integer", "num-traits", ] @@ -3367,29 +3265,17 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-rational" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" -dependencies = [ - "autocfg 1.1.0", - "num-bigint 0.3.3", - "num-integer", - "num-traits", - "serde", -] - [[package]] name = "num-rational" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ - "autocfg 1.1.0", + "autocfg", "num-bigint 0.4.4", "num-integer", "num-traits", + "serde", ] [[package]] @@ -3398,7 +3284,7 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ - "autocfg 1.1.0", + "autocfg", "libm", ] @@ -3427,26 +3313,26 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" dependencies = [ - "proc-macro-crate", - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro-crate 1.3.1", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] name = "object" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" @@ -3462,9 +3348,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.59" +version = "0.10.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33" +checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671" dependencies = [ "bitflags 2.4.1", "cfg-if 1.0.0", @@ -3481,9 +3367,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -3494,9 +3380,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.95" +version = "0.9.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9" +checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7" dependencies = [ "cc", "libc", @@ -3556,7 +3442,7 @@ dependencies = [ [[package]] name = "pairing_ce" version = "0.28.5" -source = "git+https://github.com/matter-labs/pairing.git?rev=f55393f#f55393fd366596eac792d78525d26e9c4d6ed1ca" +source = "git+https://github.com/matter-labs/pairing.git?rev=f55393fd366596eac792d78525d26e9c4d6ed1ca#f55393fd366596eac792d78525d26e9c4d6ed1ca" dependencies = [ "byteorder", "cfg-if 1.0.0", @@ -3577,93 +3463,32 @@ dependencies = [ "serde", ] -[[package]] -name = "parity-crypto" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b92ea9ddac0d6e1db7c49991e7d397d34a9fd814b4c93cda53788e8eef94e35" -dependencies = [ - "aes", - "aes-ctr", - "block-modes", - "digest 0.9.0", - "ethereum-types 0.12.1", - "hmac 0.10.1", - "lazy_static", - "pbkdf2 0.7.5", - "ripemd160", - "rustc-hex", - "scrypt", - "secp256k1 0.20.3", - "sha2 0.9.9", - "subtle", - "tiny-keccak 2.0.2", - "zeroize", -] - -[[package]] -name = "parity-scale-codec" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" -dependencies = [ - "arrayvec 0.7.4", - "bitvec 0.20.4", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive 2.3.1", - "serde", -] - [[package]] name = "parity-scale-codec" -version = "3.6.5" +version = "3.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" dependencies = [ "arrayvec 0.7.4", - "bitvec 1.0.1", + "bitvec", "byte-slice-cast", "impl-trait-for-tuples", - "parity-scale-codec-derive 3.6.5", + "parity-scale-codec-derive", "serde", ] [[package]] name = "parity-scale-codec-derive" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" -dependencies = [ - "proc-macro-crate", - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 1.0.109", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "3.6.5" +version = "3.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" dependencies = [ - "proc-macro-crate", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro-crate 2.0.0", + "proc-macro2 1.0.76", + "quote 1.0.35", "syn 1.0.109", ] -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - [[package]] name = "parking_lot" version = "0.12.1" @@ -3671,21 +3496,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.9", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if 1.0.0", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -3696,19 +3507,9 @@ checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall 0.4.1", + "redox_syscall", "smallvec", - "windows-targets", -] - -[[package]] -name = "password-hash" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54986aa4bfc9b98c6a5f40184223658d187159d7b3c6af33f2b2aa25ae1db0fa" -dependencies = [ - "base64ct", - "rand_core 0.6.4", + "windows-targets 0.48.5", ] [[package]] @@ -3717,28 +3518,6 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" -[[package]] -name = "pbkdf2" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3b8c0d71734018084da0c0354193a5edfb81b20d2d57a92c5b154aefc554a4a" -dependencies = [ - "crypto-mac 0.10.1", -] - -[[package]] -name = "pbkdf2" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf916dd32dd26297907890d99dc2740e33f6bd9073965af4ccff2967962f5508" -dependencies = [ - "base64ct", - "crypto-mac 0.10.1", - "hmac 0.10.1", - "password-hash", - "sha2 0.9.9", -] - [[package]] name = "peeking_take_while" version = "0.1.2" @@ -3765,54 +3544,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" - -[[package]] -name = "pest" -version = "2.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" -dependencies = [ - "memchr", - "thiserror", - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", -] - -[[package]] -name = "pest_meta" -version = "2.7.5" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" -dependencies = [ - "once_cell", - "pest", - "sha2 0.10.8", -] +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "petgraph" @@ -3839,9 +3573,9 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -3856,6 +3590,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der 0.7.8", + "pkcs8 0.10.2", + "spki 0.7.3", +] + [[package]] name = "pkcs8" version = "0.9.0" @@ -3873,20 +3618,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ "der 0.7.8", - "spki 0.7.2", + "spki 0.7.3", ] [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" [[package]] name = "platforms" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" +checksum = "626dec3cac7cc0e1577a2ec3fc496277ec2baa084bebad95bb6fdbfae235f84c" [[package]] name = "plotters" @@ -3918,9 +3663,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bccab0e7fd7cc19f820a1c8c91720af652d0c88dc9664dd72aef2614f04af3b" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" [[package]] name = "powerfmt" @@ -3936,25 +3681,12 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "prettyplease" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" -dependencies = [ - "proc-macro2 1.0.69", - "syn 2.0.39", -] - -[[package]] -name = "primitive-types" -version = "0.10.1" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" +checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" dependencies = [ - "fixed-hash 0.7.0", - "impl-codec 0.5.1", - "impl-rlp", - "impl-serde 0.3.2", - "uint", + "proc-macro2 1.0.76", + "syn 2.0.48", ] [[package]] @@ -3963,10 +3695,10 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ - "fixed-hash 0.8.0", - "impl-codec 0.6.0", + "fixed-hash", + "impl-codec", "impl-rlp", - "impl-serde 0.4.0", + "impl-serde", "uint", ] @@ -3980,6 +3712,24 @@ dependencies = [ "toml_edit 0.19.15", ] +[[package]] +name = "proc-macro-crate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +dependencies = [ + "toml_edit 0.20.7", +] + +[[package]] +name = "proc-macro-crate" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b2685dd208a3771337d8d386a89840f0f43cd68be8dae90a5f8c2384effc9cd" +dependencies = [ + "toml_edit 0.21.0", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -3987,8 +3737,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "syn 1.0.109", "version_check", ] @@ -3999,8 +3749,8 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "version_check", ] @@ -4021,9 +3771,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] @@ -4036,7 +3786,7 @@ checksum = "3c99afa9a01501019ac3a14d71d9f94050346f55ca471ce90c799a15c58f61e2" dependencies = [ "dtoa", "itoa", - "parking_lot 0.12.1", + "parking_lot", "prometheus-client-derive-encode", ] @@ -4046,9 +3796,9 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -4075,8 +3825,8 @@ dependencies = [ "lazy_static", "num-traits", "rand 0.8.5", - "rand_chacha 0.3.1", - "rand_xorshift 0.3.0", + "rand_chacha", + "rand_xorshift", "regex-syntax 0.8.2", "rusty-fork", "tempfile", @@ -4085,9 +3835,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5a410fc7882af66deb8d01d01737353cf3ad6204c408177ba494291a626312" +checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" dependencies = [ "bytes", "prost-derive", @@ -4095,9 +3845,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa3d084c8704911bfefb2771be2f9b6c5c0da7343a71e0021ee3c665cada738" +checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2" dependencies = [ "bytes", "heck 0.4.1", @@ -4110,22 +3860,22 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.39", + "syn 2.0.48", "tempfile", "which", ] [[package]] name = "prost-derive" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065717a5dfaca4a83d2fe57db3487b311365200000551d7a364e715dbf4346bc" +checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" dependencies = [ "anyhow", "itertools 0.11.0", - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -4134,7 +3884,7 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "057237efdb71cf4b3f9396302a3d6599a92fa94063ba537b66130980ea9909f3" dependencies = [ - "base64 0.21.5", + "base64 0.21.6", "logos", "miette", "once_cell", @@ -4146,9 +3896,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8339f32236f590281e2f6368276441394fcd1b2133b549cc895d0ae80f2f9a52" +checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" dependencies = [ "prost", ] @@ -4181,19 +3931,23 @@ dependencies = [ ] [[package]] -name = "prover-service" -version = "0.1.0" -source = "git+https://github.com/matter-labs/era-heavy-ops-service.git?branch=v1.3.3#ac6a3af6415dc12c9ae2932fa5ad906939023d82" +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" dependencies = [ - "api", - "bincode", - "crossbeam-utils 0.8.16", - "log", - "num_cpus", - "rand 0.4.6", - "serde", - "serde_json", - "zkevm_test_harness 1.3.3", + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 1.0.109", ] [[package]] @@ -4213,12 +3967,12 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab" dependencies = [ - "crossbeam-utils 0.8.16", + "crossbeam-utils 0.8.19", "libc", "mach2", "once_cell", "raw-cpuid", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "web-sys", "winapi", ] @@ -4255,19 +4009,13 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ - "proc-macro2 1.0.69", + "proc-macro2 1.0.76", ] -[[package]] -name = "radium" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" - [[package]] name = "radium" version = "0.7.0" @@ -4287,36 +4035,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -dependencies = [ - "autocfg 0.1.8", - "libc", - "rand_chacha 0.1.1", - "rand_core 0.4.2", - "rand_hc 0.1.0", - "rand_isaac", - "rand_jitter", - "rand_os", - "rand_pcg", - "rand_xorshift 0.1.1", - "winapi", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc 0.2.0", -] - [[package]] name = "rand" version = "0.8.5" @@ -4324,30 +4042,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha 0.3.1", + "rand_chacha", "rand_core 0.6.4", ] -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -dependencies = [ - "autocfg 0.1.8", - "rand_core 0.3.1", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - [[package]] name = "rand_chacha" version = "0.3.1" @@ -4373,93 +4071,13 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.11", -] - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -dependencies = [ - "libc", - "rand_core 0.4.2", - "winapi", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -dependencies = [ - "cloudabi", - "fuchsia-cprng", - "libc", - "rand_core 0.4.2", - "rdrand", - "winapi", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -dependencies = [ - "autocfg 0.1.8", - "rand_core 0.4.2", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -dependencies = [ - "rand_core 0.3.1", + "getrandom", ] [[package]] @@ -4496,8 +4114,8 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" dependencies = [ - "crossbeam-deque 0.8.3", - "crossbeam-utils 0.8.16", + "crossbeam-deque 0.8.5", + "crossbeam-utils 0.8.19", ] [[package]] @@ -4509,15 +4127,6 @@ dependencies = [ "rand_core 0.3.1", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -4527,17 +4136,6 @@ dependencies = [ "bitflags 1.3.2", ] -[[package]] -name = "redox_users" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" -dependencies = [ - "getrandom 0.2.11", - "libredox", - "thiserror", -] - [[package]] name = "regex" version = "1.10.2" @@ -4582,13 +4180,22 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "rend" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2571463863a6bd50c32f94402933f03457a3fbaf697a707c5be741e459f08fd" +dependencies = [ + "bytecheck", +] + [[package]] name = "reqwest" -version = "0.11.22" +version = "0.11.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" dependencies = [ - "base64 0.21.5", + "base64 0.21.6", "bytes", "encoding_rs", "futures-core", @@ -4677,10 +4284,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" dependencies = [ "crypto-bigint 0.4.9", - "hmac 0.12.1", + "hmac", "zeroize", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "ring" version = "0.16.20" @@ -4698,27 +4315,45 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.5" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", - "getrandom 0.2.11", + "getrandom", "libc", "spin 0.9.8", "untrusted 0.9.0", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] -name = "ripemd160" -version = "0.9.1" +name = "rkyv" +version = "0.7.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eca4ecc81b7f313189bf73ce724400a07da2a6dac19588b03c8bd76a2dcc251" +checksum = "527a97cdfef66f65998b5f3b637c26f5a5ec09cc52a3f9932313ac645f4190f5" dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "opaque-debug", + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5c462a1328c8e67e4d6dbad1eb0355dd43e8ab432c6e227a43657f16ade5033" +dependencies = [ + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 1.0.109", ] [[package]] @@ -4741,6 +4376,42 @@ dependencies = [ "librocksdb-sys", ] +[[package]] +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +dependencies = [ + "const-oid", + "digest 0.10.7", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8 0.10.2", + "rand_core 0.6.4", + "signature 2.2.0", + "spki 0.7.3", + "subtle", + "zeroize", +] + +[[package]] +name = "rust_decimal" +version = "1.33.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06676aec5ccb8fc1da723cc8c0f9a46549f21ebb8753d3915c6c41db1e7f1dc4" +dependencies = [ + "arrayvec 0.7.4", + "borsh", + "bytes", + "num-traits", + "rand 0.8.5", + "rkyv", + "serde", + "serde_json", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -4770,25 +4441,25 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.21" +version = "0.38.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.21.8" +version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", - "ring 0.17.5", + "ring 0.17.7", "rustls-webpki", "sct", ] @@ -4799,7 +4470,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.5", + "base64 0.21.6", ] [[package]] @@ -4808,7 +4479,7 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.5", + "ring 0.17.7", "untrusted 0.9.0", ] @@ -4832,18 +4503,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "salsa20" -version = "0.7.2" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "399f290ffc409596022fce5ea5d4138184be4784f2b28c62c59f0d8389059a15" -dependencies = [ - "cipher", -] +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "same-file" @@ -4856,11 +4518,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -4869,39 +4531,29 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "scrypt" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da492dab03f925d977776a0b7233d7b934d6dc2b94faead48928e2e9bacedb9" -dependencies = [ - "base64 0.13.1", - "hmac 0.10.1", - "pbkdf2 0.6.0", - "rand 0.7.3", - "rand_core 0.5.1", - "salsa20", - "sha2 0.9.9", - "subtle", -] - [[package]] name = "sct" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.5", + "ring 0.17.7", "untrusted 0.9.0", ] +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + [[package]] name = "sec1" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ - "base16ct", + "base16ct 0.1.1", "der 0.6.1", "generic-array", "pkcs8 0.9.0", @@ -4910,13 +4562,17 @@ dependencies = [ ] [[package]] -name = "secp256k1" -version = "0.20.3" +name = "sec1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d03ceae636d0fed5bae6a7f4f664354c5f4fcedf6eef053fef17e49f837d0a" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ - "rand 0.6.5", - "secp256k1-sys 0.4.2", + "base16ct 0.2.0", + "der 0.7.8", + "generic-array", + "pkcs8 0.10.2", + "subtle", + "zeroize", ] [[package]] @@ -4925,16 +4581,7 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" dependencies = [ - "secp256k1-sys 0.8.1", -] - -[[package]] -name = "secp256k1-sys" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957da2573cde917463ece3570eab4a0b3f19de6f1646cde62e6fd3868f566036" -dependencies = [ - "cc", + "secp256k1-sys", ] [[package]] @@ -4971,9 +4618,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" dependencies = [ "serde", ] @@ -5094,9 +4741,9 @@ checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" [[package]] name = "serde" -version = "1.0.192" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" dependencies = [ "serde_derive", ] @@ -5113,20 +4760,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.192" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" dependencies = [ "itoa", "ryu", @@ -5163,40 +4810,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" dependencies = [ "darling", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "syn 1.0.109", ] -[[package]] -name = "setup_key_generator_and_server" -version = "0.1.0" -dependencies = [ - "anyhow", - "api", - "circuit_testing", - "itertools 0.10.5", - "prover-service", - "structopt", - "tracing", - "vlog", - "zkevm_test_harness 1.3.3", - "zksync_config", - "zksync_env_config", - "zksync_types", -] - -[[package]] -name = "sha-1" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" -dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.10.7", -] - [[package]] name = "sha1" version = "0.10.6" @@ -5285,13 +4903,13 @@ dependencies = [ [[package]] name = "shivini" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-shivini.git?branch=main#bb3d4ad1fa454d7be54a819cc0c16561806c49fe" +source = "git+https://github.com/matter-labs/era-shivini.git?branch=v1.4.1#011aaabcfb77ad3dc189086012267161375d9cc2" dependencies = [ "bincode", "blake2 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", "boojum", "boojum-cuda", - "circuit_definitions", + "circuit_definitions 0.1.0 (git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1)", "cudart", "derivative", "hex", @@ -5332,9 +4950,16 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ + "digest 0.10.7", "rand_core 0.6.4", ] +[[package]] +name = "simdutf8" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" + [[package]] name = "simple_asn1" version = "0.6.2" @@ -5374,7 +4999,7 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ - "autocfg 1.1.0", + "autocfg", ] [[package]] @@ -5413,7 +5038,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -5427,6 +5052,9 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] [[package]] name = "spki" @@ -5440,9 +5068,9 @@ dependencies = [ [[package]] name = "spki" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", "der 0.7.8", @@ -5456,110 +5084,224 @@ checksum = "c85070f382340e8b23a75808e83573ddf65f9ad9143df9573ca37c1ed2ee956a" [[package]] name = "sqlformat" -version = "0.1.8" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" +checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" dependencies = [ - "itertools 0.10.5", + "itertools 0.12.0", "nom", "unicode_categories", ] [[package]] name = "sqlx" -version = "0.5.13" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551873805652ba0d912fec5bbb0f8b4cdd96baf8e2ebf5970e5671092966019b" +checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf" dependencies = [ "sqlx-core", "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", ] [[package]] name = "sqlx-core" -version = "0.5.13" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48c61941ccf5ddcada342cd59e3e5173b007c509e1e8e990dafc830294d9dc5" +checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd" dependencies = [ - "ahash 0.7.7", + "ahash 0.8.7", "atoi", - "base64 0.13.1", "bigdecimal", - "bitflags 1.3.2", "byteorder", "bytes", "chrono", "crc", - "crossbeam-queue 0.3.8", - "dirs", + "crossbeam-queue 0.3.11", + "dotenvy", "either", "event-listener", "futures-channel", "futures-core", "futures-intrusive", + "futures-io", "futures-util", "hashlink", "hex", - "hkdf", - "hmac 0.12.1", - "indexmap 1.9.3", + "indexmap 2.1.0", "ipnetwork", - "itoa", - "libc", "log", - "md-5", "memchr", - "num-bigint 0.3.3", + "native-tls", "once_cell", "paste", "percent-encoding", - "rand 0.8.5", + "rust_decimal", "serde", "serde_json", - "sha-1", "sha2 0.10.8", "smallvec", "sqlformat", - "sqlx-rt", - "stringprep", "thiserror", + "tokio", "tokio-stream", + "tracing", "url", - "whoami", ] [[package]] name = "sqlx-macros" -version = "0.5.13" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0fba2b0cae21fc00fe6046f8baa4c7fcb49e379f0f592b04696607f69ed2e1" +checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5" dependencies = [ - "dotenv", - "either", + "proc-macro2 1.0.76", + "quote 1.0.35", + "sqlx-core", + "sqlx-macros-core", + "syn 1.0.109", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841" +dependencies = [ + "atomic-write-file", + "dotenvy", + "either", "heck 0.4.1", "hex", "once_cell", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "serde", "serde_json", "sha2 0.10.8", "sqlx-core", - "sqlx-rt", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", "syn 1.0.109", + "tempfile", + "tokio", "url", ] [[package]] -name = "sqlx-rt" -version = "0.5.13" +name = "sqlx-mysql" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4db708cd3e459078f85f39f96a00960bd841f66ee2a669e90bf36907f5a79aae" +checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4" dependencies = [ - "native-tls", + "atoi", + "base64 0.21.6", + "bigdecimal", + "bitflags 2.4.1", + "byteorder", + "bytes", + "chrono", + "crc", + "digest 0.10.7", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", "once_cell", - "tokio", - "tokio-native-tls", + "percent-encoding", + "rand 0.8.5", + "rsa", + "rust_decimal", + "serde", + "sha1", + "sha2 0.10.8", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24" +dependencies = [ + "atoi", + "base64 0.21.6", + "bigdecimal", + "bitflags 2.4.1", + "byteorder", + "chrono", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "ipnetwork", + "itoa", + "log", + "md-5", + "memchr", + "num-bigint 0.4.4", + "once_cell", + "rand 0.8.5", + "rust_decimal", + "serde", + "serde_json", + "sha1", + "sha2 0.10.8", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490" +dependencies = [ + "atoi", + "chrono", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "tracing", + "url", + "urlencoding", ] [[package]] @@ -5616,8 +5358,8 @@ checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" dependencies = [ "heck 0.3.3", "proc-macro-error", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "syn 1.0.109", ] @@ -5637,8 +5379,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "rustversion", "syn 1.0.109", ] @@ -5666,22 +5408,34 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.39" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2 1.0.76", + "quote 1.0.35", "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", +] + [[package]] name = "sync_vm" version = "1.3.3" @@ -5740,35 +5494,45 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.8.1" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" dependencies = [ "cfg-if 1.0.0", - "fastrand 2.0.1", - "redox_syscall 0.4.1", + "fastrand", + "redox_syscall", "rustix", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "termcolor" -version = "1.3.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "test-log" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f66edd6b6cd810743c0c71e1d085e92b01ce6a72782032e3f794c8284fe4bcdd" +checksum = "6159ab4116165c99fc88cce31f99fa2c9dbe08d3691cb38da02fc3b45f357d2b" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "env_logger 0.10.1", + "test-log-macros", +] + +[[package]] +name = "test-log-macros" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba277e77219e9eea169e8508942db1bf5d8a41ff2db9b20aab5a5aadc9fa25d" +dependencies = [ + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -5782,22 +5546,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -5821,9 +5585,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" dependencies = [ "deranged", "itoa", @@ -5841,9 +5605,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" dependencies = [ "time-core", ] @@ -5893,21 +5657,21 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.34.0" +version = "1.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" dependencies = [ "backtrace", "bytes", "libc", "mio", "num_cpus", - "parking_lot 0.12.1", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2 0.5.5", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -5916,9 +5680,9 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -5994,6 +5758,28 @@ dependencies = [ "winnow", ] +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap 2.1.0", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap 2.1.0", + "toml_datetime", + "winnow", +] + [[package]] name = "tower-service" version = "0.3.2" @@ -6006,6 +5792,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -6017,9 +5804,9 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -6034,9 +5821,9 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.4" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ "log", "once_cell", @@ -6055,9 +5842,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", @@ -6077,15 +5864,15 @@ dependencies = [ [[package]] name = "triomphe" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee8098afad3fb0c54a9007aab6804558410503ad676d4633f9c2559a00ac0f" +checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" @@ -6093,12 +5880,6 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" -[[package]] -name = "ucd-trie" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" - [[package]] name = "uint" version = "0.9.5" @@ -6137,9 +5918,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] name = "unicode-ident" @@ -6192,7 +5973,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ad948c1cb799b1a70f836077721a92a35ac177d4daddf4c20a633786d4cf618" dependencies = [ - "quote 1.0.33", + "quote 1.0.35", "syn 1.0.109", ] @@ -6210,11 +5991,11 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.8.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5ccd538d4a604753ebc2f17cd9946e89b77bf87f6a8e2309667c6f2e87855e3" +checksum = "f8cdd25c339e200129fe4de81451814e5228c9b771d57378817d6117cc2b3f97" dependencies = [ - "base64 0.21.5", + "base64 0.21.6", "log", "native-tls", "once_cell", @@ -6223,12 +6004,12 @@ dependencies = [ [[package]] name = "url" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", - "idna", + "idna 0.5.0", "percent-encoding", "serde", ] @@ -6241,9 +6022,9 @@ checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" [[package]] name = "uuid" -version = "1.5.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" dependencies = [ "serde", ] @@ -6275,8 +6056,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "vise" version = "0.1.0" -source = "git+https://github.com/matter-labs/vise.git?rev=dd05139b76ab0843443ab3ff730174942c825dae#dd05139b76ab0843443ab3ff730174942c825dae" +source = "git+https://github.com/matter-labs/vise.git?rev=1c9cc500e92cf9ea052b230e114a6f9cce4fb2c1#1c9cc500e92cf9ea052b230e114a6f9cce4fb2c1" dependencies = [ + "compile-fmt", "elsa", "linkme", "once_cell", @@ -6287,7 +6069,7 @@ dependencies = [ [[package]] name = "vise-exporter" version = "0.1.0" -source = "git+https://github.com/matter-labs/vise.git?rev=dd05139b76ab0843443ab3ff730174942c825dae#dd05139b76ab0843443ab3ff730174942c825dae" +source = "git+https://github.com/matter-labs/vise.git?rev=1c9cc500e92cf9ea052b230e114a6f9cce4fb2c1#1c9cc500e92cf9ea052b230e114a6f9cce4fb2c1" dependencies = [ "hyper", "metrics-exporter-prometheus", @@ -6300,11 +6082,11 @@ dependencies = [ [[package]] name = "vise-macros" version = "0.1.0" -source = "git+https://github.com/matter-labs/vise.git?rev=dd05139b76ab0843443ab3ff730174942c825dae#dd05139b76ab0843443ab3ff730174942c825dae" +source = "git+https://github.com/matter-labs/vise.git?rev=1c9cc500e92cf9ea052b230e114a6f9cce4fb2c1#1c9cc500e92cf9ea052b230e114a6f9cce4fb2c1" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -6313,7 +6095,7 @@ version = "0.1.0" dependencies = [ "anyhow", "bincode", - "circuit_definitions", + "circuit_definitions 0.1.0 (git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1)", "itertools 0.10.5", "once_cell", "proptest", @@ -6322,13 +6104,14 @@ dependencies = [ "serde_json", "shivini", "structopt", + "toml_edit 0.14.4", "tracing", "vlog", - "zkevm_test_harness 1.4.0", + "zkevm_test_harness 1.3.3", + "zkevm_test_harness 1.4.1", "zksync_config", "zksync_env_config", "zksync_prover_fri_types", - "zksync_prover_utils", "zksync_types", ] @@ -6371,12 +6154,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -6385,9 +6162,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -6395,24 +6172,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -6422,32 +6199,32 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ - "quote 1.0.33", + "quote 1.0.35", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "wasm-streams" @@ -6464,9 +6241,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.65" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" dependencies = [ "js-sys", "wasm-bindgen", @@ -6479,24 +6256,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5388522c899d1e1c96a4c307e3797e0f697ba7c77dd8e0e625ecba9dd0342937" dependencies = [ "arrayvec 0.7.4", - "base64 0.21.5", + "base64 0.21.6", "bytes", "derive_more", "ethabi", - "ethereum-types 0.14.1", - "futures 0.3.29", + "ethereum-types", + "futures 0.3.30", "futures-timer", "headers", "hex", - "idna", + "idna 0.4.0", "jsonrpc-core", "log", "once_cell", - "parking_lot 0.12.1", + "parking_lot", "pin-project", "reqwest", "rlp", - "secp256k1 0.27.0", + "secp256k1", "serde", "serde_json", "tiny-keccak 2.0.2", @@ -6505,9 +6282,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.25.2" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" +checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" [[package]] name = "which" @@ -6526,10 +6303,6 @@ name = "whoami" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" -dependencies = [ - "wasm-bindgen", - "web-sys", -] [[package]] name = "winapi" @@ -6564,11 +6337,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.51.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets", + "windows-targets 0.52.0", ] [[package]] @@ -6577,7 +6350,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -6586,13 +6368,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -6601,47 +6398,89 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "winnow" -version = "0.5.19" +version = "0.5.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" +checksum = "b7520bbdec7211caa7c4e682eb1fbe07abe20cee6756b6e00f537c82c11816aa" dependencies = [ "memchr", ] @@ -6653,15 +6492,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ "cfg-if 1.0.0", - "windows-sys", + "windows-sys 0.48.0", ] -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" - [[package]] name = "wyz" version = "0.5.1" @@ -6673,29 +6506,29 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.25" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd369a67c0edfef15010f980c3cbe45d7f651deac2cd67ce097cd801de16557" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.25" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f140bda219a26ccc0cdb03dba58af72590c53b22642577d88a927bc5c87d6b" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] name = "zeroize" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" dependencies = [ "zeroize_derive", ] @@ -6706,9 +6539,9 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", - "syn 2.0.39", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -6717,9 +6550,9 @@ version = "1.3.1" source = "git+https://github.com/matter-labs/era-zk_evm.git?tag=v1.3.1-rc2#0a7c775932db4839ff6b7fb0db9bdb3583ab54c0" dependencies = [ "blake2 0.10.6 (git+https://github.com/RustCrypto/hashes.git?rev=1f727ce37ff40fa0cce84eb8543a45bdd3ca4a4e)", - "k256", + "k256 0.11.6", "lazy_static", - "num 0.4.1", + "num", "serde", "serde_json", "sha2 0.10.6", @@ -6735,11 +6568,11 @@ source = "git+https://github.com/matter-labs/era-zk_evm.git?tag=v1.3.3-rc2#fbee2 dependencies = [ "anyhow", "lazy_static", - "num 0.4.1", + "num", "serde", "serde_json", "static_assertions", - "zk_evm_abstractions", + "zk_evm_abstractions 0.1.0", "zkevm_opcode_defs 1.3.2", ] @@ -6750,11 +6583,11 @@ source = "git+https://github.com/matter-labs/era-zk_evm.git?branch=v1.3.3#fbee20 dependencies = [ "anyhow", "lazy_static", - "num 0.4.1", + "num", "serde", "serde_json", "static_assertions", - "zk_evm_abstractions", + "zk_evm_abstractions 0.1.0", "zkevm_opcode_defs 1.3.2", ] @@ -6765,25 +6598,53 @@ source = "git+https://github.com/matter-labs/era-zk_evm.git?branch=v1.4.0#dd76fc dependencies = [ "anyhow", "lazy_static", - "num 0.4.1", + "num", "serde", "serde_json", "static_assertions", - "zk_evm_abstractions", + "zk_evm_abstractions 0.1.0", "zkevm_opcode_defs 1.3.2", ] +[[package]] +name = "zk_evm" +version = "1.4.1" +source = "git+https://github.com/matter-labs/era-zk_evm.git?branch=v1.4.1#6250dbf64b2d14ced87a127735da559f27a432d5" +dependencies = [ + "anyhow", + "lazy_static", + "num", + "serde", + "serde_json", + "static_assertions", + "zk_evm_abstractions 1.4.1", + "zkevm_opcode_defs 1.4.1", +] + [[package]] name = "zk_evm_abstractions" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-zk_evm_abstractions.git#7502a661d7d38906d849dcd3e7a15e5848af6581" +source = "git+https://github.com/matter-labs/era-zk_evm_abstractions.git#32dd320953841aa78579d9da08abbc70bcaed175" dependencies = [ "anyhow", + "num_enum", "serde", "static_assertions", "zkevm_opcode_defs 1.3.2", ] +[[package]] +name = "zk_evm_abstractions" +version = "1.4.1" +source = "git+https://github.com/matter-labs/era-zk_evm_abstractions.git?branch=v1.4.1#0aac08c3b097ee8147e748475117ac46bddcdcef" +dependencies = [ + "anyhow", + "num_enum", + "serde", + "static_assertions", + "zkevm_opcode_defs 1.4.1", +] + [[package]] name = "zkevm-assembly" version = "1.3.2" @@ -6803,6 +6664,25 @@ dependencies = [ "zkevm_opcode_defs 1.3.2", ] +[[package]] +name = "zkevm-assembly" +version = "1.3.2" +source = "git+https://github.com/matter-labs/era-zkEVM-assembly.git?branch=v1.4.1#50282016d01bd2fd147021dd558209778db2268b" +dependencies = [ + "env_logger 0.9.3", + "hex", + "lazy_static", + "log", + "nom", + "num-bigint 0.4.4", + "num-traits", + "sha3 0.10.8", + "smallvec", + "structopt", + "thiserror", + "zkevm_opcode_defs 1.4.1", +] + [[package]] name = "zkevm_circuits" version = "1.4.0" @@ -6824,13 +6704,34 @@ dependencies = [ "zkevm_opcode_defs 1.3.2", ] +[[package]] +name = "zkevm_circuits" +version = "1.4.1" +source = "git+https://github.com/matter-labs/era-zkevm_circuits.git?branch=v1.4.1#70234e99c2492740226b9f40091e7fccc7ef28e9" +dependencies = [ + "arrayvec 0.7.4", + "bincode", + "boojum", + "cs_derive 0.1.0 (git+https://github.com/matter-labs/era-boojum?branch=main)", + "derivative", + "hex", + "itertools 0.10.5", + "rand 0.4.6", + "rand 0.8.5", + "seq-macro", + "serde", + "serde_json", + "smallvec", + "zkevm_opcode_defs 1.4.1", +] + [[package]] name = "zkevm_opcode_defs" version = "1.3.1" source = "git+https://github.com/matter-labs/era-zkevm_opcode_defs.git?branch=v1.3.1#00d4ad2292bd55374a0fa10fe11686d7a109d8a0" dependencies = [ "bitflags 1.3.2", - "ethereum-types 0.14.1", + "ethereum-types", "lazy_static", "sha2 0.10.8", ] @@ -6842,13 +6743,27 @@ source = "git+https://github.com/matter-labs/era-zkevm_opcode_defs.git?branch=v1 dependencies = [ "bitflags 2.4.1", "blake2 0.10.6 (git+https://github.com/RustCrypto/hashes.git?rev=1f727ce37ff40fa0cce84eb8543a45bdd3ca4a4e)", - "ethereum-types 0.14.1", - "k256", + "ethereum-types", + "k256 0.11.6", "lazy_static", "sha2 0.10.6", "sha3 0.10.6", ] +[[package]] +name = "zkevm_opcode_defs" +version = "1.4.1" +source = "git+https://github.com/matter-labs/era-zkevm_opcode_defs.git?branch=v1.4.1#ba8228ff0582d21f64d6a319d50d0aec48e9e7b6" +dependencies = [ + "bitflags 2.4.1", + "blake2 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types", + "k256 0.13.3", + "lazy_static", + "sha2 0.10.8", + "sha3 0.10.8", +] + [[package]] name = "zkevm_test_harness" version = "1.3.3" @@ -6856,10 +6771,10 @@ source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v dependencies = [ "bincode", "circuit_testing", - "codegen 0.2.0", - "crossbeam 0.8.2", + "codegen", + "crossbeam 0.8.4", "derivative", - "env_logger 0.10.1", + "env_logger 0.9.3", "hex", "num-bigint 0.4.4", "num-integer", @@ -6873,20 +6788,20 @@ dependencies = [ "test-log", "tracing", "zk_evm 1.3.3 (git+https://github.com/matter-labs/era-zk_evm.git?branch=v1.3.3)", - "zkevm-assembly", + "zkevm-assembly 1.3.2 (git+https://github.com/matter-labs/era-zkEVM-assembly.git?branch=v1.3.2)", ] [[package]] name = "zkevm_test_harness" version = "1.4.0" -source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.0#d2e3670e0c5115b7cc7cc24e6d3dbdd17a214aad" +source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.0#de2ecad62ac8c12777e576dca20311ad8ec770d1" dependencies = [ "bincode", - "circuit_definitions", - "codegen 0.2.0", - "crossbeam 0.8.2", + "circuit_definitions 0.1.0 (git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.0)", + "codegen", + "crossbeam 0.8.4", "derivative", - "env_logger 0.10.1", + "env_logger 0.9.3", "hex", "rand 0.4.6", "rayon", @@ -6896,73 +6811,51 @@ dependencies = [ "structopt", "test-log", "tracing", - "zkevm-assembly", -] - -[[package]] -name = "zksync_basic_types" -version = "0.1.0" -dependencies = [ - "serde", - "serde_json", - "web3", + "zkevm-assembly 1.3.2 (git+https://github.com/matter-labs/era-zkEVM-assembly.git?branch=v1.3.2)", ] [[package]] -name = "zksync_circuit_breaker" -version = "0.1.0" +name = "zkevm_test_harness" +version = "1.4.1" +source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1#badf56d613b77c25f79b684c161eab7d1e385176" dependencies = [ - "anyhow", - "async-trait", - "backon", - "convert_case 0.6.0", - "futures 0.3.29", + "bincode", + "circuit_definitions 0.1.0 (git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1)", + "codegen", + "crossbeam 0.8.4", + "curl", + "derivative", + "env_logger 0.9.3", "hex", - "metrics", + "lazy_static", + "rand 0.4.6", + "rayon", + "reqwest", + "rescue_poseidon 0.4.1 (git+https://github.com/matter-labs/rescue-poseidon.git?branch=poseidon2)", + "serde", "serde_json", - "thiserror", - "tokio", + "smallvec", + "snark_wrapper", + "structopt", + "test-log", "tracing", - "zksync_config", - "zksync_contracts", - "zksync_dal", - "zksync_eth_client", - "zksync_types", + "walkdir", + "zkevm-assembly 1.3.2 (git+https://github.com/matter-labs/era-zkEVM-assembly.git?branch=v1.4.1)", ] [[package]] -name = "zksync_circuit_synthesizer" +name = "zksync_basic_types" version = "0.1.0" dependencies = [ - "anyhow", - "ctrlc", - "futures 0.3.29", - "local-ip-address", - "prometheus_exporter", - "prover-service", - "structopt", - "thiserror", - "tokio", - "tracing", - "vise", - "vlog", - "zkevm_test_harness 1.3.3", - "zksync_config", - "zksync_dal", - "zksync_env_config", - "zksync_object_store", - "zksync_prover_fri_utils", - "zksync_prover_utils", - "zksync_queued_job_processor", - "zksync_types", - "zksync_utils", - "zksync_verification_key_generator_and_server", + "serde", + "serde_json", + "web3", ] [[package]] name = "zksync_concurrency" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=da015d4c94b19962bc11622b6cc256e214256555#da015d4c94b19962bc11622b6cc256e214256555" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=5b3d383d7a65b0fbe2a771fecf4313f5083be9ae#5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" dependencies = [ "anyhow", "once_cell", @@ -6982,6 +6875,7 @@ name = "zksync_config" version = "0.1.0" dependencies = [ "anyhow", + "rand 0.8.5", "serde", "zksync_basic_types", ] @@ -6989,14 +6883,14 @@ dependencies = [ [[package]] name = "zksync_consensus_crypto" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=da015d4c94b19962bc11622b6cc256e214256555#da015d4c94b19962bc11622b6cc256e214256555" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=5b3d383d7a65b0fbe2a771fecf4313f5083be9ae#5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" dependencies = [ "anyhow", "blst", "ed25519-dalek", "ff_ce", "hex", - "pairing_ce 0.28.5 (git+https://github.com/matter-labs/pairing.git?rev=f55393f)", + "pairing_ce 0.28.5 (git+https://github.com/matter-labs/pairing.git?rev=f55393fd366596eac792d78525d26e9c4d6ed1ca)", "rand 0.4.6", "rand 0.8.5", "sha3 0.10.8", @@ -7007,7 +6901,7 @@ dependencies = [ [[package]] name = "zksync_consensus_roles" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=da015d4c94b19962bc11622b6cc256e214256555#da015d4c94b19962bc11622b6cc256e214256555" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=5b3d383d7a65b0fbe2a771fecf4313f5083be9ae#5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" dependencies = [ "anyhow", "bit-vec", @@ -7024,10 +6918,28 @@ dependencies = [ "zksync_protobuf_build", ] +[[package]] +name = "zksync_consensus_storage" +version = "0.1.0" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=5b3d383d7a65b0fbe2a771fecf4313f5083be9ae#5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" +dependencies = [ + "anyhow", + "async-trait", + "prost", + "rand 0.8.5", + "thiserror", + "tracing", + "vise", + "zksync_concurrency", + "zksync_consensus_roles", + "zksync_protobuf", + "zksync_protobuf_build", +] + [[package]] name = "zksync_consensus_utils" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=da015d4c94b19962bc11622b6cc256e214256555#da015d4c94b19962bc11622b6cc256e214256555" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=5b3d383d7a65b0fbe2a771fecf4313f5083be9ae#5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" dependencies = [ "thiserror", "zksync_concurrency", @@ -7050,7 +6962,6 @@ dependencies = [ name = "zksync_crypto" version = "0.1.0" dependencies = [ - "base64 0.13.1", "blake2 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", "hex", "once_cell", @@ -7067,9 +6978,10 @@ dependencies = [ "anyhow", "bigdecimal", "bincode", + "chrono", "hex", "itertools 0.10.5", - "num 0.3.1", + "num", "once_cell", "prost", "rand 0.8.5", @@ -7083,6 +6995,7 @@ dependencies = [ "url", "vise", "zksync_consensus_roles", + "zksync_consensus_storage", "zksync_contracts", "zksync_health_check", "zksync_protobuf", @@ -7103,49 +7016,12 @@ dependencies = [ "zksync_config", ] -[[package]] -name = "zksync_eth_client" -version = "0.1.0" -dependencies = [ - "anyhow", - "async-trait", - "hex", - "jsonrpc-core", - "serde", - "thiserror", - "tokio", - "tracing", - "vise", - "zksync_config", - "zksync_contracts", - "zksync_eth_signer", - "zksync_types", -] - -[[package]] -name = "zksync_eth_signer" -version = "0.1.0" -dependencies = [ - "async-trait", - "hex", - "jsonrpc-core", - "parity-crypto", - "reqwest", - "rlp", - "secp256k1 0.27.0", - "serde", - "serde_derive", - "serde_json", - "thiserror", - "zksync_types", -] - [[package]] name = "zksync_health_check" version = "0.1.0" dependencies = [ "async-trait", - "futures 0.3.29", + "futures 0.3.30", "serde", "serde_json", "tokio", @@ -7168,13 +7044,17 @@ dependencies = [ "anyhow", "async-trait", "bincode", + "flate2", "google-cloud-auth", "google-cloud-storage", "http", + "prost", + "serde_json", "tokio", "tracing", "vise", "zksync_config", + "zksync_protobuf", "zksync_types", ] @@ -7186,21 +7066,23 @@ dependencies = [ "async-trait", "bincode", "ctrlc", - "futures 0.3.29", + "futures 0.3.30", "prometheus_exporter", + "reqwest", "structopt", "tokio", "tracing", "vise", "vk_setup_data_generator_server_fri", "vlog", - "zkevm_test_harness 1.4.0", + "zkevm_test_harness 1.3.3", + "zkevm_test_harness 1.4.1", "zksync_config", "zksync_dal", "zksync_env_config", "zksync_object_store", "zksync_prover_fri_types", - "zksync_prover_utils", + "zksync_prover_interface", "zksync_queued_job_processor", "zksync_types", "zksync_utils", @@ -7209,7 +7091,7 @@ dependencies = [ [[package]] name = "zksync_protobuf" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=da015d4c94b19962bc11622b6cc256e214256555#da015d4c94b19962bc11622b6cc256e214256555" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=5b3d383d7a65b0fbe2a771fecf4313f5083be9ae#5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" dependencies = [ "anyhow", "bit-vec", @@ -7227,55 +7109,17 @@ dependencies = [ [[package]] name = "zksync_protobuf_build" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=da015d4c94b19962bc11622b6cc256e214256555#da015d4c94b19962bc11622b6cc256e214256555" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=5b3d383d7a65b0fbe2a771fecf4313f5083be9ae#5b3d383d7a65b0fbe2a771fecf4313f5083be9ae" dependencies = [ "anyhow", "heck 0.4.1", "prettyplease", - "proc-macro2 1.0.69", + "proc-macro2 1.0.76", "prost-build", "prost-reflect", "protox", - "quote 1.0.33", - "syn 2.0.39", -] - -[[package]] -name = "zksync_prover" -version = "0.1.0" -dependencies = [ - "anyhow", - "api", - "bincode", - "chrono", - "ctrlc", - "ethabi", - "futures 0.3.29", - "hex", - "local-ip-address", - "prometheus_exporter", - "prover-service", - "queues", - "reqwest", - "serde", - "serde_json", - "setup_key_generator_and_server", - "thiserror", - "tokio", - "tracing", - "vise", - "vlog", - "zkevm_test_harness 1.3.3", - "zksync_circuit_breaker", - "zksync_config", - "zksync_dal", - "zksync_env_config", - "zksync_eth_client", - "zksync_object_store", - "zksync_prover_utils", - "zksync_types", - "zksync_utils", - "zksync_verification_key_generator_and_server", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -7284,11 +7128,13 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", - "circuit_definitions", + "circuit_definitions 0.1.0 (git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1)", "ctrlc", - "futures 0.3.29", + "futures 0.3.30", "local-ip-address", "prometheus_exporter", + "regex", + "reqwest", "serde", "shivini", "tokio", @@ -7296,14 +7142,13 @@ dependencies = [ "vise", "vk_setup_data_generator_server_fri", "vlog", - "zkevm_test_harness 1.4.0", + "zkevm_test_harness 1.4.1", "zksync_config", "zksync_dal", "zksync_env_config", "zksync_object_store", "zksync_prover_fri_types", "zksync_prover_fri_utils", - "zksync_prover_utils", "zksync_queued_job_processor", "zksync_types", "zksync_utils", @@ -7316,7 +7161,7 @@ dependencies = [ "anyhow", "async-trait", "ctrlc", - "futures 0.3.29", + "futures 0.3.30", "log", "prometheus_exporter", "reqwest", @@ -7329,6 +7174,7 @@ dependencies = [ "zksync_dal", "zksync_env_config", "zksync_object_store", + "zksync_prover_interface", "zksync_types", "zksync_utils", ] @@ -7337,7 +7183,7 @@ dependencies = [ name = "zksync_prover_fri_types" version = "0.1.0" dependencies = [ - "circuit_definitions", + "circuit_definitions 0.1.0 (git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1)", "serde", "zksync_object_store", "zksync_types", @@ -7347,6 +7193,9 @@ dependencies = [ name = "zksync_prover_fri_utils" version = "0.1.0" dependencies = [ + "anyhow", + "regex", + "reqwest", "serde", "tracing", "vise", @@ -7355,25 +7204,20 @@ dependencies = [ "zksync_object_store", "zksync_prover_fri_types", "zksync_types", + "zksync_utils", ] [[package]] -name = "zksync_prover_utils" +name = "zksync_prover_interface" version = "0.1.0" dependencies = [ - "anyhow", - "async-trait", - "ctrlc", - "futures 0.3.29", - "regex", - "reqwest", - "tokio", - "toml_edit 0.14.4", - "tracing", - "zksync_config", + "chrono", + "serde", + "serde_with", + "strum", + "zkevm_test_harness 1.3.3", "zksync_object_store", "zksync_types", - "zksync_utils", ] [[package]] @@ -7419,16 +7263,8 @@ dependencies = [ name = "zksync_system_constants" version = "0.1.0" dependencies = [ - "anyhow", - "bigdecimal", - "hex", - "num 0.3.1", "once_cell", - "serde", - "serde_json", - "url", "zksync_basic_types", - "zksync_contracts", "zksync_utils", ] @@ -7439,24 +7275,20 @@ dependencies = [ "anyhow", "blake2 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", "chrono", - "codegen 0.1.0", - "ethereum-types 0.12.1", "hex", - "num 0.3.1", + "num", "num_enum", "once_cell", - "parity-crypto", + "prost", "rlp", + "secp256k1", "serde", "serde_json", "serde_with", "strum", "thiserror", - "zk_evm 1.3.3 (git+https://github.com/matter-labs/era-zk_evm.git?tag=v1.3.3-rc2)", - "zk_evm 1.4.0", - "zkevm_test_harness 1.3.3", "zksync_basic_types", - "zksync_consensus_roles", + "zksync_config", "zksync_contracts", "zksync_mini_merkle_tree", "zksync_protobuf", @@ -7471,11 +7303,11 @@ version = "0.1.0" dependencies = [ "anyhow", "bigdecimal", - "futures 0.3.29", + "futures 0.3.30", "hex", "itertools 0.10.5", "metrics", - "num 0.3.1", + "num", "reqwest", "serde", "thiserror", @@ -7486,25 +7318,6 @@ dependencies = [ "zksync_basic_types", ] -[[package]] -name = "zksync_verification_key_generator_and_server" -version = "0.1.0" -dependencies = [ - "anyhow", - "bincode", - "circuit_testing", - "ff_ce", - "hex", - "itertools 0.10.5", - "once_cell", - "serde_json", - "structopt", - "tracing", - "vlog", - "zksync_prover_utils", - "zksync_types", -] - [[package]] name = "zksync_witness_generator" version = "0.1.0" @@ -7512,10 +7325,10 @@ dependencies = [ "anyhow", "async-trait", "bincode", - "circuit_definitions", + "circuit_definitions 0.1.0 (git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1)", "const-decoder", "ctrlc", - "futures 0.3.29", + "futures 0.3.30", "hex", "multivm", "prometheus_exporter", @@ -7528,15 +7341,15 @@ dependencies = [ "vise", "vk_setup_data_generator_server_fri", "vlog", - "zk_evm 1.4.0", - "zkevm_test_harness 1.4.0", + "zk_evm 1.4.1", + "zkevm_test_harness 1.4.1", "zksync_config", "zksync_dal", "zksync_env_config", "zksync_object_store", "zksync_prover_fri_types", "zksync_prover_fri_utils", - "zksync_prover_utils", + "zksync_prover_interface", "zksync_queued_job_processor", "zksync_state", "zksync_system_constants", @@ -7552,7 +7365,7 @@ dependencies = [ "async-trait", "bincode", "ctrlc", - "futures 0.3.29", + "futures 0.3.30", "prometheus_exporter", "queues", "serde", @@ -7568,7 +7381,6 @@ dependencies = [ "zksync_object_store", "zksync_prover_fri_types", "zksync_prover_fri_utils", - "zksync_prover_utils", "zksync_queued_job_processor", "zksync_types", "zksync_utils", diff --git a/prover/Cargo.toml b/prover/Cargo.toml index e38ab14aa8a7..fd0d764ea558 100644 --- a/prover/Cargo.toml +++ b/prover/Cargo.toml @@ -5,9 +5,6 @@ members = [ "prover_fri_types", # binaries - "prover", - "circuit_synthesizer", - "setup_key_generator_and_server", "witness_generator", "vk_setup_data_generator_server_fri", "prover_fri", @@ -18,6 +15,7 @@ members = [ resolver = "2" + # for `perf` profiling [profile.perf] inherits = "release" diff --git a/prover/README.md b/prover/README.md index c97cdaff2b8b..5e537bf8bc0b 100644 --- a/prover/README.md +++ b/prover/README.md @@ -35,16 +35,3 @@ witness_vector_generators, that can 'share' as single gpu based prover_fri). ### proof_fri_compressor Used as a 'last step' to compress/wrap the final FRI proof into a SNARK (to make L1 verification cheaper). - -## Old proof system - -Some of the components here belong to the old proof system: - -- circuit_synthesizer -- prover -- setup_key_generator_and_server - -Moreover old proof system is also using components from 'core' directory, like: - -- core/bin/verification_key_generator_and_server -- core/lib/zksycn_core/src/witness_generator. diff --git a/prover/circuit_synthesizer/Cargo.toml b/prover/circuit_synthesizer/Cargo.toml deleted file mode 100644 index 9ab44ae14591..000000000000 --- a/prover/circuit_synthesizer/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -[package] -name = "zksync_circuit_synthesizer" -version = "0.1.0" -edition = "2021" - -[[bin]] -name = "zksync_circuit_synthesizer" -path = "src/main.rs" - -[dependencies] -vise = { git = "https://github.com/matter-labs/vise.git", version = "0.1.0", rev = "1c9cc500e92cf9ea052b230e114a6f9cce4fb2c1" } - -zksync_dal = { path = "../../core/lib/dal" } -zksync_types = { path = "../../core/lib/types" } -zksync_queued_job_processor = { path = "../../core/lib/queued_job_processor" } -zksync_config = { path = "../../core/lib/config" } -zksync_env_config = { path = "../../core/lib/env_config" } -zksync_object_store = { path = "../../core/lib/object_store" } -zksync_utils = { path = "../../core/lib/utils" } -zksync_prover_fri_utils = { path = "../prover_fri_utils" } -vlog = { path = "../../core/lib/vlog" } -prometheus_exporter = { path = "../../core/lib/prometheus_exporter" } -zksync_prover_utils = { path = "../../core/lib/prover_utils" } -zksync_verification_key_generator_and_server = { path = "../../core/bin/verification_key_generator_and_server" } - -zkevm_test_harness = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.3.3" } - -prover-service = { git = "https://github.com/matter-labs/era-heavy-ops-service.git", branch = "v1.3.3", features = [ - "legacy", -], default-features = false } - -anyhow = "1.0" -structopt = "0.3.26" -thiserror = "1.0" -tokio = { version = "1.23.0", features = ["full"] } -futures = "0.3" -ctrlc = { version = "3.1", features = ["termination"] } -local-ip-address = "0.5.0" -tracing = "0.1" diff --git a/prover/circuit_synthesizer/README.md b/prover/circuit_synthesizer/README.md deleted file mode 100644 index cc40029cc03d..000000000000 --- a/prover/circuit_synthesizer/README.md +++ /dev/null @@ -1 +0,0 @@ -# PART OF OLD PROVER - OBSOLETE diff --git a/prover/circuit_synthesizer/src/circuit_synthesizer.rs b/prover/circuit_synthesizer/src/circuit_synthesizer.rs deleted file mode 100644 index 96a164c69c15..000000000000 --- a/prover/circuit_synthesizer/src/circuit_synthesizer.rs +++ /dev/null @@ -1,362 +0,0 @@ -use std::{ - option::Option, - time::{Duration, Instant}, -}; - -use anyhow::Context as _; -use local_ip_address::local_ip; -use prover_service::{ - prover::{Prover, ProvingAssembly}, - remote_synth::serialize_job, -}; -use tokio::{task::JoinHandle, time::sleep}; -use zkevm_test_harness::{ - abstract_zksync_circuit::concrete_circuits::ZkSyncCircuit, - bellman::plonk::better_better_cs::cs::Circuit, pairing::bn256::Bn256, - witness::oracle::VmWitnessOracle, -}; -use zksync_config::{ - configs::{prover_group::ProverGroupConfig, CircuitSynthesizerConfig}, - ProverConfigs, -}; -use zksync_dal::ConnectionPool; -use zksync_env_config::FromEnv; -use zksync_object_store::{CircuitKey, ObjectStore, ObjectStoreError, ObjectStoreFactory}; -use zksync_prover_fri_utils::socket_utils::send_assembly; -use zksync_prover_utils::{ - numeric_index_to_circuit_name, - region_fetcher::{get_region, get_zone}, -}; -use zksync_queued_job_processor::{async_trait, JobProcessor}; -use zksync_types::{ - proofs::{GpuProverInstanceStatus, SocketAddress}, - protocol_version::L1VerifierConfig, -}; - -use crate::metrics::METRICS; - -#[derive(thiserror::Error, Debug)] -pub enum CircuitSynthesizerError { - #[error("InvalidaGroupCircuits: {0}")] - InvalidGroupCircuits(u8), - #[error("InvalidCircuitId: {0}")] - InvalidCircuitId(u8), - #[error("InputLoadFailed: {0}")] - InputLoadFailed(ObjectStoreError), - #[error("GetRegionFailed: {0}")] - GetRegionFailed(anyhow::Error), - #[error("GetZoneFailed: {0}")] - GetZoneFailed(anyhow::Error), -} - -pub struct CircuitSynthesizer { - config: CircuitSynthesizerConfig, - blob_store: Box, - allowed_circuit_types: Option>, - region: String, - zone: String, - vk_commitments: L1VerifierConfig, - prover_connection_pool: ConnectionPool, -} - -impl CircuitSynthesizer { - pub async fn new( - config: CircuitSynthesizerConfig, - prover_groups: ProverGroupConfig, - store_factory: &ObjectStoreFactory, - vk_commitments: L1VerifierConfig, - prover_connection_pool: ConnectionPool, - ) -> Result { - let is_specialized = prover_groups.is_specialized_group_id(config.prover_group_id); - let allowed_circuit_types = if is_specialized { - let types = prover_groups - .get_circuit_ids_for_group_id(config.prover_group_id) - .ok_or(CircuitSynthesizerError::InvalidGroupCircuits( - config.prover_group_id, - ))? - .into_iter() - .map(|id| { - numeric_index_to_circuit_name(id) - .map(|x| (id, x.to_owned())) - .ok_or(CircuitSynthesizerError::InvalidCircuitId(id)) - }) - .collect::, CircuitSynthesizerError>>()?; - Some(types) - } else { - None - }; - - tracing::info!( - "Configured for group [{}], circuits: {allowed_circuit_types:?}", - config.prover_group_id - ); - - Ok(Self { - config, - blob_store: store_factory.create_store().await, - allowed_circuit_types: allowed_circuit_types - .map(|x| x.into_iter().map(|x| x.1).collect()), - region: get_region(&prover_groups) - .await - .map_err(CircuitSynthesizerError::GetRegionFailed)?, - zone: get_zone(&prover_groups) - .await - .map_err(CircuitSynthesizerError::GetZoneFailed)?, - vk_commitments, - prover_connection_pool, - }) - } - - pub fn synthesize( - circuit: ZkSyncCircuit>, - ) -> anyhow::Result<(ProvingAssembly, u8)> { - let start_instant = Instant::now(); - - let mut assembly = Prover::new_proving_assembly(); - circuit - .synthesize(&mut assembly) - .context("circuit synthesize failed")?; - - let circuit_type = numeric_index_to_circuit_name(circuit.numeric_circuit_type()).unwrap(); - - tracing::info!( - "Finished circuit synthesis for circuit: {circuit_type} took {:?}", - start_instant.elapsed() - ); - METRICS.synthesize[&circuit_type].observe(start_instant.elapsed()); - - // we don't perform assembly finalization here since it increases the assembly size significantly due to padding. - Ok((assembly, circuit.numeric_circuit_type())) - } -} - -#[async_trait] -impl JobProcessor for CircuitSynthesizer { - type Job = ZkSyncCircuit>; - type JobId = u32; - type JobArtifacts = (ProvingAssembly, u8); - const SERVICE_NAME: &'static str = "CircuitSynthesizer"; - - async fn get_next_job(&self) -> anyhow::Result> { - tracing::trace!( - "Attempting to fetch job types: {:?}", - self.allowed_circuit_types - ); - let mut storage = self.prover_connection_pool.access_storage().await.unwrap(); - let protocol_versions = storage - .protocol_versions_dal() - .protocol_version_for(&self.vk_commitments) - .await; - - let prover_job = match &self.allowed_circuit_types { - Some(types) => { - storage - .prover_dal() - .get_next_prover_job_by_circuit_types(types.clone(), &protocol_versions) - .await - } - None => { - storage - .prover_dal() - .get_next_prover_job(&protocol_versions) - .await - } - }; - let Some(prover_job) = prover_job else { - return Ok(None); - }; - - let circuit_key = CircuitKey { - block_number: prover_job.block_number, - sequence_number: prover_job.sequence_number, - circuit_type: &prover_job.circuit_type, - aggregation_round: prover_job.aggregation_round, - }; - let input = self - .blob_store - .get(circuit_key) - .await - .map_err(CircuitSynthesizerError::InputLoadFailed)?; - - Ok(Some((prover_job.id, input))) - } - - async fn save_failure(&self, job_id: Self::JobId, _started_at: Instant, error: String) { - let res = self - .prover_connection_pool - .access_storage() - .await - .unwrap() - .prover_dal() - .save_proof_error(job_id, error, self.config.max_attempts) - .await; - if let Err(err) = res { - tracing::error!("save_proof_error(): {err:#}"); - } - } - - async fn process_job( - &self, - job: Self::Job, - _started_at: Instant, - ) -> JoinHandle> { - tokio::task::spawn_blocking(move || Self::synthesize(job)) - } - - async fn save_result( - &self, - job_id: Self::JobId, - _started_at: Instant, - (assembly, circuit_id): Self::JobArtifacts, - ) -> anyhow::Result<()> { - tracing::trace!( - "Finished circuit synthesis for job: {job_id} in region: {}", - self.region - ); - - let now = Instant::now(); - let mut serialized: Vec = vec![]; - serialize_job(&assembly, job_id as usize, circuit_id, &mut serialized); - - tracing::trace!( - "Serialized circuit assembly for job {job_id} in {:?}", - now.elapsed() - ); - - let now = Instant::now(); - let mut attempts = 0; - - while now.elapsed() < self.config.prover_instance_wait_timeout() { - let prover = self - .prover_connection_pool - .access_storage() - .await - .unwrap() - .gpu_prover_queue_dal() - .lock_available_prover( - self.config.gpu_prover_queue_timeout(), - self.config.prover_group_id, - self.region.clone(), - self.zone.clone(), - ) - .await; - - if let Some(address) = prover { - let result = send_assembly(job_id, &serialized, &address); - handle_send_result( - &result, - job_id, - &address, - &self.prover_connection_pool, - self.region.clone(), - self.zone.clone(), - ) - .await - .context("handle_send_result()")?; - - if result.is_ok() { - return Ok(()); - } - // We'll retry with another prover again, no point in dropping the results. - - tracing::warn!( - "Could not send assembly to {address:?}. Prover group {}, region {}, \ - circuit id {circuit_id}, send attempt {attempts}.", - self.config.prover_group_id, - self.region - ); - attempts += 1; - } else { - sleep(self.config.prover_instance_poll_time()).await; - } - } - tracing::trace!( - "Not able to get any free prover instance for sending assembly for job: {job_id}" - ); - Ok(()) - } - - fn max_attempts(&self) -> u32 { - self.config.max_attempts - } - - async fn get_job_attempts(&self, _job_id: &u32) -> anyhow::Result { - // Circuit synthesizer will be removed soon in favor of FRI one, so returning blank value. - Ok(1) - } -} - -async fn handle_send_result( - result: &Result<(Duration, u64), String>, - job_id: u32, - address: &SocketAddress, - pool: &ConnectionPool, - region: String, - zone: String, -) -> anyhow::Result<()> { - match result { - Ok((elapsed, len)) => { - let local_ip = local_ip().context("Failed obtaining local IP address")?; - let blob_size_in_gb = len / (1024 * 1024 * 1024); - - // region: logs - - tracing::trace!( - "Sent assembly of size: {blob_size_in_gb}GB successfully, took: {elapsed:?} \ - for job: {job_id} by: {local_ip:?} to: {address:?}" - ); - - METRICS.blob_sending_time[&blob_size_in_gb].observe(*elapsed); - - // endregion - - pool.access_storage() - .await - .unwrap() - .prover_dal() - .update_status(job_id, "in_gpu_proof") - .await; - } - - Err(err) => { - tracing::trace!( - "Failed sending assembly to address: {address:?}, socket not reachable \ - reason: {err}" - ); - - // mark prover instance in gpu_prover_queue dead - pool.access_storage() - .await - .unwrap() - .gpu_prover_queue_dal() - .update_prover_instance_status( - address.clone(), - GpuProverInstanceStatus::Dead, - 0, - region, - zone, - ) - .await; - - let prover_config = ProverConfigs::from_env() - .context("ProverConfigs::from_env()")? - .non_gpu; - // mark the job as failed - let res = pool - .access_storage() - .await - .unwrap() - .prover_dal() - .save_proof_error( - job_id, - "prover instance unreachable".to_string(), - prover_config.max_attempts, - ) - .await; - if let Err(err) = res { - tracing::error!("save_proof_error(): {err}"); - } - } - } - Ok(()) -} diff --git a/prover/circuit_synthesizer/src/main.rs b/prover/circuit_synthesizer/src/main.rs deleted file mode 100644 index a4ac19e18d7b..000000000000 --- a/prover/circuit_synthesizer/src/main.rs +++ /dev/null @@ -1,105 +0,0 @@ -use anyhow::Context as _; -use prometheus_exporter::PrometheusExporterConfig; -use structopt::StructOpt; -use tokio::sync::{oneshot, watch}; -use zksync_config::configs::{ - AlertsConfig, CircuitSynthesizerConfig, ObjectStoreConfig, PostgresConfig, ProverGroupConfig, -}; -use zksync_dal::ConnectionPool; -use zksync_env_config::FromEnv; -use zksync_object_store::ObjectStoreFactory; -use zksync_queued_job_processor::JobProcessor; -use zksync_utils::wait_for_tasks::wait_for_tasks; -use zksync_verification_key_server::get_cached_commitments; - -use crate::circuit_synthesizer::CircuitSynthesizer; - -mod circuit_synthesizer; -mod metrics; - -#[derive(Debug, StructOpt)] -#[structopt(name = "TODO", about = "TODO")] -struct Opt { - /// Number of times circuit_synthesizer should be run. - #[structopt(short = "n", long = "n_iterations")] - number_of_iterations: Option, -} - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let log_format = vlog::log_format_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let sentry_url = vlog::sentry_url_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let environment = vlog::environment_from_env(); - - let mut builder = vlog::ObservabilityBuilder::new().with_log_format(log_format); - if let Some(sentry_url) = sentry_url { - builder = builder - .with_sentry_url(&sentry_url) - .context("Invalid Sentry URL")? - .with_sentry_environment(environment); - } - let _guard = builder.build(); - - let opt = Opt::from_args(); - let config: CircuitSynthesizerConfig = - CircuitSynthesizerConfig::from_env().context("CircuitSynthesizerConfig::from_env()")?; - let postgres_config = PostgresConfig::from_env().context("PostgresConfig::from_env()")?; - let pool = ConnectionPool::builder( - postgres_config.prover_url()?, - postgres_config.max_connections()?, - ) - .build() - .await - .context("failed to build a connection pool")?; - let vk_commitments = get_cached_commitments(); - - let object_store_config = - ObjectStoreConfig::from_env().context("ObjectStoreConfig::from_env()")?; - let circuit_synthesizer = CircuitSynthesizer::new( - config.clone(), - ProverGroupConfig::from_env().context("ProverGroupConfig::from_env()")?, - &ObjectStoreFactory::new(object_store_config), - vk_commitments, - pool, - ) - .await - .map_err(|err| anyhow::anyhow!("Could not initialize synthesizer {err:?}"))?; - - let (stop_sender, stop_receiver) = watch::channel(false); - - let (stop_signal_sender, stop_signal_receiver) = oneshot::channel(); - let mut stop_signal_sender = Some(stop_signal_sender); - ctrlc::set_handler(move || { - if let Some(stop_signal_sender) = stop_signal_sender.take() { - stop_signal_sender.send(()).ok(); - } - }) - .context("Error setting Ctrl+C handler")?; - - tracing::info!("Starting circuit synthesizer"); - let prometheus_task = - PrometheusExporterConfig::pull(config.prometheus_listener_port).run(stop_receiver.clone()); - let tasks = vec![ - tokio::spawn(prometheus_task), - tokio::spawn(circuit_synthesizer.run(stop_receiver, opt.number_of_iterations)), - ]; - - let particular_crypto_alerts = Some( - AlertsConfig::from_env() - .context("AlertsConfig::from_env()")? - .sporadic_crypto_errors_substrs, - ); - let graceful_shutdown = None::>; - let tasks_allowed_to_finish = false; - tokio::select! { - _ = wait_for_tasks(tasks, particular_crypto_alerts, graceful_shutdown, tasks_allowed_to_finish) => {}, - _ = stop_signal_receiver => { - tracing::info!("Stop signal received, shutting down"); - } - }; - stop_sender.send(true).ok(); - Ok(()) -} diff --git a/prover/circuit_synthesizer/src/metrics.rs b/prover/circuit_synthesizer/src/metrics.rs deleted file mode 100644 index 78049d6cf789..000000000000 --- a/prover/circuit_synthesizer/src/metrics.rs +++ /dev/null @@ -1,15 +0,0 @@ -use std::time::Duration; - -use vise::{Buckets, Histogram, LabeledFamily, Metrics}; - -#[derive(Debug, Metrics)] -#[metrics(prefix = "prover_circuit_synthesizer")] -pub(crate) struct CircuitSynthesizerMetrics { - #[metrics(buckets = Buckets::LATENCIES, labels = ["blob_size_in_gb"])] - pub blob_sending_time: LabeledFamily>, - #[metrics(buckets = Buckets::LATENCIES, labels = ["circuit_type"])] - pub synthesize: LabeledFamily<&'static str, Histogram>, -} - -#[vise::register] -pub(crate) static METRICS: vise::Global = vise::Global::new(); diff --git a/prover/proof_fri_compressor/Cargo.toml b/prover/proof_fri_compressor/Cargo.toml index ee5bd340686b..e0c314e61319 100644 --- a/prover/proof_fri_compressor/Cargo.toml +++ b/prover/proof_fri_compressor/Cargo.toml @@ -13,15 +13,16 @@ zksync_dal = { path = "../../core/lib/dal" } zksync_config = { path = "../../core/lib/config" } zksync_env_config = { path = "../../core/lib/env_config" } zksync_object_store = { path = "../../core/lib/object_store" } +zksync_prover_interface = { path = "../../core/lib/prover_interface" } zksync_utils = { path = "../../core/lib/utils" } prometheus_exporter = { path = "../../core/lib/prometheus_exporter" } zksync_prover_fri_types = { path = "../prover_fri_types" } zksync_queued_job_processor = { path = "../../core/lib/queued_job_processor" } vk_setup_data_generator_server_fri = { path = "../vk_setup_data_generator_server_fri" } vlog = { path = "../../core/lib/vlog" } -zksync_prover_utils = { path = "../../core/lib/prover_utils" } -zkevm_test_harness = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.0" } +zkevm_test_harness_1_3_3 = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.3.3", package = "zkevm_test_harness" } +zkevm_test_harness = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.1" } anyhow = "1.0" tracing = "0.1" @@ -31,3 +32,4 @@ futures = { version = "0.3", features = ["compat"] } ctrlc = { version = "3.1", features = ["termination"] } async-trait = "0.1" bincode = "1.0" +reqwest = { version = "0.11", features = ["blocking"] } diff --git a/prover/proof_fri_compressor/src/compressor.rs b/prover/proof_fri_compressor/src/compressor.rs index b4346305b9f9..ecf26cacd4d1 100644 --- a/prover/proof_fri_compressor/src/compressor.rs +++ b/prover/proof_fri_compressor/src/compressor.rs @@ -1,9 +1,16 @@ -use std::time::Instant; +use std::{sync::Arc, time::Instant}; use anyhow::Context as _; use async_trait::async_trait; use tokio::task::JoinHandle; use zkevm_test_harness::proof_wrapper_utils::{wrap_proof, WrapperConfig}; +use zkevm_test_harness_1_3_3::{ + abstract_zksync_circuit::concrete_circuits::{ + ZkSyncCircuit, ZkSyncProof, ZkSyncVerificationKey, + }, + bellman::{bn256::Bn256, plonk::better_better_cs::proof::Proof}, + witness::oracle::VmWitnessOracle, +}; use zksync_dal::ConnectionPool; use zksync_object_store::ObjectStore; use zksync_prover_fri_types::{ @@ -16,24 +23,15 @@ use zksync_prover_fri_types::{ }, get_current_pod_name, AuxOutputWitnessWrapper, FriProofWrapper, }; +use zksync_prover_interface::outputs::L1BatchProofForL1; use zksync_queued_job_processor::JobProcessor; -use zksync_types::{ - aggregated_operations::L1BatchProofForL1, - zkevm_test_harness::{ - abstract_zksync_circuit::concrete_circuits::{ - ZkSyncCircuit, ZkSyncProof, ZkSyncVerificationKey, - }, - bellman::{bn256::Bn256, plonk::better_better_cs::proof::Proof}, - witness::oracle::VmWitnessOracle, - }, - L1BatchNumber, -}; +use zksync_types::L1BatchNumber; use zksync_vk_setup_data_server_fri::{get_recursive_layer_vk_for_circuit_type, get_snark_vk}; use crate::metrics::METRICS; pub struct ProofCompressor { - blob_store: Box, + blob_store: Arc, pool: ConnectionPool, compression_mode: u8, verify_wrapper_proof: bool, @@ -42,7 +40,7 @@ pub struct ProofCompressor { impl ProofCompressor { pub fn new( - blob_store: Box, + blob_store: Arc, pool: ConnectionPool, compression_mode: u8, verify_wrapper_proof: bool, diff --git a/prover/proof_fri_compressor/src/initial_setup_keys.rs b/prover/proof_fri_compressor/src/initial_setup_keys.rs new file mode 100644 index 000000000000..222d2ec69cc5 --- /dev/null +++ b/prover/proof_fri_compressor/src/initial_setup_keys.rs @@ -0,0 +1,59 @@ +use std::{fs::create_dir_all, io::Cursor, path::Path, time::Duration}; + +fn download_initial_setup(key_download_url: &str) -> reqwest::Result> { + tracing::info!("Downloading initial setup from {:?}", key_download_url); + + const DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(120); + let client = reqwest::blocking::Client::builder() + .timeout(DOWNLOAD_TIMEOUT) + .build() + .unwrap(); + + const DOWNLOAD_RETRIES: usize = 5; + let mut retry_count = 0; + + while retry_count < DOWNLOAD_RETRIES { + let bytes = client + .get(key_download_url) + .send() + .and_then(|response| response.bytes().map(|bytes| bytes.to_vec())); + match bytes { + Ok(bytes) => return Ok(bytes), + Err(_) => retry_count += 1, + } + + tracing::warn!("Failed to download keys. Backing off for 5 second"); + std::thread::sleep(Duration::from_secs(5)); + } + + client + .get(key_download_url) + .send() + .and_then(|response| response.bytes().map(|bytes| bytes.to_vec())) +} + +pub fn download_initial_setup_keys_if_not_present( + initial_setup_key_path: &str, + key_download_url: &str, +) { + if Path::new(initial_setup_key_path).exists() { + tracing::info!( + "Initial setup already present at {:?}", + initial_setup_key_path + ); + return; + } + + let bytes = download_initial_setup(key_download_url).expect("Failed downloading initial setup"); + let initial_setup_key_dir = Path::new(initial_setup_key_path).parent().unwrap(); + create_dir_all(initial_setup_key_dir).unwrap_or_else(|_| { + panic!( + "Failed creating dirs recursively: {:?}", + initial_setup_key_dir + ) + }); + let mut file = std::fs::File::create(initial_setup_key_path) + .expect("Cannot create file for the initial setup"); + let mut content = Cursor::new(bytes); + std::io::copy(&mut content, &mut file).expect("Cannot write the downloaded key to the file"); +} diff --git a/prover/proof_fri_compressor/src/main.rs b/prover/proof_fri_compressor/src/main.rs index 90d937b6f309..33aaf3b9162b 100644 --- a/prover/proof_fri_compressor/src/main.rs +++ b/prover/proof_fri_compressor/src/main.rs @@ -11,9 +11,12 @@ use zksync_object_store::ObjectStoreFactory; use zksync_queued_job_processor::JobProcessor; use zksync_utils::wait_for_tasks::wait_for_tasks; -use crate::compressor::ProofCompressor; +use crate::{ + compressor::ProofCompressor, initial_setup_keys::download_initial_setup_keys_if_not_present, +}; mod compressor; +mod initial_setup_keys; mod metrics; #[derive(Debug, StructOpt)] @@ -76,7 +79,7 @@ async fn main() -> anyhow::Result<()> { }) .expect("Error setting Ctrl+C handler"); // Setting handler should always succeed. - zksync_prover_utils::ensure_initial_setup_keys_present( + download_initial_setup_keys_if_not_present( &config.universal_setup_path, &config.universal_setup_download_url, ); diff --git a/prover/prover/Cargo.toml b/prover/prover/Cargo.toml deleted file mode 100644 index aa91013f0ff6..000000000000 --- a/prover/prover/Cargo.toml +++ /dev/null @@ -1,57 +0,0 @@ -[package] -name = "zksync_prover" -version = "0.1.0" -edition = "2018" -authors = ["The Matter Labs Team "] -homepage = "https://zksync.io/" -repository = "https://github.com/matter-labs/zksync-era" -license = "MIT OR Apache-2.0" -keywords = ["blockchain", "zksync"] -categories = ["cryptography"] -publish = false # We don't want to publish our binaries. - -[dependencies] -vise = { git = "https://github.com/matter-labs/vise.git", version = "0.1.0", rev = "1c9cc500e92cf9ea052b230e114a6f9cce4fb2c1" } - -zksync_dal = { path = "../../core/lib/dal" } -zksync_config = { path = "../../core/lib/config" } -zksync_env_config = { path = "../../core/lib/env_config" } -zksync_utils = { path = "../../core/lib/utils" } -zksync_prover_utils = { path = "../../core/lib/prover_utils" } -zksync_circuit_breaker = { path = "../../core/lib/circuit_breaker" } -zksync_eth_client = { path = "../../core/lib/eth_client" } -zksync_types = { path = "../../core/lib/types" } -prometheus_exporter = { path = "../../core/lib/prometheus_exporter" } -vlog = { path = "../../core/lib/vlog" } -zksync_verification_key_generator_and_server = { path = "../../core/bin/verification_key_generator_and_server" } -zksync_object_store = { path = "../../core/lib/object_store" } - -setup_key_generator_and_server = { path = "../setup_key_generator_and_server" } -api = { git = "https://github.com/matter-labs/era-heavy-ops-service.git", branch = "v1.3.3", features = [ - "gpu", -], optional = true, default-features = false } -prover-service = { git = "https://github.com/matter-labs/era-heavy-ops-service.git", branch = "v1.3.3", features = [ - "gpu", -], optional = true, default-features = false } - -zkevm_test_harness = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.3.3" } - -anyhow = "1.0" -tracing = "0.1" -tokio = { version = "1", features = ["time"] } -futures = { version = "0.3", features = ["compat"] } -ctrlc = { version = "3.1", features = ["termination"] } -thiserror = "1.0" -chrono = "0.4" -serde_json = "1.0" -ethabi = "18.0.0" -hex = "0.4" -serde = { version = "1.0", features = ["derive"] } -bincode = "1.3.2" -reqwest = { version = "0.11", features = ["blocking"] } -queues = "1.1.0" -local-ip-address = "0.5.0" - -[features] -default = [] -gpu = ["api", "prover-service", "setup_key_generator_and_server/gpu"] diff --git a/prover/prover/README.md b/prover/prover/README.md deleted file mode 100644 index 6ccb690a33f3..000000000000 --- a/prover/prover/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# OLD PROVER - OBSOLETE - -For compiling locally (no cuda) set `features=["legacy"], default-features=false` for: - -- `./Cargo.toml`: `heavy-ops-service` dependency. -- `../setup_key_generator_and_server/Cargo.toml`: `api` and `prover-service` dependencies. - -**! Don't push those changes !** diff --git a/prover/prover/src/artifact_provider.rs b/prover/prover/src/artifact_provider.rs deleted file mode 100644 index 9af365d95f40..000000000000 --- a/prover/prover/src/artifact_provider.rs +++ /dev/null @@ -1,25 +0,0 @@ -use std::io::Read; - -use anyhow::Context as _; -use prover_service::ArtifactProvider; -use zkevm_test_harness::{ - abstract_zksync_circuit::concrete_circuits::ZkSyncVerificationKey, pairing::bn256::Bn256, -}; -use zksync_setup_key_server::get_setup_for_circuit_type; -use zksync_verification_key_server::get_vk_for_circuit_type; - -#[derive(Debug)] -pub struct ProverArtifactProvider; - -impl ArtifactProvider for ProverArtifactProvider { - type ArtifactError = anyhow::Error; - - fn get_setup(&self, circuit_id: u8) -> Result, Self::ArtifactError> { - get_setup_for_circuit_type(circuit_id).context("get_setup_for_circuit_type()") - } - - fn get_vk(&self, circuit_id: u8) -> Result, Self::ArtifactError> { - let vk = get_vk_for_circuit_type(circuit_id); - Ok(ZkSyncVerificationKey::from_verification_key_and_numeric_type(circuit_id, vk)) - } -} diff --git a/prover/prover/src/main.rs b/prover/prover/src/main.rs deleted file mode 100644 index 56ac77336c24..000000000000 --- a/prover/prover/src/main.rs +++ /dev/null @@ -1,26 +0,0 @@ -#![cfg_attr(not(feature = "gpu"), allow(unused_imports))] - -#[cfg(feature = "gpu")] -mod artifact_provider; -mod metrics; -#[cfg(feature = "gpu")] -mod prover; -#[cfg(feature = "gpu")] -mod prover_params; -#[cfg(feature = "gpu")] -mod run; -#[cfg(feature = "gpu")] -mod socket_listener; -#[cfg(feature = "gpu")] -mod synthesized_circuit_provider; - -#[cfg(not(feature = "gpu"))] -fn main() { - unimplemented!("This binary is only available with `gpu` feature enabled"); -} - -#[cfg(feature = "gpu")] -#[tokio::main] -async fn main() -> anyhow::Result<()> { - run::run().await -} diff --git a/prover/prover/src/metrics.rs b/prover/prover/src/metrics.rs deleted file mode 100644 index ab18c59bcf7c..000000000000 --- a/prover/prover/src/metrics.rs +++ /dev/null @@ -1,41 +0,0 @@ -use std::time::Duration; - -use vise::{Buckets, Counter, Histogram, LabeledFamily, Metrics}; - -const PROVER_LATENCY_BUCKETS: Buckets = Buckets::values(&[ - 1.0, 10.0, 20.0, 40.0, 60.0, 120.0, 240.0, 360.0, 600.0, 1800.0, 3600.0, -]); - -#[derive(Debug, Metrics)] -#[metrics(prefix = "prover")] -pub(crate) struct ProverMetrics { - #[metrics(buckets = PROVER_LATENCY_BUCKETS, labels = ["circuit_type"])] - pub proof_generation_time: LabeledFamily>, - #[metrics(buckets = PROVER_LATENCY_BUCKETS, labels = ["circuit_type"])] - pub circuit_synthesis_time: LabeledFamily>, - #[metrics(buckets = PROVER_LATENCY_BUCKETS, labels = ["circuit_type"])] - pub assembly_finalize_time: LabeledFamily>, - #[metrics(buckets = PROVER_LATENCY_BUCKETS, labels = ["circuit_type"])] - pub assembly_encoding_time: LabeledFamily>, - #[metrics(buckets = PROVER_LATENCY_BUCKETS, labels = ["circuit_type"])] - pub assembly_decoding_time: LabeledFamily>, - #[metrics(buckets = PROVER_LATENCY_BUCKETS, labels = ["circuit_type"])] - pub assembly_transferring_time: LabeledFamily>, - #[metrics(buckets = PROVER_LATENCY_BUCKETS, labels = ["circuit_type"])] - pub setup_load_time: LabeledFamily>, - #[metrics(labels = ["circuit_type"])] - pub setup_loading_cache_miss: LabeledFamily, - #[metrics(buckets = PROVER_LATENCY_BUCKETS)] - pub prover_wait_idle_time: Histogram, - #[metrics(buckets = PROVER_LATENCY_BUCKETS)] - pub setup_load_wait_idle_time: Histogram, - #[metrics(buckets = PROVER_LATENCY_BUCKETS)] - pub scheduler_wait_idle_time: Histogram, - #[metrics(buckets = PROVER_LATENCY_BUCKETS)] - pub download_time: Histogram, - #[metrics(buckets = PROVER_LATENCY_BUCKETS, labels = ["queue_capacity"])] - pub queue_free_slots: LabeledFamily>, -} - -#[vise::register] -pub(crate) static METRICS: vise::Global = vise::Global::new(); diff --git a/prover/prover/src/prover.rs b/prover/prover/src/prover.rs deleted file mode 100644 index efb570050b57..000000000000 --- a/prover/prover/src/prover.rs +++ /dev/null @@ -1,286 +0,0 @@ -use std::{env, time::Duration}; - -use anyhow::Context as _; -use prover_service::{ - JobReporter, - JobResult::{self, Failure, ProofGenerated}, -}; -use tokio::runtime::Handle; -use zkevm_test_harness::{ - abstract_zksync_circuit::concrete_circuits::ZkSyncProof, pairing::bn256::Bn256, -}; -use zksync_config::{PostgresConfig, ProverConfig}; -use zksync_dal::{ConnectionPool, StorageProcessor}; -use zksync_object_store::{Bucket, ObjectStore, ObjectStoreFactory}; -use zksync_types::proofs::ProverJobMetadata; - -use crate::metrics::METRICS; - -#[derive(Debug)] -pub struct ProverReporter { - rt_handle: Handle, - pool: ConnectionPool, - config: ProverConfig, - processed_by: String, - object_store: Box, -} - -fn assembly_debug_blob_url(job_id: usize, circuit_id: u8) -> String { - format!("assembly_debugging_{}_{}.bin", job_id, circuit_id) -} - -impl ProverReporter { - pub(crate) fn new( - postgres_config: PostgresConfig, - config: ProverConfig, - store_factory: &ObjectStoreFactory, - rt_handle: Handle, - ) -> anyhow::Result { - let pool = rt_handle - .block_on(ConnectionPool::singleton(postgres_config.prover_url()?).build()) - .context("failed to build a connection pool")?; - Ok(Self { - pool, - config, - processed_by: env::var("POD_NAME").unwrap_or("Unknown".to_string()), - object_store: rt_handle.block_on(store_factory.create_store()), - rt_handle, - }) - } - - fn handle_successful_proof_generation( - &self, - job_id: usize, - proof: ZkSyncProof, - duration: Duration, - index: usize, - ) { - let circuit_type = self.get_circuit_type(job_id); - let serialized = bincode::serialize(&proof).expect("Failed to serialize proof"); - tracing::info!( - "Successfully generated proof with id {:?} and type: {} for index: {}. Size: {:?}KB took: {:?}", - job_id, - circuit_type, - index, - serialized.len() >> 10, - duration, - ); - - METRICS.proof_generation_time[&circuit_type].observe(duration); - - let job_id = job_id as u32; - self.rt_handle.block_on(async { - let mut connection = self.pool.access_storage().await.unwrap(); - let mut transaction = connection.start_transaction().await.unwrap(); - - // BEWARE, HERE BE DRAGONS. - // `send_report` method is called in an operating system thread, - // which is in charge of saving proof output (ok, errored, etc.). - // The code that calls it is in a thread that does not check it's status. - // If the thread panics, proofs will be generated, but their status won't be saved. - // So a prover will work like this: - // Pick task, execute task, prepare task to be saved, be restarted as nothing happens. - // The error prevents the "fake" work by killing the prover, which causes it to restart. - // A proper fix would be to have the thread signal it was dead or be watched from outside. - // Given we want to deprecate old prover, this is the quick and dirty hack I'm not proud of. - let result = transaction - .prover_dal() - .save_proof(job_id, duration, serialized, &self.processed_by) - .await; - if let Err(e) = result { - tracing::warn!("panicked inside heavy-ops thread: {e:?}; exiting..."); - std::process::exit(-1); - } - self.get_prover_job_metadata_by_id_and_exit_if_error(&mut transaction, job_id) - .await; - transaction.commit().await.unwrap(); - }); - } - - fn get_circuit_type(&self, job_id: usize) -> String { - let prover_job_metadata = self.rt_handle.block_on(async { - let mut connection = self.pool.access_storage().await.unwrap(); - self.get_prover_job_metadata_by_id_and_exit_if_error(&mut connection, job_id as u32) - .await - }); - prover_job_metadata.circuit_type - } - - async fn get_prover_job_metadata_by_id_and_exit_if_error( - &self, - connection: &mut StorageProcessor<'_>, - job_id: u32, - ) -> ProverJobMetadata { - // BEWARE, HERE BE DRAGONS. - // `send_report` method is called in an operating system thread, - // which is in charge of saving proof output (ok, errored, etc.). - // The code that calls it is in a thread that does not check it's status. - // If the thread panics, proofs will be generated, but their status won't be saved. - // So a prover will work like this: - // Pick task, execute task, prepare task to be saved, be restarted as nothing happens. - // The error prevents the "fake" work by killing the prover, which causes it to restart. - // A proper fix would be to have the thread signal it was dead or be watched from outside. - // Given we want to deprecate old prover, this is the quick and dirty hack I'm not proud of. - let result = connection.prover_dal().get_prover_job_by_id(job_id).await; - let prover_job_metadata = match result { - Ok(option) => option, - Err(e) => { - tracing::warn!("panicked inside heavy-ops thread: {e:?}; exiting..."); - std::process::exit(-1); - } - }; - match prover_job_metadata { - Some(val) => val, - None => { - tracing::error!("No job with id: {} exist; exiting...", job_id); - std::process::exit(-1); - } - } - } -} - -impl JobReporter for ProverReporter { - fn send_report(&mut self, report: JobResult) { - match report { - Failure(job_id, error) => { - tracing::error!( - "Failed to generate proof for id {:?}. error reason; {}", - job_id, - error - ); - self.rt_handle.block_on(async { - let result = self - .pool - .access_storage() - .await - .unwrap() - .prover_dal() - .save_proof_error(job_id as u32, error, self.config.max_attempts) - .await; - // BEWARE, HERE BE DRAGONS. - // `send_report` method is called in an operating system thread, - // which is in charge of saving proof output (ok, errored, etc.). - // The code that calls it is in a thread that does not check it's status. - // If the thread panics, proofs will be generated, but their status won't be saved. - // So a prover will work like this: - // Pick task, execute task, prepare task to be saved, be restarted as nothing happens. - // The error prevents the "fake" work by killing the prover, which causes it to restart. - // A proper fix would be to have the thread signal it was dead or be watched from outside. - // Given we want to deprecate old prover, this is the quick and dirty hack I'm not proud of. - if let Err(e) = result { - tracing::warn!("panicked inside heavy-ops thread: {e:?}; exiting..."); - std::process::exit(-1); - } - }); - } - - ProofGenerated(job_id, duration, proof, index) => { - self.handle_successful_proof_generation(job_id, proof, duration, index); - } - - JobResult::Synthesized(job_id, duration) => { - let circuit_type = self.get_circuit_type(job_id); - tracing::trace!( - "Successfully synthesized circuit with id {:?} and type: {}. took: {:?}", - job_id, - circuit_type, - duration, - ); - METRICS.circuit_synthesis_time[&circuit_type].observe(duration); - } - - JobResult::AssemblyFinalized(job_id, duration) => { - let circuit_type = self.get_circuit_type(job_id); - tracing::trace!( - "Successfully finalized assembly with id {:?} and type: {}. took: {:?}", - job_id, - circuit_type, - duration, - ); - METRICS.assembly_finalize_time[&circuit_type].observe(duration); - } - - JobResult::SetupLoaded(job_id, duration, cache_miss) => { - let circuit_type = self.get_circuit_type(job_id); - tracing::trace!( - "Successfully setup loaded with id {:?} and type: {}. \ - took: {:?} and had cache_miss: {}", - job_id, - circuit_type, - duration, - cache_miss - ); - METRICS.setup_load_time[&circuit_type].observe(duration); - METRICS.setup_loading_cache_miss[&circuit_type].inc(); - } - - JobResult::AssemblyEncoded(job_id, duration) => { - let circuit_type = self.get_circuit_type(job_id); - tracing::trace!( - "Successfully encoded assembly with id {:?} and type: {}. took: {:?}", - job_id, - circuit_type, - duration, - ); - METRICS.assembly_encoding_time[&circuit_type].observe(duration); - } - - JobResult::AssemblyDecoded(job_id, duration) => { - let circuit_type = self.get_circuit_type(job_id); - tracing::trace!( - "Successfully decoded assembly with id {:?} and type: {}. took: {:?}", - job_id, - circuit_type, - duration, - ); - METRICS.assembly_decoding_time[&circuit_type].observe(duration); - } - - JobResult::FailureWithDebugging(job_id, circuit_id, assembly, error) => { - tracing::trace!( - "Failed assembly decoding for job-id {} and circuit-type: {}. error: {}", - job_id, - circuit_id, - error, - ); - let blob_url = assembly_debug_blob_url(job_id, circuit_id); - let put_task = self - .object_store - .put_raw(Bucket::ProverJobs, &blob_url, assembly); - self.rt_handle - .block_on(put_task) - .expect("Failed saving debug assembly to GCS"); - } - - JobResult::AssemblyTransferred(job_id, duration) => { - let circuit_type = self.get_circuit_type(job_id); - tracing::trace!( - "Successfully transferred assembly with id {:?} and type: {}. took: {:?}", - job_id, - circuit_type, - duration, - ); - METRICS.assembly_transferring_time[&circuit_type].observe(duration); - } - - JobResult::ProverWaitedIdle(prover_id, duration) => { - tracing::trace!( - "Prover wait idle time: {:?} for prover-id: {:?}", - duration, - prover_id - ); - METRICS.prover_wait_idle_time.observe(duration); - } - - JobResult::SetupLoaderWaitedIdle(duration) => { - tracing::trace!("Setup load wait idle time: {:?}", duration); - METRICS.setup_load_wait_idle_time.observe(duration); - } - - JobResult::SchedulerWaitedIdle(duration) => { - tracing::trace!("Scheduler wait idle time: {:?}", duration); - METRICS.scheduler_wait_idle_time.observe(duration); - } - } - } -} diff --git a/prover/prover/src/prover_params.rs b/prover/prover/src/prover_params.rs deleted file mode 100644 index fc59b88ddf77..000000000000 --- a/prover/prover/src/prover_params.rs +++ /dev/null @@ -1,35 +0,0 @@ -use std::time::Duration; - -use prover_service::Params; -use zksync_config::ProverConfig; - -#[derive(Debug)] -pub struct ProverParams { - number_of_threads: u8, - polling_duration: Duration, - number_of_setup_slots: u8, -} - -impl ProverParams { - pub(crate) fn new(config: &ProverConfig) -> Self { - Self { - number_of_threads: config.number_of_threads as u8, - polling_duration: Duration::from_millis(config.polling_duration_in_millis), - number_of_setup_slots: config.number_of_setup_slots, - } - } -} - -impl Params for ProverParams { - fn number_of_parallel_synthesis(&self) -> u8 { - self.number_of_threads - } - - fn number_of_setup_slots(&self) -> u8 { - self.number_of_setup_slots - } - - fn polling_duration(&self) -> Duration { - self.polling_duration - } -} diff --git a/prover/prover/src/run.rs b/prover/prover/src/run.rs deleted file mode 100644 index 9784b2f1b666..000000000000 --- a/prover/prover/src/run.rs +++ /dev/null @@ -1,255 +0,0 @@ -use std::{env, future::Future, sync::Arc, time::Instant}; - -use anyhow::Context as _; -use local_ip_address::local_ip; -use prometheus_exporter::PrometheusExporterConfig; -use queues::Buffer; -use tokio::sync::{oneshot, Mutex}; -use zksync_config::{ - configs::{ - api::PrometheusConfig, prover_group::ProverGroupConfig, AlertsConfig, ObjectStoreConfig, - }, - ApiConfig, PostgresConfig, ProverConfig, ProverConfigs, -}; -use zksync_dal::ConnectionPool; -use zksync_env_config::FromEnv; -use zksync_object_store::ObjectStoreFactory; -use zksync_prover_utils::region_fetcher::{get_region, get_zone}; -use zksync_types::proofs::{GpuProverInstanceStatus, SocketAddress}; -use zksync_utils::wait_for_tasks::wait_for_tasks; - -use crate::{ - artifact_provider::ProverArtifactProvider, metrics::METRICS, prover::ProverReporter, - prover_params::ProverParams, socket_listener::incoming_socket_listener, - synthesized_circuit_provider::SynthesizedCircuitProvider, -}; - -async fn graceful_shutdown() -> anyhow::Result> { - let postgres_config = PostgresConfig::from_env().context("PostgresConfig::from_env()")?; - let pool = ConnectionPool::singleton(postgres_config.prover_url()?) - .build() - .await - .context("failed to build a connection pool")?; - let host = local_ip().context("Failed obtaining local IP address")?; - let port = ProverConfigs::from_env() - .context("ProverConfigs")? - .non_gpu - .assembly_receiver_port; - let prover_group_config = - ProverGroupConfig::from_env().context("ProverGroupConfig::from_env()")?; - let region = get_region(&prover_group_config) - .await - .context("get_region()")?; - let zone = get_zone(&prover_group_config).await.context("get_zone()")?; - let address = SocketAddress { host, port }; - Ok(async move { - pool.access_storage() - .await - .unwrap() - .gpu_prover_queue_dal() - .update_prover_instance_status(address, GpuProverInstanceStatus::Dead, 0, region, zone) - .await - }) -} - -fn get_ram_per_gpu() -> anyhow::Result { - use api::gpu_prover::cuda_bindings; - - let device_info = - cuda_bindings::device_info(0).map_err(|err| anyhow::anyhow!("device_info(): {err:?}"))?; - let ram_in_gb: u64 = device_info.total / (1024 * 1024 * 1024); - tracing::info!("Detected RAM per GPU: {:?} GB", ram_in_gb); - Ok(ram_in_gb) -} - -fn get_prover_config_for_machine_type() -> anyhow::Result<(ProverConfig, u8)> { - use api::gpu_prover::cuda_bindings; - - let prover_configs = ProverConfigs::from_env().context("ProverConfigs::from_env()")?; - let actual_num_gpus = match cuda_bindings::devices() { - Ok(gpus) => gpus as u8, - Err(err) => { - tracing::error!("unable to get number of GPUs: {err:?}"); - anyhow::bail!("unable to get number of GPUs: {:?}", err); - } - }; - tracing::info!("detected number of gpus: {}", actual_num_gpus); - let ram_in_gb = get_ram_per_gpu().context("get_ram_per_gpu()")?; - - Ok(match actual_num_gpus { - 1 => { - tracing::info!("Detected machine type with 1 GPU and 80GB RAM"); - (prover_configs.one_gpu_eighty_gb_mem, actual_num_gpus) - } - 2 => { - if ram_in_gb > 39 { - tracing::info!("Detected machine type with 2 GPU and 80GB RAM"); - (prover_configs.two_gpu_eighty_gb_mem, actual_num_gpus) - } else { - tracing::info!("Detected machine type with 2 GPU and 40GB RAM"); - (prover_configs.two_gpu_forty_gb_mem, actual_num_gpus) - } - } - 4 => { - tracing::info!("Detected machine type with 4 GPU and 80GB RAM"); - (prover_configs.four_gpu_eighty_gb_mem, actual_num_gpus) - } - _ => anyhow::bail!("actual_num_gpus: {} not supported yet", actual_num_gpus), - }) -} - -pub async fn run() -> anyhow::Result<()> { - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let log_format = vlog::log_format_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let sentry_url = vlog::sentry_url_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let environment = vlog::environment_from_env(); - - let mut builder = vlog::ObservabilityBuilder::new().with_log_format(log_format); - if let Some(sentry_url) = sentry_url { - builder = builder - .with_sentry_url(&sentry_url) - .context("Invalid Sentry URL")? - .with_sentry_environment(environment); - } - let _guard = builder.build(); - - tracing::trace!("starting prover"); - let (prover_config, num_gpu) = - get_prover_config_for_machine_type().context("get_prover_config_for_machine_type()")?; - - let prometheus_config = PrometheusConfig { - listener_port: prover_config.prometheus_port, - ..ApiConfig::from_env() - .context("ApiConfig::from_env()")? - .prometheus - }; - - let prover_group_config = - ProverGroupConfig::from_env().context("ProverGroupConfig::from_env()")?; - let region = get_region(&prover_group_config) - .await - .context("get_region()")?; - let zone = get_zone(&prover_group_config).await.context("get_zone()")?; - - let (stop_signal_sender, stop_signal_receiver) = oneshot::channel(); - let mut stop_signal_sender = Some(stop_signal_sender); - ctrlc::set_handler(move || { - if let Some(sender) = stop_signal_sender.take() { - sender.send(()).ok(); - } - }) - .expect("Error setting Ctrl+C handler"); - - let started_at = Instant::now(); - zksync_prover_utils::ensure_initial_setup_keys_present( - &prover_config.initial_setup_key_path, - &prover_config.key_download_url, - ); - METRICS.download_time.observe(started_at.elapsed()); - env::set_var("CRS_FILE", prover_config.initial_setup_key_path.clone()); - // We don't have a graceful shutdown process for the prover, so `_stop_sender` is unused. - // Though we still need to create a channel because circuit breaker expects `stop_receiver`. - let (_stop_sender, stop_receiver) = tokio::sync::watch::channel(false); - - let circuit_ids = - prover_group_config.get_circuit_ids_for_group_id(prover_config.specialized_prover_group_id); - - tracing::info!( - "Starting proof generation for circuits: {circuit_ids:?} \ - in region: {region} and zone: {zone} with group-id: {}", - prover_config.specialized_prover_group_id - ); - let mut tasks = vec![]; - - let exporter_config = PrometheusExporterConfig::pull(prometheus_config.listener_port); - tasks.push(tokio::spawn(exporter_config.run(stop_receiver.clone()))); - - let assembly_queue = Buffer::new(prover_config.assembly_queue_capacity); - let shared_assembly_queue = Arc::new(Mutex::new(assembly_queue)); - let producer = shared_assembly_queue.clone(); - let consumer = shared_assembly_queue.clone(); - let local_ip = local_ip().context("Failed obtaining local IP address")?; - let address = SocketAddress { - host: local_ip, - port: prover_config.assembly_receiver_port, - }; - tracing::info!("local IP address is: {:?}", local_ip); - - let postgres_config = PostgresConfig::from_env().context("PostgresConfig::from_env()")?; - tasks.push(tokio::task::spawn(incoming_socket_listener( - local_ip, - prover_config.assembly_receiver_port, - producer, - ConnectionPool::singleton(postgres_config.prover_url()?) - .build() - .await - .context("failed to build a connection pool")?, - prover_config.specialized_prover_group_id, - region.clone(), - zone.clone(), - num_gpu, - ))); - - let params = ProverParams::new(&prover_config); - let object_store_config = - ObjectStoreConfig::from_env().context("ObjectStoreConfig::from_env()")?; - let store_factory = ObjectStoreFactory::new(object_store_config); - - let circuit_provider_pool = ConnectionPool::singleton(postgres_config.prover_url()?) - .build() - .await - .context("failed to build circuit_provider_pool")?; - tasks.push(tokio::task::spawn_blocking(move || { - let rt_handle = tokio::runtime::Handle::current(); - let synthesized_circuit_provider = SynthesizedCircuitProvider::new( - consumer, - circuit_provider_pool, - address, - region, - zone, - rt_handle.clone(), - ); - let prover_job_reporter = - ProverReporter::new(postgres_config, prover_config, &store_factory, rt_handle) - .context("ProverReporter::new()")?; - prover_service::run_prover::run_prover_with_remote_synthesizer( - synthesized_circuit_provider, - ProverArtifactProvider, - prover_job_reporter, - circuit_ids, - params, - ); - Ok(()) - })); - - let particular_crypto_alerts = Some( - AlertsConfig::from_env() - .context("AlertsConfig::from_env()")? - .sporadic_crypto_errors_substrs, - ); - let graceful_shutdown = Some( - graceful_shutdown() - .await - .context("failed to prepare graceful shutdown future")?, - ); - let tasks_allowed_to_finish = false; - tokio::select! { - _ = wait_for_tasks(tasks, particular_crypto_alerts, graceful_shutdown, tasks_allowed_to_finish) => {}, - _ = stop_signal_receiver => { - tracing::info!("Stop signal received, shutting down"); - - // BEWARE, HERE BE DRAGONS. - // This is necessary because of blocking prover. See end of functions for more details. - std::process::exit(0); - }, - }; - - // BEWARE, HERE BE DRAGONS. - // The process hangs here if we panic outside `run_prover_with_remote_synthesizer`. - // Given the task is spawned as blocking, it's in a different thread that can't be cancelled on demand. - // See: https://docs.rs/tokio/latest/tokio/task/fn.spawn_blocking.html for more information - // Follow [PR](https://github.com/matter-labs/zksync-2-dev/pull/2129) for logic behind it - std::process::exit(-1); -} diff --git a/prover/prover/src/socket_listener.rs b/prover/prover/src/socket_listener.rs deleted file mode 100644 index 95a369e70786..000000000000 --- a/prover/prover/src/socket_listener.rs +++ /dev/null @@ -1,122 +0,0 @@ -use std::{ - net::{IpAddr, SocketAddr}, - time::Instant, -}; - -use anyhow::Context as _; -use queues::IsQueue; -use tokio::{ - io::copy, - net::{TcpListener, TcpStream}, -}; -use zksync_dal::ConnectionPool; -use zksync_types::proofs::{GpuProverInstanceStatus, SocketAddress}; - -use crate::synthesized_circuit_provider::SharedAssemblyQueue; - -#[allow(clippy::too_many_arguments)] -pub async fn incoming_socket_listener( - host: IpAddr, - port: u16, - queue: SharedAssemblyQueue, - pool: ConnectionPool, - specialized_prover_group_id: u8, - region: String, - zone: String, - num_gpu: u8, -) -> anyhow::Result<()> { - let listening_address = SocketAddr::new(host, port); - tracing::info!( - "Starting assembly receiver at host: {}, port: {}", - host, - port - ); - let listener = TcpListener::bind(listening_address) - .await - .with_context(|| format!("Failed binding address: {listening_address:?}"))?; - let address = SocketAddress { host, port }; - - let queue_capacity = queue.lock().await.capacity(); - pool.access_storage() - .await - .unwrap() - .gpu_prover_queue_dal() - .insert_prover_instance( - address.clone(), - queue_capacity, - specialized_prover_group_id, - region.clone(), - zone.clone(), - num_gpu, - ) - .await; - - let mut now = Instant::now(); - - loop { - let stream = listener - .accept() - .await - .context("could not accept connection")? - .0; - tracing::trace!( - "Received new assembly send connection, waited for {}ms.", - now.elapsed().as_millis() - ); - - handle_incoming_file( - stream, - queue.clone(), - pool.clone(), - address.clone(), - region.clone(), - zone.clone(), - ) - .await; - - now = Instant::now(); - } -} - -async fn handle_incoming_file( - mut stream: TcpStream, - queue: SharedAssemblyQueue, - pool: ConnectionPool, - address: SocketAddress, - region: String, - zone: String, -) { - let mut assembly: Vec = vec![]; - let started_at = Instant::now(); - copy(&mut stream, &mut assembly) - .await - .expect("Failed reading from stream"); - let file_size_in_gb = assembly.len() / (1024 * 1024 * 1024); - tracing::trace!( - "Read file of size: {}GB from stream took: {} seconds", - file_size_in_gb, - started_at.elapsed().as_secs() - ); - // acquiring lock from queue and updating db must be done atomically otherwise it results in TOCTTOU - // Time-of-Check to Time-of-Use - let mut assembly_queue = queue.lock().await; - let (queue_free_slots, status) = { - assembly_queue - .add(assembly) - .expect("Failed saving assembly to queue"); - let status = if assembly_queue.capacity() == assembly_queue.size() { - GpuProverInstanceStatus::Full - } else { - GpuProverInstanceStatus::Available - }; - let queue_free_slots = assembly_queue.capacity() - assembly_queue.size(); - (queue_free_slots, status) - }; - - pool.access_storage() - .await - .unwrap() - .gpu_prover_queue_dal() - .update_prover_instance_status(address, status, queue_free_slots, region, zone) - .await; -} diff --git a/prover/prover/src/synthesized_circuit_provider.rs b/prover/prover/src/synthesized_circuit_provider.rs deleted file mode 100644 index e1cec64162b0..000000000000 --- a/prover/prover/src/synthesized_circuit_provider.rs +++ /dev/null @@ -1,81 +0,0 @@ -use std::{ - io::{Cursor, Read}, - sync::Arc, -}; - -use prover_service::RemoteSynthesizer; -use queues::{Buffer, IsQueue}; -use tokio::{runtime::Handle, sync::Mutex}; -use zksync_dal::ConnectionPool; -use zksync_types::proofs::SocketAddress; - -use crate::metrics::METRICS; - -pub type SharedAssemblyQueue = Arc>>>; - -pub struct SynthesizedCircuitProvider { - rt_handle: Handle, - queue: SharedAssemblyQueue, - pool: ConnectionPool, - address: SocketAddress, - region: String, - zone: String, -} - -impl SynthesizedCircuitProvider { - pub fn new( - queue: SharedAssemblyQueue, - pool: ConnectionPool, - address: SocketAddress, - region: String, - zone: String, - rt_handle: Handle, - ) -> Self { - Self { - rt_handle, - queue, - pool, - address, - region, - zone, - } - } -} - -impl RemoteSynthesizer for SynthesizedCircuitProvider { - fn try_next(&mut self) -> Option> { - let mut assembly_queue = self.rt_handle.block_on(async { self.queue.lock().await }); - let is_full = assembly_queue.capacity() == assembly_queue.size(); - return match assembly_queue.remove() { - Ok(blob) => { - let queue_free_slots = assembly_queue.capacity() - assembly_queue.size(); - if is_full { - self.rt_handle.block_on(async { - self.pool - .access_storage() - .await - .unwrap() - .gpu_prover_queue_dal() - .update_prover_instance_from_full_to_available( - self.address.clone(), - queue_free_slots, - self.region.clone(), - self.zone.clone(), - ) - .await - }); - } - tracing::trace!( - "Queue free slot {} for capacity {}", - queue_free_slots, - assembly_queue.capacity() - ); - METRICS.queue_free_slots[&assembly_queue.capacity().to_string()] - .observe(queue_free_slots); - - Some(Box::new(Cursor::new(blob))) - } - Err(_) => None, - }; - } -} diff --git a/prover/prover_fri/Cargo.toml b/prover/prover_fri/Cargo.toml index bfef44fd65b3..45ab5e966731 100644 --- a/prover/prover_fri/Cargo.toml +++ b/prover/prover_fri/Cargo.toml @@ -15,19 +15,18 @@ zksync_env_config = { path = "../../core/lib/env_config" } prometheus_exporter = { path = "../../core/lib/prometheus_exporter" } vlog = { path = "../../core/lib/vlog" } zksync_object_store = { path = "../../core/lib/object_store" } -zksync_prover_utils = { path = "../../core/lib/prover_utils" } zksync_queued_job_processor = { path = "../../core/lib/queued_job_processor" } zksync_prover_fri_utils = { path = "../prover_fri_utils" } zksync_prover_fri_types = { path = "../prover_fri_types" } zksync_utils = { path = "../../core/lib/utils" } vk_setup_data_generator_server_fri = { path = "../vk_setup_data_generator_server_fri" } -shivini = { git = "https://github.com/matter-labs/era-shivini.git", branch = "main", optional = true, features = [ +shivini = { git = "https://github.com/matter-labs/era-shivini.git", branch = "v1.4.1", optional = true, features = [ "circuit_definitions", "zksync", ] } -zkevm_test_harness = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.0" } -circuit_definitions = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.0", features = [ +zkevm_test_harness = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.1" } +circuit_definitions = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.1", features = [ "log_tracing", ] } @@ -39,6 +38,8 @@ ctrlc = { version = "3.1", features = ["termination"] } serde = { version = "1.0", features = ["derive"] } async-trait = "0.1" local-ip-address = "0.5.0" +reqwest = { version = "0.11", features = ["blocking"] } +regex = "1.7.2" [features] default = [] diff --git a/prover/prover_fri/README.md b/prover/prover_fri/README.md index f46a89ae4981..54d678a39ab2 100644 --- a/prover/prover_fri/README.md +++ b/prover/prover_fri/README.md @@ -27,7 +27,7 @@ from the database and do their part of the pipeline. ```mermaid flowchart LR A["Operator"] --> |Produces block| F[Prover Gateway] - F --> |Inserts into DB| B["Postgress DB"] + F --> |Inserts into DB| B["Postgres DB"] B --> |Retrieves proven block \nafter compression| F B --> C["Witness"] C --- C1["Basic Circuits"] @@ -43,8 +43,9 @@ flowchart LR ### Prerequisites -Make sure these dependencies are installed and available on your machine: [Installing dependencies](./setup-dev.md) Once -that is done, before starting, make sure you go into the root of the repository, then run +Make sure these dependencies are installed and available on your machine: +[Installing dependencies](../../docs/guides/setup-dev.md) Once that is done, before starting, make sure you go into the +root of the repository, then run ``` export ZKSYNC_HOME=$(pwd) @@ -108,8 +109,8 @@ Machine specs: API_PROMETHEUS_LISTENER_PORT=3116 zk f cargo run --release --bin zksync_witness_generator -- --all_rounds ``` - Note that this will automatically open the three ports after the one specified in enviromental variable, in this case - 3117, 3118 and 3119. + Note that this will automatically open the three ports after the one specified in environmental variable, in this + case 3117, 3118 and 3119. 7. Run prover to perform actual proving: @@ -201,7 +202,7 @@ zk status prover ``` This might take a while (around an hour and a half on my machine using the CPU prover), you can check on it once in a -while. A succesful flow should output something like +while. A successful flow should output something like ``` ==== FRI Prover status ==== @@ -211,7 +212,7 @@ Verification key hash on contract is 0x4be443afd605a782b6e56d199df2460a025c81b3d Verification key in database is 0x4be443afd605a782b6e56d199df2460a025c81b3dea144e135bece83612563f2 Verifier hash matches. Verifier params on contract are 0x5a3ef282b21e12fe1f4438e5bb158fc5060b160559c5158c6389d62d9fe3d080, 0x72167c43a46cf38875b267d67716edc4563861364a3c03ab7aee73498421e828, 0x0000000000000000000000000000000000000000000000000000000000000000 -Verifcation params match. +Verification params match. Next block that should be verified is: 2 Checking status of the proofs... Proof progress for 1 : 111 successful, 0 failed, 0 in progress, 0 queued. Compression job status: successful @@ -231,8 +232,8 @@ Performing circuit upgrade requires crypto library to be updated and generating finalization hints if the circuit changes. Below steps can be used to perform circuit upgrade: 1. checkout if the circuit geometry has changed in the new version of the circuit by running the - [workflow](https://github.com/matter-labs/zkevm_test_harness/actions/workflows/geometry-config-generator.yml) in - harness and merge the generated PR. + [workflow](https://github.com/matter-labs/era-zkevm_test_harness/blob/v1.4.0/.github/workflows/.github/workflows/geometry-config-generator.yml) + in harness and merge the generated PR. 2. update the relevant crypto dependencies(boojum, zkevm_circuit, harness, etc) in `Cargo.lock`, for example: `cargo update -p zkevm_test_harness@1.4.0` 3. prepare an PR with the updated dependencies [sample PR](https://github.com/matter-labs/zksync-2-dev/pull/2481). @@ -250,8 +251,5 @@ finalization hints if the circuit changes. Below steps can be used to perform ci PR to generate the gpu setup data. 8. Once the setup data generation workflows are successful, update the PR with `setup_keys_id` id in [build-docker-from-tag.yml](../../.github/workflows/build-docker-from-tag.yml) and in - [fri-gpu-prover-integration-test.yml](../../.github/workflows/fri-gpu-prover-integration-test.yml), make sure to only - do it from `FRI prover` not old. -9. Run the GPU integration test - [workflow](https://github.com/matter-labs/zksync-era/actions/workflows/fri-gpu-prover-integration-test.yml) against - the PR to verify the GPU prover is working fine with new circuits. + [fri-gpu-prover-integration-test.yml](https://github.com/matter-labs/zksync-2-dev/blob/main/.github/workflows/fri-gpu-prover-integration-test.yml), + make sure to only do it from `FRI prover` not old. diff --git a/prover/prover_fri/src/gpu_prover_job_processor.rs b/prover/prover_fri/src/gpu_prover_job_processor.rs index 5e576bc114bd..82b78024a98d 100644 --- a/prover/prover_fri/src/gpu_prover_job_processor.rs +++ b/prover/prover_fri/src/gpu_prover_job_processor.rs @@ -6,7 +6,7 @@ pub mod gpu_prover { use shivini::{gpu_prove_from_external_witness_data, ProverContext}; use tokio::task::JoinHandle; use zksync_config::configs::{fri_prover_group::FriProverGroupConfig, FriProverConfig}; - use zksync_dal::ConnectionPool; + use zksync_dal::{fri_prover_dal::types::SocketAddress, ConnectionPool}; use zksync_env_config::FromEnv; use zksync_object_store::ObjectStore; use zksync_prover_fri_types::{ @@ -26,7 +26,7 @@ pub mod gpu_prover { CircuitWrapper, FriProofWrapper, ProverServiceDataKey, WitnessVectorArtifacts, }; use zksync_queued_job_processor::{async_trait, JobProcessor}; - use zksync_types::{basic_fri_types::CircuitIdRoundTuple, proofs::SocketAddress}; + use zksync_types::basic_fri_types::CircuitIdRoundTuple; use zksync_vk_setup_data_server_fri::{ get_setup_data_for_circuit_type, GoldilocksGpuProverSetupData, }; @@ -49,8 +49,8 @@ pub mod gpu_prover { #[allow(dead_code)] pub struct Prover { - blob_store: Box, - public_blob_store: Option>, + blob_store: Arc, + public_blob_store: Option>, config: Arc, prover_connection_pool: ConnectionPool, setup_load_mode: SetupLoadMode, @@ -66,8 +66,8 @@ pub mod gpu_prover { impl Prover { #[allow(dead_code)] pub fn new( - blob_store: Box, - public_blob_store: Option>, + blob_store: Arc, + public_blob_store: Option>, config: FriProverConfig, prover_connection_pool: ConnectionPool, setup_load_mode: SetupLoadMode, diff --git a/prover/prover_fri/src/main.rs b/prover/prover_fri/src/main.rs index a1f1ae0088d1..d867fd5e93c9 100644 --- a/prover/prover_fri/src/main.rs +++ b/prover/prover_fri/src/main.rs @@ -1,5 +1,5 @@ #![feature(generic_const_exprs)] -use std::future::Future; +use std::{future::Future, sync::Arc}; use anyhow::Context as _; use local_ip_address::local_ip; @@ -9,21 +9,20 @@ use tokio::{ task::JoinHandle, }; use zksync_config::configs::{ - fri_prover_group::FriProverGroupConfig, FriProverConfig, PostgresConfig, ProverGroupConfig, + fri_prover_group::FriProverGroupConfig, FriProverConfig, PostgresConfig, +}; +use zksync_dal::{ + fri_prover_dal::types::{GpuProverInstanceStatus, SocketAddress}, + ConnectionPool, }; -use zksync_dal::ConnectionPool; use zksync_env_config::{ object_store::{ProverObjectStoreConfig, PublicObjectStoreConfig}, FromEnv, }; use zksync_object_store::{ObjectStore, ObjectStoreFactory}; -use zksync_prover_fri_utils::get_all_circuit_id_round_tuples_for; -use zksync_prover_utils::region_fetcher::get_zone; +use zksync_prover_fri_utils::{get_all_circuit_id_round_tuples_for, region_fetcher::get_zone}; use zksync_queued_job_processor::JobProcessor; -use zksync_types::{ - basic_fri_types::CircuitIdRoundTuple, - proofs::{GpuProverInstanceStatus, SocketAddress}, -}; +use zksync_types::basic_fri_types::CircuitIdRoundTuple; use zksync_utils::wait_for_tasks::wait_for_tasks; mod gpu_prover_job_processor; @@ -39,9 +38,10 @@ async fn graceful_shutdown(port: u16) -> anyhow::Result .await .context("failed to build a connection pool")?; let host = local_ip().context("Failed obtaining local IP address")?; - let prover_group_config = - ProverGroupConfig::from_env().context("ProverGroupConfig::from_env()")?; - let zone = get_zone(&prover_group_config).await.context("get_zone()")?; + let zone_url = &FriProverConfig::from_env() + .context("FriProverConfig::from_env()")? + .zone_read_url; + let zone = get_zone(zone_url).await.context("get_zone()")?; let address = SocketAddress { host, port }; Ok(async move { pool.access_storage() @@ -170,7 +170,7 @@ async fn get_prover_tasks( prover_config: FriProverConfig, stop_receiver: Receiver, store_factory: ObjectStoreFactory, - public_blob_store: Option>, + public_blob_store: Option>, pool: ConnectionPool, circuit_ids_for_round_to_be_proven: Vec, ) -> anyhow::Result>>> { @@ -204,7 +204,7 @@ async fn get_prover_tasks( prover_config: FriProverConfig, stop_receiver: Receiver, store_factory: ObjectStoreFactory, - public_blob_store: Option>, + public_blob_store: Option>, pool: ConnectionPool, circuit_ids_for_round_to_be_proven: Vec, ) -> anyhow::Result>>> { @@ -221,9 +221,9 @@ async fn get_prover_tasks( let shared_witness_vector_queue = Arc::new(Mutex::new(witness_vector_queue)); let consumer = shared_witness_vector_queue.clone(); - let prover_group_config = - ProverGroupConfig::from_env().context("ProverGroupConfig::from_env()")?; - let zone = get_zone(&prover_group_config).await.context("get_zone()")?; + let zone = get_zone(&prover_config.zone_read_url) + .await + .context("get_zone()")?; let local_ip = local_ip().context("Failed obtaining local IP address")?; let address = SocketAddress { host: local_ip, diff --git a/prover/prover_fri/src/prover_job_processor.rs b/prover/prover_fri/src/prover_job_processor.rs index dbe4bee0c86e..40275b681b70 100644 --- a/prover/prover_fri/src/prover_job_processor.rs +++ b/prover/prover_fri/src/prover_job_processor.rs @@ -43,8 +43,8 @@ pub enum SetupLoadMode { } pub struct Prover { - blob_store: Box, - public_blob_store: Option>, + blob_store: Arc, + public_blob_store: Option>, config: Arc, prover_connection_pool: ConnectionPool, setup_load_mode: SetupLoadMode, @@ -57,8 +57,8 @@ pub struct Prover { impl Prover { #[allow(dead_code)] pub fn new( - blob_store: Box, - public_blob_store: Option>, + blob_store: Arc, + public_blob_store: Option>, config: FriProverConfig, prover_connection_pool: ConnectionPool, setup_load_mode: SetupLoadMode, diff --git a/prover/prover_fri/src/socket_listener.rs b/prover/prover_fri/src/socket_listener.rs index 36efc7721459..8c564ea13a06 100644 --- a/prover/prover_fri/src/socket_listener.rs +++ b/prover/prover_fri/src/socket_listener.rs @@ -11,10 +11,13 @@ pub mod gpu_socket_listener { net::{TcpListener, TcpStream}, sync::watch, }; - use zksync_dal::ConnectionPool; + use zksync_dal::{ + fri_prover_dal::types::{GpuProverInstanceStatus, SocketAddress}, + ConnectionPool, + }; use zksync_object_store::bincode; use zksync_prover_fri_types::{CircuitWrapper, ProverServiceDataKey, WitnessVectorArtifacts}; - use zksync_types::proofs::{AggregationRound, GpuProverInstanceStatus, SocketAddress}; + use zksync_types::basic_fri_types::AggregationRound; use zksync_vk_setup_data_server_fri::{ get_finalization_hints, get_round_for_recursive_circuit_type, }; @@ -136,7 +139,7 @@ pub mod gpu_socket_listener { witness_vector_artifacts: witness_vector, assembly, }; - // acquiring lock from queue and updating db must be done atomically otherwise it results in TOCTTOU + // acquiring lock from queue and updating db must be done atomically otherwise it results in `TOCTTOU` // Time-of-Check to Time-of-Use let mut queue = self.queue.lock().await; diff --git a/prover/prover_fri/src/utils.rs b/prover/prover_fri/src/utils.rs index d86adbf4e899..b111f22605c4 100644 --- a/prover/prover_fri/src/utils.rs +++ b/prover/prover_fri/src/utils.rs @@ -27,7 +27,10 @@ use zksync_prover_fri_types::{ CircuitWrapper, FriProofWrapper, ProverServiceDataKey, WitnessVectorArtifacts, }; use zksync_prover_fri_utils::get_base_layer_circuit_id_for_recursive_layer; -use zksync_types::{basic_fri_types::CircuitIdRoundTuple, proofs::AggregationRound, L1BatchNumber}; +use zksync_types::{ + basic_fri_types::{AggregationRound, CircuitIdRoundTuple}, + L1BatchNumber, +}; use crate::metrics::METRICS; @@ -192,7 +195,7 @@ mod tests { let result = get_setup_data_key(key); - // Check if the circuit_id has been changed to NodeLayerCircuit's id + // Check if the `circuit_id` has been changed to `NodeLayerCircuit's` id assert_eq!(expected, result); } diff --git a/prover/prover_fri/tests/basic_test.rs b/prover/prover_fri/tests/basic_test.rs index 89089ac8249e..ebcc43e93afc 100644 --- a/prover/prover_fri/tests/basic_test.rs +++ b/prover/prover_fri/tests/basic_test.rs @@ -4,10 +4,12 @@ use anyhow::Context as _; use serde::Serialize; use zksync_config::{configs::FriProverConfig, ObjectStoreConfig}; use zksync_env_config::FromEnv; -use zksync_object_store::{bincode, FriCircuitKey, ObjectStoreFactory}; +use zksync_object_store::{bincode, ObjectStoreFactory}; use zksync_prover_fri::prover_job_processor::Prover; -use zksync_prover_fri_types::{CircuitWrapper, ProverJob, ProverServiceDataKey}; -use zksync_types::{proofs::AggregationRound, L1BatchNumber}; +use zksync_prover_fri_types::{ + keys::FriCircuitKey, CircuitWrapper, ProverJob, ProverServiceDataKey, +}; +use zksync_types::{basic_fri_types::AggregationRound, L1BatchNumber}; use zksync_vk_setup_data_server_fri::generate_cpu_base_layer_setup_data; fn compare_serialized(expected: &T, actual: &T) { diff --git a/prover/prover_fri_gateway/Cargo.toml b/prover/prover_fri_gateway/Cargo.toml index 3e826a2f5c5b..bfe772bef64d 100644 --- a/prover/prover_fri_gateway/Cargo.toml +++ b/prover/prover_fri_gateway/Cargo.toml @@ -11,6 +11,7 @@ zksync_dal = { path = "../../core/lib/dal" } zksync_config = { path = "../../core/lib/config" } zksync_env_config = { path = "../../core/lib/env_config" } zksync_object_store = { path = "../../core/lib/object_store" } +zksync_prover_interface = { path = "../../core/lib/prover_interface" } zksync_utils = { path = "../../core/lib/utils" } prometheus_exporter = { path = "../../core/lib/prometheus_exporter" } vlog = { path = "../../core/lib/vlog" } diff --git a/prover/prover_fri_gateway/src/api_data_fetcher.rs b/prover/prover_fri_gateway/src/api_data_fetcher.rs index f56a9af4cc8f..9e0277d1ea89 100644 --- a/prover/prover_fri_gateway/src/api_data_fetcher.rs +++ b/prover/prover_fri_gateway/src/api_data_fetcher.rs @@ -1,4 +1,4 @@ -use std::time::Duration; +use std::{sync::Arc, time::Duration}; use async_trait::async_trait; use reqwest::Client; @@ -16,7 +16,7 @@ pub(crate) const PROOF_GENERATION_DATA_PATH: &str = "/proof_generation_data"; pub(crate) const SUBMIT_PROOF_PATH: &str = "/submit_proof"; pub(crate) struct PeriodicApiStruct { - pub(crate) blob_store: Box, + pub(crate) blob_store: Arc, pub(crate) pool: ConnectionPool, pub(crate) api_url: String, pub(crate) poll_duration: Duration, diff --git a/prover/prover_fri_gateway/src/main.rs b/prover/prover_fri_gateway/src/main.rs index 15329ce955a8..0ab2475d4196 100644 --- a/prover/prover_fri_gateway/src/main.rs +++ b/prover/prover_fri_gateway/src/main.rs @@ -6,7 +6,7 @@ use zksync_config::configs::{FriProverGatewayConfig, PostgresConfig}; use zksync_dal::ConnectionPool; use zksync_env_config::{object_store::ProverObjectStoreConfig, FromEnv}; use zksync_object_store::ObjectStoreFactory; -use zksync_types::prover_server_api::{ProofGenerationDataRequest, SubmitProofRequest}; +use zksync_prover_interface::api::{ProofGenerationDataRequest, SubmitProofRequest}; use zksync_utils::wait_for_tasks::wait_for_tasks; use crate::api_data_fetcher::{PeriodicApiStruct, PROOF_GENERATION_DATA_PATH, SUBMIT_PROOF_PATH}; diff --git a/prover/prover_fri_gateway/src/proof_gen_data_fetcher.rs b/prover/prover_fri_gateway/src/proof_gen_data_fetcher.rs index a25d447ad221..09d322ce940d 100644 --- a/prover/prover_fri_gateway/src/proof_gen_data_fetcher.rs +++ b/prover/prover_fri_gateway/src/proof_gen_data_fetcher.rs @@ -1,5 +1,5 @@ use async_trait::async_trait; -use zksync_types::prover_server_api::{ +use zksync_prover_interface::api::{ ProofGenerationData, ProofGenerationDataRequest, ProofGenerationDataResponse, }; diff --git a/prover/prover_fri_gateway/src/proof_submitter.rs b/prover/prover_fri_gateway/src/proof_submitter.rs index 78c7a6a6d8e7..3af3e81e20fb 100644 --- a/prover/prover_fri_gateway/src/proof_submitter.rs +++ b/prover/prover_fri_gateway/src/proof_submitter.rs @@ -1,9 +1,7 @@ use async_trait::async_trait; use zksync_dal::fri_proof_compressor_dal::ProofCompressionJobStatus; -use zksync_types::{ - prover_server_api::{SubmitProofRequest, SubmitProofResponse}, - L1BatchNumber, -}; +use zksync_prover_interface::api::{SubmitProofRequest, SubmitProofResponse}; +use zksync_types::L1BatchNumber; use crate::api_data_fetcher::{PeriodicApi, PeriodicApiStruct}; diff --git a/prover/prover_fri_types/Cargo.toml b/prover/prover_fri_types/Cargo.toml index 9f84afe2207c..bcb609d31caf 100644 --- a/prover/prover_fri_types/Cargo.toml +++ b/prover/prover_fri_types/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" zksync_object_store = { path = "../../core/lib/object_store" } zksync_types = { path = "../../core/lib/types" } -circuit_definitions = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.0", features = [ +circuit_definitions = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.1", features = [ "log_tracing", ] } diff --git a/prover/prover_fri_types/src/keys.rs b/prover/prover_fri_types/src/keys.rs new file mode 100644 index 000000000000..729db7541788 --- /dev/null +++ b/prover/prover_fri_types/src/keys.rs @@ -0,0 +1,37 @@ +//! Different key types for object store. + +use zksync_types::{basic_fri_types::AggregationRound, L1BatchNumber}; + +/// Storage key for a [AggregationWrapper`]. +#[derive(Debug, Clone, Copy)] +pub struct AggregationsKey { + pub block_number: L1BatchNumber, + pub circuit_id: u8, + pub depth: u16, +} + +/// Storage key for a [ClosedFormInputWrapper`]. +#[derive(Debug, Clone, Copy)] +pub struct ClosedFormInputKey { + pub block_number: L1BatchNumber, + pub circuit_id: u8, +} + +/// Storage key for a [`CircuitWrapper`]. +#[derive(Debug, Clone, Copy)] +pub struct FriCircuitKey { + pub block_number: L1BatchNumber, + pub sequence_number: usize, + pub circuit_id: u8, + pub aggregation_round: AggregationRound, + pub depth: u16, +} + +/// Storage key for a [`ZkSyncCircuit`]. +#[derive(Debug, Clone, Copy)] +pub struct CircuitKey<'a> { + pub block_number: L1BatchNumber, + pub sequence_number: usize, + pub circuit_type: &'a str, + pub aggregation_round: AggregationRound, +} diff --git a/prover/prover_fri_types/src/lib.rs b/prover/prover_fri_types/src/lib.rs index c244cb99f5a7..a1572ee2a2c2 100644 --- a/prover/prover_fri_types/src/lib.rs +++ b/prover/prover_fri_types/src/lib.rs @@ -11,9 +11,12 @@ use circuit_definitions::{ zkevm_circuits::scheduler::block_header::BlockAuxilaryOutputWitness, ZkSyncDefaultRoundFunction, }; -use zksync_object_store::{serialize_using_bincode, Bucket, FriCircuitKey, StoredObject}; -use zksync_types::{proofs::AggregationRound, L1BatchNumber}; +use zksync_object_store::{serialize_using_bincode, Bucket, StoredObject}; +use zksync_types::{basic_fri_types::AggregationRound, L1BatchNumber}; +use crate::keys::FriCircuitKey; + +pub mod keys; pub mod queue; #[derive(serde::Serialize, serde::Deserialize, Clone)] diff --git a/prover/prover_fri_utils/Cargo.toml b/prover/prover_fri_utils/Cargo.toml index 148f68f5c0f8..e2023f92b2dc 100644 --- a/prover/prover_fri_utils/Cargo.toml +++ b/prover/prover_fri_utils/Cargo.toml @@ -13,6 +13,10 @@ zksync_config = { path = "../../core/lib/config" } zksync_types = { path = "../../core/lib/types" } zksync_prover_fri_types = { path = "../prover_fri_types" } zksync_dal = { path = "../../core/lib/dal" } +zksync_utils = { path = "../../core/lib/utils" } tracing = "0.1" serde = { version = "1.0", features = ["derive"] } +reqwest = { version = "0.11", features = ["blocking"] } +regex = "1.7.2" +anyhow = "1.0" diff --git a/prover/prover_fri_utils/src/lib.rs b/prover/prover_fri_utils/src/lib.rs index eee7293b591b..39971555f932 100644 --- a/prover/prover_fri_utils/src/lib.rs +++ b/prover/prover_fri_utils/src/lib.rs @@ -1,7 +1,7 @@ use std::time::Instant; use zksync_dal::StorageProcessor; -use zksync_object_store::{FriCircuitKey, ObjectStore}; +use zksync_object_store::ObjectStore; use zksync_prover_fri_types::{ circuit_definitions::{ circuit_definitions::recursion_layer::{ @@ -9,16 +9,19 @@ use zksync_prover_fri_types::{ }, zkevm_circuits::scheduler::aux::BaseLayerCircuitType, }, - get_current_pod_name, CircuitWrapper, ProverJob, ProverServiceDataKey, + get_current_pod_name, + keys::FriCircuitKey, + CircuitWrapper, ProverJob, ProverServiceDataKey, }; use zksync_types::{ - basic_fri_types::CircuitIdRoundTuple, proofs::AggregationRound, + basic_fri_types::{AggregationRound, CircuitIdRoundTuple}, protocol_version::L1VerifierConfig, }; use crate::metrics::{CircuitLabels, PROVER_FRI_UTILS_METRICS}; pub mod metrics; +pub mod region_fetcher; pub mod socket_utils; pub async fn fetch_next_circuit( diff --git a/prover/prover_fri_utils/src/metrics.rs b/prover/prover_fri_utils/src/metrics.rs index acb48bacb3e3..b33bcc6d4481 100644 --- a/prover/prover_fri_utils/src/metrics.rs +++ b/prover/prover_fri_utils/src/metrics.rs @@ -1,7 +1,7 @@ use std::time::Duration; use vise::{Buckets, EncodeLabelSet, EncodeLabelValue, Family, Histogram, Metrics}; -use zksync_types::proofs::AggregationRound; +use zksync_types::basic_fri_types::AggregationRound; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelSet)] pub struct CircuitLabels { diff --git a/prover/prover_fri_utils/src/region_fetcher.rs b/prover/prover_fri_utils/src/region_fetcher.rs new file mode 100644 index 000000000000..cae211c26cbe --- /dev/null +++ b/prover/prover_fri_utils/src/region_fetcher.rs @@ -0,0 +1,51 @@ +use anyhow::Context; +use regex::Regex; +use reqwest::{ + header::{HeaderMap, HeaderValue}, + Method, +}; +use zksync_utils::http_with_retries::send_request_with_retries; + +pub async fn get_zone(zone_url: &str) -> anyhow::Result { + let data = fetch_from_url(zone_url).await.context("fetch_from_url()")?; + parse_zone(&data).context("parse_zone") +} + +async fn fetch_from_url(url: &str) -> anyhow::Result { + let mut headers = HeaderMap::new(); + headers.insert("Metadata-Flavor", HeaderValue::from_static("Google")); + let response = send_request_with_retries(url, 5, Method::GET, Some(headers), None).await; + response + .map_err(|err| anyhow::anyhow!("Failed fetching response from url: {url}: {err:?}"))? + .text() + .await + .context("Failed to read response as text") +} + +fn parse_zone(data: &str) -> anyhow::Result { + // Statically provided Regex should always compile. + let re = Regex::new(r"^projects/\d+/zones/(\w+-\w+-\w+)$").unwrap(); + if let Some(caps) = re.captures(data) { + let zone = &caps[1]; + return Ok(zone.to_string()); + } + anyhow::bail!("failed to extract zone from: {data}"); +} + +#[cfg(test)] +mod tests { + use crate::region_fetcher::parse_zone; + + #[test] + fn test_parse_zone() { + let data = "projects/295056426491/zones/us-central1-a"; + let zone = parse_zone(data).unwrap(); + assert_eq!(zone, "us-central1-a"); + } + + #[test] + fn test_parse_zone_panic() { + let data = "invalid data"; + assert!(parse_zone(data).is_err()); + } +} diff --git a/prover/prover_fri_utils/src/socket_utils.rs b/prover/prover_fri_utils/src/socket_utils.rs index c0c5ddcbcb9b..d6d7e80f8cb6 100644 --- a/prover/prover_fri_utils/src/socket_utils.rs +++ b/prover/prover_fri_utils/src/socket_utils.rs @@ -4,20 +4,17 @@ use std::{ time::{Duration, Instant}, }; -use zksync_types::proofs::SocketAddress; - pub fn send_assembly( job_id: u32, mut serialized: &[u8], - address: &SocketAddress, + socket_address: &SocketAddr, ) -> Result<(Duration, u64), String> { tracing::trace!( "Sending assembly to {}:{}, job id {{{job_id}}}", - address.host, - address.port + socket_address.ip(), + socket_address.port() ); - let socket_address = SocketAddr::new(address.host, address.port); let started_at = Instant::now(); let mut error_messages = vec![]; diff --git a/prover/setup-data-cpu-keys.json b/prover/setup-data-cpu-keys.json index 1a0427e53463..8b7a9165e2c2 100644 --- a/prover/setup-data-cpu-keys.json +++ b/prover/setup-data-cpu-keys.json @@ -1,5 +1,5 @@ { - "us": "gs://matterlabs-setup-data-us/e2e94ff/", - "europe": "gs://matterlabs-setup-data-europe/e2e94ff/", - "asia": "gs://matterlabs-setup-data-asia/e2e94ff/" + "us": "gs://matterlabs-setup-data-us/8ef5506/", + "europe": "gs://matterlabs-setup-data-europe/8ef5506/", + "asia": "gs://matterlabs-setup-data-asia/8ef5506/" } diff --git a/prover/setup-data-gpu-keys.json b/prover/setup-data-gpu-keys.json index 295d43ddaa4a..38057979f61b 100644 --- a/prover/setup-data-gpu-keys.json +++ b/prover/setup-data-gpu-keys.json @@ -1,5 +1,5 @@ { - "us": "gs://matterlabs-setup-data-us/5e22273-gpu/", - "europe": "gs://matterlabs-setup-data-europe/5e22273-gpu/", - "asia": "gs://matterlabs-setup-data-asia/5e22273-gpu/" + "us": "gs://matterlabs-setup-data-us/8ef5506-gpu/", + "europe": "gs://matterlabs-setup-data-europe/8ef5506-gpu/", + "asia": "gs://matterlabs-setup-data-asia/8ef5506-gpu/" } diff --git a/prover/setup_key_generator_and_server/Cargo.toml b/prover/setup_key_generator_and_server/Cargo.toml deleted file mode 100644 index 22b1cef97bd6..000000000000 --- a/prover/setup_key_generator_and_server/Cargo.toml +++ /dev/null @@ -1,42 +0,0 @@ -[package] -name = "setup_key_generator_and_server" -version = "0.1.0" -edition = "2018" -authors = ["The Matter Labs Team "] -homepage = "https://zksync.io/" -repository = "https://github.com/matter-labs/zksync-era" -license = "MIT OR Apache-2.0" -keywords = ["blockchain", "zksync"] -categories = ["cryptography"] - -[lib] -name = "zksync_setup_key_server" -path = "src/lib.rs" - -[[bin]] -name = "zksync_setup_key_generator" -path = "src/main.rs" - -[dependencies] -zksync_types = { path = "../../core/lib/types" } -vlog = { path = "../../core/lib/vlog" } -zksync_config = { path = "../../core/lib/config" } -zksync_env_config = { path = "../../core/lib/env_config" } - -circuit_testing = { git = "https://github.com/matter-labs/era-circuit_testing.git", branch = "main" } -api = { git = "https://github.com/matter-labs/era-heavy-ops-service.git", branch = "v1.3.3", features = [ - "gpu", -], optional = true, default-features = false } -prover-service = { git = "https://github.com/matter-labs/era-heavy-ops-service.git", branch = "v1.3.3", features = [ - "gpu", -], optional = true, default-features = false } -zkevm_test_harness = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.3.3" } - -anyhow = "1.0" -tracing = "0.1" -structopt = "0.3.26" -itertools = "0.10.5" - -[features] -default = [] -gpu = ["api", "prover-service"] diff --git a/prover/setup_key_generator_and_server/data/.gitkeep b/prover/setup_key_generator_and_server/data/.gitkeep deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/prover/setup_key_generator_and_server/src/lib.rs b/prover/setup_key_generator_and_server/src/lib.rs deleted file mode 100644 index 34b4896cefe1..000000000000 --- a/prover/setup_key_generator_and_server/src/lib.rs +++ /dev/null @@ -1,63 +0,0 @@ -use std::{fs::File, io::Read, path::Path}; - -use anyhow::Context as _; -use zkevm_test_harness::{ - abstract_zksync_circuit::concrete_circuits::ZkSyncCircuit, - bellman::bn256::Bn256, - witness::{ - oracle::VmWitnessOracle, recursive_aggregation::padding_aggregations, - vk_set_generator::circuits_for_vk_generation, - }, -}; -use zksync_config::ProverConfigs; -use zksync_env_config::FromEnv; -use zksync_types::circuit::{ - GEOMETRY_CONFIG, LEAF_SPLITTING_FACTOR, NODE_SPLITTING_FACTOR, SCHEDULER_UPPER_BOUND, -}; - -pub fn get_setup_for_circuit_type(circuit_type: u8) -> anyhow::Result> { - let filepath = get_setup_key_file_path(circuit_type).context("get_setup_key_file_path()")?; - tracing::info!("Fetching setup key from path: {}", filepath); - let file = File::open(filepath.clone()) - .with_context(|| format!("Failed reading setup key from path: {filepath}"))?; - Ok(Box::new(file)) -} - -pub fn get_circuits_for_vk() -> anyhow::Result>>> { - ensure_setup_key_exist().context("ensure_setup_key_exists()")?; - let padding_aggregations = padding_aggregations(NODE_SPLITTING_FACTOR); - Ok(circuits_for_vk_generation( - GEOMETRY_CONFIG, - LEAF_SPLITTING_FACTOR, - NODE_SPLITTING_FACTOR, - SCHEDULER_UPPER_BOUND, - padding_aggregations, - )) -} - -fn ensure_setup_key_exist() -> anyhow::Result<()> { - if !Path::new("setup_2^26.key").exists() { - anyhow::bail!("File setup_2^26.key is required to be present in current directory."); - } - Ok(()) -} - -pub fn get_setup_key_write_file_path(circuit_type: u8) -> String { - let zksync_home = std::env::var("ZKSYNC_HOME").unwrap_or_else(|_| "/".into()); - format!("{}/{}", zksync_home, get_setup_key_filename(circuit_type)) -} - -fn get_setup_key_file_path(circuit_type: u8) -> anyhow::Result { - let prover_config = ProverConfigs::from_env() - .context("ProverConfigs::from_env()")? - .non_gpu; - Ok(format!( - "{}/{}", - prover_config.setup_keys_path, - get_setup_key_filename(circuit_type) - )) -} - -fn get_setup_key_filename(circuit_type: u8) -> String { - format!("setup_{}_key.bin", circuit_type) -} diff --git a/prover/setup_key_generator_and_server/src/main.rs b/prover/setup_key_generator_and_server/src/main.rs deleted file mode 100644 index 9eee0aa5c09e..000000000000 --- a/prover/setup_key_generator_and_server/src/main.rs +++ /dev/null @@ -1,68 +0,0 @@ -#![cfg_attr(not(feature = "gpu"), allow(unused_imports))] - -use std::{env, fs::File}; - -use anyhow::Context as _; -use structopt::StructOpt; -use zkevm_test_harness::{ - abstract_zksync_circuit::concrete_circuits::ZkSyncCircuit, bellman::bn256::Bn256, - witness::oracle::VmWitnessOracle, -}; -use zksync_setup_key_server::{get_circuits_for_vk, get_setup_key_write_file_path}; - -#[cfg(feature = "gpu")] -#[derive(Debug, StructOpt)] -#[structopt( - name = "Generate setup keys for individual circuit", - about = "Tool for generating setup key for individual circuit" -)] -struct Opt { - /// Numeric circuit type valid value from [0-17]. - #[structopt(long)] - numeric_circuit: u8, -} - -#[cfg(not(feature = "gpu"))] -fn main() { - unimplemented!("This binary is only available with `gpu` feature enabled"); -} - -#[cfg(feature = "gpu")] -fn main() -> anyhow::Result<()> { - let opt = Opt::from_args(); - env::set_var("CRS_FILE", "setup_2^26.key"); - tracing::info!("Starting setup key generation!"); - get_circuits_for_vk() - .context("get_circuits_for_vk()")? - .into_iter() - .filter(|c| c.numeric_circuit_type() == opt.numeric_circuit) - .for_each(generate_setup_key_for_circuit); - Ok(()) -} - -#[cfg(feature = "gpu")] -fn generate_setup_key_for_circuit(circuit: ZkSyncCircuit>) { - use prover_service::utils::generate_setup_for_circuit; - - let mut prover = api::Prover::new(); - let setup = generate_setup_for_circuit(&mut prover, &circuit); - save_setup_for_circuit_type(circuit.numeric_circuit_type(), setup); - tracing::info!( - "Finished setup key generation for circuit {:?} (id {:?})", - circuit.short_description(), - circuit.numeric_circuit_type() - ); -} - -#[cfg(feature = "gpu")] -fn save_setup_for_circuit_type(circuit_type: u8, setup: prover_service::Setup) { - let filepath = get_setup_key_write_file_path(circuit_type); - tracing::info!("saving setup key to: {}", filepath); - let setup_file = File::create(&filepath).unwrap(); - setup - .write(setup_file) - .expect("Failed saving setup key to file."); - let setup_file = File::open(filepath).expect("Unable to open file"); - let size = setup_file.metadata().unwrap().len() as f64 / (1024.0 * 1024.0); - println!("Saved file size: {:?}MB", size); -} diff --git a/prover/vk_setup_data_generator_server_fri/Cargo.toml b/prover/vk_setup_data_generator_server_fri/Cargo.toml index 59df5f37cf89..bb1253f80270 100644 --- a/prover/vk_setup_data_generator_server_fri/Cargo.toml +++ b/prover/vk_setup_data_generator_server_fri/Cargo.toml @@ -23,14 +23,14 @@ path = "src/commitment_generator.rs" [dependencies] vlog = { path = "../../core/lib/vlog" } zksync_types = { path = "../../core/lib/types" } -zksync_prover_utils = { path = "../../core/lib/prover_utils" } zksync_prover_fri_types = { path = "../prover_fri_types" } -zkevm_test_harness = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.0" } -circuit_definitions = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.0", features = [ +zkevm_test_harness_1_3_3 = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.3.3", package = "zkevm_test_harness" } +zkevm_test_harness = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.1" } +circuit_definitions = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.1", features = [ "log_tracing", ] } -shivini = { git = "https://github.com/matter-labs/era-shivini.git", branch = "main", optional = true } +shivini = { git = "https://github.com/matter-labs/era-shivini.git", branch = "v1.4.1", optional = true } zksync_config = { path = "../../core/lib/config" } zksync_env_config = { path = "../../core/lib/env_config" } @@ -43,6 +43,7 @@ itertools = "0.10.5" bincode = "1" structopt = "0.3.26" once_cell = "1.8.0" +toml_edit = "0.14.4" [dev-dependencies] proptest = "1.2.0" diff --git a/prover/vk_setup_data_generator_server_fri/data/finalization_hints_basic_1.bin b/prover/vk_setup_data_generator_server_fri/data/finalization_hints_basic_1.bin index be9b474bd0dc..f1af57a5cdfe 100644 Binary files a/prover/vk_setup_data_generator_server_fri/data/finalization_hints_basic_1.bin and b/prover/vk_setup_data_generator_server_fri/data/finalization_hints_basic_1.bin differ diff --git a/prover/vk_setup_data_generator_server_fri/data/finalization_hints_basic_5.bin b/prover/vk_setup_data_generator_server_fri/data/finalization_hints_basic_5.bin index efed390e9107..4ef8ad2edd4e 100644 Binary files a/prover/vk_setup_data_generator_server_fri/data/finalization_hints_basic_5.bin and b/prover/vk_setup_data_generator_server_fri/data/finalization_hints_basic_5.bin differ diff --git a/prover/vk_setup_data_generator_server_fri/data/finalization_hints_basic_7.bin b/prover/vk_setup_data_generator_server_fri/data/finalization_hints_basic_7.bin index 35d82d21ed62..2dbd63c71931 100644 Binary files a/prover/vk_setup_data_generator_server_fri/data/finalization_hints_basic_7.bin and b/prover/vk_setup_data_generator_server_fri/data/finalization_hints_basic_7.bin differ diff --git a/prover/vk_setup_data_generator_server_fri/data/finalization_hints_leaf_9.bin b/prover/vk_setup_data_generator_server_fri/data/finalization_hints_leaf_9.bin index 082fcccf6d4c..2bda22f5779a 100644 Binary files a/prover/vk_setup_data_generator_server_fri/data/finalization_hints_leaf_9.bin and b/prover/vk_setup_data_generator_server_fri/data/finalization_hints_leaf_9.bin differ diff --git a/prover/vk_setup_data_generator_server_fri/data/finalization_hints_scheduler.bin b/prover/vk_setup_data_generator_server_fri/data/finalization_hints_scheduler.bin index b4daf641fe58..b74bfd796ed0 100644 Binary files a/prover/vk_setup_data_generator_server_fri/data/finalization_hints_scheduler.bin and b/prover/vk_setup_data_generator_server_fri/data/finalization_hints_scheduler.bin differ diff --git a/prover/vk_setup_data_generator_server_fri/data/snark_verification_scheduler_key.json b/prover/vk_setup_data_generator_server_fri/data/snark_verification_scheduler_key.json index 5d33f98b183f..4b83fd50553f 100644 --- a/prover/vk_setup_data_generator_server_fri/data/snark_verification_scheduler_key.json +++ b/prover/vk_setup_data_generator_server_fri/data/snark_verification_scheduler_key.json @@ -6,16 +6,16 @@ "gate_setup_commitments": [ { "x": [ - 4563648229522529090, - 12621273650309129924, - 6198549568814142266, - 2552508369834820982 + 18196698015838820804, + 13870798184679972679, + 10383601464080125147, + 2890147079142100565 ], "y": [ - 6942986305285328922, - 13872369038900622115, - 16362071052994133467, - 804758705072609803 + 15077880217479618043, + 409257657776446622, + 7624188368705821190, + 571146283794538062 ], "infinity": false }, @@ -96,16 +96,16 @@ }, { "x": [ - 17877966991893524598, - 5994085157062523222, - 1757001537059388699, - 624319710399696047 + 6133635431083343666, + 17066500748032848681, + 9464481803886990457, + 3099188496124947302 ], "y": [ - 4763287561833789230, - 2005258298669826833, - 16972767076042430273, - 143191352994868054 + 11826823385291662601, + 13141227272786891670, + 936697723418808310, + 619083601736774460 ], "infinity": false }, diff --git a/prover/vk_setup_data_generator_server_fri/data/verification_basic_1_key.json b/prover/vk_setup_data_generator_server_fri/data/verification_basic_1_key.json index dba61453753c..666f79b512cc 100644 --- a/prover/vk_setup_data_generator_server_fri/data/verification_basic_1_key.json +++ b/prover/vk_setup_data_generator_server_fri/data/verification_basic_1_key.json @@ -19,19 +19,19 @@ "public_inputs_locations": [ [ 0, - 1047658 + 1033357 ], [ 1, - 1047658 + 1033357 ], [ 2, - 1047658 + 1033357 ], [ 3, - 1047658 + 1033357 ] ], "extra_constant_polys_for_selectors": 3, @@ -183,100 +183,100 @@ }, "setup_merkle_tree_cap": [ [ - 14869022747991704186, - 17031358815991649117, - 4714282231372708414, - 6414019057952366663 + 13979541772562812886, + 628221230774609014, + 18373366089216843595, + 17288643748939748082 ], [ - 6900602175855696430, - 6670794569935170089, - 10800109531102252604, - 17486750553116564567 + 497560230331914293, + 12933065490353267070, + 610531049548094364, + 2561281819852481556 ], [ - 17299361551409797093, - 11990751079425151913, - 6826444113393762570, - 10932118118889734350 + 6872202279589309483, + 15371443137485864328, + 14042185857374951614, + 2871085713710647736 ], [ - 6474368291910763152, - 7951437263957002667, - 16115489689031613949, - 7133133995520501271 + 14717287901379274289, + 11041091584433246952, + 1516317718358551577, + 17942326492608764586 ], [ - 10017359634641638081, - 5101743302584875322, - 5266371437134340172, - 6069099232595401770 + 11102657606425854019, + 16719055288925226903, + 251505614603105506, + 788154469314461155 ], [ - 17756274064208120672, - 3982804959467006511, - 10666837127743053144, - 5042305760262773346 + 14609783504099553169, + 8414020072480378909, + 5493814014146289405, + 11182914537731016461 ], [ - 6276015788824777492, - 7548026914440268726, - 7686087580556345175, - 70678741505519130 + 3985640097063592337, + 11522574954802621414, + 3987867522671712202, + 6993409547661445349 ], [ - 17054606409621314666, - 12181652464079780487, - 16509905652014130420, - 18326959307811580345 + 9457187851706480139, + 5415597435441111057, + 2054966732353439166, + 4687827253126200545 ], [ - 11297851890381778013, - 4519272151514850089, - 11187164861287540939, - 11860631544716366680 + 10511650860939798500, + 5585198921532047811, + 16190623865304580725, + 4707719904878919289 ], [ - 6694400911557434438, - 10320855386973467141, - 6409090468016993938, - 1691791456834022317 + 835496114275750140, + 11205584076775867467, + 14617309449219062577, + 14840896155754974551 ], [ - 12631827227087810588, - 17420660366875362680, - 8998719038651802977, - 7868656510918289268 + 8838401009958590877, + 4356703539172827619, + 15906895008509963830, + 15213987306529390063 ], [ - 6457505234632244247, - 13541404564190215974, - 16187962154051613109, - 17552751586718992793 + 15386648629189748383, + 981209449049965222, + 17702894300685706682, + 7188184581569627427 ], [ - 16545123790363978986, - 5350362016628834362, - 18354051751822556975, - 6117654413762589372 + 11773289872945276065, + 14292663988536993999, + 4995957744780789767, + 11157975329762130496 ], [ - 489622670611184909, - 15319066911773803522, - 18442076011714885642, - 6096263545427509383 + 10992634905557330633, + 6679058793747630815, + 7619754239129113371, + 15635323274093564751 ], [ - 15489313913065919449, - 8423761693489524867, - 15818905453819585194, - 15653211152174043194 + 5612302911762512037, + 7066509597590412204, + 16090150944640300635, + 8925201513572491903 ], [ - 5640704920035577473, - 4663598453214139985, - 1172539769174279254, - 11923632706292759615 + 49562861942122717, + 78347250110042296, + 15729365300851668553, + 5811723960573072789 ] ] } diff --git a/prover/vk_setup_data_generator_server_fri/data/verification_basic_5_key.json b/prover/vk_setup_data_generator_server_fri/data/verification_basic_5_key.json index 4537187b9b36..5cf937317a97 100644 --- a/prover/vk_setup_data_generator_server_fri/data/verification_basic_5_key.json +++ b/prover/vk_setup_data_generator_server_fri/data/verification_basic_5_key.json @@ -19,19 +19,19 @@ "public_inputs_locations": [ [ 0, - 1047292 + 957655 ], [ 1, - 1047292 + 957655 ], [ 2, - 1047292 + 957655 ], [ 3, - 1047292 + 957655 ] ], "extra_constant_polys_for_selectors": 2, @@ -144,100 +144,100 @@ }, "setup_merkle_tree_cap": [ [ - 5926546619152935907, - 11291861669768573654, - 11100100891141895430, - 1040099038134319144 + 5863338309468690805, + 6612807556868623855, + 14384447122223208889, + 4869624617941633977 ], [ - 9405378490457870663, - 11971348617109093172, - 7779954465112100917, - 8521139113892942903 + 7203568093424325982, + 11467433213790803023, + 3331132209617185572, + 12059630931627430867 ], [ - 1041442145290466080, - 2626937507866398782, - 4297959424787982903, - 7963254695121664304 + 17754341693454587497, + 7044019905110787629, + 13344874745221604862, + 689445111894783375 ], [ - 8679424872010178168, - 928230210029079843, - 17862919271344969949, - 9085342720844642067 + 12146861234544017277, + 10376115062914418911, + 8960119128938611413, + 8559956938223261930 ], [ - 2346566700143956389, - 751827788815495159, - 18018129704559687246, - 6344673729449349673 + 16520223933708511688, + 3172930642611959373, + 17561897383101277942, + 8480394309945227558 ], [ - 12798999539756004171, - 2962217720855368908, - 17815764746262544024, - 6141433679632029898 + 1996517481667965644, + 7377981481713124790, + 4085759919146714953, + 14547160858649434950 ], [ - 10612436896218340091, - 5382517797965219051, - 1440771605952502920, - 6120504474919675320 + 6783829941378618951, + 4164473016846576356, + 6466125109246198457, + 5555424632322755268 ], [ - 5639210895028949894, - 17579589483393163114, - 8531068549022389838, - 9055992165271810945 + 15545095573096466305, + 6069931892954605821, + 9897118900133603670, + 623299142232746660 ], [ - 15625252378325581383, - 11791782086341113568, - 1976318982912441593, - 16561636205817299485 + 2729973951622970375, + 2475966630698408655, + 6354477244264616033, + 16467651095039013404 ], [ - 9291503982934971506, - 5967409911022700010, - 9096839168538146295, - 3004596177933970509 + 3475789501107470785, + 6545047721624920952, + 13708118956887446396, + 8327911440041257243 ], [ - 9243725287341188464, - 6878316427230924845, - 7270708110528992687, - 15417458474646493002 + 12619459378778019696, + 4556930387203524575, + 15096694625117428691, + 968312946067281062 ], [ - 15577762808206668193, - 10775213926343901301, - 4900917235853777300, - 8940673145641313937 + 15417126618137433078, + 919913711636678455, + 601385876894393616, + 10002950656997366990 ], [ - 18157038451252266825, - 13776543473230491269, - 17449669960102455201, - 1902286122568749061 + 13539183528986038681, + 18114796302738189862, + 17405354768003119916, + 15572242745340962324 ], [ - 10247491007925641249, - 5411016508841956578, - 11766519965796614613, - 1073824923129670847 + 9674870974878238491, + 12069223024267066514, + 7771360710281282208, + 14926388438391014942 ], [ - 10691592838471536401, - 16863854034452440410, - 16989985027265774429, - 10784858673090746367 + 18104374714769140792, + 16885383007413710616, + 14207969031693102569, + 13387272531183358013 ], [ - 5688638173552292266, - 2543022480770607266, - 1257951713416281965, - 6435312724052439304 + 4720607235344128981, + 8734926750581912691, + 8602628498785008248, + 9428253327807062948 ] ] } diff --git a/prover/vk_setup_data_generator_server_fri/data/verification_basic_7_key.json b/prover/vk_setup_data_generator_server_fri/data/verification_basic_7_key.json index b905a476ea43..2e8bd4248a45 100644 --- a/prover/vk_setup_data_generator_server_fri/data/verification_basic_7_key.json +++ b/prover/vk_setup_data_generator_server_fri/data/verification_basic_7_key.json @@ -15,23 +15,23 @@ } }, "domain_size": 1048576, - "total_tables_len": 132096, + "total_tables_len": 197632, "public_inputs_locations": [ [ 0, - 872841 + 938954 ], [ 1, - 872841 + 938954 ], [ 2, - 872841 + 938954 ], [ 3, - 872841 + 938954 ] ], "extra_constant_polys_for_selectors": 2, @@ -49,7 +49,7 @@ "Fork": { "left": { "GateOnly": { - "gate_idx": 2, + "gate_idx": 3, "num_constants": 2, "degree": 3, "needs_selector": true, @@ -62,7 +62,7 @@ "Fork": { "left": { "GateOnly": { - "gate_idx": 4, + "gate_idx": 2, "num_constants": 0, "degree": 2, "needs_selector": true, @@ -95,7 +95,7 @@ "GateOnly": { "gate_idx": 7, "num_constants": 0, - "degree": 0, + "degree": 2, "needs_selector": true, "is_lookup": false } @@ -107,19 +107,32 @@ } }, "right": { - "GateOnly": { - "gate_idx": 1, - "num_constants": 0, - "degree": 2, - "needs_selector": true, - "is_lookup": false + "Fork": { + "left": { + "GateOnly": { + "gate_idx": 1, + "num_constants": 0, + "degree": 2, + "needs_selector": true, + "is_lookup": false + } + }, + "right": { + "GateOnly": { + "gate_idx": 8, + "num_constants": 0, + "degree": 0, + "needs_selector": true, + "is_lookup": false + } + } } } } }, "right": { "GateOnly": { - "gate_idx": 3, + "gate_idx": 4, "num_constants": 1, "degree": 2, "needs_selector": true, @@ -132,7 +145,7 @@ "Fork": { "left": { "GateOnly": { - "gate_idx": 8, + "gate_idx": 9, "num_constants": 4, "degree": 2, "needs_selector": true, @@ -157,100 +170,100 @@ }, "setup_merkle_tree_cap": [ [ - 13818450912197620420, - 5079205692118648775, - 14615787041360044769, - 2941606671776647183 + 10364558592939111741, + 2704090932534378545, + 3848869986273969160, + 16106328006947126620 ], [ - 6715253104770723417, - 3160280029457127352, - 11108406980823166906, - 15487865556610611893 + 18358486967141014750, + 14641508205909281179, + 7093116894832566610, + 7500598559033532768 ], [ - 14039903923831613967, - 15298198763143829103, - 17031409250405123985, - 10266023324667771113 + 16215619146982875852, + 931552260993232306, + 12732515925355865703, + 10874000891781998666 ], [ - 17366151300788544369, - 13314676565834570017, - 17521241757753748935, - 13066688955830816807 + 16696055299959994592, + 7517181201234171849, + 13530124260986169974, + 12420742919152555831 ], [ - 14445090483790969730, - 15708367780098206326, - 2336844413511710318, - 3268235585540529265 + 12935551582494340631, + 11277556804627122699, + 2585203450556476813, + 6641635578391032765 ], [ - 2882405134850480170, - 14247534382965114291, - 17531255653612736614, - 11676635700695125188 + 14147502223221812516, + 10219199483850226233, + 9787631410983267539, + 2756256845301132553 ], [ - 11530141675448575062, - 8910365257612403024, - 300072654586353643, - 8472188536913229506 + 15406861586967121153, + 6131399528017195276, + 14224933511241022797, + 8698057950989472792 ], [ - 1426612518547638168, - 17806679375517512145, - 14835333334022265221, - 2007845272495904476 + 10880960805700971620, + 16164526380247682456, + 12282645756801863671, + 6794498938134022476 ], [ - 6034343869761808836, - 13937750910508416181, - 16942548919853718543, - 16086518391257789831 + 5447689690988908031, + 11077827740731268910, + 11281826336784931146, + 1857605592445416779 ], [ - 15933462173546075175, - 8612525819877657624, - 4132383244121115701, - 9288543398092863864 + 16543238481770974716, + 15644234753306810707, + 7325159377101369499, + 9364028963032249345 ], [ - 8157130847726661070, - 4231891352218163681, - 14620351586778336684, - 4186724240746204294 + 15668430137612641656, + 9735500688010860318, + 6232756292978092916, + 596001075134187400 ], [ - 7440132245224537493, - 6666895991749911132, - 8404993517441732468, - 6556569653095950475 + 10401718076460605202, + 11567967099757836303, + 12006248804213440045, + 17385738920789950897 ], [ - 1982595939619922877, - 17561202624392859313, - 14381497498171193805, - 17908865555917026633 + 5700779282136820007, + 6374023460690849286, + 2926225761189217992, + 120655127472319182 ], [ - 7384278864004035589, - 10191778068274570585, - 6103937442735162958, - 5142419559331404710 + 14205253813728620805, + 16457174518919888691, + 366727105995090878, + 3239884099992559905 ], [ - 3651117166359200686, - 3827322296271305097, - 14799462710376656576, - 13600220646083181205 + 12999528173970371119, + 14057657825586485436, + 11885903378658833926, + 3645634639162950888 ], [ - 1989104086172888026, - 7796359126421144184, - 16967575681666150511, - 5993683835612332048 + 9127695548309953097, + 9124168086734357914, + 4696446350416763314, + 14190588963396757344 ] ] } diff --git a/prover/vk_setup_data_generator_server_fri/data/verification_basic_9_key.json b/prover/vk_setup_data_generator_server_fri/data/verification_basic_9_key.json index 26a0c0c3e387..2a80fcf04d1d 100644 --- a/prover/vk_setup_data_generator_server_fri/data/verification_basic_9_key.json +++ b/prover/vk_setup_data_generator_server_fri/data/verification_basic_9_key.json @@ -157,100 +157,100 @@ }, "setup_merkle_tree_cap": [ [ - 11871327302077385347, - 16906876010300982827, - 1595439427548031919, - 8289977278285908320 + 4720381805984417431, + 13078422028573677966, + 12719610199416872768, + 814461378397191674 ], [ - 1781098816832363622, - 3478218372991964399, - 7533433777158627341, - 14771106422370550145 + 7528162393526520082, + 16021794900358493536, + 10778196681779195944, + 16999373544006604274 ], [ - 2685684430663814546, - 12416630179340889407, - 2015102854033739219, - 5941892917351537077 + 6747601332592429411, + 10839430478686810097, + 13645038614460463708, + 13820943711197201062 ], [ - 11253028729705493819, - 14850400929314449282, - 8678044000034959641, - 17294624061384818276 + 3296980954753787898, + 16847154708500530922, + 4760207114567346237, + 933989207013374596 ], [ - 14258883085276585451, - 6370442713006574674, - 14046750730761444155, - 17791869273332245871 + 435751225506322730, + 11838854342511914922, + 8141668552314414324, + 2080639242020278276 ], [ - 7220276552024778410, - 8960130478379828559, - 16936405896975145419, - 5038663776382566512 + 12577933521680800715, + 7013157337092792023, + 8948304311622302542, + 13444594627920045180 ], [ - 13808097963622191673, - 11828988786702917270, - 2233362366627924, - 6612334601851706078 + 10039030243356480714, + 16189912181289242789, + 10233207085455746896, + 9133045755698092179 ], [ - 7478203141391683139, - 224415780917265400, - 7567502678051235826, - 7851341697237293082 + 4258951657397630338, + 7089329735582865970, + 7454083395219072742, + 6942440874612228572 ], [ - 16539824364674252288, - 4519676258951332695, - 18049825257493226995, - 1267218050479719768 + 4205365380387206769, + 4810070288054886759, + 12185381545408489993, + 9168852501594036569 ], [ - 3826454470928570687, - 1236146101240459873, - 6372203166973826150, - 6930153498226497616 + 10516394727687757858, + 13834473449189539894, + 14081317825129873045, + 6351648171885016957 ], [ - 3167281621364929622, - 2762481164640470670, - 8362276586345702073, - 14045722791397864122 + 18078042118328183988, + 6073950769044690696, + 16412846409205043478, + 2130555455391847686 ], [ - 14365302546843858790, - 17322057150049918196, - 286070742254960491, - 8246670609891611634 + 11243654607886467582, + 16949864848604250653, + 9402265113410343268, + 5314745691722462235 ], [ - 7988693957097790412, - 314963851507072118, - 17207369419682640756, - 412453697544464209 + 15979853768668375314, + 12543007664588017291, + 12965088303373453422, + 2147288991358425708 ], [ - 14890448417542266631, - 5963437462474119237, - 9763006742695214759, - 17659455413153344670 + 244366469137530999, + 6419427921450944899, + 11667939960797081159, + 12423571797082389411 ], [ - 13083329023803443846, - 10870396255388184280, - 17412894322433867553, - 4879290934605969545 + 1119341028349378585, + 6534556044367196007, + 17980160443578730518, + 15264250936810044760 ], [ - 7034677264054074316, - 3672095934764717273, - 6174572782407460075, - 6718668524195598096 + 13689391307335641715, + 17074269686100848413, + 17922241310959477038, + 13088974302469761152 ] ] } diff --git a/prover/vk_setup_data_generator_server_fri/data/verification_leaf_3_key.json b/prover/vk_setup_data_generator_server_fri/data/verification_leaf_3_key.json index f03848a09751..20bd6a9d1749 100644 --- a/prover/vk_setup_data_generator_server_fri/data/verification_leaf_3_key.json +++ b/prover/vk_setup_data_generator_server_fri/data/verification_leaf_3_key.json @@ -162,100 +162,100 @@ }, "setup_merkle_tree_cap": [ [ - 1805040357731911032, - 12724391787715131487, - 16479521122472510699, - 16667703969508778391 + 1247576564412051418, + 12273306257668670509, + 14191376561140331689, + 10310912622041030225 ], [ - 12688435309079006504, - 14734642188927813728, - 11915884033454147184, - 17329321226955875183 + 5225236367749136421, + 603187870752456963, + 9837780210091125930, + 2506013264691550385 ], [ - 16315437509239525068, - 14908436607574402415, - 2084428987844243846, - 15413041179037655921 + 8497193842162297485, + 4845860822409534304, + 4138334177467689966, + 9202074843839089802 ], [ - 2823702871692091034, - 6376153290603778949, - 10890272396514589925, - 8026713020686697748 + 9654034842841910269, + 708990255886442263, + 10107840680979664389, + 5808533714672310191 ], [ - 17397137686907845637, - 2064022542849488262, - 3786405316970836609, - 5437499595967723836 + 14251291393125869883, + 3616107614863400854, + 2010682359417586096, + 12456662796675379513 ], [ - 2550071694179416093, - 4897423300632444750, - 13062462915336389501, - 18372839862930961551 + 7970212854162698408, + 14194713765138589776, + 5849242043577428661, + 12606622141811352806 ], [ - 17088995408991024798, - 16316191327122804523, - 5528066820138050503, - 14599942305495755459 + 11948724638653550851, + 8947958806821567157, + 12909128685306703210, + 14917378813839046977 ], [ - 5958767730804376795, - 6660452824628491350, - 5783408552721592941, - 14088521578529200272 + 5412287161492062871, + 6606116647402177461, + 13017829696219856153, + 7487301845602534303 ], [ - 2291071995718572256, - 907353728885268958, - 129782464141134801, - 9589777919267926845 + 9477201289532820910, + 9800973848806475446, + 3508021038584770051, + 3235776687244218864 ], [ - 16187707968438160509, - 11100373869445159993, - 5237804265105284075, - 9739986537750733952 + 2791092338875051443, + 18194879996262719903, + 2899450023178678246, + 14069689187928679177 ], [ - 16892182605566285738, - 1703786579928301563, - 8812499024578960746, - 17823411878542653115 + 13666503722421095396, + 14491872544075331112, + 9386967518782130527, + 16009683032302829790 ], [ - 13683376511744176189, - 5433888418576498236, - 15343790216728546383, - 16285187192287214848 + 2839395143875783163, + 7648396343194982154, + 13937364562578226328, + 8063553841239143405 ], [ - 17452383859621845374, - 17719367598200163617, - 1419014138942951485, - 7011441981346002658 + 5966137847999981886, + 2198398451338343366, + 10088393797769586259, + 16125482633308865245 ], [ - 6400096584820601208, - 16235194395642444364, - 11311947162131944240, - 7598189765195297754 + 16215892849491971068, + 17210376177731213089, + 7447200587018988406, + 4975940832749883899 ], [ - 8933333390708774665, - 12091548374904536228, - 14131593419057989631, - 3687065922153051144 + 14769784807006985958, + 653301846789535760, + 6822608902746300061, + 6085195747006357764 ], [ - 4357902627493767816, - 8081210589813839837, - 15890918119202411959, - 12214732213338934860 + 14032400430012753659, + 10972800536044118388, + 2081969033107576242, + 9228417089775570723 ] ] } diff --git a/prover/vk_setup_data_generator_server_fri/data/verification_leaf_7_key.json b/prover/vk_setup_data_generator_server_fri/data/verification_leaf_7_key.json index 1ab34e32a4f7..1250098066e9 100644 --- a/prover/vk_setup_data_generator_server_fri/data/verification_leaf_7_key.json +++ b/prover/vk_setup_data_generator_server_fri/data/verification_leaf_7_key.json @@ -162,100 +162,100 @@ }, "setup_merkle_tree_cap": [ [ - 15278222994235313807, - 4647505541828109982, - 11601404244072907522, - 7495301362149670205 + 2754337122404035131, + 13536623891656361365, + 1007616849063951008, + 15105252681621581082 ], [ - 2294446454282967643, - 10852196555067806436, - 4676542110718751671, - 3650676510146080911 + 8308444090318189338, + 7446058959525096525, + 13329207951509548855, + 7561889402802668448 ], [ - 10036426682390389619, - 15410534417517518379, - 411748073143090898, - 1725429274294449186 + 15626189183123654473, + 9389275788860639449, + 7727979895208578309, + 8967557569387905568 ], [ - 10773139363930294963, - 14784009814759595952, - 4523828744129500622, - 14635565308295099932 + 1271041653742580722, + 1508771155767829929, + 3539674211903238731, + 6674336842512236791 ], [ - 11532260655451503527, - 2889442075290561580, - 7947536971337998641, - 9006850837384135593 + 14993085933639327428, + 12859616637151917255, + 17451807438447563279, + 18361547219004635882 ], [ - 18268520902352688907, - 17460815273130161567, - 5448683527846534560, - 16860223759333541117 + 2596569918238049986, + 9535951245061094004, + 3612719904693838716, + 15669710216801791634 ], [ - 8586752129609394016, - 17056726335999361043, - 13247832408825538184, - 10865075704067323346 + 2923247806064529346, + 476025466236692654, + 219470078253531684, + 3253637150697045053 ], [ - 4810539255563012829, - 3494541358111189199, - 7443746985302784339, - 1488118652209005646 + 11455918723444914411, + 12760698121370134283, + 1348665151397345538, + 1503330250917801638 ], [ - 13632843557374648899, - 11530787504038845899, - 8016420701220086345, - 2100494706314940875 + 3882061487409180567, + 4539967518573931769, + 16041271276470561136, + 13198977187430751226 ], [ - 12565007434827640436, - 2122488373912552994, - 7924677296826511433, - 4337201927455963919 + 9175887734272823437, + 11834689895461412171, + 15661083739716912511, + 11679573170871122987 ], [ - 9121346173552113908, - 8257616625819727572, - 1352571964050839537, - 1245015447612032209 + 16807522636555833221, + 8478021735953695140, + 6319467368854890639, + 9055828631796683676 ], [ - 5550331618999138407, - 15197131088442812142, - 17401528975137618793, - 7876503578710888777 + 17441028216195758717, + 16733042275859432057, + 16209233366181649846, + 16396552402939532160 ], [ - 10581471072917622415, - 11057977535360446233, - 4745650017347491925, - 16374614618217057484 + 6210356141414087397, + 4943182941258025608, + 7273397807824898264, + 11582999888436731797 ], [ - 15877663159259953297, - 13196700387970223678, - 987069829507588466, - 1239752961099076877 + 14142343453086872024, + 17506279899770493168, + 9608284523774702738, + 609745290150469595 ], [ - 1564056242532596441, - 8225585740585112689, - 8013357208824893542, - 8291061420556283364 + 8310851111766432853, + 13548474419145163485, + 15450231847428594055, + 12223625109163810065 ], [ - 10408011788640723232, - 11035192730597666502, - 7808927156371652130, - 8373070655798680509 + 18255684948340198040, + 10371054994206808107, + 3264758647817486750, + 6747927017612155762 ] ] } diff --git a/prover/vk_setup_data_generator_server_fri/data/verification_leaf_9_key.json b/prover/vk_setup_data_generator_server_fri/data/verification_leaf_9_key.json index 88a48a0bf911..e819d87f0563 100644 --- a/prover/vk_setup_data_generator_server_fri/data/verification_leaf_9_key.json +++ b/prover/vk_setup_data_generator_server_fri/data/verification_leaf_9_key.json @@ -162,100 +162,100 @@ }, "setup_merkle_tree_cap": [ [ - 1966688024276265163, - 1600999376577297955, - 9979283765343242481, - 10853158383047279373 + 14148284386830541652, + 14837085299135448704, + 6322573177435797385, + 9541235098780333065 ], [ - 9617115799973676416, - 1436692352837490106, - 16621229234254045212, - 17649471158808930813 + 18026891006762862860, + 8815462913262358846, + 3028459576654036894, + 4764978179870290626 ], [ - 10598997254576197179, - 6191890180530301291, - 485325547092687385, - 17866822217569560015 + 3143414711632972556, + 215009862632575109, + 115871183085121437, + 15678879580422096616 ], [ - 17529069959174406385, - 1822730242748867421, - 10607268541276403219, - 10369730414641253572 + 7008443537620227362, + 15405045094706661453, + 7054378897351244413, + 15063094779164469832 ], [ - 9559948904275293033, - 271393452476373483, - 10294727560225979037, - 13356808215545342022 + 11380051289982529587, + 14537160074260598253, + 319143631423375734, + 3054216871356863172 ], [ - 3330505141292591439, - 14604912162246460234, - 13747490798131143365, - 9686392462153294316 + 6677826033770529061, + 12532558508585119885, + 6483341484367915585, + 13833715102611979913 ], [ - 1308334442155460802, - 8411248012498029090, - 1727122243552046217, - 1891983150748887801 + 16383714077146582615, + 6099349887502755988, + 611692769071329528, + 6249348051757898139 ], [ - 13628794098518472387, - 9775581327398472118, - 10952798350389999267, - 3791915693702783252 + 13655984727793006641, + 16299779079612206176, + 6852678328562466162, + 372227381623477635 ], [ - 5150729729317744106, - 15268081752408833175, - 11313693800895322733, - 7645258866415024451 + 4425585391371569673, + 6763900039933749019, + 16006906678055998259, + 1427464989992584471 ], [ - 4492405884498997751, - 1462600329700613046, - 4494587633368393420, - 13835293745083269390 + 10046306903330433098, + 5388931302017828778, + 14561141494124910623, + 17810178181842901525 ], [ - 16786735218378765255, - 13489016634632055711, - 780880140016370703, - 1632417931049291348 + 7153732502663673262, + 10145905956758704652, + 5539285688413432284, + 838720682164893952 ], [ - 15419598237747857050, - 17379853454459968259, - 1377883698753277247, - 17090368996477921986 + 10222632123310734549, + 15639343223634758385, + 11763187165521672016, + 3632059402025063524 ], [ - 5453156352466670830, - 7921752778252981104, - 15901693682958424795, - 7759079127470880643 + 15347417540234677848, + 734067739620863189, + 13817834505400578135, + 4053013374259122068 ], [ - 13945928657949258565, - 10630556046992331796, - 5947903586431352857, - 13970701039664769056 + 1278154817848231719, + 10728883570888770764, + 18088295704053736009, + 15861821502158970546 ], [ - 11402992940883704805, - 14254801701412570920, - 16823021910688666954, - 16435058721419375579 + 14731074814234828267, + 7249639464351543805, + 14262815218043638628, + 2820426900263260210 ], [ - 1434897606543124534, - 7242596307416400095, - 1722748060955112357, - 1262887759339605102 + 8806343049474442429, + 10816590200059736523, + 7404010135457618112, + 14366274165457799247 ] ] } diff --git a/prover/vk_setup_data_generator_server_fri/data/verification_scheduler_key.json b/prover/vk_setup_data_generator_server_fri/data/verification_scheduler_key.json index 198f0389a72c..ab9545b38f33 100644 --- a/prover/vk_setup_data_generator_server_fri/data/verification_scheduler_key.json +++ b/prover/vk_setup_data_generator_server_fri/data/verification_scheduler_key.json @@ -19,19 +19,19 @@ "public_inputs_locations": [ [ 0, - 1001025 + 1001364 ], [ 1, - 1001025 + 1001364 ], [ 2, - 1001025 + 1001364 ], [ 3, - 1001025 + 1001364 ] ], "extra_constant_polys_for_selectors": 4, @@ -170,100 +170,100 @@ }, "setup_merkle_tree_cap": [ [ - 4522138600368992679, - 9538550764574095149, - 12350165878820403151, - 17316455735707094331 + 12689670017976745265, + 4735744839674262721, + 13286982813628318381, + 9149186980107562073 ], [ - 5497320764894852275, - 1590480833349456203, - 6557309322687596584, - 15454422223540210306 + 11392738209994648966, + 9093985895872596846, + 10573344842509535237, + 17700304896358218640 ], [ - 5558505086540283030, - 13943227629024743939, - 10259100634144494257, - 5704170399326630549 + 7067297734958509313, + 9354967931491158103, + 16182722545820495396, + 16144754456929631304 ], [ - 2951435633176249116, - 9236611820854085075, - 7033504824356317789, - 6878637342940269074 + 16740527296473943989, + 3880867293805242982, + 14726916748278129428, + 13912258461398978671 ], [ - 14892753504099420541, - 5719263246041693687, - 4025705708519747499, - 1086118372881038482 + 5388324952186405061, + 8461633823113748075, + 18417727201095296026, + 7513276821057635636 ], [ - 7732214748303870430, - 9037879918645611146, - 5795905425560049291, - 5456605407758692913 + 6835783195916312963, + 2764814759828064484, + 16360792463144143961, + 5031433507456284412 ], [ - 6947322728148447593, - 6382294998862546420, - 7884427302760020118, - 2212936554013177065 + 15018426371866855766, + 4216590438341145666, + 8141336991557864596, + 18027566136801125192 ], [ - 2343438613885863348, - 13493857712239522643, - 14424009770652266387, - 12969912574245991559 + 8197677022277307310, + 1039519033649920171, + 5587998336806073757, + 350261181032052949 ], [ - 16858795808644713105, - 6129396520459104783, - 209477910023536873, - 13344925663188092269 + 2502911159112974589, + 13478164380649649834, + 16148336361712138832, + 8401471201750923846 ], [ - 14152833547677278430, - 12581387048991719122, - 15917744314847466427, - 14443470950772122977 + 517633987246350732, + 12439096122626936100, + 14664043968721607634, + 3303256595393751370 ], [ - 10299081693196569961, - 350315107343268130, - 6173847887082203307, - 1849093595195412250 + 5150386132855813766, + 14910776297213771263, + 18320842773032635721, + 2341887992598697076 ], [ - 9042415970339022369, - 11988457939756485920, - 10336433647276674537, - 1259669594789643496 + 13646814683590542464, + 15026224737243689799, + 16971519653333540083, + 18306550087952130765 ], [ - 14433184155184276283, - 13064790874012444560, - 14980870107816026210, - 2386527707606459321 + 14077330435849067750, + 8641340920988484366, + 996700081834100300, + 10087635324876250651 ], [ - 15192505525596647383, - 7015684183971452334, - 11289275074222101729, - 15044015789923655184 + 17645985847504542483, + 975231828184945972, + 8892884311156010064, + 13142281407395312794 ], [ - 9328083477760636394, - 9428251331620260633, - 11272001100772856, - 15622689851435689927 + 17909979348139777087, + 17963293453564535400, + 3853686384403451731, + 4326736934406905567 ], [ - 12073756266594964092, - 6962117934383929276, - 8722407149087296616, - 8660375341615685433 + 14322063846564984431, + 8636438762882737544, + 12279387165399832419, + 17171376743426295351 ] ] } diff --git a/prover/vk_setup_data_generator_server_fri/data/witness_artifacts.json b/prover/vk_setup_data_generator_server_fri/data/witness_artifacts.json index 98857952935b..821a2d6e3881 100644 --- a/prover/vk_setup_data_generator_server_fri/data/witness_artifacts.json +++ b/prover/vk_setup_data_generator_server_fri/data/witness_artifacts.json @@ -1,22 +1 @@ -{ - "entry_point_address": "0xc54E30ABB6a3eeD1b9DC0494D90c9C22D76FbA7e", - "entry_point_code": "0x0004000000000002000200000000000200000000030100190000006003300270000002b70430019700030000004103550002000000010355000002b70030019d000100000000001f00000080010000390000004004000039000000000014043500000001012001900000006f0000c13d0000000002000031000000040120008c0000007a0000413d0000000201000367000000000101043b000000e001100270000002b90310009c000000290000c13d0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000000310004c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d0ad708e90000040f000000270000013d000200000004001d000002ba0310009c000000810000613d000002bb0310009c0000009c0000613d000002bc0310009c000000be0000613d000002bd0310009c000000d80000613d000002be0310009c000000f30000613d000002bf0310009c0000010d0000613d000002c00310009c000002200000613d000002c10310009c000001460000613d000002c20210009c0000023b0000613d000002c30210009c000001580000613d000002c40210009c000001720000613d000002c50210009c000002550000613d000002c60210009c0000018c0000613d000002c70210009c000002780000613d000002c80210009c000001a20000613d000002c90210009c0000028e0000613d000002ca0210009c000001ba0000613d000002cb0210009c000001d20000613d000002cc0210009c000001ec0000613d000002cd0210009c000002060000613d000002ce0110009c000002d20000c13d0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000000310004c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d00000004010000390ad70ad50000040f00000002020000290000000003020433000002d00110019700000000001304350000002002000039000000000103001900000000030000190ad7039b0000040f0000000001000416000000000110004c000002d20000c13d000000200200003900000100010000390000000000210439000001200200003900000000000204390000004002000039000002b8030000410ad7039b0000040f000000000120004c000002d20000c13d0ad703ff0000040f0000000001000019000000000200001900000000030000190ad7039b0000040f0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000000310004c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d00000000010000190ad70ad50000040f00000002020000290000000003020433000002d00110019700000000001304350000002002000039000000000103001900000000030000190ad7039b0000040f0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000200310008c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d00000004010000390000000201100367000000000101043b0000000005010433000002b7010000410000000002000414000002b70320009c0000000001024019000000c001100210000002d4011001c70000800d020000390000000203000039000002d5040000410ad70ac90000040f0000000101200190000002d20000613d000002d50000013d0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000000310004c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d00000003010000390ad70ad50000040f0000000202000029000000000302043300000000001304350000002002000039000000000103001900000000030000190ad7039b0000040f0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000000310004c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d00000002010000390ad70ad50000040f00000002020000290000000003020433000000e00110021000000000001304350000002002000039000000000103001900000000030000190ad7039b0000040f0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000000310004c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d00000006010000390ad70ad50000040f0000000202000029000000000302043300000000001304350000002002000039000000000103001900000000030000190ad7039b0000040f0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000800310008c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d000000000100041400000002040003670000006402400370000000000602043b0000004402400370000000000502043b0000000402400370000000000302043b0000000002000410000000040720008c000002cd0000c13d0000001f0160018f0000000502600270000000000420004c000001360000613d0000000004000019000000050640021000000000076500190000000006630019000000000606043300000000006704350000000104400039000000000624004b0000012e0000413d000000000410004c000002d50000613d0000000502200210000000000323001900000000022500190000000301100210000000000402043300000000041401cf000000000414022f00000000030304330000010001100089000000000313022f00000000011301cf000000000141019f0000000000120435000002d50000013d000000040120008a000002cf02000041000000000310004c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d0ad706e60000040f0000000001000019000000000200001900000000030000190ad7039b0000040f0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000000310004c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d0000000a010000390ad70ad50000040f0000000202000029000000000302043300000000001304350000002002000039000000000103001900000000030000190ad7039b0000040f0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000000310004c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d00000008010000390ad70ad50000040f0000000202000029000000000302043300000000001304350000002002000039000000000103001900000000030000190ad7039b0000040f0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000000310004c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d0ad70a100000040f0000000001000019000000000200001900000000030000190ad7039b0000040f0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000000310004c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d00000002010000290000000001010433000002d3020000410000000000210435000000200200003900000000030000190ad7039b0000040f0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000400310008c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d00000002010003670000002402100370000000000202043b0000000401100370000000000101043b00000000030000190ad7039b0000040f0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000000310004c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d00000001010000390ad70ad50000040f0000000202000029000000000302043300000000001304350000002002000039000000000103001900000000030000190ad7039b0000040f0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000000310004c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d0000000b010000390ad70ad50000040f0000000202000029000000000302043300000000001304350000002002000039000000000103001900000000030000190ad7039b0000040f0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000000310004c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d00000005010000390ad70ad50000040f0000000202000029000000000302043300000000001304350000002002000039000000000103001900000000030000190ad7039b0000040f0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000000310004c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d00000009010000390ad70ad50000040f00000002020000290000000003020433000002d00110019700000000001304350000002002000039000000000103001900000000030000190ad7039b0000040f0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000000310004c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d00000007010000390ad70ad50000040f0000000202000029000000000302043300000000001304350000002002000039000000000103001900000000030000190ad7039b0000040f0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000200310008c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d00000002010003670000000402100370000000000202043b000000000121034f000000000501043b000002b7010000410000000002000414000002b70320009c0000000001024019000000c001100210000002d4011001c70000800d020000390000000203000039000002d5040000410ad70ac90000040f0000000101200190000002d50000c13d000002d20000013d0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000000310004c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d0ad707770000040f0000000001000019000000000200001900000000030000190ad7039b0000040f0000000001000416000000000110004c000002d20000c13d000000040100008a0000000001100031000002cf02000041000000000310004c00000000030000190000000003024019000002cf01100197000000000410004c000000000200a019000002cf0110009c00000000010300190000000001026019000000000110004c000002d20000c13d00000002010000290000000003010433000002d1010000410000000000130435000000000100041400000002020000390000000e04000039000000200600003900000000050000190ad7031f0000040f000000000110004c000002d90000c13d000000030200036700000001040000310000001f0340018f000000020100002900000000010104330000000504400270000000000540004c000002bc0000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b000002b40000413d000000000530004c000002cb0000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000310ad703a50000040f0000002404400370000000000404043b0ad702ea0000040f000000000110004c000002d50000c13d000000000100001900000000020000190ad703a50000040f0000000001000019000000000200001900000000030000190ad7039b0000040f0000000001000433000002d20410016700000002030000290000000001030433000100000001001d000000400210003900000000004204350000002004100039000002d202000041000000000024043500000000003104350ad703ae0000040f00000001010000290ad709ab0000040f000000000100001900000000020000190ad703a50000040f0002000000000002000200000006001d000100000005001d000002b705000041000002b70630009c00000000030580190000004003300210000002b70640009c00000000040580190000006004400210000000000334019f000002b70410009c0000000001058019000000c001100210000000000113019f0ad70ac90000040f000000010800002900000002040000290000001f0340018f0000000504400270000000000540004c000003090000613d000000000500001900000005065002100000000007680019000000000661034f000000000606043b00000000006704350000000105500039000000000645004b000003010000413d000000010220018f000000000530004c000003190000613d0000000504400210000000000541034f00000000044800190000000303300210000000000604043300000000063601cf000000000636022f000000000505043b0000010003300089000000000535022f00000000033501cf000000000363019f000000000034043500030000000103550000006001100270000102b70010019d00000000010200190000000200000005000000000001042d0002000000000002000200000006001d000100000005001d000002b705000041000002b70630009c00000000030580190000004003300210000002b70640009c00000000040580190000006004400210000000000334019f000002b70410009c0000000001058019000000c001100210000000000113019f0ad70ace0000040f000000010800002900000002040000290000001f0340018f0000000504400270000000000540004c0000033e0000613d000000000500001900000005065002100000000007680019000000000661034f000000000606043b00000000006704350000000105500039000000000645004b000003360000413d000000010220018f000000000530004c0000034e0000613d0000000504400210000000000541034f00000000044800190000000303300210000000000604043300000000063601cf000000000636022f000000000505043b0000010003300089000000000535022f00000000033501cf000000000363019f000000000034043500030000000103550000006001100270000102b70010019d00000000010200190000000200000005000000000001042d000002b703000041000002b70410009c00000000010380190000004001100210000002b70420009c00000000020380190000006002200210000000000112019f0000000002000414000002b70420009c0000000002038019000000c002200210000000000112019f000002d4011001c700008010020000390ad70ace0000040f0000000102200190000003680000613d000000000101043b000000000001042d000000000100001900000000020000190ad703a50000040f0000000003010019000002b7010000410000000004000414000002b70540009c0000000001044019000000c00110021000000060022002100000000001120019000002d60110004100000000020300190ad70ace0000040f00000001022001900000037a0000613d000000000101043b000000000001042d000000000100001900000000020000190ad703a50000040f0000004402100039000000000300041400000060040000390000000000420435000002d70200004100000000002104350000006402100039000000000002043500000004021000390000000000020435000002b702000041000002b70430009c0000000003028019000002b70410009c00000000010280190000004001100210000000c002300210000000000112019f000002d8011001c700008006020000390ad70ac90000040f0000000102200190000003960000613d000000000101043b0000039a0000013d00030000000103550000006001100270000102b70010019d0000000001000019000000000001042d000002b704000041000002b70510009c000000000104801900000040011002100000000001310019000002b70320009c00000000020480190000006002200210000000000121001900000ad80001042e000002b703000041000002b70420009c0000000002038019000002b70410009c000000000103801900000040011002100000006002200210000000000112019f00000ad900010430000002d90210009c000003b40000813d000000600110003900000040020000390000000000120435000000000001042d000002da010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190ad703a50000040f0000004002100039000002db030000410000000000320435000000200210003900000017030000390000000000320435000000200200003900000000002104350000006001100039000000000001042d0000006002100039000002dc0300004100000000003204350000004002100039000002dd030000410000000000320435000000200210003900000026030000390000000000320435000000200200003900000000002104350000008001100039000000000001042d0000004002100039000002de03000041000000000032043500000020021000390000002003000039000000000032043500000000003104350000006001100039000000000001042d0000006002100039000002df0300004100000000003204350000004002100039000002e0030000410000000000320435000000200210003900000022030000390000000000320435000000200200003900000000002104350000008001100039000000000001042d0000004002100039000002e103000041000000000032043500000020021000390000002003000039000000000032043500000000003104350000006001100039000000000001042d0000006002100039000002e20300004100000000003204350000004002100039000002e303000041000000000032043500000020021000390000002c030000390000000000320435000000200200003900000000002104350000008001100039000000000001042d00080000000000020000000001000412000002d0021001970000000001000410000800000002001d000000000112004b000005dc0000c13d0ad706e60000040f0ad707770000040f0000000c010000390ad70ad50000040f000500000001001d000000000110004c000005eb0000613d000002e60100004100000000001004390000000401000039000300000001001d00000008020000290000000000210439000080020100003900000024020000390ad7036b0000040f000000000110004c000005cb0000613d0000004001000039000700000001001d0000000002010433000002e701000041000600000002001d000000000012043500000000010004140000000802000029000000040320008c000005ce0000613d00000004040000390000000603000029000400000004001d000000000503001900000000060000190ad702ea0000040f000000000110004c000005ce0000c13d0000000c010000390ad70ad50000040f0000000502000029000000000121004b000005fa0000c13d000002e6010000410000000000100439000000080200002900000004010000290000000000210439000080020100003900000024020000390ad7036b0000040f000000000110004c000005cb0000613d00000007010000290000000003010433000002e9010000410000000000130435000000000100041400000004040000390000000802000029000600000004001d000500000003001d000000000503001900000000060000190ad702ea0000040f000000000110004c000006090000c13d0ad70a100000040f00000000010004140000000003000416000000000230004c0000045d0000613d000002b702000041000002b70410009c0000000001028019000000c001100210000002d4011001c70000800902000039000002eb0400004100000000050000190ad70ac90000040f000000000301034f000000010120018f000300000003035500000000020300190000006002200270000102b70020019d000002b702200197000004640000013d000002eb0200004100000000030000190000000004000019000000000500001900000000060000190ad702ea0000040f0000000102000031000000000320004c0000000809000029000004950000613d0000003f03200039000000200400008a000000000443016f000000070700002900000000030704330000000004430019000000000534004b00000000050000190000000105004039000002ea0640009c000006a30000213d0000000105500190000006a30000c13d000000000047043500000000002304350000002002300039000000030300036700000001050000310000001f0450018f0000000505500270000000000650004c000004860000613d000000000600001900000005076002100000000008720019000000000773034f000000000707043b00000000007804350000000106600039000000000756004b0000047e0000413d000000000640004c000004950000613d0000000505500210000000000353034f00000000025200190000000304400210000000000502043300000000054501cf000000000545022f000000000303043b0000010004400089000000000343022f00000000034301cf000000000353019f0000000000320435000000000110004c000006170000613d0000000001000414000500000001001d000002e601000041000000000010043900000006010000290000000000910439000080020100003900000024020000390ad7036b0000040f000000000110004c000005cb0000613d000000070100002900000000030104330000002401300039000002b7020000410000000000210435000002ec0100004100000000001304350000000401300039000200000001001d00000000000104350000000501000029000027102110011a00000044040000390000000802000029000400000003001d000000000503001900000000060000190ad702ea0000040f000000000110004c000006260000c13d0000000001000414000500000001001d000002e6010000410000000000100439000000060100002900000008020000290000000000210439000080020100003900000024020000390ad7036b0000040f000000000110004c000005cb0000613d000000070100002900000000030104330000002401300039000000010200008a000400000002001d0000000000210435000002ec0100004100000000001304350000000401300039000100000001001d00000000000104350000000501000029000027102110011a00000044040000390000000802000029000200000003001d000000000503001900000000060000190ad702ea0000040f000000000110004c000006350000c13d000002e6010000410000000000100439000000060100002900000008020000290000000000210439000080020100003900000024020000390ad7036b0000040f000000000110004c000005cb0000613d00000007010000290000000003010433000002ed01000041000000000013043500000004043000390000000001000414000002b702000041000200000004001d000000000024043500000024040000390000000802000029000500000003001d000000000503001900000000060000190ad702ea0000040f000000000110004c000006440000c13d000002e6010000410000000000100439000000060100002900000008020000290000000000210439000080020100003900000024020000390ad7036b0000040f000000000110004c000005cb0000613d00000007010000290000000003010433000002ed01000041000000000013043500000004043000390000000001000414000002ee02000041000200000004001d000000000024043500000024040000390000000802000029000500000003001d000000000503001900000000060000190ad702ea0000040f000000000110004c000006530000c13d0000000001000414000500000001001d000002e6010000410000000000100439000000060100002900000008020000290000000000210439000080020100003900000024020000390ad7036b0000040f000000000110004c000005cb0000613d00000007010000290000000003010433000002ef0100004100000000001304350000000402300039000002f001000041000100000002001d00000000001204350000000501000029000027102110011a00000024040000390000000802000029000200000003001d000000000503001900000000060000190ad702ea0000040f000000000110004c000006620000c13d0000000001000414000500000001001d000002e6010000410000000000100439000000060100002900000008020000290000000000210439000080020100003900000024020000390ad7036b0000040f000000000110004c000005cb0000613d00000007010000290000000003010433000002ef0100004100000000001304350000000402300039000002b701000041000100000002001d00000000001204350000000501000029000027102110011a00000024040000390000000802000029000200000003001d000000000503001900000000060000190ad702ea0000040f000000000110004c000006710000c13d0000000001000414000500000001001d000002e6010000410000000000100439000000060100002900000008020000290000000000210439000080020100003900000024020000390ad7036b0000040f000000000110004c000005cb0000613d00000007010000290000000003010433000002ef01000041000000000013043500000004023000390000000401000029000100000002001d00000000001204350000000501000029000027102110011a00000024040000390000000802000029000200000003001d000000000503001900000000060000190ad702ea0000040f000000000110004c000006800000c13d0000000001000414000500000001001d000002e6010000410000000000100439000000060100002900000008020000290000000000210439000080020100003900000024020000390ad7036b0000040f000000000110004c000005cb0000613d000000070100002900000000030104330000006401300039000002f102000041000000000021043500000044013000390000000000210435000002f2010000410000000000130435000000240130003900000000000104350000000401300039000200000001001d00000000000104350000000501000029000027102110011a00000084040000390000000802000029000400000003001d000000000503001900000000060000190ad702ea0000040f000000000110004c0000068f0000c13d0000000001000414000500000001001d000002e6010000410000000000100439000000060100002900000008020000290000000000210439000080020100003900000024020000390ad7036b0000040f000000000110004c000005cb0000613d00000007010000290000000003010433000002f20100004100000000001304350000002401300039000002f10200004100000000002104350000000401300039000400000001001d000000000021043500000064013000390000000000010435000000440130003900000000000104350000000501000029000027102110011a00000084040000390000000802000029000600000003001d000000000503001900000000060000190ad702ea0000040f000000000110004c0000069e0000c13d00000007010000290000000001010433000002f30210009c000006a30000213d0000002402100039000002f40300004100000000003204350ad7037d0000040f000000000210004c000006ab0000613d000002d005100197000000000150004c000006cd0000613d000002b7010000410000000002000414000002b70320009c0000000001024019000000c001100210000002d4011001c70000800d020000390000000303000039000002f50400004100000000060004110ad70ac90000040f0000000101200190000005cb0000613d0000000800000005000000000001042d000000000100001900000000020000190ad703a50000040f0000000601000029000002f80110009c0000000701000029000006a30000813d00000006020000290000000000210435000002e501000041000000000012043500000004012000390ad703bc0000040f0000000603000029000000000231004900000000010300190ad703a50000040f000000400100003900000000010104330000004402100039000002e4030000410000000000320435000000240210003900000010030000390000000000320435000002e502000041000000000021043500000004021000390000002003000039000000000032043500000064020000390ad703a50000040f000000400100003900000000010104330000004402100039000002f9030000410000000000320435000000240210003900000018030000390000000000320435000002e502000041000000000021043500000004021000390000002003000039000000000032043500000064020000390ad703a50000040f000000070100002900000000010104330000004402100039000002e803000041000000000032043500000024021000390000001b030000390000000000320435000002e502000041000000000021043500000004021000390000002003000039000000000032043500000064020000390ad703a50000040f0000000501000029000002ea0110009c0000000701000029000006a30000213d00000005020000290000000000210435000002e501000041000000000012043500000004012000390ad703c60000040f0000000503000029000000000231004900000000010300190ad703a50000040f000000070100002900000000010104330000004402100039000002f7030000410000000000320435000000240210003900000014030000390000000000320435000002e502000041000000000021043500000004021000390000002003000039000000000032043500000064020000390ad703a50000040f00000002020000290000000401000029000002ea0110009c0000000701000029000006a30000213d00000004030000290000000000310435000002e501000041000000000013043500000000010200190ad703d30000040f0000000403000029000000000231004900000000010300190ad703a50000040f00000001020000290000000201000029000002ea0110009c0000000701000029000006a30000213d00000002030000290000000000310435000002e501000041000000000013043500000000010200190ad703d30000040f0000000203000029000000000231004900000000010300190ad703a50000040f00000002020000290000000501000029000002ea0110009c0000000701000029000006a30000213d00000005030000290000000000310435000002e501000041000000000013043500000000010200190ad703dc0000040f0000000503000029000000000231004900000000010300190ad703a50000040f00000002020000290000000501000029000002ea0110009c0000000701000029000006a30000213d00000005030000290000000000310435000002e501000041000000000013043500000000010200190ad703dc0000040f0000000503000029000000000231004900000000010300190ad703a50000040f00000001020000290000000201000029000002ea0110009c0000000701000029000006a30000213d00000002030000290000000000310435000002e501000041000000000013043500000000010200190ad703e90000040f0000000203000029000000000231004900000000010300190ad703a50000040f00000001020000290000000201000029000002ea0110009c0000000701000029000006a30000213d00000002030000290000000000310435000002e501000041000000000013043500000000010200190ad703e90000040f0000000203000029000000000231004900000000010300190ad703a50000040f00000001020000290000000201000029000002ea0110009c0000000701000029000006a30000213d00000002030000290000000000310435000002e501000041000000000013043500000000010200190ad703e90000040f0000000203000029000000000231004900000000010300190ad703a50000040f00000002020000290000000401000029000002ea0110009c0000000701000029000006a30000213d00000004030000290000000000310435000002e501000041000000000013043500000000010200190ad703f20000040f0000000403000029000000000231004900000000010300190ad703a50000040f00000004020000290000000601000029000002ea0110009c0000000701000029000006dc0000a13d000002da010000410000000000100435000000410100003900000003020000290000000000120435000000240200003900000000010000190ad703a50000040f000000030200036700000001040000310000001f0340018f000000070100002900000000010104330000000504400270000000000540004c000006bc0000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b000006b40000413d000000000530004c000006cb0000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000310ad703a50000040f000000070100002900000000010104330000004402100039000002f6030000410000000000320435000000240210003900000019030000390000000000320435000002e502000041000000000021043500000004021000390000002003000039000000000032043500000064020000390ad703a50000040f00000006030000290000000000310435000002e501000041000000000013043500000000010200190ad703f20000040f0000000603000029000000000231004900000000010300190ad703a50000040f0004000000000002000002fa0100004100000000001004390000800b0100003900000004020000390ad7036b0000040f0000000002000411000000000121004b000007740000c13d0000000001000032000007740000c13d000002fb0100004100000000001004390000800b0100003900000004020000390ad7036b0000040f000000000110004c000007120000613d000002fb0100004100000000001004390000800b010000390000000402000039000100000002001d0ad7036b0000040f000000000110004c0000076c0000613d000002fb01000041000400000001001d00000000001004390000800b01000039000300000001001d0000000402000039000200000002001d0ad7036b0000040f00000004020000290000000000200439000400000001001d000000030100002900000002020000290ad7036b0000040f000003e8011000390000000402000029000000000112004b0000076c0000213d000002fc0100004100000000001004390000800b01000039000300000001001d0000000402000039000400000002001d0ad7036b0000040f0000000a020000390ad70ad30000040f000002fd010000410000000000100439000000030100002900000004020000290ad7036b0000040f000100000001001d0000000901000039000200000001001d0ad70ad50000040f0000000102000029000002d002200197000002fe01100197000000000121019f00000002020000290ad70ad30000040f000002ff010000410000000000100439000000030100002900000004020000290ad7036b0000040f00000008020000390ad70ad30000040f00000300010000410000000000100439000000030100002900000004020000290ad7036b0000040f00000007020000390ad70ad30000040f00000301010000410000000000100439000000030100002900000004020000290ad7036b0000040f00000006020000390ad70ad30000040f00000302010000410000000000100439000000030100002900000004020000290ad7036b0000040f00000003020000390ad70ad30000040f000002fa010000410000000000100439000000030100002900000004020000290ad7036b0000040f000200000001001d00000004010000290ad70ad50000040f0000000202000029000002d002200197000002fe01100197000000000121019f00000004020000290ad70ad30000040f0000000201000367000000000101043b000100000001001d0000000201000039000200000001001d0ad70ad50000040f0000000102000029000000e0022002700000030301100197000000000121019f00000002020000290ad70ad30000040f000002fb010000410000000000100439000000030100002900000004020000290ad7036b0000040f00000005020000390ad70ad30000040f00000000010004160000000b020000390ad70ad30000040f0000000400000005000000000001042d000002da010000410000000000100435000000110100003900000001020000290000000000120435000000240200003900000000010000190ad703a50000040f000000000100001900000000020000190ad703a50000040f000a0000000000020000000001000414000100000001001d0000004001000039000400000001001d0000000003010433000003040130009c000008640000813d000000a001300039000000040200002900000000001204350000008001300039000003050200004100000000002104350000006001300039000003060200004100000000002104350000004001300039000003070200004100000000002104350000002001300039000003080200004100000000002104350000007a0100003900000000001304350000000002000019000000030120008c000a00000003001d0000082d0000213d000200000002001d000000000203043300000020013000390ad703540000040f0000000a0700002900000004020000290000000003020433000900000001001d000000000100041400000000040704330000000002000019000000000542004b000007a70000813d000000000532001900000020022000390000000006720019000000000606043300000000006504350000079f0000013d000000000234001900000000000204350000000202000039000000200600003900000000050000190ad7031f0000040f000000000110004c0000086c0000613d00000000020004330000000a0800002900000000010804330000000403000029000000000703043300000020037000390000000004000019000000000514004b000007be0000813d00000000053400190000002004400039000000000684001900000000060604330000000000650435000007b60000013d0000000904000029000000000442013f0000000002310019000500000004001d0000000000420435000000200210003900000000002704350000005f01100039000000200200008a000000000221016f000300000007001d0000000001720019000000000221004b00000000020000190000000102004039000002ea0310009c000008640000213d0000000102200190000008640000c13d000000040200002900000000001204350000000c01000039000a00000001001d0ad70ad50000040f0000000003010019000002ea0130009c000008640000213d00000001013000390000000a02000029000900000003001d0ad70ad30000040f0000000a01000029000000000010043500000009010000290000030c0210004100000005010000290ad70ad30000040f0000000a010000290ad70ad50000040f000000000210004c0000085c0000613d000000010110008a000000000210004c000008190000613d000a00000001001d0ad708b00000040f000800000002001d0ad70ad50000040f000600000001001d0000000a01000029000000010110008a0000000101100270000900000001001d0ad708b00000040f000700000002001d0ad70ad50000040f00000007020000290000000302200210000000000121022f000000ff0220008c000000000100201900000008020000290000000302200210000000ff0320008c0000000a03000029000008190000213d0000000604000029000000000224022f000000000112004b000008190000a13d00000009010000290ad708b00000040f000800000002001d0ad70ad50000040f000700000001001d0000000a010000290ad708b00000040f000000080300002900000003033002100000000704000029000000000434022f000000ff0330008c000000000304001900000000030020190ad708c60000040f00000009010000290ad708b00000040f00000005030000290ad708c60000040f0000000901000029000007e80000013d0000000c010000390ad70ad50000040f000000000210004c0000085c0000613d000000010210008a0000000001210170000008270000c13d0000000d010000390ad70ad50000040f000002ea01100197000002ea0210009c0000085c0000613d00000001011000390ad708dc0000040f00000003010000290ad709ab0000040f000000020200002900000001022000390000000303000029000007910000013d0ad708e90000040f0000000007000414000000040100002900000000010104330000000102000029000000000272004b0000088e0000a13d0000000a0600002900000000020604330000000003000019000000000423004b0000083f0000813d00000000041300190000002003300039000000000563001900000000050504330000000000540435000008370000013d00000000031200190000000000030435000a00000007001d0ad703540000040f00000001020000290000000a0300002900000000023200490000000403000029000000000303043300000000002304350000000005010019000002b7010000410000000002000414000002b70420009c0000000002018019000002b70430009c00000000010340190000004001100210000000c002200210000000000112019f0000030a011001c70000800d0200003900000002030000390000030b040000410ad70ac90000040f00000001012001900000089b0000613d0000000a00000005000000000001042d000002da010000410000000000100435000000110100003900000004020000390000000000120435000000240200003900000000010000190ad703a50000040f000002da010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190ad703a50000040f000000030200036700000001040000310000001f0340018f000000040100002900000000010104330000000504400270000000000540004c0000087d0000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b000008750000413d000000000530004c0000088c0000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000310ad703a50000040f000000440210003900000309030000410000000000320435000000240210003900000012030000390000000000320435000002e502000041000000000021043500000004021000390000002003000039000000000032043500000064020000390ad703a50000040f000000000100001900000000020000190ad703a50000040f00010000000000020000000c01000039000100000001001d0ad70ad50000040f000000000110004c000008a80000613d000000010100002900000000001004350000000100000005000000000001042d000002da010000410000000000100435000000320100003900000004020000390000000000120435000000240200003900000000010000190ad703a50000040f0002000000000002000200000001001d0000000c01000039000100000001001d0ad70ad50000040f0000000202000029000000000121004b000008be0000a13d000000010100002900000000001004350000030c0120004100000000020000190000000200000005000000000001042d000002da010000410000000000100435000000320100003900000004020000390000000000120435000000240200003900000000010000190ad703a50000040f0003000000000002000200000003001d000100000002001d000300000001001d0ad70ad50000040f00000001020000290000000302200210000000010300008a00000000042301cf000000ff0520008c0000000004002019000000020500002900000000022501cf0000000002002019000000000242016f000000000334013f000000000131016f000000000121019f00000003020000290ad70ad30000040f0000000300000005000000000001042d0002000000000002000100000001001d0000000d01000039000200000001001d0ad70ad50000040f0000000102000029000002ea022001970000030d01100197000000000121019f00000002020000290ad70ad30000040f0000000200000005000000000001042d00080000000000020000000c010000390ad70ad50000040f000700000001001d000000000110004c000009940000613d0ad7089e0000040f0000030c01000041000800000001001d0ad70ad50000040f0000000701000029000000010110008a0ad708b00000040f0ad70ad50000040f000700000001001d0ad7089e0000040f00000008010000290ad70ad50000040f000000070100002900000008020000290ad70ad30000040f0000000c01000039000200000001001d0ad70ad50000040f000000000210004c000009a30000613d00000002020000290000000000200435000800000001001d0000030e0210004100000000010000190ad70ad30000040f0000000801000029000000010110008a00000002020000290ad70ad30000040f000000010100008a000100000001001d0000000003000019000700000003001d000002cf010000410000000102000029000000000223004b00000000020000190000000002012019000002cf03300197000002cf0430009c0000000001008019000002cf03300167000002cf0330009c000000000102c019000000000110004c0000098c0000613d00000002010000290ad70ad50000040f0000000704000029000000010240021000000001032001bf000800000003001d000000000313004b0000097b0000813d0000000202200039000000000112004b000009430000813d0000000801000029000600000002001d0ad708b00000040f000500000002001d0ad70ad50000040f000400000001001d00000006010000290ad708b00000040f000300000002001d0ad70ad50000040f000000050200002900000003022002100000000403000029000000000323022f000000ff0220008c0000000002030019000000000200201900000003030000290000000303300210000000ff0430008c0000000604000029000009430000213d000000000131022f000000000121004b000009430000a13d000800000004001d00000008010000290ad708b00000040f000600000002001d0ad70ad50000040f000400000001001d00000007010000290ad708b00000040f000500000002001d0ad70ad50000040f000000070400002900000005020000290000000302200210000000000121022f000000ff0220008c000000000100201900000006020000290000000302200210000000ff0320008c0000097b0000213d0000000403000029000000000223022f000000000112004b0000097b0000a13d00000000010400190ad708b00000040f000600000002001d0ad70ad50000040f000500000001001d0000000801000029000800000001001d0ad708b00000040f000400000002001d0ad70ad50000040f000300000001001d00000007010000290ad708b00000040f000000040300002900000003033002100000000304000029000000000434022f000000ff0330008c000000000304001900000000030020190ad708c60000040f00000008010000290ad708b00000040f000000060300002900000003033002100000000504000029000000000434022f000000ff0330008c000000000304001900000000030020190ad708c60000040f0000000803000029000009100000013d0000000c010000390ad70ad50000040f0000000102000029000000000221004b0000098c0000613d000000010210003900000000011201700000098a0000c13d0000000d010000390ad70ad50000040f000002ea01100197000000010110008a000002ea0210009c0000098c0000213d0ad708dc0000040f0000000800000005000000000001042d000002da010000410000000000100435000000110100003900000004020000390000000000120435000000240200003900000000010000190ad703a50000040f0000004001000039000000000101043300000044021000390000030f030000410000000000320435000000240210003900000001030000390000000000320435000002e502000041000000000021043500000004021000390000002003000039000000000032043500000064020000390ad703a50000040f000002da010000410000000000100435000000310100003900000004020000390000000000120435000000240200003900000000010000190ad703a50000040f00020000000000020000004002000039000200000002001d00000000030204330000031002000041000000000023043500000004023000390000002004000039000000000042043500000000020104330000002404300039000000000024043500000044073000390000000004000019000000000524004b000009c10000813d00000000057400190000002004400039000000000614001900000000060604330000000000650435000009b90000013d000000000172001900000000000104350000001f01200039000000200200008a000000000121016f00000044041000390000000001000414000080080200003900000020060000390000000005030019000100000003001d0ad702ea0000040f0000000104000031000000000110004c000009e40000613d000000200140008c000000200100003900000000010440190000001f01100039000000600210018f00000001010000290000000001120019000000000221004b00000000020000190000000102004039000002ea0310009c00000a050000213d000000010220019000000a050000c13d00000002020000290000000000120435000000200140008c00000a0d0000413d0000000200000005000000000001042d00000003030003670000001f0240018f000000020100002900000000010104330000000504400270000000000540004c000009f40000613d000000000500001900000005065002100000000007610019000000000663034f000000000606043b00000000006704350000000105500039000000000645004b000009ec0000413d000000000520004c00000a030000613d0000000504400210000000000343034f00000000044100190000000302200210000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f000000000024043500000001020000310ad703a50000040f000002da010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190ad703a50000040f000000000100001900000000020000190ad703a50000040f000300000000000200000040050000390000000001050433000002d90210009c00000a6e0000813d00000060021000390000000000250435000003110200004100000000002104350000000002050433000003120320009c00000a6e0000213d0000008003200039000000000035043500000060032000390000031304000041000000000043043500000040032000390000031404000041000000000043043500000020032000390000031504000041000000000043043500000041060000390000000000620435000000400310003900000316040000410000000000430435000000200310003900000000002304350000000007050433000003170270009c00000a6e0000213d00000060027000390000000000250435000003180200004100000000002704350000000002050433000003120320009c00000a6e0000213d0000008003200039000000000035043500000060032000390000031304000041000000000043043500000040032000390000031904000041000000000043043500000020032000390000031a040000410000000000430435000000000062043500000040037000390000031b04000041000000000043043500000020037000390000000000230435000300000005001d000200000006001d000100000007001d0ad70a760000040f00000001010000290ad70a760000040f000000020500002900000003040000290000000001040433000003170210009c00000a6e0000213d000000600210003900000000002404350000031c0200004100000000002104350000000002040433000003120320009c00000a6e0000213d0000008003200039000000000034043500000060032000390000031d04000041000000000043043500000040032000390000031e04000041000000000043043500000020032000390000031f040000410000000000430435000000000052043500000020031000390000000000230435000000400210003900000000000204350ad70a760000040f0000000300000005000000000001042d000002da010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190ad703a50000040f0002000000000002000000200210003900000000030204330000000002030433000000410220008c00000aa40000c13d00000041023000390000000002020433000000ff0220018f0000001b0420008a000000010440008c00000aa40000213d00000040041000390000000004040433000200000004001d000000000101043300000020043000390000000004040433000000400330003900000000050304330000004003000039000100000003001d000000000303043300000060063000390000000000560435000000400530003900000000004504350000002004300039000000000024043500000000001304350000000000000435000000000100041400000001020000390000008004000039000000200600003900000000050000190ad7031f0000040f000000000110004c00000aa70000613d00000000010004330000000202000029000000000121013f000002d00110019800000aa40000c13d0000000200000005000000000001042d000000000100001900000000020000190ad703a50000040f000000030200036700000001040000310000001f0340018f000000010100002900000000010104330000000504400270000000000540004c00000ab80000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b00000ab00000413d000000000530004c00000ac70000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000310ad703a50000040f00000acc002104210000000102000039000000000001042d0000000002000019000000000001042d00000ad1002104230000000102000039000000000001042d0000000002000019000000000001042d000000000012041b000000000001042d000000000101041a000000000001042d00000ad70000043200000ad80001042e00000ad9000104300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006603c2f10000000000000000000000000000000000000000000000000000000002d05d3f000000000000000000000000000000000000000000000000000000000738693d0000000000000000000000000000000000000000000000000000000019d8ac610000000000000000000000000000000000000000000000000000000022844fbc000000000000000000000000000000000000000000000000000000002abbd748000000000000000000000000000000000000000000000000000000003b29037c000000000000000000000000000000000000000000000000000000004840a05100000000000000000000000000000000000000000000000000000000579ae3ec0000000000000000000000000000000000000000000000000000000059308f0f000000000000000000000000000000000000000000000000000000005efe4bb4000000000000000000000000000000000000000000000000000000007737dde7000000000000000000000000000000000000000000000000000000007b494b6e000000000000000000000000000000000000000000000000000000007fd5946100000000000000000000000000000000000000000000000000000000874e8f8f00000000000000000000000000000000000000000000000000000000993a04b700000000000000000000000000000000000000000000000000000000ab25690f00000000000000000000000000000000000000000000000000000000aea34ae800000000000000000000000000000000000000000000000000000000af640d0f00000000000000000000000000000000000000000000000000000000be8b112000000000000000000000000000000000000000000000000000000000c6f9688400000000000000000000000000000000000000000000000000000000fb38aa568000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff54657374206d65737361676520320000000000000000000000000000000000003ea98af6e35141fbcacc1724e14f5d76b9b58e41f6c35d0e8ae2e204e66695eb993a04b70000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000449bf97d987c61f24f2a6bbac8f2e426eab123cdfadfc01364acfff36c658d902000002000000000000000000000000000000000000000000000000000000009c4d535bdea7cd8a978f128b93471df48c7dbab89d703809115bdc118c235bfd0200000000000000000000000000000000000084000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffa04e487b71000000000000000000000000000000000000000000000000000000006865617020746573742073686f756c64206661696c65640000000000000000006661696c6564000000000000000000000000000000000000000000000000000073656e64696e67206c31206d6573736167657320746573742073686f756c642072657475726e206d656d6f727920746573742073686f756c64206661696c656465640000000000000000000000000000000000000000000000000000000000006163636573732063616c6c6461746120746573742073686f756c64206661696c616363657373206d656d6f727920746573742073686f756c64206661696c6564686f756c64206661696c656400000000000000000000000000000000000000007261772063616c6c2074657374207769746820626967206f7574207075742073696e2064656c65676174652063616c6c0000000000000000000000000000000008c379a0000000000000000000000000000000000000000000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b836603c2f100000000000000000000000000000000000000000000000000000000486561702073686f756c64206e6f74206265206d6f6469666965640000000000ab25690f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeaea34ae8000000000000000000000000000000000000000000000000000000007b494b6e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000738693d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffff00000000000000000000000000000000000000000000000000000000800000003b29037c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff7b01000035cd4a1b3f84331419050d6ae2d93c44ec0563f2f82bd890769ed5abec2d49c67975aadd2d389580b368cfff5b49965b0bd5da33c144922ce01e7a4d7b4661696c656420746f206465706c6f7920636f6e7472616374000000000000006661696c6564207472616e736665722063616c6c0000000000000000000000000000000000000000000000000000000000000000000000010000000000000000486561702073686f756c64206e6f7420626520656d7074790000000000000000938b5f3299a1f3b18e458564efbb950733226014eece26fae19012d850b48d8342cbb15ccdc3cad6266b0e7a08c0454b23bf29dc2df74b6f3c209e9336465bd119cae4629a2dd7890036d0d1f6a82742845b778b7184e38d5bebfd4cce3b181ea6ae0aac158b2d5c9a9c9285743419d62a32f6727a640955e4ce8ee41503c784ffffffffffffffffffffffff00000000000000000000000000000000000000007877a797fe6dca4321f33fd95414da079ab78e698d761514c01ced9211af267efe173b97ed9aa263236c52fa3eb334d07741add95e972d17352d76816b4aaea39a8a0592ac89c5ad3bc6df8224c17b485976f597df104ee20d0df415241f670b796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d95539132ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000ffffffffffffff6074686520696e6475737472792773207374616e646172642e2e2e00000000000020696e6475737472792e204c6f72656d20497073756d20686173206265656e20206f6620746865207072696e74696e6720616e64207479706573657474696e674c6f72656d20497073756d2069732073696d706c792064756d6d792074657874536f6d65206572726f72206d6573736167650000000000000000000000000000020000000000000000000000000000000000002000000000000000000000000085bd2d2aa0e5528cca3248dfb1e992d0113a553802d7924fdf049ae9ed1d5b30df6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000df6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c6770000000000000000000000000000000000000000000000000000000000000062f84b240000000000000000000000000000000000000000000000000000000014431339128bd25f2c7f93baa611e367472048757f4ad67f6d71a5ca0da550f5000000000000000000000000000000000000000000000000ffffffffffffff7f1c0000000000000000000000000000000000000000000000000000000000000046eabf35680328e26ef4579caf8aeb2cf9ece05dbf67a4f3d1f28c7b1d0e354651e4dbbbcebade695a3f0fdf10beb8b5f83fda161e1a3105a14c41168bf3dce00000000000000000000000007f8b3b04bf34618f4a1723fba96b5db211279a2b000000000000000000000000000000000000000000000000ffffffffffffff9fe0682fd4a26032afff3b18053a0c33d2a6c465c0e19cb1e4c10eb0a949f2827c0bdb5f0ac79d1a7efdc255f399a045038c1b433e9d06c1b1abd58a5fcaab33f1c46cdc50a66f4d07c6e9a127a7277e882fb21bcfb5b068f2b58c7f7283993b790000000000000000000000000865a77d4d68c7e3cdd219d431cfee9271905074dd69e9950f52dddcbc6751fdbb6949787cc1b84ac4020ab0617ec8ad950e554a1b000000000000000000000000000000000000000000000000000000000000004068f5b5e6c4b442e83fcb7b6290520ebb5e077cd10d3bd86cf431ca4b640162b00986d8bb52ee7acb06cabfa6c2c099d8904c7c8d56707a267ddbafd7aed0700000000000000000000000000000000000000000000000000000000000000000", - "default_account_code": "0x0004000000000002000700000000000200000000030100190000006003300270000003540430019700030000004103550002000000010355000003540030019d000100000000001f00000080010000390000004007000039000000000017043500000001012001900000005b0000c13d0000000001000031000000040210008c000000660000413d0000000202000367000000000302043b000000e003300270000003560430009c000000000a00041100000000090004120000000008000410000000740000613d000003570430009c0000008c0000613d000003580430009c000000b30000613d000003590430009c000000c50000613d0000035a0330009c0000006c0000c13d000000040310008a0000035b04000041000000200530008c000000000500001900000000050440190000035b03300197000000000630004c000000000400a0190000035b0330009c00000000030500190000000003046019000000000330004c000000cb0000c13d0000000402200370000000000602043b0000035c0260009c000000cb0000213d000000040560003900000000015100490000035b02000041000002600310008c000000000300001900000000030240190000035b01100197000000000410004c000000000200a0190000035b0110009c00000000010300190000000001026019000000000110004c000000cb0000c13d0000800101a0008c000000680000c13d0000035d09900197000000000189004b000000680000c13d0000000001000414000000000207043300000020032000390000035e04000041000000000043043500000104036000390000000203300367000000000303043b00000024042000390000000000340435000000240300003900000000003204350000035f0320009c000000f60000a13d00000363010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190d4902a00000040f0000000001000416000000000110004c000000cb0000c13d00000020020000390000010001000039000000000021043900000120020000390000000000020439000000400200003900000355030000410d4902960000040f000000000110004c0000006c0000c13d0000000001000019000000000200001900000000030000190d4902960000040f0000000001000416000000000110004c000000cb0000c13d0d4905bf0000040f0000000001000019000000000200001900000000030000190d4902960000040f000500000009001d000600000008001d000400000007001d00070000000a001d0d4902a90000040f0000000701000029000080010110008c000000680000c13d00000005010000290000035d011001970000000604000029000000000141004b000000680000c13d000000000102001900000000020300190d49042e0000040f00000004020000290000000003020433000003640110019700000000001304350000002002000039000000000103001900000000030000190d4902960000040f000500000009001d000600000008001d000400000007001d00070000000a001d0d4902a90000040f0000000701000029000080010110008c000000680000c13d00000005010000290000035d021001970000000601000029000000000112004b000000680000c13d000600000002001d00000220023000390000000001030019000700000002001d000300000003001d0d4903300000040f000000030120008c000000c60000213d0000000401000029000000000101043300000064021000390000036f03000041000000000032043500000044021000390000037003000041000000000032043500000024021000390000003a0300003900000000003204350000036702000041000000000021043500000004021000390000002003000039000000000032043500000084020000390d4902a00000040f000500000009001d000600000008001d00070000000a001d0d4902a90000040f0000000701000029000080010110008c000000680000c13d00000005010000290000035d011001970000000602000029000000000121004b000000680000c13d00000000010300190d49049f0000040f0000000001000019000000000200001900000000030000190d4902960000040f0d4902d10000040f000000030100002900000007020000290d4903300000040f000000040220008c000000ce0000813d000000000100001900000000020000190d4902a00000040f0000000201100367000000000101043b0000036401100197000003650210009c000000e90000c13d000000030100002900000007020000290d4903300000040f000000430120008c000001390000213d0000000404000029000000000104043300000064021000390000036d03000041000000000032043500000044021000390000036e030000410000000000320435000000240210003900000000004204350000036702000041000000000021043500000004021000390000002003000039000000000032043500000084020000390d4902a00000040f000003660110009c000000680000613d00000004010000290000000002010433000700000002001d0000036701000041000000000012043500000004012000390d490c390000040f0000000703000029000000000231004900000000010300190d4902a00000040f000500000009001d000000600320003900000000003704350000035401100197000700000005001d000600000006001d0d4905cb0000040f00000007010000290d49061b0000040f000400000001001d000000060100002900000044011000390000000201100367000000000101043b000080060110008c0000010e0000c13d0000000601000029000001c40210003900000007010000290d4903300000040f000000030120008c000000000100001900000001010020390d49035d0000040f00000007010000290d490c430000040f0000036002000041000000000020043900000004030000390000000502000029000300000003001d0000000000230439000500000001001d0000800a0100003900000024020000390d4902840000040f0000000502000029000000000112004b0000000001000019000000010100a0390d49036e0000040f0000000601000029000001e402100039000600000002001d00000007010000290d4903300000040f00000000030000310d4903830000040f000000070100002900000006020000290d4903300000040f000000000120004c0000018d0000c13d000000060100002900000007010000290d4903c40000040f0000000002010433000000410220008c000001860000213d00000363010000410000000000100435000000320100003900000003020000290000000000120435000000240200003900000000010000190d4902a00000040f000000030100002900000007020000290d4903300000040f000000440220008c000000cb0000413d00000004031000390000000202000367000000000332034f000000000603043b0000035d0360009c000000cb0000213d0000000303000029000000e003300039000000000332034f0000002401100039000000000112034f000000000101043b000500000001001d000000000203043b000000040500002900000000030504330000036801000041000000000013043500000004073000390000000001000414000000060400002900000000004704350000035d042001970000002402300039000300000004001d0000000000420435000000040260008c0000019b0000613d000000440400003900000000020600190000000005030019000700000006001d000200000003001d0d49024a0000040f000000020300002900000007060000290000000405000029000000000110004c0000019b0000c13d000000030200036700000001040000310000001f0340018f00000000010504330000000504400270000000000540004c000001750000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b0000016d0000413d000000000530004c000001840000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000310d4902a00000040f00000061011000390000000002010433000003610220019700000362022001c7000000000021043500000007010000290000000601000029000000070100002900000006020000290d4903300000040f00000000030000310d4903830000040f000000000201001900000004010000290d4905410000040f00000007010000290d49049f0000040f0000000001000019000000000200001900000000030000190d4902960000040f0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600420018f00000000070300190000000002340019000000000342004b000000000300001900000001030040390000035c0420009c000000530000213d0000000103300190000000530000c13d0000000000250435000000200110008c000000cb0000413d000700000006001d00000000010704330000000503000029000000000131004b000000680000813d0000002001200039000003690300004100000000003104350000002401200039000000030300002900000000003104350000004401000039000100000001001d0000000000120435000000440120003900000000000104350000036a0120009c00000004030000290000000701000029000000530000213d000000800420003900000000004304350d490c7d0000040f000000070200002900000004050000290000000006050433000003680100004100000000001604350000002403600039000000000100041400000003040000290000000000430435000200000006001d000000040460003900000006030000290000000000340435000000040320008c000001da0000613d0000004404000039000000020300002900000000050300190d49024a0000040f0000000405000029000000000110004c000001650000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600220018f00000002030000290000000003320019000000000223004b000000000200001900000001020040390000035c0430009c000000530000213d0000000102200190000000530000c13d0000000000350435000000200110008c000000cb0000413d00000002010000290000000001010433000000000110004c000002040000c13d000000200130003900000369020000410000000000210435000000440130003900000005020000290000000000210435000000240130003900000003020000290000000000210435000000010100002900000000001304350000036a0130009c00000004020000290000000701000029000000530000213d0000008004300039000000000042043500000000020300190d490c7d0000040f000000680000013d00000064013000390000036b02000041000000000021043500000044013000390000036c02000041000000000021043500000024013000390000003602000039000000000021043500000367010000410000000000130435000000040130003900000020020000390000000000210435000000840200003900000000010300190d4902a00000040f0002000000000002000200000006001d000100000005001d0000035405000041000003540630009c00000000030580190000004003300210000003540640009c00000000040580190000006004400210000000000334019f000003540410009c0000000001058019000000c001100210000000000113019f0d490d3f0000040f000000010800002900000002040000290000001f0340018f0000000504400270000000000540004c000002340000613d000000000500001900000005065002100000000007680019000000000661034f000000000606043b00000000006704350000000105500039000000000645004b0000022c0000413d000000010220018f000000000530004c000002440000613d0000000504400210000000000541034f00000000044800190000000303300210000000000604043300000000063601cf000000000636022f000000000505043b0000010003300089000000000535022f00000000033501cf000000000363019f000000000034043500030000000103550000006001100270000103540010019d00000000010200190000000200000005000000000001042d0001000000000002000100000005001d0000035405000041000003540630009c00000000030580190000004003300210000003540640009c00000000040580190000006004400210000000000334019f000003540410009c0000000001058019000000c001100210000000000113019f0d490d440000040f0000000106000029000000010220018f000000000300001900000005043002100000000005460019000000000441034f000000000404043b00000000004504350000000103300039000000000430004c0000000004000019000000010400603900000001044001900000025c0000c13d00030000000103550000006001100270000103540010019d00000000010200190000000100000005000000000001042d0000035403000041000003540410009c00000000010380190000004001100210000003540420009c00000000020380190000006002200210000000000112019f0000000002000414000003540420009c0000000002038019000000c002200210000000000112019f00000371011001c700008010020000390d490d440000040f0000000102200190000002810000613d000000000101043b000000000001042d000000000100001900000000020000190d4902a00000040f000000000301001900000354010000410000000004000414000003540540009c0000000001044019000000c00110021000000060022002100000000001120019000003720110004100000000020300190d490d440000040f0000000102200190000002930000613d000000000101043b000000000001042d000000000100001900000000020000190d4902a00000040f0000035404000041000003540510009c000000000104801900000040011002100000000001310019000003540320009c00000000020480190000006002200210000000000121001900000d4a0001042e0000035403000041000003540420009c0000000002038019000003540410009c000000000103801900000040011002100000006002200210000000000112019f00000d4b00010430000000040210008a0000035b030000410000005f0420008c000000000400001900000000040320190000035b02200197000000000520004c00000000030080190000035b0220009c00000000020400190000000002036019000000000220004c000002ce0000613d00000002020003670000004403200370000000000303043b0000035c0430009c000002ce0000213d000000040330003900000000013100490000035b04000041000002600510008c000000000500001900000000050440190000035b01100197000000000610004c000000000400a0190000035b0110009c00000000010500190000000001046019000000000110004c000002ce0000c13d0000000401200370000000000101043b0000002402200370000000000202043b000000000001042d000000000100001900000000020000190d4902a00000040f000300000000000200000000010000310d4902a90000040f0000000001000411000080010110008c000003080000c13d00000000010004120000035d011001970000000002000410000000000121004b000003080000c13d000000a00230003900000000010004140000000204000367000000000524034f0000006002300039000000000224034f000000000202043b000000000405043b000000000340004c0000030c0000c13d0000000004000415000000030440008a00000020044000c9000300000000001d000100000004001d000080010200003900000000030000190000000004000019000000000500001900000000060000190d4902150000040f0000000103000029000000200230011a000000000201001f000000000110004c000003080000c13d000000400100003900000000010104330000006402100039000003730300004100000000003204350000004402100039000003740300004100000000003204350000002402100039000000250300003900000000003204350000036702000041000000000021043500000004021000390000002003000039000000000032043500000084020000390d4902a00000040f0000000001000019000000000200001900000000030000190d4902960000040f00000000534200a900000000544300d9000000000224004b000003280000c13d0000000004000415000000020440008a00000020044000c9000200000000001d000000000230004c000002ea0000613d0000035402000041000003540410009c0000000001028019000000c00110021000000371011001c70000800902000039000080010400003900000000050000190d490d3f0000040f00000000030100190000006003300270000103540030019d0000000003000415000000020330008a00000020033000c90003000000010355000000010120018f000002f20000013d00000363010000410000000000100435000000110100003900000004020000390000000000120435000000240200003900000000010000190d4902a00000040f000000000300003100000000041300490000001f0540008a0000000204000367000000000224034f000000000202043b0000035b06000041000000000752004b000000000700001900000000070640190000035b055001970000035b08200197000000000958004b000000000600a019000000000558013f0000035b0550009c00000000050700190000000005066019000000000550004c0000035a0000613d0000000001120019000000000214034f000000000202043b0000035c0420009c0000035a0000213d000000000323004900000020011000390000035b04000041000000000531004b000000000500001900000000050420190000035b033001970000035b06100197000000000736004b0000000004008019000000000336013f0000035b0330009c00000000030500190000000003046019000000000330004c0000035a0000c13d000000000001042d000000000100001900000000020000190d4902a00000040f000000000110004c000003600000613d000000000001042d00000040010000390000000001010433000000440210003900000375030000410000000000320435000003670200004100000000002104350000002402100039000000200300003900000000003204350000000402100039000000000032043500000064020000390d4902a00000040f000000000110004c000003710000613d000000000001042d000000400100003900000000010104330000006402100039000003760300004100000000003204350000004402100039000003770300004100000000003204350000002402100039000000220300003900000000003204350000036702000041000000000021043500000004021000390000002003000039000000000032043500000084020000390d4902a00000040f0000000004010019000003780120009c000003b90000813d0000003f01200039000000200500008a000000000651016f000000400500003900000000010504330000000006610019000000000716004b000000000700001900000001070040390000035c0860009c000003b90000213d0000000107700190000003b90000c13d000000000065043500000000002104350000000005420019000000000335004b000003c10000213d0000001f0520018f000000020440036700000020031000390000000506200270000000000760004c000003a70000613d000000000700001900000005087002100000000009830019000000000884034f000000000808043b00000000008904350000000107700039000000000867004b0000039f0000413d000000000750004c000003b60000613d0000000506600210000000000464034f00000000066300190000000305500210000000000706043300000000075701cf000000000757022f000000000404043b0000010005500089000000000454022f00000000045401cf000000000474019f000000000046043500000000022300190000000000020435000000000001042d00000363010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190d4902a00000040f000000000100001900000000020000190d4902a00000040f00000040020000390000000001020433000003790310009c000003d90000813d0000008003100039000000000032043500000041020000390000000000210435000000200210003900000000030000310000000203300367000000000400001900000005054002100000000006520019000000000553034f000000000505043b00000000005604350000000104400039000000030540008c000003d00000413d000000000001042d00000363010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190d4902a00000040f000000400200003900000000010204330000037a0310009c000003f90000813d0000004003100039000000000032043500000001020000390000000000210435000000200210003900000000030000310000000203300367000000000400001900000005054002100000000006520019000000000553034f000000000505043b00000000005604350000000104400039000000000540004c000000000500001900000001050060390000000105500190000003ed0000c13d000000000001042d00000363010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190d4902a00000040f0000000002010019000003780120009c000004260000813d0000003f01200039000000200300008a000000000431016f000000400300003900000000010304330000000004410019000000000514004b000000000500001900000001050040390000035c0640009c000004260000213d0000000105500190000004260000c13d000000000043043500000000002104350000001f022000390000000502200270000000000320004c000004230000613d000000200310003900000000040000310000000204400367000000000500001900000005065002100000000007630019000000000664034f000000000606043b00000000006704350000000105500039000000000625004b0000041b0000413d000000000200004c000004250000613d000000000001042d00000363010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190d4902a00000040f00040000000000020000000006020019000300000001001d00000000010004140000004003000039000000000203043300000020042000390000035e050000410000000000540435000400000006001d00000100046000390000000204400367000000000404043b00000024052000390000000000450435000000240400003900000000004204350000037b0420009c0000048f0000813d0000006004200039000000000043043500000354011001970d4905cb0000040f0000000302000029000000000120004c00000000010200190000044b0000c13d00000004010000290d49061b0000040f000300000001001d000000040100002900000040021000390000000202200367000000000202043b000080060220008c000004590000c13d000001c0021000390d4903300000040f000000030120008c000000000100001900000001010020390d49035d0000040f00000004010000290d490c430000040f0000036002000041000000000020043900000000020004100000000403000039000100000003001d0000000000230439000200000001001d0000800a0100003900000024020000390d4902840000040f0000000202000029000000000112004b0000000001000019000000010100a0390d49036e0000040f0000000401000029000001e002100039000200000002001d0d4903300000040f00000000030000310d4903830000040f000000040100002900000002020000290d4903300000040f000000000120004c0000000401000029000004820000c13d000000020100002900000001010000290d4903c40000040f0000000002010433000000410220008c000004970000a13d00000061011000390000000002010433000003610220019700000362022001c700000000002104350000000401000029000000020200002900000002020000290d4903300000040f00000000030000310d4903830000040f000000000201001900000003010000290d4905410000040f0000037c02000041000000000110004c000000000102001900000000010060190000000400000005000000000001042d00000363010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190d4902a00000040f00000363010000410000000000100435000000320100003900000001020000290000000000120435000000240200003900000000010000190d4902a00000040f0004000000000002000200000001001d00000120031000390000000202000367000000000432034f0000004003100039000000000232034f000000000202043b000400000002001d000000000104043b000300000001001d0000037d0110009c000000000100001900000001010040390d490c6b0000040f0000000201000029000001c0021000390d4903300000040f00000000030000310d4903830000040f00000003020000290000037e062001970000000002010019000000000700041400000004010000290000035d04100197000080060140008c000004e00000c13d0000037f0170009c00000000010000190000000101004039000300000006001d000100000007001d000400000002001d0d490c6b0000040f00000004010000290000000001010433000200000001001d0000037f0110009c000000000100001900000001010040390d490c6b0000040f00000003030000290000000101000029000000c00110021000000380011001970000000402000029000000400220021000000381022000410000038202200197000000000112019f000000020200002900000060022002100000038302200197000000000121019f00000384011001c7000000000230004c000004ff0000613d00008009020000390000800604000039000000010500003900000000060000190d490d3f0000040f000300000002001d000005060000013d000000040140008c0000053c0000613d00000000050204330000002003200039000000000160004c000005340000613d0000035401000041000003540230009c000000000201001900000000020340190000004002200210000003540350009c000000000301001900000000030540190000006003300210000000000223019f000003540370009c0000000001074019000000c001100210000000000112019f00000371011001c70000800902000039000000000306001900000000050000190d490d3f0000040f00000000030100190000006003300270000103540030019d0003000000010355000000010120018f0000053a0000013d000080060200003900000000030000190000000004000019000000000500001900000000060000190d490d3f0000040f000300000002001d00030000000103550000006001100270000103540010019d0000035401100197000400000001001d0d4904010000040f00000004050000290000000102000031000000000225004b0000053e0000213d000000200310003900000003040003670000001f0250018f0000000505500270000000000650004c0000051f0000613d000000000600001900000005076002100000000008730019000000000774034f000000000707043b00000000007804350000000106600039000000000756004b000005170000413d000000000620004c0000052e0000613d0000000505500210000000000454034f00000000055300190000000302200210000000000605043300000000062601cf000000000626022f000000000404043b0000010002200089000000000424022f00000000022401cf000000000262019f0000000000250435000000030200002900000001022001900000053c0000c13d000000000201043300000000010300190d4902a00000040f000000000107001900000000020400190000000004050019000000000500001900000000060000190d4902150000040f000000000110004c0000053e0000613d0000000400000005000000000001042d000000000100001900000000020000190d4902a00000040f00010000000000020000000003020433000000410330008c000005710000c13d00000041032000390000000003030433000000ff0430018f0000001d0340008a000000030500008a000000000353004b000005800000a13d00000040032000390000000005030433000000200220003900000000020204330000004003000039000100000003001d0000000003030433000003860650009c0000058f0000813d0000006006300039000000000056043500000040053000390000000000250435000000200230003900000000004204350000000000130435000000000000043500000000010004140000000102000039000000800400003900000000050000190d49024a0000040f000000000110004c0000059d0000613d00000000010004330000035d011001970000000002000410000000000221004b00000000020000190000000102006039000000000110004c0000000001000019000000010100c039000000000112016f000000010110018f0000000100000005000000000001042d0000004001000039000000000101043300000044021000390000038503000041000000000032043500000024021000390000001d0300003900000000003204350000036702000041000000000021043500000004021000390000002003000039000000000032043500000064020000390d4902a00000040f000000400100003900000000010104330000004402100039000003880300004100000000003204350000002402100039000000160300003900000000003204350000036702000041000000000021043500000004021000390000002003000039000000000032043500000064020000390d4902a00000040f00000044013000390000038702000041000000000021043500000024013000390000000902000039000000000021043500000367010000410000000000130435000000040130003900000020020000390000000000210435000000640200003900000000010300190d4902a00000040f000000030200036700000001040000310000001f0340018f000000010100002900000000010104330000000504400270000000000540004c000005ae0000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b000005a60000413d000000000530004c000005bd0000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000310d4902a00000040f0000000001000411000080010110008c000005c30000613d000000000001042d00000363010000410000000000100435000000010100003900000004020000390000000000120435000000240200003900000000010000190d4902a00000040f0003000000000002000200000002001d000100000001001d0000000001020433000300000001001d0000037f0110009c000000000100001900000001010040390d490c6b0000040f0000000101000029000000c00110021000000380011001970000000202000029000000400220021000000381022000410000038202200197000000000121019f000000030200002900000060022002100000038302200197000000000121019f00000384011001c7000080030200003900000000030000190000000004000019000000000500001900000000060000190d490d3f0000040f000200000002001d00030000000103550000006001100270000103540010019d0000035401100197000300000001001d0d4904010000040f00000003050000290000000102000031000000000225004b000006150000213d000000200310003900000003040003670000001f0250018f0000000505500270000000000650004c000006010000613d000000000600001900000005076002100000000008730019000000000774034f000000000707043b00000000007804350000000106600039000000000756004b000005f90000413d000000000620004c000006100000613d0000000505500210000000000454034f00000000055300190000000302200210000000000605043300000000062601cf000000000626022f000000000404043b0000010002200089000000000424022f00000000022401cf000000000262019f000000000025043500000002020000290000000102200190000006180000613d0000000300000005000000000001042d000000000100001900000000020000190d4902a00000040f000000000201043300000000010300190d4902a00000040f000f0000000000020000000207000367000000000217034f000000000302043b000000000230004c0000010004100039000000a00610003900000060051000390000004002100039000a00000002001d0000012002100039000b00000002001d000001c002100039000f00000001001d000e00000002001d000d00000005001d000c00000006001d0000070b0000613d000900000004001d000000710430008c000000c004100039000007780000c13d000800000004001d0d4903300000040f00000000030000310d4903830000040f000000000201043300000020011000390d49026d0000040f0000000f020000290000020003200039000000000400003100000000022400490000001f0520008a0000000202000367000000000332034f000000000303043b0000035b06000041000000000753004b000000000700001900000000070640190000035b055001970000035b08300197000000000958004b000000000600a019000000000558013f0000035b0550009c00000000050700190000000005066019000000000a010019000000000150004c00000b200000613d0000000f010000290000000001130019000000000312034f000000000503043b0000035c0350009c00000b200000213d0000000503500210000000000434004900000020061000390000035b01000041000000000746004b000000000700001900000000070120190000035b044001970000035b08600197000000000948004b0000000001008019000000000448013f0000035b0440009c000000000107c019000000000110004c00000b200000c13d0000004001000039000e00000001001d000000000401043300000020014000390000038c05500197000000000750004c000006760000613d000000000262034f000000000600001900000005076002100000000008710019000000000772034f000000000707043b00000000007804350000000106600039000000000756004b0000066e0000413d000000000200004c000006780000613d00070000000a001d00000000003404350000003f02300039000000200300008a000000000232016f0000000002240019000000000342004b000000000300001900000001030040390000035c0520009c00000b180000213d000000010330019000000b180000c13d0000000e03000029000000000023043500000000020404330d49026d0000040f000600000001001d0000000f0100002900000220021000390d4903300000040f00000000030000310d4903830000040f000000000201043300000020011000390d49026d0000040f00000002020003670000000d03000029000000000632034f0000000a03000029000000000532034f0000000f0c0000290000002003c00039000000000432034f0000000b03000029000000000732034f0000000903000029000000000832034f000000e003c00039000000000932034f0000000803000029000000000a32034f0000000c03000029000000000b32034f0000008003c00039000000000d0c0019000000000c32034f0000000002d2034f000000000302043b000000000404043b000000000505043b000000000606043b000000000c0c043b000000000b0b043b000000000a0a043b000000000909043b000000000808043b000000000707043b0000000e020000290000000002020433000001c00d20003900000000001d0435000001a001200039000000060d0000290000000000d104350000018001200039000000070d0000290000000000d1043500000160012000390000000000710435000001400120003900000000008104350000012001200039000000000091043500000100012000390000000000a10435000000e0012000390000000000b10435000000c0012000390000000000c10435000000a0012000390000000000610435000000800120003900000000005104350000006001200039000000000041043500000040012000390000000000310435000001c00100003900000000001204350000038d03000041000000200120003900000000003104350000038e0320009c00000b180000213d000001e0032000390000000e04000029000000000034043500000000020204330d49026d0000040f0000000e020000290000000002020433000f00000002001d0000038a020000410000000000200439000d00000001001d0000800b0100003900000004020000390d4902840000040f0000038f020000410000000f040000290000006003400039000000000023043500000390020000410000004003400039000000000023043500000000030400190000008002300039000000000012043500000391020000410000002001300039000000000021043500000080020000390000000000230435000003920230009c00000b180000213d000000a0023000390000000e04000029000000000024043500000000020304330d49026d0000040f0000000e02000029000000000402043300000042024000390000000d03000029000000000032043500000393020000410000002003400039000000000023043500000022024000390000000000120435000000420100003900000000001404350000036a0140009c00000b180000213d000000800140003900000b110000013d000000000147034f000000000101043b00090000000703530d490b720000040f000000090200035f0000000c03000029000000000232034f000000000202043b000c00000001001d00000000010200190d490b720000040f0000000d02000029000000090300035f000000000223034f000000000202043b000d00000001001d00000000010200190d490b720000040f0000000d0700002900000000020704330000004009000039000000000809043300000020038000390000000004000019000000000524004b0000072b0000813d00000000053400190000002004400039000000000674001900000000060604330000000000650435000007230000013d0000000003320019000000000003043500000000040104330000000005000019000000000645004b000007370000813d000000000635001900000020055000390000000007150019000000000707043300000000007604350000072f0000013d00000000013400190000000000010435000000000124001900000000001804350000003f01100039000000200200008a000700000002001d000000000221016f000d00000008001d0000000001820019000000000221004b000000000200001900000001020040390000035c0310009c00000b180000213d000000010220019000000b180000c13d000900000009001d00000000001904350000000a010000290000000201100367000000000101043b0000035d011001970d490b5a0000040f0000000b020000290000000202200367000000000202043b000a00000001001d00000000010200190d490b720000040f000b00000001001d0000000f010000290000000e020000290d4903300000040f0000035c01200197000000010210008c000007ba0000c13d0000000f010000290000000e020000290d4903300000040f000000000220004c00000b230000613d0000000205000367000000000115034f000000000101043b000000010200008a0000035b03000041000000000221004b000000000200001900000000020320190000035b011001970000035b0410009c00000000030080190000035b011001670000035b0110009c000000000102001900000000010360190000006006000039000000000110004c000007bd0000c13d00080000000503530d490b460000040f000000080500035f0000000006010019000007bd0000013d000000020230008c000008ad0000c13d0000038a0100004100000000001004390000800b010000390000000402000039000800000004001d0d4902840000040f0d490b720000040f000000020300036700070000000303530000000902000029000000000223034f000000000202043b000500000001001d00000000010200190d490b720000040f000000070200035f0000000803000029000000000232034f000000000202043b000600000001001d00000000010200190d490b720000040f000000070200035f0000000c03000029000000000232034f000000000202043b000800000001001d00000000010200190d490b720000040f0000000d02000029000000070300035f000000000223034f000000000202043b000900000001001d00000000010200190d490b720000040f0000000a02000029000000070300035f000000000223034f000000000202043b0000035d02200197000c00000001001d00000000010200190d490b5a0000040f0000000b020000290000000202200367000000000202043b000d00000001001d00000000010200190d490b720000040f000000050700002900000000020704330000004009000039000000000809043300000020038000390000000004000019000000000524004b000008e70000813d00000000053400190000002004400039000000000674001900000000060604330000000000650435000007b20000013d0d490ba70000040f000000020500036700000000060100190000000f010000290000014002100039000000000225034f0000006007000039000000000202043b000000000220004c0000000d020000290000000c030000290000000b040000290000000a050000290000000908000029000600000006001d000007f40000613d0000038a0100004100000000001004390000800b0100003900000004020000390d4902840000040f0d490b720000040f00000009080000290000000007080433000000200370003900000000020104330000000004000019000000000524004b000007dd0000813d00000000053400190000002004400039000000000614001900000000060604330000000000650435000007d50000013d0000000001320019000003940300004100000000003104350000000201200039000000000017043500000041012000390000000702000029000000000221016f0000000001720019000000000221004b000000000200001900000001020040390000035c0310009c00000b180000213d000000010220019000000b180000c13d00000000001804350000000f010000290000000d020000290000000c030000290000000b040000290000000a050000290000000606000029000800000007001d0000000006060433000500000006001d0000000004040433000400000004001d0000000004050433000300000004001d0000000002020433000200000002001d0000000002030433000100000002001d0000000e020000290d4903300000040f00000002010000290000000103000029000000000131001900000003030000290000000001310019000000040300002900000000013100190000000503000029000000000131001900000000012100190000000802000029000000000202043300000000012100190000035c011001970d490be70000040f000500000001001d0000000f010000290000000e020000290d4903300000040f000000050900002900000000050904330000000903000029000000000403043300000020034000390000000006000019000000000756004b000008220000813d000000000736001900000020066000390000000008960019000000000808043300000000008704350000081a0000013d00000000063500190000000000060435000000000545001900000020075000390000000c0c00002900000000060c043300000000080000190000000d0b000029000000000968004b000008320000813d00000000097800190000002008800039000000000ac80019000000000a0a04330000000000a904350000082a0000013d000000000776001900000000000704350000000005560019000000200750003900000000060b043300000000080000190000000a0c000029000000000968004b000008410000813d00000000097800190000002008800039000000000ab80019000000000a0a04330000000000a90435000008390000013d000000000776001900000000000704350000000005560019000000200750003900000000060c043300000000080000190000000b0b000029000000000968004b000008500000813d00000000097800190000002008800039000000000ac80019000000000a0a04330000000000a90435000008480000013d000000000776001900000000000704350000000005560019000000200750003900000000060b04330000000008000019000000000968004b0000085e0000813d00000000097800190000002008800039000000000ab80019000000000a0a04330000000000a90435000008560000013d0000000007760019000000000007043500000000055600190000002007500039000000060b00002900000000060b04330000000008000019000000000968004b0000086d0000813d00000000097800190000002008800039000000000ab80019000000000a0a04330000000000a90435000008650000013d0000000007760019000000000007043500000000055600190000001f0620018f000000200750003900000002011003670000000508200270000000000980004c0000087f0000613d0000000009000019000000050a900210000000000ba70019000000000aa1034f000000000a0a043b0000000000ab04350000000109900039000000000a89004b000008770000413d000000000960004c0000088e0000613d0000000508800210000000000181034f00000000078700190000000306600210000000000807043300000000086801cf000000000868022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000181019f0000000000170435000000000125001900000020051000390000000000050435000000080900002900000000020904330000000006000019000000000726004b0000089c0000813d00000000075600190000002006600039000000000896001900000000080804330000000000870435000008940000013d000000000552001900000000000504350000000001410049000000000112001900000000001404350000003f011000390000000702000029000000000221016f0000000001420019000000000221004b000000000200001900000001020040390000035c0510009c00000b180000213d000000010220019000000b110000613d00000b180000013d000000010130008c00000b2b0000c13d0000038a0100004100000000001004390000800b0100003900000004020000390d4902840000040f0d490b720000040f000000020300036700080000000303530000000902000029000000000223034f000000000202043b000600000001001d00000000010200190d490b720000040f0000000c02000029000000080300035f000000000223034f000000000202043b000700000001001d00000000010200190d490b720000040f0000000d02000029000000080300035f000000000223034f000000000202043b000900000001001d00000000010200190d490b720000040f0000000a02000029000000080300035f000000000223034f000000000202043b0000035d02200197000c00000001001d00000000010200190d490b5a0000040f0000000b020000290000000202200367000000000202043b000d00000001001d00000000010200190d490b720000040f000000060700002900000000020704330000004009000039000000000809043300000020038000390000000004000019000000000524004b000009710000813d00000000053400190000002004400039000000000674001900000000060604330000000000650435000008df0000013d0000000003320019000000000003043500000000028200190000002004200039000000060e00002900000000030e043300000000050000190000000d0a0000290000000c0b000029000000090c000029000000080d000029000000000635004b000008fa0000813d000000000645001900000020055000390000000007e5001900000000070704330000000000760435000008f20000013d000000000443001900000000000404350000000002230019000000200420003900000000030d04330000000005000019000000000635004b000009080000813d000000000645001900000020055000390000000007d5001900000000070704330000000000760435000009000000013d000000000443001900000000000404350000000002230019000000200420003900000000030c04330000000005000019000000000635004b000009160000813d000000000645001900000020055000390000000007c50019000000000707043300000000007604350000090e0000013d000000000443001900000000000404350000000002230019000000200420003900000000030b04330000000005000019000000000635004b000009240000813d000000000645001900000020055000390000000007b50019000000000707043300000000007604350000091c0000013d000000000443001900000000000404350000000002230019000000200420003900000000030a04330000000005000019000000000635004b000009320000813d000000000645001900000020055000390000000007a50019000000000707043300000000007604350000092a0000013d000000000443001900000000000404350000000002230019000000200420003900000000030104330000000005000019000000000635004b000009400000813d00000000064500190000002005500039000000000715001900000000070704330000000000760435000009380000013d000000000143001900000000000104350000000001820049000000000113001900000000001804350000003f01100039000000200200008a000a00000002001d000000000221016f000d00000008001d0000000001820019000000000221004b000000000200001900000001020040390000035c0310009c00000b180000213d000000010220019000000b180000c13d000900000009001d00000000001904350000000f010000290000000e020000290d4903300000040f0000035c01200197000000010210008c000009ec0000c13d0000000f010000290000000e020000290d4903300000040f000000000220004c00000b230000613d0000000201100367000000000101043b000000010200008a0000035b03000041000000000221004b000000000200001900000000020320190000035b011001970000035b0410009c00000000030080190000035b011001670000035b0110009c00000000020360190000006001000039000000000220004c000009ed0000c13d0d490b460000040f000009ed0000013d0000000003320019000000000003043500000000028200190000002004200039000000070d00002900000000030d043300000000050000190000000d0a0000290000000c0b000029000000090c000029000000000635004b000009830000813d000000000645001900000020055000390000000007d50019000000000707043300000000007604350000097b0000013d000000000443001900000000000404350000000002230019000000200420003900000000030c04330000000005000019000000000635004b000009910000813d000000000645001900000020055000390000000007c5001900000000070704330000000000760435000009890000013d000000000443001900000000000404350000000002230019000000200420003900000000030b04330000000005000019000000000635004b0000099f0000813d000000000645001900000020055000390000000007b5001900000000070704330000000000760435000009970000013d000000000443001900000000000404350000000002230019000000200420003900000000030a04330000000005000019000000000635004b000009ad0000813d000000000645001900000020055000390000000007a5001900000000070704330000000000760435000009a50000013d000000000443001900000000000404350000000002230019000000200420003900000000030104330000000005000019000000000635004b000009bb0000813d00000000064500190000002005500039000000000715001900000000070704330000000000760435000009b30000013d000000000143001900000000000104350000000001820049000000000113001900000000001804350000003f01100039000000200200008a000a00000002001d000000000221016f000d00000008001d0000000001820019000000000221004b000000000200001900000001020040390000035c0310009c00000b180000213d000000010220019000000b180000c13d000900000009001d00000000001904350000000f010000290000000e020000290d4903300000040f0000035c01200197000000010210008c00000a7f0000c13d0000000f010000290000000e020000290d4903300000040f000000000220004c00000b230000613d0000000201100367000000000101043b000000010200008a0000035b03000041000000000221004b000000000200001900000000020320190000035b011001970000035b0410009c00000000030080190000035b011001670000035b0110009c00000000020360190000006001000039000000000220004c00000a800000c13d0d490b460000040f00000a800000013d0d490ba70000040f000c00000001001d0d4903e10000040f00000000030100190000000001030433000000000110004c00000b230000613d0000002001300039000000000201043300000361022001970000038b022001c700000000002104350000000c010000290000000001010433000800000001001d0000000d010000290000000001010433000700000001001d0000000f010000290000000e02000029000b00000003001d0d4903300000040f00000008010000290000000703000029000000000131001900000000012100190000000b02000029000000000202043300000000012100190000035c011001970d490be70000040f000800000001001d0000000f010000290000000e020000290d4903300000040f000000080a00002900000009030000290000000004030433000003710500004100000020034000390000000000530435000000210640003900000000050a04330000000007000019000000000857004b00000a200000813d000000000867001900000020077000390000000009a700190000000009090433000000000098043500000a180000013d00000000066500190000000000060435000000000545001900000021075000390000000d0b00002900000000060b04330000000008000019000000000968004b00000a2f0000813d00000000097800190000002008800039000000000ab80019000000000a0a04330000000000a9043500000a270000013d00000000077600190000000000070435000000000556001900000021075000390000000c0b00002900000000060b04330000000008000019000000000968004b00000a3e0000813d00000000097800190000002008800039000000000ab80019000000000a0a04330000000000a9043500000a360000013d0000000007760019000000000007043500000000055600190000001f0620018f000000210750003900000002011003670000000508200270000000000980004c00000a500000613d0000000009000019000000050a900210000000000ba70019000000000aa1034f000000000a0a043b0000000000ab04350000000109900039000000000a89004b00000a480000413d000000000960004c00000a5f0000613d0000000508800210000000000181034f00000000078700190000000306600210000000000807043300000000086801cf000000000868022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000181019f00000000001704350000000001250019000000210510003900000000000504350000000b0900002900000000020904330000000006000019000000000726004b00000a6d0000813d0000000007560019000000200660003900000000089600190000000008080433000000000087043500000a650000013d00000000055200190000000000050435000000000141004900000000011200190000000102100039000000000024043500000040011000390000000a02000029000000000221016f0000000001420019000000000221004b000000000200001900000001020040390000035c0510009c00000b180000213d000000010220019000000b110000613d00000b180000013d0d490ba70000040f000c00000001001d0d4903e10000040f00000000030100190000000001030433000000000110004c00000b230000613d0000002001300039000000000201043300000361022001970000038b022001c700000000002104350000000c010000290000000001010433000800000001001d0000000d010000290000000001010433000700000001001d0000000f010000290000000e02000029000b00000003001d0d4903300000040f00000008010000290000000703000029000000000131001900000000012100190000000b02000029000000000202043300000000012100190000035c011001970d490be70000040f000800000001001d0000000f010000290000000e020000290d4903300000040f000000080a00002900000009030000290000000004030433000003840500004100000020034000390000000000530435000000210640003900000000050a04330000000007000019000000000857004b00000ab30000813d000000000867001900000020077000390000000009a700190000000009090433000000000098043500000aab0000013d00000000066500190000000000060435000000000545001900000021075000390000000d0b00002900000000060b04330000000008000019000000000968004b00000ac20000813d00000000097800190000002008800039000000000ab80019000000000a0a04330000000000a9043500000aba0000013d00000000077600190000000000070435000000000556001900000021075000390000000c0b00002900000000060b04330000000008000019000000000968004b00000ad10000813d00000000097800190000002008800039000000000ab80019000000000a0a04330000000000a9043500000ac90000013d0000000007760019000000000007043500000000055600190000001f0620018f000000210750003900000002011003670000000508200270000000000980004c00000ae30000613d0000000009000019000000050a900210000000000ba70019000000000aa1034f000000000a0a043b0000000000ab04350000000109900039000000000a89004b00000adb0000413d000000000960004c00000af20000613d0000000508800210000000000181034f00000000078700190000000306600210000000000807043300000000086801cf000000000868022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000181019f00000000001704350000000001250019000000210510003900000000000504350000000b0900002900000000020904330000000006000019000000000726004b00000b000000813d0000000007560019000000200660003900000000089600190000000008080433000000000087043500000af80000013d00000000055200190000000000050435000000000141004900000000011200190000000102100039000000000024043500000040011000390000000a02000029000000000221016f0000000001420019000000000221004b000000000200001900000001020040390000035c0510009c00000b180000213d000000010220019000000b180000c13d00000040020000390000000000120435000000000204043300000000010300190d49026d0000040f0000000f00000005000000000001042d00000363010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190d4902a00000040f000000000100001900000000020000190d4902a00000040f00000363010000410000000000100435000000320100003900000004020000390000000000120435000000240200003900000000010000190d4902a00000040f000000400100003900000000010104330000004402100039000003890300004100000000003204350000002402100039000000170300003900000000003204350000036702000041000000000021043500000004021000390000002003000039000000000032043500000064020000390d4902a00000040f0000000004000019000000000534004b00000b430000813d0000000005240019000000000614001900000000060604330000000000650435000000200440003900000b3b0000013d00000000012300190000000000010435000000000001042d000000400200003900000000010204330000037a0310009c00000b520000813d0000004003100039000000000032043500000020021000390000039503000041000000000032043500000001020000390000000000210435000000000001042d00000363010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190d4902a00000040f0000000002010019000000400300003900000000010304330000037a0410009c00000b6a0000813d0000004004100039000000000043043500000020031000390000039604000041000000000043043500000060022002100000002103100039000000000023043500000015020000390000000000210435000000000001042d00000363010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190d4902a00000040f00020000000000020000007f0210008c000200000001001d00000b8f0000a13d0d490c1d0000040f000100000001001d00000002011000390d4904010000040f0000000002010433000000000220004c00000b9f0000613d0000002002100039000000000302043300000361033001970000000105000029000000f804500210000000000334019f000003950330004100000000003204350000000302500210000000f802200089000000020300002900000000032301cf000000ff0220008c000000000203001900000000020020190000002103100039000000000023043500000b9d0000013d0d4903e10000040f0000000002010433000000000220004c00000b9f0000613d0000000204000029000000f8024002100000035b03000041000000000440004c0000000002036019000000200310003900000000040304330000036104400197000000000224019f00000000002304350000000200000005000000000001042d00000363010000410000000000100435000000320100003900000004020000390000000000120435000000240200003900000000010000190d4902a00000040f000200000000000200000000030100190000035c01300197000000010210008c00000bd70000613d000000370210008c00000bc80000a13d000200000001001d0d490c1d0000040f000100000001001d00000002011000390d4904010000040f0000000002010433000000000220004c00000bdf0000613d0000002002100039000000000302043300000361033001970000000105000029000000f804500210000000000334019f000003970330004100000000003204350000000302500210000000f802200089000000020300002900000000032301cf000000ff0220008c000000000203001900000000020020190000002103100039000000000023043500000bd50000013d000200000003001d0d4903e10000040f0000000002010433000000000220004c00000bdf0000613d0000000202000029000000f802200210000000200310003900000000040304330000036104400197000000000224019f0000035b0220016700000000002304350000000200000005000000000001042d00000363010000410000000000100435000000010100003900000004020000390000000000120435000000240200003900000000010000190d4902a00000040f00000363010000410000000000100435000000320100003900000004020000390000000000120435000000240200003900000000010000190d4902a00000040f000200000000000200000000030100190000035c01300197000000370210008c00000c060000a13d000200000001001d0d490c1d0000040f000100000001001d00000002011000390d4904010000040f0000000002010433000000000220004c00000c150000613d0000002002100039000000000302043300000361033001970000000105000029000000f804500210000000000334019f000003980330004100000000003204350000000302500210000000f802200089000000020300002900000000032301cf000000ff0220008c000000000203001900000000020020190000002103100039000000000023043500000c130000013d000200000003001d0d4903e10000040f0000000002010433000000000220004c00000c150000613d0000000202000029000000f802200210000000200310003900000000040304330000036104400197000000000242019f0000038b0220004100000000002304350000000200000005000000000001042d00000363010000410000000000100435000000320100003900000004020000390000000000120435000000240200003900000000010000190d4902a00000040f00000080021002700000037e0310009c000000000201a0190000037e0110009c0000000001000019000000100100203900000008031001bf0000035c0420009c000000000103201900000040032002700000035c0420009c000000000203201900000004031001bf000003540420009c00000000010320190000002003200270000003540420009c000000000203201900000002031001bf0000ffff0420008c000000000103201900000010032002700000000002032019000000ff0220008c000000000200001900000001020020390000000001210019000000000001042d00000040021000390000039903000041000000000032043500000020021000390000001a030000390000000000320435000000200200003900000000002104350000006001100039000000000001042d000000e0031000390000000202000367000000000332034f000000000303043b0000035d0330019800000c4d0000613d0000012001100039000000000112034f000000000101043b00000c620000013d000000a003100039000000000332034f0000006004100039000000000442034f000000000404043b000000000503043b00000000635400a9000000000650004c00000c590000613d00000000655300d9000000000445004b00000c630000c13d0000012001100039000000000112034f000000000201043b0000000001320019000000000221004b00000000020000190000000102004039000000010220019000000c630000c13d000000000001042d00000363010000410000000000100435000000110100003900000004020000390000000000120435000000240200003900000000010000190d4902a00000040f000000000110004c00000c6e0000613d000000000001042d0000004001000039000000000101043300000044021000390000039a0300004100000000003204350000002402100039000000080300003900000000003204350000036702000041000000000021043500000004021000390000002003000039000000000032043500000064020000390d4902a00000040f00050000000000020000035d0a1001970000004009000039000000000b0904330000037a01b0009c00000cfb0000813d0000004001b0003900000000001904350000002001000039000400000001001d00000000001b04350000002003b000390000039b01000041000300000003001d0000000000130435000000010100003900000000050004140000000403a0008c00000c9d0000613d00000000040204330000002003200039000000000105001900000000020a001900000000050000190000000006000019000500000009001d00020000000a001d00010000000b001d0d4902150000040f000000010b000029000000020a0000290000000509000029000000600c0000390000000102000031000000000320004c00000cd00000613d0000035c0320009c00000cfb0000213d0000003f03200039000000200400008a000000000343016f000000000c09043300000000033c00190000000004c3004b000000000400001900000001040040390000035c0530009c00000cfb0000213d000000010440019000000cfb0000c13d000000000039043500000000002c04350000002002c00039000000030300036700000001050000310000001f0450018f0000000505500270000000000650004c00000cc10000613d000000000600001900000005076002100000000008720019000000000773034f000000000707043b00000000007804350000000106600039000000000756004b00000cb90000413d000000000640004c00000cd00000613d0000000505500210000000000353034f00000000025200190000000304400210000000000502043300000000054501cf000000000545022f000000000303043b0000010004400089000000000343022f00000000034301cf000000000353019f000000000032043500000000020c0433000000000110004c00000d060000613d000000000120004c00000ce50000c13d00030000000c001d000500000009001d0000039c01000041000000000010043900000004010000390000000000a10439000080020100003900000024020000390d4902840000040f000000000110004c00000d300000613d000000030c00002900000000020c0433000000000120004c000000050900002900000cf90000613d0000035b01000041000000200320008c000000000300001900000000030140190000035b02200197000000000420004c000000000100a0190000035b0220009c000000000103c019000000000110004c00000d030000c13d0000002001c000390000000001010433000000000210004c0000000002000019000000010200c039000000000221004b00000d030000c13d000000000110004c00000d1d0000613d0000000500000005000000000001042d00000363010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190d4902a00000040f000000000100001900000000020000190d4902a00000040f000000000120004c00000d2e0000c13d0000000004090433000500000004001d0000036701000041000000000014043500000004014000390000000402000029000000000021043500000000030b0433000400000003001d00000024014000390000000000310435000000440240003900000003010000290d490b3a0000040f00000004010000290000001f01100039000000200200008a000000000121016f000000440210003900000005010000290d4902a00000040f000000000109043300000064021000390000039d03000041000000000032043500000044021000390000039e03000041000000000032043500000024021000390000002a0300003900000000003204350000036702000041000000000021043500000004021000390000000403000029000000000032043500000084020000390d4902a00000040f0000002001c000390d4902a00000040f0000000501000029000000000101043300000044021000390000039f03000041000000000032043500000024021000390000001d0300003900000000003204350000036702000041000000000021043500000004021000390000000403000029000000000032043500000064020000390d4902a00000040f00000d42002104210000000102000039000000000001042d0000000002000019000000000001042d00000d47002104230000000102000039000000000001042d0000000002000019000000000001042d00000d490000043200000d4a0001042e00000d4b00010430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000202bcce700000000000000000000000000000000000000000000000000000000a28c1aee00000000000000000000000000000000000000000000000000000000df9c158900000000000000000000000000000000000000000000000000000000e2f318e300000000000000000000000000000000000000000000000000000000eeb8cb098000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff000000000000000000000000ffffffffffffffffffffffffffffffffffffffffe1239cd800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff9f9cc7f708afc65944829bd487b90b72536b1951864fbfc14e125fc972a6507f3900ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1b000000000000000000000000000000000000000000000000000000000000004e487b7100000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000000949431dc000000000000000000000000000000000000000000000000000000008c5a34450000000000000000000000000000000000000000000000000000000008c379a000000000000000000000000000000000000000000000000000000000dd62ed3e00000000000000000000000000000000000000000000000000000000095ea7b300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff7f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000005361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f74206d757374206265206174206c65617374203638206279746573206c6f6e6754686520617070726f76616c4261736564207061796d617374657220696e707574206265206174206c656173742034206279746573206c6f6e67000000000000546865207374616e64617264207061796d617374657220696e707574206d7573020000000000000000000000000000000000000000000000000000000000000002000002000000000000000000000000000000000000000000000000000000007261746f720000000000000000000000000000000000000000000000000000004661696c656420746f20706179207468652066656520746f20746865206f7065496e76616c69642063616c6c20746f20436f6e74726163744465706c6f79657275650000000000000000000000000000000000000000000000000000000000004e6f7420656e6f7567682062616c616e636520666f7220666565202b2076616c0000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000ffffffffffffff80000000000000000000000000000000000000000000000000ffffffffffffffc0000000000000000000000000000000000000000000000000ffffffffffffffa0202bcce700000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000010000000000000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000ffffffff000000000000000000000000000000000000000000000000ffffffff00000000000000000000000001000000000000000000000000000000000000000000000000000000000000005369676e6174757265206c656e67746820697320696e636f72726563740000007fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1496e76616c69642073000000000000000000000000000000000000000000000076206973206e656974686572203237206e6f7220323800000000000000000000456e636f64696e6720756e737570706f727465642074780000000000000000009a8a0592ac89c5ad3bc6df8224c17b485976f597df104ee20d0df415241f670bc00000000000000000000000000000000000000000000000000000000000000007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff848e1bfa1ac4e3576b728bda6721b215c70a7799a5b4866282a71bab954baac8000000000000000000000000000000000000000000000000fffffffffffffe1fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a519b453ce45aaaaf3a300f5a9ec95869b4f28ab10430b572ee218c3a6a5e07d6fc2f8787176b8ac6bf7215b4adcc1e069bf4ab82d9ab1df05a57a91d425935b6e000000000000000000000000000000000000000000000000ffffffffffffff5f1901000000000000000000000000000000000000000000000000000000000000808000000000000000000000000000000000000000000000000000000000000081000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000f800000000000000000000000000000000000000000000000000000000000000556e737570706f72746564207061796d617374657220666c6f770000000000004f766572666c6f770000000000000000000000000000000000000000000000005361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65641806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b836f742073756363656564000000000000000000000000000000000000000000005361666545524332303a204552433230206f7065726174696f6e20646964206e416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000000000000000000000000000000000000000000000000000000000000000000000", - "predeployed_contracts": { - "0xdeadbeafdeadbeafdeadbeafdeadbeafdeadbeaf": "0x00020000000000020001000000000002000000000301001900000060033002700000002b033001970001000000310355000000000000001f0000008001000039000000400a00003900000000001a04350000000102200190000000190000c13d000000300200004100000000002104350000002002000039000000840300003900000000002304350000001d02000039000000a40300003900000000002304350000003202000041000000c4030000390000000000230435000000640200003900a6009a0000040f0000000001000416000000000110004c000000390000c13d000000010100003900000000030004140000000002000410000000040420008c000000250000613d000000000103001900010000000a001d00a6008d0000040f000000010a00002900000060020000390000000003000031000000000430004c0000003c0000c13d000000000110004c000000760000c13d00000000010a043300000044021000390000003103000041000000000032043500000024021000390000001303000039000000000032043500000030020000410000000000210435000000040210003900000020030000390000000000320435000000640200003900a6009a0000040f0000000001000019000000000200001900a6009a0000040f0000002c0230009c0000006e0000813d0000001f02300039000000200400008a000000000242016f0000003f02200039000000000442016f00000000020a04330000000004420019000000000524004b000000000500001900000001050040390000002d0640009c0000006e0000213d00000001055001900000006e0000c13d00000000004a043500000000003204350000002003200039000000010400036700000000060000310000001f0560018f0000000506600270000000000760004c0000005e0000613d000000000700001900000005087002100000000009830019000000000884034f000000000808043b00000000008904350000000107700039000000000867004b000000560000413d000000000750004c000000290000613d0000000506600210000000000464034f00000000036300190000000305500210000000000603043300000000065601cf000000000656022f000000000404043b0000010005500089000000000454022f00000000045401cf000000000464019f0000000000430435000000290000013d0000002e0100004100000000001004350000004101000039000000040200003900000000001204350000002402000039000000000100001900a6009a0000040f0000000001020433000000000110004c0000007f0000c13d0000002001000039000001000200003900000000001204390000012001000039000000000001043900a600980000040f00000000010a043300000044021000390000002f03000041000000000032043500000024021000390000001403000039000000000032043500000030020000410000000000210435000000040210003900000020030000390000000000320435000000640200003900a6009a0000040f0000002b030000410000002b0410009c0000000001038019000000c00110021000a600a10000040f000000000301001900000060033002700000002b0030019d0001000000010355000000010120018f000000000001042d0000003301000041000000a70001042e0000002b030000410000002b0410009c000000000103801900000040011002100000006002200210000000000121019f000000a800010430000000a4002104210000000102000039000000000001042d0000000002000019000000000001042d000000a600000432000000a70001042e000000a80001043000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff4e487b7100000000000000000000000000000000000000000000000000000000646174612073686f756c6420626520656d70747900000000000000000000000008c379a00000000000000000000000000000000000000000000000000000000063616c6c2073686f756c6420737563636565640000000000000000000000000066616c6c6261636b2073686f756c64206e6f742062652063616c6c656400000000000002000000000000000000000000000000400000010000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000008002": "0x0004000000000002000400000000000200000000030100190000006003300270000000630430019700030000004103550002000000010355000000630030019d000100000000001f0000008006000039000000400500003900000000006504350000000101200190000000460000c13d0000000001000031000000040110008c000001150000413d0000000201000367000000000101043b000000e001100270000000650210009c000000510000613d000000660210009c0000009e0000613d000000670210009c000000ba0000613d000000680210009c000000dd0000613d000000690110009c000001150000c13d0000000001000416000000000110004c000001150000c13d000000040100008a00000000011000310000006a02000041000000200310008c000000000300001900000000030240190000006a01100197000000000410004c000000000200a0190000006a0110009c00000000010300190000000001026019000000000110004c000001150000c13d00000004010000390000000201100367000000000101043b0000006b01100197000400000006001d018701850000040f0000006f02100197000000700220009c00000000020000190000000102006039000000000310004c0000000003000019000000010300603900000000022301a0000000db0110027000000073011001970000000002010019000000000200c0190000000401000029000000000021043500000020020000390000000003000019018701620000040f0000000001000416000000000110004c000001150000c13d0000002002000039000001000100003900000000002104390000012002000039000000000002043900000040020000390000006403000041018701620000040f0000000001000416000000000110004c000001150000c13d000000040100008a00000000011000310000006a02000041000000200310008c000000000300001900000000030240190000006a01100197000000000410004c000000000200a0190000006a0110009c00000000010300190000000001026019000000000110004c000001150000c13d0000000401000039000200000001001d0000000201100367000000000101043b0000006b01100197000300000001001d000400000005001d018701850000040f000000040200002900000000020204330000000003010019000000000130004c000001260000c13d000100000003001d0000006c010000410000000000120435000000040120003900000003030000290000000000310435000000000100041400000020040000390000000003020019000300000002001d0187012f0000040f000000000110004c000001020000c13d000000030200036700000001040000310000001f0340018f000000040100002900000000010104330000000504400270000000000540004c0000008d0000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b000000850000413d000000000530004c0000009c0000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000310187016c0000040f0000000001000416000000000110004c000001150000c13d000000040100008a00000000011000310000006a02000041000000200310008c000000000300001900000000030240190000006a01100197000000000410004c000000000200a0190000006a0110009c00000000010300190000000001026019000000000110004c000001150000c13d000400000005001d018701750000040f0000006b01100197018701850000040f000000040200002900000000030204330000000000130435000000200200003900000000010300190000000003000019018701620000040f0000000001000416000000000110004c000001150000c13d000000040100008a00000000011000310000006a02000041000000400310008c000000000300001900000000030240190000006a01100197000000000410004c000000000200a0190000006a0110009c00000000010300190000000001026019000000000110004c000001150000c13d00000002010003670000000402100370000000000202043b0000006b0320009c000001150000213d0000002401100370000000000101043b0000006f031001970000000004000411000080060440008c000001150000c13d000000700330009c000001150000c13d018701830000040f000000000100001900000000020000190000000003000019018701620000040f0000000001000416000000000110004c000001150000c13d000000040100008a00000000011000310000006a02000041000000200310008c000000000300001900000000030240190000006a01100197000000000410004c000000000200a0190000006a0110009c00000000010300190000000001026019000000000110004c000001150000c13d00000004010000390000000201100367000000000101043b0000006b0210009c000001150000213d0000000002000411000080060220008c000001150000c13d000400000001001d018701850000040f0000006f02100197000000700220009c0000000402000029000001150000c13d0000007201100197018701830000040f000000000100001900000000020000190000000003000019018701620000040f0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600310018f00000003050000290000000001530019000000000331004b000000000300001900000001030040390000006d0410009c0000000404000029000001180000213d0000000103300190000001180000c13d0000000000140435000000200220008c000001200000813d000000000100001900000000020000190187016c0000040f00000071010000410000000000100435000000410100003900000002020000290000000000120435000000240200003900000000010000190187016c0000040f0000006e040000410000000003050433000000000330004c000000000201001900000001030000290000012b0000c13d0000006f013001970000006e04000041000000700110009c000000000403c0190000000001020019000000000041043500000020020000390000000003000019018701620000040f0002000000000002000200000004001d000100000003001d0000006303000041000000630420009c0000000002038019000000630410009c0000000001038019000000c0011002100000004002200210000000000112019f00000074011001c700008003020000390187017e0000040f000000010800002900000002040000290000001f0340018f0000000504400270000000000540004c0000014c0000613d000000000500001900000005065002100000000007680019000000000661034f000000000606043b00000000006704350000000105500039000000000645004b000001440000413d000000010220018f000000000530004c0000015c0000613d0000000504400210000000000541034f00000000044800190000000303300210000000000604043300000000063601cf000000000636022f000000000505043b0000010003300089000000000535022f00000000033501cf000000000363019f000000000034043500030000000103550000006001100270000100630010019d00000000010200190000000200000005000000000001042d0000006304000041000000630510009c000000000104801900000040011002100000000001310019000000630320009c000000000204801900000060022002100000000001210019000001880001042e0000006303000041000000630420009c0000000002038019000000630410009c000000000103801900000040011002100000006002200210000000000112019f000001890001043000000004010000390000000201100367000000000101043b000000750210009c0000017b0000813d000000000001042d000000000100001900000000020000190187016c0000040f00000181002104230000000102000039000000000001042d0000000002000019000000000001042d000000000012041b000000000001042d000000000101041a000000000001042d0000018700000432000001880001042e00000189000104300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e03fe177000000000000000000000000000000000000000000000000000000004de2e468000000000000000000000000000000000000000000000000000000004f1e1be000000000000000000000000000000000000000000000000000000000c2e4ff97000000000000000000000000000000000000000000000000000000001806aa188000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff5aa9b6b500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47000ff00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000004e487b7100000000000000000000000000000000000000000000000000000000ff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000001fffe0000000000000000000000000000000000000002400000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "0x000000000000000000000000000000000000800b": "0x0002000000000002000300000000000200010000000103550000006001100270000000cd0010019d00000080010000390000004005000039000000000015043500000001012001900000004d0000c13d0000000001000031000000040110008c000002610000413d0000000101000367000000000101043b000000e001100270000000d20210009c0000009a0000613d000000d30210009c000000650000613d000000d40210009c000000b50000613d000000d50210009c0000007f0000613d000000d60210009c000000e50000613d000000d70210009c000001000000613d000000d80210009c000001190000613d000000d90210009c0000014b0000613d000000da0210009c0000016f0000613d000000db0210009c0000018b0000613d000000dc0210009c000001a60000613d000000dd0210009c000001d60000613d000000de0210009c000001f10000613d000000df0210009c0000020d0000613d000000e00210009c000002330000613d000000e10210009c000002500000613d000000e20110009c000002610000c13d0000000001000416000000000110004c000002610000c13d000000040100008a0000000001100031000000e302000041000000000310004c00000000030000190000000003024019000000e301100197000000000410004c000000000200a019000000e30110009c00000000010300190000000001026019000000000110004c000002610000c13d0000000501000039000300000005001d032f032d0000040f000000030200002900000000030204330000000000130435000000200200003900000000010300190000000003000019032f02c30000040f0000000001000416000000000110004c000002610000c13d000000ce010000410000000302000039032f032b0000040f0000000401000039000300000001001d032f032d0000040f000000cf0110019700008001011001bf0000000302000029032f032b0000040f000000d0010000410000000502000039032f032b0000040f000000200200003900000100010000390000000000210439000001200200003900000000000204390000004002000039000000d103000041032f02c30000040f0000000001000416000000000110004c000002610000c13d000000040100008a0000000001100031000000e302000041000000000310004c00000000030000190000000003024019000000e301100197000000000410004c000000000200a019000000e30110009c00000000010300190000000001026019000000000110004c000002610000c13d000300000005001d032f02df0000040f000000030200002900000000030204330000000000130435000000200200003900000000010300190000000003000019032f02c30000040f0000000001000416000000000110004c000002610000c13d000000040100008a0000000001100031000000e302000041000000000310004c00000000030000190000000003024019000000e301100197000000000410004c000000000200a019000000e30110009c00000000010300190000000001026019000000000110004c000002610000c13d0000000601000039000300000005001d032f032d0000040f000000030200002900000000030204330000000000130435000000200200003900000000010300190000000003000019032f02c30000040f0000000001000416000000000110004c000002610000c13d000000040100008a0000000001100031000000e302000041000000000310004c00000000030000190000000003024019000000e301100197000000000410004c000000000200a019000000e30110009c00000000010300190000000001026019000000000110004c000002610000c13d0000000201000039000300000005001d032f032d0000040f000000030200002900000000030204330000000000130435000000200200003900000000010300190000000003000019032f02c30000040f0000000001000416000000000110004c000002610000c13d000000040100008a0000000001100031000000e302000041000000600310008c00000000030000190000000003024019000000e301100197000000000410004c000000000200a019000000e30110009c00000000010300190000000001026019000000000110004c000002610000c13d00000001010003670000002402100370000000000302043b0000000002000411000080010220008c000002610000c13d0000008002300210000000000430004c000000d20000613d00000000433200d9000000e90330009c000001430000c13d0000000401100370000000000301043b0000000001230019000000000231004b000000000200001900000001020040390000000102200190000001430000c13d0000000702000039032f032b0000040f00000044010000390000000101100367000000000101043b0000000602000039032f032b0000040f000000000100001900000000020000190000000003000019032f02c30000040f0000000001000416000000000110004c000002610000c13d000000040100008a0000000001100031000000e302000041000000000310004c00000000030000190000000003024019000000e301100197000000000410004c000000000200a019000000e30110009c00000000010300190000000001026019000000000110004c000002610000c13d0000000301000039000300000005001d032f032d0000040f000000030200002900000000030204330000000000130435000000200200003900000000010300190000000003000019032f02c30000040f0000000001000416000000000110004c000002610000c13d000000040100008a0000000001100031000000e302000041000000000310004c00000000030000190000000003024019000000e301100197000000000410004c000000000200a019000000e30110009c00000000010300190000000001026019000000000110004c000002610000c13d000300000005001d032f02df0000040f00000003010000290000000001010433000000000021043500000020020000390000000003000019032f02c30000040f0000000001000416000000000110004c000002610000c13d000000040100008a0000000001100031000000e302000041000000200310008c00000000030000190000000003024019000000e301100197000000000410004c000000000200a019000000e30110009c00000000010300190000000001026019000000000110004c000002610000c13d000300000005001d00000004010000390000000101100367000000000101043b000200000001001d000000e8010000410000000000100439032f02b40000040f0000000202000029000000000121004b00000000010000190000027a0000413d000000e801000041000100000001001d0000000000100439032f02b40000040f0000000102000029000000000020043900000002020000290000000001210049000100000001001d032f02b40000040f0000000102000029000000000112004b0000026f0000a13d000000ea01000041000000000010043500000011010000390000000402000039000000000012043500000024020000390000000001000019032f02cb0000040f0000000001000416000000000110004c000002610000c13d000000040100008a0000000001100031000000e302000041000000200310008c00000000030000190000000003024019000000e301100197000000000410004c000000000200a019000000e30110009c00000000010300190000000001026019000000000110004c000002610000c13d00000004010000390000000101100367000000000101043b000000000010043500000008010000390000002002000039000200000002001d00000000001204350000000001000019000300000005001d032f02a10000040f032f032d0000040f000000030200002900000000020204330000000000120435000000000102001900000002020000290000000003000019032f02c30000040f0000000001000416000000000110004c000002610000c13d000000040100008a0000000001100031000000e302000041000000000310004c00000000030000190000000003024019000000e301100197000000000410004c000000000200a019000000e30110009c00000000010300190000000001026019000000000110004c000002610000c13d0000000101000039000300000005001d032f032d0000040f00000003020000290000000003020433000000e4011001970000000000130435000000200200003900000000010300190000000003000019032f02c30000040f0000000001000416000000000110004c000002610000c13d000000040100008a0000000001100031000000e302000041000000000310004c00000000030000190000000003024019000000e301100197000000000410004c000000000200a019000000e30110009c00000000010300190000000001026019000000000110004c000002610000c13d0000000001000019000300000005001d032f032d0000040f000000030200002900000000030204330000000000130435000000200200003900000000010300190000000003000019032f02c30000040f0000000001000416000000000110004c000002610000c13d000000040100008a0000000001100031000000e302000041000000800310008c00000000030000190000000003024019000000e301100197000000000410004c000000000200a019000000e30110009c00000000010300190000000001026019000000000110004c000002610000c13d00000001010003670000002402100370000000000202043b0000000401100370000000000301043b0000000001000411000080010110008c000002610000c13d000100000003001d000300000005001d0000000701000039000200000002001d032f032d0000040f0000000203000029000000e502100197000000000223004b000002810000813d000000030100002900000000010104330000004402100039000000e6030000410000000000320435000000e7020000410000000000210435000000240210003900000020030000390000000000320435000000040210003900000000003204350000006402000039032f02cb0000040f0000000001000416000000000110004c000002610000c13d000000040100008a0000000001100031000000e302000041000000000310004c00000000030000190000000003024019000000e301100197000000000410004c000000000200a019000000e30110009c00000000010300190000000001026019000000000110004c000002610000c13d0000000701000039000300000005001d032f032d0000040f000000030200002900000000030204330000000000130435000000200200003900000000010300190000000003000019032f02c30000040f0000000001000416000000000110004c000002610000c13d000000040100008a0000000001100031000000e302000041000000000310004c00000000030000190000000003024019000000e301100197000000000410004c000000000200a019000000e30110009c00000000010300190000000001026019000000000110004c000002610000c13d0000000401000039000300000005001d032f032d0000040f00000003020000290000000003020433000000e4011001970000000000130435000000200200003900000000010300190000000003000019032f02c30000040f0000000001000416000000000110004c000002610000c13d000000040100008a0000000001100031000000e302000041000000200310008c00000000030000190000000003024019000000e301100197000000000410004c000000000200a019000000e30110009c00000000010300190000000001026019000000000110004c000002610000c13d00000004010000390000000101100367000000000201043b000000e40120009c000002610000213d0000000001000411000080010110008c000002610000c13d0000000101000039000300000001001d000200000002001d032f032d0000040f000000cf011001970000000202000029000000000121019f0000000302000029032f032b0000040f000000000100001900000000020000190000000003000019032f02c30000040f0000000001000416000000000110004c000002610000c13d000000040100008a0000000001100031000000e302000041000000200310008c00000000030000190000000003024019000000e301100197000000000410004c000000000200a019000000e30110009c00000000010300190000000001026019000000000110004c000002610000c13d0000000001000411000080010110008c000002610000c13d00000004010000390000000101100367000000000101043b0000000202000039032f032b0000040f000000000100001900000000020000190000000003000019032f02c30000040f0000000001000416000000000110004c000002610000c13d000000040100008a0000000001100031000000e302000041000000000310004c00000000030000190000000003024019000000e301100197000000000410004c000000000200a019000000e30110009c00000000010300190000000001026019000000000110004c000002640000613d00000000010000190000000002000019032f02cb0000040f000300000005001d032f02df0000040f00000003050000290000000003050433000000200430003900000000002404350000000000130435000000000103001900000000020500190000000003000019032f02c30000040f000001010120008c000000000100001900000002020000290000027a0000813d00000000002004350000000801000039000000200200003900000000001204350000000001000019032f02a10000040f032f032d0000040f000000030200002900000000030204330000000000130435000000200200003900000000010300190000000003000019032f02c30000040f00000044020000390000000102200367000000000202043b0000008001100270000300000001001d0000000101100039000000000121004b00000000010000190000000101006039032f03010000040f0000000301000029032f02d20000040f00000000020100190000000101000029032f032b0000040f0000000301000029032f02e50000040f032f03160000040f0000000202000029032f02f20000040f032f02d90000040f00000064010000390000000101100367000000000101043b032f02dc0000040f00000002010000290000000102000029000000000021041c000000000100001900000000020000190000000003000019032f02c30000040f000000cd020000410000000003000414000000cd0430009c0000000003028019000000cd0410009c00000000010280190000004001100210000000c002300210000000000112019f000000eb011001c70000801002000039032f03260000040f0000000102200190000002b10000613d000000000101043b000000000001042d00000000010000190000000002000019032f02cb0000040f000000cd010000410000000002000414000000cd0320009c0000000001024019000000c001100210000000ec011001c70000800b02000039032f03260000040f0000000102200190000002c00000613d000000000101043b000000000001042d00000000010000190000000002000019032f02cb0000040f000000cd04000041000000cd0510009c000000000104801900000040011002100000006002200210000000000121019f0000000001310019000003300001042e000000cd03000041000000cd0410009c000000000103801900000040011002100000006002200210000000000121019f000003310001043000000000001004350000000801000039000000200200003900000000001204350000000001000019032f02a10000040f000000000001042d0000000702000039032f032b0000040f000000000001042d0000000602000039032f032b0000040f000000000001042d0000000701000039032f032d0000040f0000008003100270000000e5021001970000000001030019000000000001042d000000010200008a000000000221004b000002ea0000613d0000000101100039000000000001042d000000ea01000041000000000010043500000011010000390000000402000039000000000012043500000024020000390000000001000019032f02cb0000040f0000000001120019000000000221004b000000000200001900000001020040390000000102200190000002f90000c13d000000000001042d000000ea01000041000000000010043500000011010000390000000402000039000000000012043500000024020000390000000001000019032f02cb0000040f000000000110004c000003040000613d000000000001042d000000400100003900000000010104330000006402100039000000ed0300004100000000003204350000004402100039000000ee030000410000000000320435000000240210003900000028030000390000000000320435000000e70200004100000000002104350000000402100039000000200300003900000000003204350000008402000039032f02cb0000040f00000000020100190000008001200210000000000320004c0000031d0000613d00000000322100d9000000e90220009c0000031e0000c13d000000000001042d000000ea01000041000000000010043500000011010000390000000402000039000000000012043500000024020000390000000001000019032f02cb0000040f00000329002104230000000102000039000000000001042d0000000002000019000000000001042d000000000012041b000000000001042d000000000101041a000000000001042d0000032f00000432000003300001042e00000331000104300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000000000000000000000000000000000000000000000000000040000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008e1bc9bf04000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe173b970000000000000000000000000000000000000000000000000000000042cbb15c000000000000000000000000000000000000000000000000000000004d59979f000000000000000000000000000000000000000000000000000000006ef25c3a000000000000000000000000000000000000000000000000000000007877a79700000000000000000000000000000000000000000000000000000000796b89b90000000000000000000000000000000000000000000000000000000080b412460000000000000000000000000000000000000000000000000000000085df51fd00000000000000000000000000000000000000000000000000000000938b5f32000000000000000000000000000000000000000000000000000000009a8a0592000000000000000000000000000000000000000000000000000000009e830ad300000000000000000000000000000000000000000000000000000000a0803ef700000000000000000000000000000000000000000000000000000000a6ae0aac00000000000000000000000000000000000000000000000000000000a851ae7800000000000000000000000000000000000000000000000000000000bf1fe42000000000000000000000000000000000000000000000000000000000d4a4ca0d0000000000000000000000000000000000000000000000000000000019cae4628000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000ffffffffffffffffffffffffffffffff54696d657374616d70732073686f756c6420626520696e6372656d656e74616c08c379a00000000000000000000000000000000000000000000000000000000042cbb15ccdc3cad6266b0e7a08c0454b23bf29dc2df74b6f3c209e9336465bd100000000000000000000000000000001000000000000000000000000000000004e487b71000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000040000000000000000000000000020000020000000000000000000000000000000400000000000000000000000020636f72726563740000000000000000000000000000000000000000000000005468652070726f766964656420626c6f636b206e756d626572206973206e6f74", - "0x0000000000000000000000000000000000008006": "0x0005000000000002000900000000000200000000030100190000006003300270000003050430019700040000004103550003000000010355000003050030019d000200000002001f000100000000001f0000008001000039000000400800003900000000001804350000000102200190000000550000c13d0000000002000031000000040320008c000003990000413d0000000303000367000000000403043b000000e006400270000003070460009c000000040520008a0000000404300370000000000a000411000001f40000613d000003080760009c000400000008001d000000600000613d000003090760009c000002540000613d0000030a0760009c000002810000613d0000030b0760009c000000a30000613d0000030c0760009c000002c50000613d0000030d0760009c000000ef0000613d0000030e0760009c000002f60000613d0000030f0760009c000001310000613d000003100160009c000001700000613d000003110160009c000001b10000613d000003120160009c000003990000c13d0000000001000416000000000110004c000003990000c13d000000040100008a00000000011000310000031302000041000000400310008c000000000300001900000000030240190000031301100197000000000410004c000000000200a019000003130110009c00000000010300190000000001026019000000000110004c000003990000c13d000000030100036700080000000103530000000401100370000000000101043b000900000001001d0c0f059b0000040f000000080100035f0000002401100370000000000201043b00000009010000290c0f079e0000040f00000004020000290000000003020433000003150110019700000000001304350000002002000039000000000103001900000000030000190c0f05880000040f0000000001000416000000000110004c000003990000c13d00000020020000390000010001000039000000000021043900000120020000390000000000020439000000400200003900000306030000410c0f05880000040f00090000000a001d00000000010200190c0f05bd0000040f000300000001001d000500000002001d000700000003001d000600000004001d000000020100003900000002021001870000000101200270000000000220004c000000700000c13d0000000901000029000003180110009c000000000100001900000001010040390c0f06c20000040f00000004010000290000000003010433000003190100004100000000001304350000000401300039000000090200002900000000002104350000000001000414000080030200003900000024040000390000002006000039000800000003001d00000000050300190c0f050a0000040f0000000104000031000000000110004c000003190000c13d00000004030003670000001f0240018f000000040100002900000000010104330000000504400270000000000540004c000000920000613d000000000500001900000005065002100000000007610019000000000663034f000000000606043b00000000006704350000000105500039000000000645004b0000008a0000413d000000000520004c000000a10000613d0000000504400210000000000343034f00000000044100190000000302200210000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f000000000024043500000001020000310c0f05920000040f0000000001000416000000000110004c000003990000c13d000000040100008a00000000011000310000031302000041000000200310008c000000000300001900000000030240190000031301100197000000000410004c000000000200a019000003130110009c00000000010300190000000001026019000000000110004c000003990000c13d00000004010000390000000301100367000000000101043b000900000001001d0c0f059b0000040f0c0f06250000040f00000009010000290000031501100197000000000010043500000020010000390000000000010435000000000100001900000004020000290c0f05620000040f000800000001001d00000004010000290000000001010433000900000001001d0c0f06170000040f00000008010000290c0f0c0d0000040f000800000001001d000000ff0110018f000700000001001d0c0f060c0000040f00000009010000290000000702000029000000000021043500000008010000290000000801100270000000ff0110018f000700000001001d0c0f060c0000040f00000009010000290000002002100039000800000002001d000000070300002900000000003204350000000002010433000700000002001d00000004010000290000000001010433000900000001001d00000000010200190c0f060c0000040f00000009010000290000000702000029000000000021043500000008010000290000000001010433000800000001001d0c0f060c0000040f0000000901000029000000200210003900000008030000290000000000320435000000040200002900000000030000190c0f05880000040f00090000000a001d00000000010200190c0f05bd0000040f000500000002001d000700000003001d000600000004001d000000020100003900000002021001870000000101200270000000000220004c000000fe0000c13d0000000901000029000003180110009c000000000100001900000001010040390c0f06c20000040f00000004010000290000000003010433000003190100004100000000001304350000000401300039000000090200002900000000002104350000000001000414000080030200003900000024040000390000002006000039000800000003001d00000000050300190c0f050a0000040f0000000104000031000000000110004c0000033f0000c13d00000004030003670000001f0240018f000000040100002900000000010104330000000504400270000000000540004c000001200000613d000000000500001900000005065002100000000007610019000000000663034f000000000606043b00000000006704350000000105500039000000000645004b000001180000413d000000000520004c0000012f0000613d0000000504400210000000000343034f00000000044100190000000302200210000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f000000000024043500000001020000310c0f05920000040f0000031306000041000000200750008c000000000700001900000000070640190000031305500197000000000850004c000000000600a019000003130550009c00000000050700190000000005066019000000000550004c000003990000c13d000000000404043b000003140540009c000003990000213d00000023054000390000031306000041000000000725004b0000000007000019000000000706801900000313082001970000031305500197000000000985004b0000000006008019000000000585013f000003130550009c00000000050700190000000005066019000000000550004c000003990000c13d0000000405400039000000000353034f000000000b03043b0000031403b0009c000003990000213d00000024044000390000000503b00210000600000004001d0000000003430019000000000223004b000003990000213d0000800702a0008c000003b00000c13d0000000002000019000000000300001900070000000b001d0000000001b3004b000003bf0000813d0000000601000029000800000002001d00000000020b0019000900000003001d00000009030000290c0f07ba0000040f00000009030000290000000802000029000000070b00002900000060011000390000000301100367000000000101043b000000000221001900000001033000390000015f0000013d0000000001000416000000000110004c000003990000c13d000000040100008a00000000011000310000031302000041000000200310008c000000000300001900000000030240190000031301100197000000000410004c000000000200a019000003130110009c00000000010300190000000001026019000000000110004c000003990000c13d00000004030000390000000301300367000000000201043b000000010120008c000003990000213d000800000003001d000700000002001d0000000101000039000000020200003900000002022001880000018f0000c13d0000031801a0009c0000000001000019000000010100403900090000000a001d0c0f06c20000040f0000000901000029000000000010043500000020010000390000000000010435000000000100001900000004020000290c0f05620000040f000000040300002900000000040304330000031a0240009c000004870000213d00000040024000390000000000230435000600000004001d0c0f0c0d0000040f0000000604000029000000ff0210018f000000020320008c000001a90000813d00000000002404350000000801100270000000ff0110018f000000010210008c0000048f0000a13d0000031b010000410000000000100435000000210100003900000008020000290000000000120435000000240200003900000000010000190c0f05920000040f00090000000a001d00000000010200190c0f05e20000040f000500000002001d000700000003001d000600000004001d000300000005001d000000020100003900000002021001870000000101200270000000000220004c000001c10000c13d0000000901000029000003180110009c000000000100001900000001010040390c0f06c20000040f00000004010000290000000003010433000003190100004100000000001304350000000401300039000000090200002900000000002104350000000001000414000080030200003900000024040000390000002006000039000800000003001d00000000050300190c0f050a0000040f0000000104000031000000000110004c000003620000c13d00000004030003670000001f0240018f000000040100002900000000010104330000000504400270000000000540004c000001e30000613d000000000500001900000005065002100000000007610019000000000663034f000000000606043b00000000006704350000000105500039000000000645004b000001db0000413d000000000520004c000001f20000613d0000000504400210000000000343034f00000000044100190000000302200210000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f000000000024043500000001020000310c0f05920000040f0000031301000041000000400250008c000000000200001900000000020140190000031306500197000000000760004c000000000100a019000003130660009c000000000102c019000000000110004c000003990000c13d000000000604043b000003140160009c000003990000213d00000000016500490000031302000041000000a00410008c000000000400001900000000040240190000031301100197000000000510004c000000000200a019000003130110009c00000000010400190000000001026019000000000110004c000003990000c13d0000002401300370000000000201043b000003150120009c000003990000213d000000000100041000000000011a004b000003990000c13d0000000401600039000500000001001d000000000113034f000000000101043b000800000001001d000700000002001d000900000006001d0c0f09980000040f000000090100002900000024031000390000000301300367000000000101043b000003150210009c000003990000213d0000000802000029000400000003001d000600000001001d0c0f09fa0000040f0c0f06250000040f000000000201001900000020012000390000000000010435000000000002043500000006010000290c0f07050000040f000000090700002900000006020000290000000404000029000000070500002900000044037000390000000301000367000000000331034f000000000603043b000000000360004c0000000003000019000000010300c039000000000336004b000003990000c13d0000000803000029000000000360004c000004b70000c13d000000000141034f000000000701043b000003150170009c0000000806000029000003990000213d00000305010000410000000002000414000003050320009c0000000001024019000000c00110021000000316011001c70000800d02000039000000040300003900000317040000410c0f0bfb0000040f0000000101200190000003990000613d0000000001000019000000000200001900000000030000190c0f05880000040f0000000001000416000000000110004c000003990000c13d000000040100008a00000000011000310000031302000041000000200310008c000000000300001900000000030240190000031301100197000000000410004c000000000200a019000003130110009c00000000010300190000000001026019000000000110004c000003990000c13d00000004010000390000000301100367000000000201043b000000010120008c000003990000213d000800000002001d000000010100003900000002020000390000000202200188000002720000c13d0000031801a0009c0000000001000019000000010100403900090000000a001d0c0f06c20000040f0000000901000029000000000010043500000020010000390000000000010435000000400200003900000000010000190c0f05620000040f00000008020000290c0f06d70000040f0000000001000019000000000200001900000000030000190c0f05880000040f00090000000a001d00000000010200190c0f05e20000040f000200000001001d000500000002001d000700000003001d000600000004001d000300000005001d000000020100003900000002021001870000000101200270000000000220004c000002920000c13d0000000901000029000003180110009c000000000100001900000001010040390c0f06c20000040f00000004010000290000000003010433000003190100004100000000001304350000000401300039000000090200002900000000002104350000000001000414000080030200003900000024040000390000002006000039000800000003001d00000000050300190c0f050a0000040f0000000104000031000000000110004c000003860000c13d00000004030003670000001f0240018f000000040100002900000000010104330000000504400270000000000540004c000002b40000613d000000000500001900000005065002100000000007610019000000000663034f000000000606043b00000000006704350000000105500039000000000645004b000002ac0000413d000000000520004c000002c30000613d0000000504400210000000000343034f00000000044100190000000302200210000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f000000000024043500000001020000310c0f05920000040f0000000001000416000000000110004c000003990000c13d0000000002000031000000040120008a0000031303000041000000800410008c000000000400001900000000040340190000031301100197000000000510004c000000000300a019000003130110009c00000000010400190000000001036019000000000110004c000003990000c13d00000003010003670000000403100370000000000403043b000003150340009c000003990000213d0000006401100370000000000101043b000003140310009c000003990000213d0000000401100039000900000004001d0c0f05a10000040f00000003030003670000002404300370000000000404043b0000004403300370000000000303043b0000000005010019000000000602001900000009010000290000000002040019000000000405001900000000050600190c0f076f0000040f00000004020000290000000003020433000003150110019700000000001304350000002002000039000000000103001900000000030000190c0f05880000040f0000000001000416000000000110004c000003990000c13d000000040100008a00000000011000310000031302000041000000200310008c000000000300001900000000030240190000031301100197000000000410004c000000000200a019000003130110009c00000000010300190000000001026019000000000110004c000003990000c13d00000004010000390000000301100367000000000101043b000900000001001d0c0f059b0000040f00000009010000290c0f06430000040f00000004020000290000000002020433000900000002001d000800000001001d0c0f060c0000040f000000090100002900000008020000290000000000210435000000200200003900000000030000190c0f05880000040f000000200140008c000000200100003900000000010440190000001f01100039000000600210018f00000008010000290000000001120019000000000221004b00000000020000190000000102004039000003140310009c0000000406000029000004870000213d0000000102200190000004870000c13d0000000000160435000000200140008c0000000901000029000003990000413d00000005020000290000000303000029000000070400002900000006050000290c0f076f0000040f0000000002010019000900000002001d0000000501000029000000070300002900000006040000290c0f08280000040f00000009010000290000031502100197000000040100002900000000010104330000000000210435000000200200003900000000030000190c0f05880000040f000000200140008c000000200100003900000000010440190000001f01100039000000600210018f00000008050000290000000001520019000000000221004b00000000020000190000000102004039000003140310009c0000000403000029000004870000213d0000000102200190000004870000c13d0000000000130435000000200140008c0000000901000029000003990000413d00000000020504330c0f079e0000040f0000000002010019000900000002001d0000000501000029000000070300002900000006040000290c0f08280000040f00000009010000290000031502100197000000040100002900000000010104330000000000210435000000200200003900000000030000190c0f05880000040f000000200140008c000000200100003900000000010440190000001f01100039000000600210018f00000008050000290000000001520019000000000221004b00000000020000190000000102004039000003140310009c0000000403000029000004870000213d0000000102200190000004870000c13d0000000000130435000000200140008c0000000901000029000003990000413d00000000020504330c0f079e0000040f0000000002010019000900000002001d00000005010000290000000303000029000000070400002900000006050000290c0f08da0000040f00000009010000290000031502100197000000040100002900000000010104330000000000210435000000200200003900000000030000190c0f05880000040f000000200140008c000000200100003900000000010440190000001f01100039000000600210018f00000008010000290000000001120019000000000221004b00000000020000190000000102004039000003140310009c0000000406000029000004870000213d0000000102200190000004870000c13d0000000000160435000000200140008c00000009010000290000039c0000813d000000000100001900000000020000190c0f05920000040f00000005020000290000000203000029000000070400002900000006050000290c0f076f0000040f0000000002010019000900000002001d00000005010000290000000303000029000000070400002900000006050000290c0f08da0000040f00000009010000290000031502100197000000040100002900000000010104330000000000210435000000200200003900000000030000190c0f05880000040f0000031c0200004100000000002104350000002003000039000000840200003900000000003204350000002d03000039000000a40400003900000000003404350000031d03000041000000c40400003900000000003404350000031e03000041000000e40400003900000000003404350c0f05920000040f0000000001000416000000000121004b000004a20000c13d0000000001000410000800000001001d0000000401000039000200000001001d0000000001000019000900000001001d0000000001b1004b000002500000813d000000060100002900000000020b001900000009030000290c0f07ba0000040f00000060011000390000000301100367000000000101043b000300000001001d0000000601000029000000070200002900000009030000290c0f07ba0000040f00000322020000410000000000200439000000080200002900000002030000290000000000230439000500000001001d0c0f05790000040f000000050d000029000000070b000029000000040a000029000000000110004c000003990000613d000000000c0a0433000003230100004100000000001c04350000000402c0003900000000010004140000000000a204350000000302d00367000000000202043b0000004403c0003900000000002304350000002002d000390000000302200367000000000202043b000003150320009c000003990000213d0000006403c0003900000000002304350000004002d000390000000302200367000000000202043b000000000320004c0000000003000019000000010300c039000000000332004b000003990000c13d0000008403c0003900000000002304350000006002d000390000000302200367000000000202043b000000a403c00039000000000023043500000000030000310000000002d300490000008004d000390000001f0520008a0000000302000367000000000442034f000000000404043b0000031306000041000000000754004b0000000007000019000000000706801900000313055001970000031308400197000000000958004b0000000006008019000000000558013f000003130550009c00000000050700190000000005066019000000000550004c000003990000c13d0000000004d40019000000000242034f000000000202043b000003140520009c000003990000213d000000200440003900000000032300490000031305000041000000000634004b0000000006000019000000000605201900000313033001970000031307400197000000000837004b0000000005008019000000000337013f000003130330009c00000000030600190000000003056019000000000330004c000003990000c13d000000c403c00039000000a0050000390000000000530435000000e403c0003900000000002304350000010403c0003900000003044003670000000505200270000000000650004c0000043f0000613d000000000600001900000005076002100000000008730019000000000774034f000000000707043b00000000007804350000000106600039000000000756004b000004370000413d0000001f0620018f000000000760004c0000044f0000613d0000000505500210000000000454034f00000000055300190000000306600210000000000705043300000000076701cf000000000767022f000000000404043b0000010006600089000000000464022f00000000046401cf000000000474019f0000000000450435000000000332001900000000000304350000002403c00039000080070400003900000000004304350000000803000029000000040330008c000004810000613d0000001f02200039000000200300008a000000000232016f00000104042000390000000303000029000000000230004c00010000000c001d000004770000613d00000305020000410000030505c0009c000000000502001900000000050c40190000004006500210000003050540009c00000000040280190000006004400210000000000564019f000003050410009c0000000001028019000000c001100210000000000115019f00000316011001c70000800902000039000000080400002900000000050000190c0f0bfb0000040f00000000030100190000006003300270000103050030019d0004000000010355000000010120018f0000047c0000013d000000080200002900000000030c001900000000050c001900000000060000190c0f050a0000040f000000000110004c000000040a000029000000070b000029000000010c000029000004e90000613d0000031401c0009c000004870000213d0000000000ca043500000009010000290000000101100039000003c70000013d0000031b010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190c0f05920000040f0000002002400039000800000002001d00000000001204350000000702000029000000010220015f00000000011201a0000000000100001900000001010060390c0f06ed0000040f000000080100002900000007020000290c0f06370000040f000000090100002900000006020000290c0f07050000040f0000000001000019000000000200001900000000030000190c0f05880000040f0000000401000029000000000101043300000084021000390000031f0300004100000000003204350000006402100039000003200300004100000000003204350000004402100039000003210300004100000000003204350000002402100039000000450300003900000000003204350000031c020000410000000000210435000000040210003900000020030000390000000000320435000000a4020000390c0f05920000040f0000008403700039000000000331034f000000000a00003100000000047a0049000000230440008a000000000303043b0000031309000041000000000643004b0000000006000019000000000609801900000313044001970000031307300197000000000847004b00000000080000190000000008094019000000000447013f000003130440009c00000000040600190000000004086019000000000440004c000003990000c13d00000005040000290000000003430019000000000131034f000000000401043b000003140140009c000003990000213d00000000014a004900000020033000390000031309000041000000000613004b0000000008000019000000000809201900000313011001970000031306300197000000000716004b00000000070000190000000007094019000000000116013f000003130110009c00000000010800190000000001076019000000000110004c000003990000c13d00000000010500190c0f0a510000040f0000000404000029000000070500002900000003010003670000023f0000013d000000040200036700000001040000310000001f0340018f00000000010a04330000000504400270000000000540004c000004f90000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b000004f10000413d000000000530004c000005080000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000310c0f05920000040f0002000000000002000200000006001d000100000005001d0000030505000041000003050630009c00000000030580190000004003300210000003050640009c00000000040580190000006004400210000000000334019f000003050410009c0000000001058019000000c001100210000000000113019f0c0f0bfb0000040f000000010800002900000002040000290000001f0340018f0000000504400270000000000540004c000005290000613d000000000500001900000005065002100000000007680019000000000661034f000000000606043b00000000006704350000000105500039000000000645004b000005210000413d000000010220018f000000000530004c000005390000613d0000000504400210000000000541034f00000000044800190000000303300210000000000604043300000000063601cf000000000636022f000000000505043b0000010003300089000000000535022f00000000033501cf000000000363019f000000000034043500040000000103550000006001100270000103050010019d00000000010200190000000200000005000000000001042d0001000000000002000100000005001d0000030505000041000003050630009c00000000030580190000004003300210000003050640009c00000000040580190000006004400210000000000334019f000003050410009c0000000001058019000000c001100210000000000113019f0c0f0c000000040f0000000106000029000000010220018f000000000300001900000005043002100000000005460019000000000441034f000000000404043b00000000004504350000000103300039000000000430004c000000000400001900000001040060390000000104400190000005510000c13d00040000000103550000006001100270000103050010019d00000000010200190000000100000005000000000001042d0000030503000041000003050410009c00000000010380190000004001100210000003050420009c00000000020380190000006002200210000000000112019f0000000002000414000003050420009c0000000002038019000000c002200210000000000112019f00000316011001c700008010020000390c0f0c000000040f0000000102200190000005760000613d000000000101043b000000000001042d000000000100001900000000020000190c0f05920000040f00000305010000410000000002000414000003050320009c0000000001024019000000c00110021000000324011001c700008002020000390c0f0c000000040f0000000102200190000005850000613d000000000101043b000000000001042d000000000100001900000000020000190c0f05920000040f0000030504000041000003050510009c000000000104801900000040011002100000000001310019000003050320009c00000000020480190000006002200210000000000121001900000c100001042e0000030503000041000003050420009c0000000002038019000003050410009c000000000103801900000040011002100000006002200210000000000112019f00000c1100010430000003250110009c0000059e0000813d000000000001042d000000000100001900000000020000190c0f05920000040f0000001f031000390000031304000041000000000523004b0000000005000019000000000504401900000313062001970000031303300197000000000763004b000000000400a019000000000363013f000003130330009c00000000030500190000000003046019000000000330004c000005ba0000613d0000000303100367000000000303043b000003140430009c000005ba0000213d00000020011000390000000004310019000000000224004b000005ba0000213d0000000002030019000000000001042d000000000100001900000000020000190c0f05920000040f00020000000000020000000002010019000000040120008a00000313030000410000005f0410008c000000000400001900000000040320190000031301100197000000000510004c0000000003008019000003130110009c00000000010400190000000001036019000000000110004c000005df0000613d00000003030003670000004401300370000000000101043b000003140410009c000005df0000213d0000000404300370000000000404043b000200000004001d0000002403300370000000000303043b000100000003001d00000004011000390c0f05a10000040f00000000030100190000000004020019000000020100002900000001020000290000000200000005000000000001042d000000000100001900000000020000190c0f05920000040f00020000000000020000000002010019000000040120008a00000313030000410000007f0410008c000000000400001900000000040320190000031301100197000000000510004c0000000003008019000003130110009c00000000010400190000000001036019000000000110004c000006090000613d00000003010003670000002403100370000000000303043b000200000003001d0000000403100370000000000303043b000100000003001d0000004401100370000000000101043b000003140310009c000006090000213d00000004011000390c0f05a10000040f0000000003010019000000000402001900000064010000390000000301100367000000000501043b000000010150008c000006090000213d000000010100002900000002020000290000000200000005000000000001042d000000000100001900000000020000190c0f05920000040f000000020110008c0000060f0000813d000000000001042d0000031b010000410000000000100435000000210100003900000004020000390000000000120435000000240200003900000000010000190c0f05920000040f000003260210009c0000061d0000813d000000400110003900000040020000390000000000120435000000000001042d0000031b010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190c0f05920000040f00000040020000390000000001020433000003260310009c0000062f0000813d00000040031000390000000000320435000000200210003900000000000204350000000000010435000000000001042d0000031b010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190c0f05920000040f000000020320008c0000063b0000813d0000000000210435000000000001042d0000031b010000410000000000100435000000210100003900000004020000390000000000120435000000240200003900000000010000190c0f05920000040f00030000000000020000031501100197000100000001001d0000000000100435000000200100003900000000000104350000004002000039000300000002001d00000000010000190c0f05620000040f00000003030000290000000004030433000003260240009c000006960000813d00000040024000390000000000230435000200000004001d0c0f0c0d0000040f0000000204000029000000ff0210018f000000020320008c0000068e0000813d00000000002404350000000801100270000000ff0110018f000000010210008c0000068e0000213d000000200240003900000000001204350000000002040433000000010120008c0000068e0000213d0000000101000039000000000220004c0000068c0000c13d00000003010000290000000005010433000003270100004100000000001504350000000402500039000000000100041400000001030000290000000000320435000080020200003900000024040000390000000003050019000200000005001d0c0f053f0000040f0000000104000031000000000110004c0000069e0000613d000000200140008c000000200100003900000000010440190000001f01100039000000600210018f00000002050000290000000001520019000000000221004b00000000020000190000000102004039000003140310009c0000000303000029000006960000213d0000000102200190000006960000c13d00000000001304350000001f0140008c000006bf0000a13d0000000001050433000000000110004c000000000100001900000001010060390000000300000005000000000001042d0000031b010000410000000000100435000000210100003900000004020000390000000000120435000000240200003900000000010000190c0f05920000040f0000031b010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190c0f05920000040f00000004030003670000001f0240018f000000030100002900000000010104330000000504400270000000000540004c000006ae0000613d000000000500001900000005065002100000000007610019000000000663034f000000000606043b00000000006704350000000105500039000000000645004b000006a60000413d000000000520004c000006bd0000613d0000000504400210000000000343034f00000000044100190000000302200210000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f000000000024043500000001020000310c0f05920000040f000000000100001900000000020000190c0f05920000040f000000000110004c000006c50000613d000000000001042d000000400100003900000000010104330000006402100039000003280300004100000000003204350000004402100039000003290300004100000000003204350000002402100039000000240300003900000000003204350000031c02000041000000000021043500000004021000390000002003000039000000000032043500000084020000390c0f05920000040f0002000000000002000200000002001d000000020220008c000006e50000813d000100000001001d0c0f0c0d0000040f000001000200008a000000000121016f0000000202000029000000000121019f00000001020000290c0f0c0b0000040f0000000200000005000000000001042d0000031b010000410000000000100435000000210100003900000004020000390000000000120435000000240200003900000000010000190c0f05920000040f000000000110004c000006f00000613d000000000001042d0000004001000039000000000101043300000084021000390000032a03000041000000000032043500000064021000390000032b03000041000000000032043500000044021000390000032c0300004100000000003204350000002402100039000000430300003900000000003204350000031c020000410000000000210435000000040210003900000020030000390000000000320435000000a4020000390c0f05920000040f0002000000000002000200000002001d0000031501100197000000000010043500000020010000390000000000010435000000400200003900000000010000190c0f05620000040f00000002020000290000000002020433000000020320008c000007260000813d000100000001001d0c0f06d70000040f0000000101000029000000020200002900000020022000390000000002020433000200000002001d000000010220008c000007260000213d0c0f0c0d0000040f0000032d02000041000000000121016f000000020200002900000008022002100000ff000220018f000000000121019f00000001020000290c0f0c0b0000040f0000000200000005000000000001042d0000031b010000410000000000100435000000210100003900000004020000390000000000120435000000240200003900000000010000190c0f05920000040f00000000040100190000032e0120009c000007640000813d0000003f01200039000000200500008a000000000651016f000000400500003900000000010504330000000006610019000000000716004b00000000070000190000000107004039000003140860009c000007640000213d0000000107700190000007640000c13d000000000065043500000000002104350000000005420019000000000335004b0000076c0000213d0000001f0520018f000000030440036700000020031000390000000506200270000000000760004c000007520000613d000000000700001900000005087002100000000009830019000000000884034f000000000808043b00000000008904350000000107700039000000000867004b0000074a0000413d000000000750004c000007610000613d0000000506600210000000000464034f00000000066300190000000305500210000000000706043300000000075701cf000000000757022f000000000404043b0000010005500089000000000454022f00000000045401cf000000000474019f000000000046043500000000022300190000000000020435000000000001042d0000031b010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190c0f05920000040f000000000100001900000000020000190c0f05920000040f0003000000000002000200000003001d000300000002001d000100000001001d0000000003000031000000000104001900000000020500190c0f072e0000040f000000000201043300000020011000390c0f05620000040f000000010200002900000315042001970000004003000039000000000203043300000040052000390000000000450435000000600420003900000002050000290000000000540435000000800420003900000003050000290000000000540435000000a0042000390000000000140435000000a00100003900000000001204350000032f0400004100000020012000390000000000410435000003300420009c000007960000813d000000c004200039000000000043043500000000020204330c0f05620000040f00000315011001970000000300000005000000000001042d0000031b010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190c0f05920000040f000000400400003900000000030404330000006005300039000000000025043500000315011001970000004002300039000000000012043500000060010000390000000000130435000000200130003900000331020000410000000000210435000003320230009c000007b20000813d0000008002300039000000000024043500000000020304330c0f05620000040f0000031501100197000000000001042d0000031b010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190c0f05920000040f000000000223004b000007d20000813d000000050230021000000000021200190000000302200367000000000202043b00000000031000790000009f0330008a0000031304000041000000000532004b0000000005000019000000000504401900000313033001970000031306200197000000000736004b000000000400a019000000000336013f000003130330009c00000000030500190000000003046019000000000330004c000007da0000613d0000000001120019000000000001042d0000031b010000410000000000100435000000320100003900000004020000390000000000120435000000240200003900000000010000190c0f05920000040f000000000100001900000000020000190c0f05920000040f000000000110004c000007e00000613d000000000001042d0000004001000039000000000101043300000044021000390000033303000041000000000032043500000024021000390000001c0300003900000000003204350000031c02000041000000000021043500000004021000390000002003000039000000000032043500000064020000390c0f05920000040f000000000110004c000007f20000613d000000000001042d000000400100003900000000010104330000006402100039000003340300004100000000003204350000004402100039000003350300004100000000003204350000002402100039000000280300003900000000003204350000031c02000041000000000021043500000004021000390000002003000039000000000032043500000084020000390c0f05920000040f000000000110004c000008070000613d000000000001042d000000400100003900000000010104330000004402100039000003360300004100000000003204350000002402100039000000150300003900000000003204350000031c02000041000000000021043500000004021000390000002003000039000000000032043500000064020000390c0f05920000040f000000000110004c000008190000613d000000000001042d000000400100003900000000010104330000004402100039000003370300004100000000003204350000002402100039000000130300003900000000003204350000031c02000041000000000021043500000004021000390000002003000039000000000032043500000064020000390c0f05920000040f0007000000000002000200000004001d000100000003001d000700000002001d000400000001001d000000000110004c0000000001000019000000010100c0390c0f07dd0000040f00000007010000290000031501100197000500000001001d0000ffff0110008c000000000100001900000001010020390c0f07ef0000040f0000004001000039000600000001001d000000000301043300000338010000410000000000130435000000040230003900000000010004140000000504000029000000000042043500008002020000390000002404000039000300000003001d00000000050300190c0f053f0000040f000000000110004c000008b00000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600320018f00000003050000290000000002530019000000000332004b00000000030000190000000103004039000003140420009c0000000004050019000008d20000213d0000000103300190000008d20000c13d000000060300002900000000002304350000001f0110008c000008ad0000a13d0000000001040433000000000110004c000000000100001900000001010060390c0f08040000040f00000006010000290000000005010433000003390100004100000000001504350000000402500039000000000100041400000005030000290000000000320435000080030200003900000024040000390000000003050019000300000005001d0c0f053f0000040f000000000110004c000008b00000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600320018f00000003050000290000000002530019000000000332004b00000000030000190000000103004039000003140420009c0000000004050019000008d20000213d0000000103300190000008d20000c13d00000006030000290000000000230435000000200110008c000008ad0000413d0000000001040433000000000110004c000000000100001900000001010060390c0f08160000040f00000004010000290c0f09980000040f000000070100002900000004020000290c0f09fa0000040f0c0f06250000040f000000000201001900000020012000390000000000010435000000000002043500000007010000290c0f07050000040f0000000001000411000600000001001d0000000702000029000000010300002900000002040000290c0f0a510000040f00000305010000410000000002000414000003050320009c000000000102401900000006020000290000031505200197000000c00110021000000316011001c70000800d0200003900000004030000390000031704000041000000040600002900000005070000290c0f0bfb0000040f0000000101200190000008ad0000613d0000000700000005000000000001042d000000000100001900000000020000190c0f05920000040f000000040200036700000001040000310000001f0340018f000000060100002900000000010104330000000504400270000000000540004c000008c10000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b000008b90000413d000000000530004c000008d00000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000310c0f05920000040f0000031b010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190c0f05920000040f0008000000000002000200000005001d000100000004001d000300000003001d000800000002001d000500000001001d000000000110004c0000000001000019000000010100c0390c0f07dd0000040f00000008010000290000031501100197000600000001001d0000ffff0110008c000000000100001900000001010020390c0f07ef0000040f0000004001000039000700000001001d000000000301043300000338010000410000000000130435000000040230003900000000010004140000000604000029000000000042043500008002020000390000002404000039000400000003001d00000000050300190c0f053f0000040f000000000110004c000009660000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600320018f00000004050000290000000002530019000000000332004b00000000030000190000000103004039000003140420009c0000000004050019000009880000213d0000000103300190000009880000c13d000000070300002900000000002304350000001f0110008c000009630000a13d0000000001040433000000000110004c000000000100001900000001010060390c0f08040000040f00000007010000290000000005010433000003390100004100000000001504350000000402500039000000000100041400000006030000290000000000320435000080030200003900000024040000390000000003050019000400000005001d0c0f053f0000040f000000000110004c000009660000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600320018f00000004050000290000000002530019000000000332004b00000000030000190000000103004039000003140420009c0000000004050019000009880000213d0000000103300190000009880000c13d00000007030000290000000000230435000000200110008c000009630000413d0000000001040433000000000110004c000000000100001900000001010060390c0f08160000040f00000005010000290c0f09980000040f000000080100002900000005020000290c0f09fa0000040f0c0f06250000040f00000000020100190000000303000029000000020130008c000009900000813d00000000003204350000002001200039000000000001043500000008010000290c0f07050000040f0000000001000411000700000001001d0000000802000029000000010300002900000002040000290c0f0a510000040f00000305010000410000000002000414000003050320009c000000000102401900000007020000290000031505200197000000c00110021000000316011001c70000800d0200003900000004030000390000031704000041000000050600002900000006070000290c0f0bfb0000040f0000000101200190000009630000613d0000000800000005000000000001042d000000000100001900000000020000190c0f05920000040f000000040200036700000001040000310000001f0340018f000000070100002900000000010104330000000504400270000000000540004c000009770000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b0000096f0000413d000000000530004c000009860000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000310c0f05920000040f0000031b010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190c0f05920000040f0000031b010000410000000000100435000000210100003900000004020000390000000000120435000000240200003900000000010000190c0f05920000040f00020000000000020000004002000039000200000002001d00000000030204330000033a02000041000000000023043500000004023000390000000000120435000000000100041400008004020000390000002404000039000100000003001d00000000050300190c0f053f0000040f0000000104000031000000000110004c000009c10000613d000000200140008c000000200100003900000000010440190000001f01100039000000600210018f00000001050000290000000001520019000000000221004b00000000020000190000000102004039000003140310009c0000000003050019000009e20000213d0000000102200190000009e20000c13d000000020200002900000000001204350000001f0240008c000009ea0000a13d0000000002030433000000000220004c000009ed0000613d0000000200000005000000000001042d00000004030003670000001f0240018f000000020100002900000000010104330000000504400270000000000540004c000009d10000613d000000000500001900000005065002100000000007610019000000000663034f000000000606043b00000000006704350000000105500039000000000645004b000009c90000413d000000000520004c000009e00000613d0000000504400210000000000343034f00000000044100190000000302200210000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f000000000024043500000001020000310c0f05920000040f0000031b010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190c0f05920000040f000000000100001900000000020000190c0f05920000040f00000044021000390000033b03000041000000000032043500000024021000390000001a0300003900000000003204350000031c02000041000000000021043500000004021000390000002003000039000000000032043500000064020000390c0f05920000040f0003000000000002000200000002001d000300000001001d0000032201000041000000000010043900008002010000390000000402000039000100000002001d00000000001204390c0f05790000040f000000000110004c00000a240000613d00000002010000290000033c011001970000033d011001c70000004002000039000200000002001d0000000003020433000000240230003900000000001204350000033e0100004100000000001304350000000301000029000003150110019700000004023000390000000000120435000000000100041400008002020000390000004404000039000300000003001d000000000503001900000000060000190c0f050a0000040f000000000110004c00000a270000613d00000003020000290000032e0120009c00000a490000813d000000020100002900000000002104350000000300000005000000000001042d000000000100001900000000020000190c0f05920000040f000000040200036700000001040000310000001f0340018f000000020100002900000000010104330000000504400270000000000540004c00000a380000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b00000a300000413d000000000530004c00000a470000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000310c0f05920000040f0000031b010000410000000000100435000000410100003900000001020000290000000000120435000000240200003900000000010000190c0f05920000040f00060000000000020000000005030019000500000002001d000600000001001d0000000001000416000000000110004c00000a850000613d000300000005001d000400000004001d000003220100004100000000001004390000800a01000039000000040200003900000000001204390c0f05790000040f000000000110004c00000ba20000613d0000004001000039000100000001001d00000000050104330000033f0100004100000000001504350000004402500039000000000100041400000000030004160000000000320435000000050200002900000315022001970000002403500039000000000023043500000000020004100000031502200197000000040350003900000000002304350000800a0200003900000064040000390000000003050019000200000005001d00000000060000190c0f050a0000040f000000000110004c00000bad0000613d0000000202000029000003140120009c0000000404000029000000030500002900000ba50000213d000000010100002900000000002104350000000001000416000003400110019700000000000104170000000003000031000000000105001900000000020400190c0f072e0000040f000400000001001d00000000010104330c0f0be90000040f000300000001001d00000000010004140c0f0be90000040f0000000402000029000000400220021000000341022000410000034202200197000000030300002900000060033002100000034303300197000000000232019f000000c0011002100000034401100197000000000112019f0000000602000029000003150d2001970000033d011001c700000005020000290c0f0c050000040f000000000302001900000000020100190000006002200270000103050020019d0000030502200197000400000001035500000001033001900000001f0320018f000000050420027000000bcf0000613d0000003f012000390000034506100197000000400c00003900000000050c04330000000001650019000000000751004b00000000070000190000000107004039000003140810009c00000ba50000213d000000010770019000000ba50000c13d00000000001c043500000000002504350000002001500039000000200860008a0000001f0680018f000000000700003100000003077003670000000508800270000000000980004c00000ac80000613d0000000009000019000000050a900210000000000ba10019000000000aa7034f000000000a0a043b0000000000ab04350000000109900039000000000a89004b00000ac00000413d000000000960004c00000ad70000613d0000000508800210000000000787034f00000000088100190000000306600210000000000908043300000000096901cf000000000969022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000696019f000000000068043500000000002504350000000106000031000000000262004b00000ba20000213d0000000402000367000000000640004c00000ae70000613d000000000600001900000005076002100000000008710019000000000772034f000000000707043b00000000007804350000000106600039000000000746004b00000adf0000413d000000000630004c00000af60000613d0000000504400210000000000242034f00000000044100190000000303300210000000000604043300000000063601cf000000000636022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000262019f000000000024043500000000020504330000031303000041000000200420008c000000000400001900000000040340190000031305200197000000000650004c000000000300a019000003130550009c000000000304c019000000000330004c00000ba20000c13d0000000003010433000003140430009c00000ba20000213d000000000221001900000000011300190000001f031000390000031304000041000000000523004b0000000005000019000000000504801900000313033001970000031306200197000000000763004b0000000004008019000000000363013f000003130330009c00000000030500190000000003046019000000000330004c00000ba20000c13d0000000003010433000003140430009c00000ba50000213d00000005043002100000003f04400039000000200500008a000000000454016f00000000090c04330000000004490019000000000594004b00000000050000190000000105004039000003140640009c00000ba50000213d000000010550019000000ba50000c13d00000000004c04350000000000390435000000200110003900000006033002100000000003130019000000000423004b00000ba20000213d0000000004090019000000000531004b00000b4c0000813d00000000051200490000031306000041000000400750008c000000000700001900000000070640190000031305500197000000000850004c000000000600a019000003130550009c00000000050700190000000005066019000000000550004c00000ba20000c13d00000000050c04330000031a0650009c00000ba50000213d0000002004400039000000400650003900000000006c04350000000006010433000000000065043500000020061000390000000006060433000000200750003900000000006704350000000000540435000000400110003900000b2e0000013d0000032201000041000000000010043900008005010000390000000402000039000300000002001d000000000012043900060000000c001d000400000009001d0c0f05790000040f00000004070000290000000604000029000000000110004c00000ba20000613d000000000304043300000346010000410000000000130435000000240230003900000000010004140000000000420435000000050200002900000315042001970000000402300039000200000004001d000000000042043500000000020704330000004404300039000000000024043500000064083000390000000004000019000000000524004b00000b760000813d000000200770003900000000050704330000000006050433000000000068043500000020055000390000000005050433000000200680003900000000005604350000000104400039000000400880003900000b690000013d0000000004380049000080050200003900000000050300190000000006000019000500000003001d0c0f050a0000040f000000000110004c00000bad0000613d0000000502000029000003140120009c000000060100002900000ba50000213d0000000000210435000003220100004100000000001004390000800201000039000000030200002900000000001204390c0f05790000040f0000000602000029000000000110004c00000ba20000613d0000000005020433000003470100004100000000001504350000000402500039000000000100041400000002030000290000000000320435000080020200003900000024040000390000000003050019000500000005001d00000000060000190c0f050a0000040f000000000110004c00000bad0000613d0000000502000029000003140120009c000000060100002900000ba50000213d00000000002104350000000600000005000000000001042d000000000100001900000000020000190c0f05920000040f0000031b010000410000000000100435000000410100003900000004020000390000000000120435000000240200003900000000010000190c0f05920000040f000000040200036700000001040000310000001f0340018f000000400100003900000000010104330000000504400270000000000540004c00000bbe0000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b00000bb60000413d000000000530004c00000bcd0000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000310c0f05920000040f000000000540004c00000bd90000613d00000000050000190000000506500210000000000761034f000000000707043b00000000007604350000000105500039000000000645004b00000bd20000413d000000000530004c00000be70000613d00000003033002100000000504400210000000000504043300000000053501cf000000000535022f000000000141034f000000000101043b0000010003300089000000000131022f00000000013101cf000000000151019f000000000014043500000000010000190c0f05920000040f000003480210009c00000bec0000813d000000000001042d000000400100003900000000010104330000004402100039000003490300004100000000003204350000002402100039000000080300003900000000003204350000031c02000041000000000021043500000004021000390000002003000039000000000032043500000064020000390c0f05920000040f00000bfe002104210000000102000039000000000001042d0000000002000019000000000001042d00000c03002104230000000102000039000000000001042d0000000002000019000000000001042d000000000f0d001900000c09002104290000000102000039000000000001042d0000000002000019000000000001042d000000000012041b000000000001042d000000000101041a000000000001042d00000c0f0000043200000c100001042e00000c11000104300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f3385fb6000000000000000000000000000000000000000000000000000000003cda33510000000000000000000000000000000000000000000000000000000057180981000000000000000000000000000000000000000000000000000000005d382700000000000000000000000000000000000000000000000000000000007b510fe80000000000000000000000000000000000000000000000000000000084da1fb4000000000000000000000000000000000000000000000000000000009c4d535b00000000000000000000000000000000000000000000000000000000bb0fd61000000000000000000000000000000000000000000000000000000000e9f18c1700000000000000000000000000000000000000000000000000000000ec8067c700000000000000000000000000000000000000000000000000000000ecf95b8a00000000000000000000000000000000000000000000000000000000187598a58000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0200000000000000000000000000000000000000000000000000000000000000290afdae231a3fc0bbae8b1af63698b0a1d79b21ad17df0342dfb952fe74f8e50000000000000000000000000000000000000000000000000000000000010000306395c600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffbf4e487b710000000000000000000000000000000000000000000000000000000008c379a00000000000000000000000000000000000000000000000000000000043616e206f6e6c792062652063616c6c656420627920464f5243455f4445504c4f5945525f434f4e5452414354000000000000000000000000000000000000006d656e74730000000000000000000000000000000000000000000000000000002074686520636f6d62696e6564206076616c75656073206f66206465706c6f796076616c7565602070726f7669646564206973206e6f7420657175616c20746f1806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b83f3385fb60000000000000000000000000000000000000000000000000000000002000002000000000000000000000000000000240000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffc04de2e46800000000000000000000000000000000000000000000000000000000666c61670000000000000000000000000000000000000000000000000000000054686973206d6574686f6420726571756972652073797374656d2063616c6c20696e6700000000000000000000000000000000000000000000000000000000006f6d2073657175656e7469616c20746f20617262697472617279206f726465724974206973206f6e6c7920706f737369626c6520746f206368616e6765206672ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff00000000000000000000000000000000000000000000000100000000000000002020dba91b30cc0006188af794c2fb30dd8520db7e2c088b7fc7c103c00ca494000000000000000000000000000000000000000000000000ffffffffffffff4063bae3a9951d38e8a3fbb7b70909afc1200610fc5bc55ade242f815974674f23000000000000000000000000000000000000000000000000ffffffffffffff8042797465636f6465486173682063616e206e6f74206265207a65726f00000000656c20737061636500000000000000000000000000000000000000000000000043616e206e6f74206465706c6f7920636f6e74726163747320696e206b65726e436f64652068617368206973206e6f6e2d7a65726f00000000000000000000004163636f756e74206973206f6363757069656400000000000000000000000000e03fe177000000000000000000000000000000000000000000000000000000005aa9b6b5000000000000000000000000000000000000000000000000000000004c6314f00000000000000000000000000000000000000000000000000000000054686520636f64652068617368206973206e6f74206b6e6f776e000000000000ff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00010000000000000000000000000000000000000000000000000000000000004f1e1be000000000000000000000000000000000000000000000000000000000579952fc0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000ffffffff000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001ffffffe0ad7e232e00000000000000000000000000000000000000000000000000000000c2e4ff970000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000004f766572666c6f770000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000001": "0x00010000000000020000000000010355000000800300003900000040010000390000000000310435000000000300041600000001022001900000003b0000c13d000000000230004c000000450000c13d00000000020004120000001a022001970000000003000410000000000232004b000000450000c13d00000000040003670000006002400370000000000302043b0000001b063000410000002002400370000000000202043b0000004005400370000000000505043b0000001b075000410000001c0770009c000000470000413d0000001d0720008a000000020800008a000000000787004b000000470000413d0000001b0660009c000000470000a13d000000000404043b000000000101043300000060061000390000000000360435000000400310003900000000005304350000001b0220008a000000200310003900000000002304350000000000410435000000800110008c0000004b0000c13d0000000001000414000004580110008c000000450000413d00000458010000390000001e020000410000000001120420000000000110004c000000450000613d0000000001000433000000010110008c000000470000c13d000000200100003900000000020100190000000003000019005e00520000040f000000000130004c000000450000c13d0000002002000039000001000100003900000000002104390000012002000039000000000002043900000040020000390000001903000041005e00520000040f0000000001000019005e005c0000040f000000000100001900000000020000190000000003000019005e00520000040f0000001d0100004100000000001004350000000101000039000000040200003900000000001204350000002401000039005e005c0000040f0000001f040000410000001f0510009c0000000001048019000000400110021000000000013100190000001f0320009c0000000002048019000000600220021000000000012100190000005f0001042e000000600110021000000060000104300000005e000004320000005f0001042e00000060000104300000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000014551231950b75fc4402da1732fc9bebf000000000000000000000000000000014551231950b75fc4402da1732fc9bec04e487b7100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000040000000400000000000000000000000000000000000000000000000000000000ffffffff0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000008005": "0x00020000000000020007000000000002000100000001035500000060011002700000003a0010019d00000080050000390000004001000039000000000051043500000001012001900000003d0000c13d0000000001000031000000040110008c000000a50000413d0000000101000367000000000101043b000000e0011002700000003c0210009c000000480000613d0000003d0110009c000000a50000c13d0000000001000416000000000110004c000000a50000c13d000000040100008a00000000011000310000003e02000041000000400310008c000000000300001900000000030240190000003e01100197000000000410004c000000000200a0190000003e0110009c00000000010300190000000001026019000000000110004c000000a50000c13d000600000005001d00e400d20000040f0000003f0110019700000000001004350000002001000039000700000001001d0000000000010435000000000100001900e400ac0000040f00000024020000390000000102200367000000000202043b000000000020043500000007020000290000000000120435000000000100001900e400ac0000040f00e400e20000040f0000000602000029000000000012043500000000010200190000000702000029000000000300001900e400bf0000040f0000000001000416000000000110004c000000a50000c13d0000002002000039000001000100003900000000002104390000012002000039000000000002043900000040020000390000003b0300004100e400bf0000040f0000000001000416000000000110004c000000a50000c13d0000000001000031000000040210008a0000003e03000041000000400420008c000000000400001900000000040340190000003e02200197000000000520004c000000000300a0190000003e0220009c00000000020400190000000002036019000000000220004c000000a50000c13d00000001020003670000000403200370000000000303043b000300000003001d0000003f0330009c000000a50000213d0000002403200370000000000303043b000000400430009c000000a50000213d00000023043000390000003e05000041000000000614004b000000000600001900000000060580190000003e071001970000003e04400197000000000874004b0000000005008019000000000474013f0000003e0440009c00000000040600190000000004056019000000000440004c000000a50000c13d0000000404300039000000000242034f000000000402043b000000400240009c000000a50000213d00000024033000390000000602400210000200000003001d0000000002320019000000000112004b000000a50000213d0000000001000411000080060110008c000000a50000c13d0000002001000039000700000001001d0000000002000019000100000004001d000000000142004b000000a80000813d0000000601200210000600000002001d000000020200002900000000012100190000000102000367000000000312034f0000002001100039000000000112034f000000000101043b000500000001001d000000000103043b000400000001001d0000000301000029000000000010043500000007010000290000000000010435000000000100001900e400ac0000040f0000000402000029000000000020043500000007020000290000000000120435000000000100001900e400ac0000040f0000000002010019000000050100002900e400e00000040f000000060200002900000001040000290000000102200039000000840000013d0000000001000019000000000200001900e400c90000040f00000000010000190000000002000019000000000300001900e400bf0000040f0000003a0200004100000000030004140000003a0430009c00000000030280190000003a0410009c00000000010280190000004001100210000000c002300210000000000112019f00000041011001c7000080100200003900e400db0000040f0000000102200190000000bc0000613d000000000101043b000000000001042d0000000001000019000000000200001900e400c90000040f0000003a040000410000003a0510009c0000000001048019000000400110021000000000013100190000003a0320009c000000000204801900000060022002100000000001210019000000e50001042e0000003a030000410000003a0420009c00000000020380190000003a0410009c000000000103801900000040011002100000006002200210000000000112019f000000e60001043000000004010000390000000101100367000000000101043b000000420210009c000000d80000813d000000000001042d0000000001000019000000000200001900e400c90000040f000000de002104230000000102000039000000000001042d0000000002000019000000000001042d000000000012041b000000000001042d000000000101041a000000000001042d000000e400000432000000e50001042e000000e600010430000000000000000000000000000000000000000000000000000000000000000000000000ffffffff000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ad7e232e00000000000000000000000000000000000000000000000000000000310ab0898000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000ffffffffffffffff02000000000000000000000000000000000000400000000000000000000000000000000000000000000000010000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000008010": "0x0002000000000002000200000000000200010000000103550000006001100270000000280010019d00000080010000390000004004000039000000000014043500000000030004160000000102200190000000550000c13d000000000230004c0000005f0000c13d00000000020004120000002a022001970000000003000410000000000232004b0000005f0000c13d000000010500036700000000030000310000001f0630018f0000000004040433000000882730011a0000000507300270000000000870004c000000230000613d00000000080000190000000509800210000000000a940019000000000995034f000000000909043b00000000009a04350000000108800039000000000978004b0000001b0000413d000000000860004c000000320000613d0000000507700210000000000575034f00000000077400190000000306600210000000000807043300000000086801cf000000000868022f000000000505043b0000010006600089000000000565022f00000000056501cf000000000585019f0000000000570435000000800440008c000000620000c13d000000000323004900000088043000390000002c030000410000000001100031000000870220008c0000003e0000613d0000002d0200004100000000002104350000002e030000410000007f014000390000000000310435000000881240011a000100000002001d00000028212000c9000200000004001d009a00880000040f0000000102000029000000c00220021000000002030000290000001b033002100000002f033000410000003003300197000000000223019f00000031022001c7000000000301001900000000010200190000000002030019009a007f0000040f009a00790000040f000000200200003900000000010000190000000003000019009a006a0000040f000000000130004c0000005f0000c13d0000002002000039000001000100003900000000002104390000012002000039000000000002043900000040020000390000002903000041009a006a0000040f00000000010000190000000002000019009a00720000040f0000002b01000041000000000010043500000001010000390000000402000039000000000012043500000024020000390000000001000019009a00720000040f0000002804000041000000280510009c000000000104801900000040011002100000006002200210000000000121019f00000000013100190000009b0001042e0000002803000041000000280410009c000000000103801900000040011002100000006002200210000000000121019f0000009c00010430000000000110004c0000007c0000613d000000000001042d00000000010000190000000002000019009a00720000040f00000028022001970000000003000414000000000323004b000000850000413d0000000001210420000000000001042d00000000010000190000000002000019009a00720000040f000000320210009c0000008b0000813d000000000001042d00000040010000390000000001010433000000440210003900000033030000410000000000320435000000240210003900000008030000390000000000320435000000340200004100000000002104350000000402100039000000200300003900000000003204350000006402000039009a00720000040f0000009a000004320000009b0001042e0000009c0001043000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000200000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff4e487b710000000000000000000000000000000000000000000000000000000081000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f8000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000100000000000000000000000400000000000000000000000000000000000000000000000000000001000000004f766572666c6f7700000000000000000000000000000000000000000000000008c379a000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000008004": "0x0002000000000002000100000000000200010000000103550000006001100270000000520010019d0000008005000039000000400100003900000000005104350000000101200190000000300000c13d0000000001000031000000040110008c000000710000413d0000000101000367000000000101043b000000e001100270000000540210009c0000003b0000613d000000550110009c000000710000c13d0000000001000416000000000110004c000000710000c13d000000040100008a00000000011000310000005602000041000000200310008c000000000300001900000000030240190000005601100197000000000410004c000000000200a019000000560110009c00000000010300190000000001026019000000000110004c000000710000c13d00000004010000390000000101100367000000000101043b000100000005001d014201400000040f00000001030000290000000000130435000000200200003900000000010300190000000003000019014200790000040f0000000001000416000000000110004c000000710000c13d0000002002000039000001000100003900000000002104390000012002000039000000000002043900000040020000390000005303000041014200790000040f0000000001000416000000000110004c000000710000c13d0000000004000031000000040140008a0000005602000041000000400310008c000000000300001900000000030240190000005601100197000000000510004c000000000200a019000000560110009c00000000010300190000000001026019000000000110004c000000710000c13d00000001020003670000000401200370000000000101043b000000000310004c0000000003000019000000010300c039000000000331004b000000710000c13d0000002403200370000000000503043b000000570350009c000000710000213d00000023035000390000005606000041000000000743004b0000000007000019000000000706801900000056084001970000005603300197000000000983004b0000000006008019000000000383013f000000560330009c00000000030700190000000003066019000000000330004c000000710000c13d0000000403500039000000000232034f000000000302043b000000570230009c000000710000213d000000240250003900000005053002100000000005250019000000000445004b000000740000a13d00000000010000190000000002000019014200830000040f0142008c0000040f000000000100001900000000020000190000000003000019014200790000040f0000005204000041000000520510009c000000000104801900000040011002100000000001310019000000520320009c000000000204801900000060022002100000000001210019000001430001042e0000005203000041000000520420009c0000000002038019000000520410009c000000000103801900000040011002100000006002200210000000000112019f0000014400010430000a000000000002000700000003001d000600000002001d00000000030100190000000001000411000080010110008c0000012a0000c13d000000000130004c0000000001000019000000010100c039000500000001001d0000000101000039000400000001001d0000800d01000039000300000001001d0000000301000039000200000001001d0000000001000413000100000001001d0000000002000019000800000003001d0000000701000029000000000112004b000000df0000813d000a00000002001d0000000501200210000000060200002900000000012100190000000101100367000000000101043b000900000001001d014201400000040f0000000803000029000000000110004c000000dc0000c13d00000009020000290000005a012001970000005b0110009c000000e40000c13d0000005e01200198000000f60000613d000000000130004c000000cb0000613d00000001010000290000005205100197000000db012002700000005f01100197000000640310003900000000413500a900000000433100d9000000000335004b000001040000c13d0000000003020019000000610210009c0000010c0000813d0000000002000414000000000212004b000000e10000413d0000000001100420000000000110004c0000011b0000613d0000000002030019000000000002041d00000004010000290142013e0000040f00000052010000410000000002000414000000520320009c0000000001024019000000c00110021000000064011001c700000065040000410000000302000029000000020300002900000009050000290000000506000029014201390000040f00000008030000290000000101200190000000e10000613d0000000a020000290000000102200039000000a10000013d0000000a00000005000000000001042d00000000010000190000000002000019014200830000040f0000004001000039000000000101043300000064021000390000005c03000041000000000032043500000044021000390000005d030000410000000000320435000000240210003900000022030000390000000000320435000000590200004100000000002104350000000402100039000000200300003900000000003204350000008402000039014200830000040f0000004001000039000000000101043300000044021000390000006603000041000000000032043500000059020000410000000000210435000000240210003900000020030000390000000000320435000000040210003900000000003204350000006402000039014200830000040f0000006001000041000000000010043500000011010000390000000402000039000000000012043500000024020000390000000001000019014200830000040f00000040010000390000000001010433000000440210003900000063030000410000000000320435000000240210003900000008030000390000000000320435000000590200004100000000002104350000000402100039000000200300003900000000003204350000006402000039014200830000040f00000040010000390000000001010433000000440210003900000062030000410000000000320435000000240210003900000014030000390000000000320435000000590200004100000000002104350000000402100039000000200300003900000000003204350000006402000039014200830000040f0000004001000039000000000101043300000044021000390000005803000041000000000032043500000024021000390000001f030000390000000000320435000000590200004100000000002104350000000402100039000000200300003900000000003204350000006402000039014200830000040f0000013c002104210000000102000039000000000001042d0000000002000019000000000001042d000000000012041b000000000001042d000000000101041a000000000001042d0000014200000432000001430001042e000001440001043000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e516761e000000000000000000000000000000000000000000000000000000004c6314f08000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff43616c6c61626c65206f6e6c792062792074686520626f6f746c6f616465720008c379a000000000000000000000000000000000000000000000000000000000ffff00000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000007368000000000000000000000000000000000000000000000000000000000000496e636f72726563746c7920666f726d61747465642062797465636f64654861000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001fffe04e487b710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000004661696c656420746f20636861726765206761730000000000000000000000004f766572666c6f770000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000c94722ff13eacf53547c4741dab5228353a05938ffcdd5d4a2d533ae0e618287436f6465206c656e67746820696e20776f726473206d757374206265206f6464", - "0x0000000000000000000000000000000000008008": "0x00020000000000020001000000000002000100000001035500000060011002700000004c0010019d00000080010000390000004008000039000000000018043500000001012001900000007a0000c13d0000000001000031000000040110008c000000850000413d0000000101000367000000000101043b0000004e011001970000004f0110009c000000850000c13d0000000001000416000000000110004c000000850000c13d0000000001000031000000040210008a0000005003000041000000200420008c000000000400001900000000040340190000005002200197000000000520004c000000000300a019000000500220009c00000000020400190000000002036019000000000220004c000000850000c13d00000001020003670000000403200370000000000303043b000000510430009c000000850000213d00000023043000390000005005000041000000000614004b0000000006000019000000000605801900000050011001970000005004400197000000000714004b0000000005008019000000000114013f000000500110009c00000000010600190000000001056019000000000110004c000000850000c13d0000000401300039000000000112034f000000000201043b000000520120009c000000880000813d0000001f01200039000000200400008a000000000141016f0000003f01100039000000000441016f00000000010804330000000004410019000000000514004b00000000050000190000000105004039000000510640009c000000880000213d0000000105500190000000880000c13d00000000004804350000000000210435000000240330003900000000043200190000000005000031000000000454004b000000850000213d000100000008001d0000001f0420018f000000010530036700000020031000390000000506200270000000000760004c000000610000613d000000000700001900000005087002100000000009830019000000000885034f000000000808043b00000000008904350000000107700039000000000867004b000000590000413d000000000740004c000000700000613d0000000506600210000000000565034f00000000066300190000000304400210000000000706043300000000074701cf000000000747022f000000000505043b0000010004400089000000000545022f00000000044501cf000000000474019f000000000046043500000000022300190000000000020435012a00ba0000040f000000010200002900000000030204330000000000130435000000200200003900000000010300190000000003000019012a00a70000040f0000000001000416000000000110004c000000850000c13d0000002002000039000001000100003900000000002104390000012002000039000000000002043900000040020000390000004d03000041012a00a70000040f00000000010000190000000002000019012a00b10000040f0000005301000041000000000010043500000041010000390000000402000039000000000012043500000024020000390000000001000019012a00b10000040f0000004c030000410000004c0410009c000000000103801900000040011002100000004c0420009c00000000020380190000006002200210000000000112019f00000000020004140000004c0420009c0000000002038019000000c002200210000000000112019f00000054011001c70000801002000039012a01250000040f0000000102200190000000a40000613d000000000101043b000000000001042d00000000010000190000000002000019012a00b10000040f0000004c040000410000004c0510009c0000000001048019000000400110021000000000013100190000004c0320009c0000000002048019000000600220021000000000012100190000012b0001042e0000004c030000410000004c0420009c00000000020380190000004c0410009c000000000103801900000040011002100000006002200210000000000112019f0000012c000104300001000000000002000100000001001d00000000020104330000002001100039012a00900000040f000000010a00002900000000020a04330000005f03200039000000200200008a000000000323016f000000000901001900000000010004130000004c0410019700000000514300a9000000000530004c000000cf0000613d00000000533100d9000000000334004b000001090000c13d000000550310009c000001110000813d00000058011001970000000003000414000000000313004b000001060000413d0000000001100420000000000110004c000001060000613d0000000005000411000000000095041d000000400100003900000000010104330000002003000039000000000031043500000000030a04330000002004100039000000000034043500000040041000390000000006000019000000000736004b000000e90000813d000000000746001900000020066000390000000008a6001900000000080804330000000000870435000000e10000013d000000000443001900000000000404350000005f03300039000000000223016f0000004c030000410000004c0410009c000000000103801900000040011002100000004c0420009c00000000020380190000006002200210000000000112019f00000000020004140000004c0420009c0000000002038019000000c002200210000000000112019f00000054011001c70000800d02000039000000030300003900000059040000410000000006090019000100000009001d012a01200000040f00000001010000290000000102200190000001060000613d0000000100000005000000000001042d00000000010000190000000002000019012a00b10000040f0000005301000041000000000010043500000011010000390000000402000039000000000012043500000024020000390000000001000019012a00b10000040f00000040010000390000000001010433000000440210003900000056030000410000000000320435000000240210003900000008030000390000000000320435000000570200004100000000002104350000000402100039000000200300003900000000003204350000006402000039012a00b10000040f00000123002104210000000102000039000000000001042d0000000002000019000000000001042d00000128002104230000000102000039000000000001042d0000000002000019000000000001042d0000012a000004320000012b0001042e0000012c0001043000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000200000000000000000000000000000000000000000000000000000000ffffffff0000000000000000000000000000000000000000000000000000000062f84b24000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff00000000000000000000000000000000000000000000000100000000000000004e487b7100000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000004f766572666c6f7700000000000000000000000000000000000000000000000008c379a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffe03a36e47291f4201faf137fab081d92295bce2d53be2c6ca68ba82c7faa9ce2410000000000000000000000000000000000000000000000000000000000000000", - "0x000000000000000000000000000000000000800a": "0x0004000000000002000600000000000200000000030100190000006003300270000000b60430019700030000004103550002000000010355000000b60030019d000100000000001f0000008001000039000000400600003900000000001604350000000101200190000000440000c13d0000000003000031000000040130008c000002410000413d0000000201000367000000000201043b000000e002200270000000b90420009c000000e90000613d000000ba0420009c0000010c0000613d000000bb0420009c000001270000613d000000bc0420009c0000013e0000613d000000bd0420009c000000550000613d000000be0120009c0000018f0000613d000000bf0120009c000000c10000613d000000c00120009c000002410000c13d0000000001000416000000000110004c000002410000c13d000000040100008a0000000001100031000000c102000041000000000310004c00000000030000190000000003024019000000c101100197000000000410004c000000000200a019000000c10110009c00000000010300190000000001026019000000000110004c000002410000c13d000600000006001d02d102b20000040f00000000020100190000002001200039000000d103000041000000000031043500000006010000290000000001010433000600000001001d02d1029d0000040f000000060300002900000000023100490000000001030019000000000300001902d102770000040f0000000001000416000000000110004c000002410000c13d0000000201000039000600000001001d02d102cf0000040f000000b701100197000000060200002902d102cd0000040f000000200200003900000100010000390000000000210439000001200200003900000000000204390000004002000039000000b80300004102d102770000040f000000040230008a000000c103000041000000200420008c00000000040000190000000004034019000000c102200197000000000520004c000000000300a019000000c10220009c00000000020400190000000002036019000000000220004c000002410000c13d0000000401100370000000000201043b000000c20120009c000002410000213d0000000001000410000000c20110019700000000001004350000002001000039000300000001001d0000000000010435000600000006001d000500000002001d02d102680000040f000400000001001d02d102cf0000040f00000000020004160000000001210049000000040200002902d102cd0000040f0000000101000039000400000001001d02d102cf0000040f00000000020004160000000001210049000000040200002902d102cd0000040f000000060500002900000000020004160000000001050433000000c9030000410000002004100039000000000034043500000005030000290000006003300210000000240410003900000000003404350000003803100039000000000023043500000038020000390000000000210435000000ca0210009c000001ce0000813d0000006003100039000400000003001d0000000000350435000000cb02000041000000000023043500000064021000390000000003000414000200000003001d00000003030000290000000000320435000000840210003902d1028a0000040f000000040200002900000000032100490000000201000029000000000402001902d102440000040f0000000104000031000000000110004c000001c30000c13d00000003030003670000001f0240018f000000060100002900000000010104330000000504400270000000000540004c000000b00000613d000000000500001900000005065002100000000007610019000000000663034f000000000606043b00000000006704350000000105500039000000000645004b000000a80000413d000000000520004c000000bf0000613d0000000504400210000000000343034f00000000044100190000000302200210000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f0000000000240435000000010200003102d102810000040f0000000001000416000000000110004c000002410000c13d000000040100008a0000000001100031000000c102000041000000000310004c00000000030000190000000003024019000000c101100197000000000410004c000000000200a019000000c10110009c00000000010300190000000001026019000000000110004c000002410000c13d0000000001060433000500000001001d000600000006001d02d102a40000040f00000005030000290000002001300039000000c302000041000000000021043500000003010000390000000000130435000000000103001900000006020000290000000003020433000600000003001d00000020020000390000000000230435000000200230003902d1028a0000040f000000060300002900000000023100490000000001030019000000000300001902d102770000040f0000000001000416000000000110004c000002410000c13d000000040100008a0000000001100031000000c102000041000000200310008c00000000030000190000000003024019000000c101100197000000000410004c000000000200a019000000c10110009c00000000010300190000000001026019000000000110004c000002410000c13d00000004010000390000000201100367000000000101043b000000c20110019700000000001004350000002001000039000500000001001d0000000000010435000600000006001d02d102680000040f02d102cf0000040f00000006020000290000000002020433000000000012043500000000010200190000000502000029000000000300001902d102770000040f0000000001000416000000000110004c000002410000c13d000000040100008a0000000001100031000000c102000041000000000310004c00000000030000190000000003024019000000c101100197000000000410004c000000000200a019000000c10110009c00000000010300190000000001026019000000000110004c000002410000c13d0000000101000039000600000006001d02d102cf0000040f00000006020000290000000003020433000000000013043500000020020000390000000001030019000000000300001902d102770000040f0000000001000416000000000110004c000002410000c13d000000040100008a0000000001100031000000c102000041000000000310004c00000000030000190000000003024019000000c101100197000000000410004c000000000200a019000000c10110009c00000000010300190000000001026019000000000110004c000002410000c13d0000000001060433000000120200003900000000002104350000002002000039000000000300001902d102770000040f0000000001000416000000000110004c000002410000c13d000000040100008a0000000001100031000000c102000041000000400310008c00000000030000190000000003024019000000c101100197000000000410004c000000000200a019000000c10110009c00000000010300190000000001026019000000000110004c000002410000c13d00000002010003670000000402100370000000000302043b000000c20230009c000002410000213d0000002401100370000000000201043b0000000001000411000080010110008c000001d60000c13d000400000003001d000600000006001d0000000101000039000500000002001d02d102cf0000040f000000000201001900000005010000290000000001120019000000000221004b000000000200001900000001020040390000000102200190000002210000c13d000000010200003902d102cd0000040f000000040100002900000000001004350000002001000039000000000001043502d102680000040f000300000001001d02d102cf0000040f000000050300002900000000020100190000000001320019000000000221004b000000000200001900000001020040390000000102200190000002210000c13d000000030200002902d102cd0000040f0000000601000029000000000101043300000005020000290000000000210435000000b6020000410000000003000414000000b60430009c0000000003028019000000b60410009c00000000010280190000004001100210000000c002300210000000000112019f000000c4011001c70000800d020000390000000203000039000000d004000041000000040500002902d102c30000040f0000000101200190000002410000613d000001fd0000013d0000000001000416000000000110004c000002410000c13d000000040100008a0000000001100031000000c102000041000000600310008c00000000030000190000000003024019000000c101100197000000000410004c000000000200a019000000c10110009c00000000010300190000000001026019000000000110004c000002410000c13d00000002010003670000000402100370000000000302043b000000c20230009c000002410000213d0000002402100370000000000402043b000000c20240009c000002410000213d00000000020004110000004401100370000000000501043b000080060120008c000002010000613d000000090100008a000000000112016f000080010110008c000002010000613d00000000010604330000006402100039000000c60300004100000000003204350000004402100039000000c703000041000000000032043500000024021000390000003e030000390000000000320435000000c8020000410000000000210435000000040210003900000020030000390000000000320435000000840200003902d102810000040f000000200140008c000000200100003900000000010440190000001f01100039000000600110018f00000004020000290000000001210019000000cc0210009c00000006020000290000000506000029000001e40000a13d000000ce0100004100000000001004350000004101000039000000040200003900000000001204350000002402000039000000000100001902d102810000040f00000000010604330000004402100039000000cf03000041000000000032043500000024021000390000001f030000390000000000320435000000c8020000410000000000210435000000040210003900000020030000390000000000320435000000640200003902d102810000040f0000000000120435000000200140008c000002410000413d0000000001000416000000000016041d000000000102043300000000020004160000000000210435000000b6020000410000000003000414000000b60430009c0000000003028019000000b60410009c00000000010280190000004001100210000000c002300210000000000112019f000000c4011001c70000800d020000390000000303000039000000cd04000041000000000500041102d102c30000040f0000000101200190000002410000613d00000000010000190000000002000019000000000300001902d102770000040f000400000004001d000600000006001d000100000003001d00000000003004350000002001000039000300000001001d0000000000010435000500000005001d02d102680000040f000200000001001d02d102cf0000040f0000000503000029000000000231004b000002210000413d0000000001310049000000020200002902d102cd0000040f000000040100002900000000001004350000000301000029000000000001043502d102680000040f000300000001001d02d102cf0000040f000000050300002900000000020100190000000001320019000000000221004b000000000200001900000001020040390000000102200190000002290000613d000000ce0100004100000000001004350000001101000039000000040200003900000000001204350000002402000039000000000100001902d102810000040f000000030200002902d102cd0000040f0000000601000029000000000101043300000005020000290000000000210435000000b6020000410000000003000414000000b60430009c0000000003028019000000b60410009c00000000010280190000004001100210000000c002300210000000000112019f000000c4011001c70000800d020000390000000303000039000000c5040000410000000105000029000000040600002902d102c30000040f0000000101200190000001fd0000c13d0000000001000019000000000200001902d102810000040f0001000000000002000100000004001d000000b604000041000000b60520009c00000000020480190000004002200210000000b60530009c00000000030480190000006003300210000000000223019f000000b60310009c0000000001048019000000c001100210000000000112019f000080080200003902d102c30000040f0000000106000029000000010220018f000000000300001900000005043002100000000005460019000000000441034f000000000404043b00000000004504350000000103300039000000000430004c000000000400001900000001040060390000000104400190000002570000c13d00030000000103550000006001100270000100b60010019d00000000010200190000000100000005000000000001042d000000b6010000410000000002000414000000b60320009c0000000001024019000000c001100210000000d2011001c7000080100200003902d102c80000040f0000000102200190000002740000613d000000000101043b000000000001042d0000000001000019000000000200001902d102810000040f000000b604000041000000b60510009c000000000104801900000040011002100000000001310019000000b60320009c000000000204801900000060022002100000000001210019000002d20001042e000000b603000041000000b60420009c0000000002038019000000b60410009c000000000103801900000040011002100000006002200210000000000112019f000002d3000104300000000003010433000000000032043500000020022000390000000004000019000000000534004b000002960000813d000000000542001900000020044000390000000006140019000000000606043300000000006504350000028e0000013d000000000132001900000000000104350000001f01300039000000200300008a000000000131016f0000000001120019000000000001042d0000000003020019000000200200003900000000002104350000002002100039000000000103001902d1028a0000040f000000000001042d000000d30210009c000002aa0000813d000000400110003900000040020000390000000000120435000000000001042d000000ce0100004100000000001004350000004101000039000000040200003900000000001204350000002402000039000000000100001902d102810000040f00000040020000390000000001020433000000d30310009c000002bb0000813d0000004003100039000000000032043500000005020000390000000000210435000000000001042d000000ce0100004100000000001004350000004101000039000000040200003900000000001204350000002402000039000000000100001902d102810000040f000002c6002104210000000102000039000000000001042d0000000002000019000000000001042d000002cb002104230000000102000039000000000001042d0000000002000019000000000001042d000000000012041b000000000001042d000000000101041a000000000001042d000002d100000432000002d20001042e000002d300010430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009cc7f7080000000000000000000000000000000000000000000000000000000018160ddd00000000000000000000000000000000000000000000000000000000313ce5670000000000000000000000000000000000000000000000000000000040c10f190000000000000000000000000000000000000000000000000000000051cff8d900000000000000000000000000000000000000000000000000000000579952fc0000000000000000000000000000000000000000000000000000000095d89b410000000000000000000000000000000000000000000000000000000006fdde038000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff45544800000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000020000000000000000000000000ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef616c206163636573732063616e2063616c6c2074686973206d6574686f6400004f6e6c792073797374656d20636f6e747261637473207769746820737065636908c379a0000000000000000000000000000000000000000000000000000000006c0960f900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffa062f84b2400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b63984e487b710000000000000000000000000000000000000000000000000000000043616c6c61626c65206f6e6c792062792074686520626f6f746c6f61646572000f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688545746865720000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffc00000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000008009": "0x0008000000000002000400000000000200000000060100190000006006600270000000740760019700070000007103550006000000010355000300000003001f000400000004001f000500000005001f000000740060019d000200000002001f000100000000001f00000080010000390000004007000039000000000017043500000001022001900000002c0000c13d000000020200003900000002032001870000000102300270000000000330004c00000000030004110000001b0000c13d000000760230009c00000000020000190000000102004039000000000220004c000000370000c13d0000007d0200004100000000002104350000002003000039000000840200003900000000003204350000002403000039000000a40400003900000000003404350000007e03000041000000c40400003900000000003404350000007f03000041000000e404000039000000000034043501cc00c90000040f0000000001000416000000000110004c000000660000c13d000000200200003900000100010000390000000000210439000001200200003900000000000204390000004002000039000000750300004101cc00bf0000040f0000000504000031000000770200004100000004052001870000000306000031000000000260004c000400000004001d000300000005001d0000004d0000c13d00000000000604170000000001000031000000000201001901cc00d20000040f00000000030100190000000401000029000000010410018f0000000002000411000000030100002901cc01120000040f00000000020104330000002001100039000000000300001901cc00bf0000040f0000007804000041000000a00200003900000000004204350000007703300197000000a4040000390000000000340435000000c4030000390000000000530435000000e403000039000100000006001d0000000000630435000000640300003900000000003104350000012003000039000200000007001d000000000037043500000000040004140000000003010433000000000104001901cc00ab0000040f0000000102000031000000000320004c000000690000c13d000000000110004c000000a20000c13d0000000001000019000000000200001901cc00c90000040f000000790320009c00000002070000290000009a0000813d0000003f03200039000000200400008a000000000443016f00000000030704330000000004430019000000000534004b000000000500001900000001050040390000007a0640009c0000009a0000213d00000001055001900000009a0000c13d000000000047043500000000002304350000002002300039000000070300036700000001050000310000001f0450018f0000000505500270000000000650004c0000008a0000613d000000000600001900000005076002100000000008720019000000000773034f000000000707043b00000000007804350000000106600039000000000756004b000000820000413d000000000640004c000000640000613d0000000505500210000000000353034f00000000025200190000000304400210000000000502043300000000054501cf000000000545022f000000000303043b0000010004400089000000000343022f00000000034301cf000000000353019f0000000000320435000000640000013d0000007b0100004100000000001004350000004101000039000000040200003900000000001204350000002402000039000000000100001901cc00c90000040f00000001060000290000007c0160009c000000040400002900000003050000290000003f0000413d00000000010000190000000002000019000000000300001901cc00bf0000040f0000007404000041000000740520009c00000000020480190000004002200210000000740530009c00000000030480190000006003300210000000000223019f000000740310009c0000000001048019000000c001100210000000000112019f0000800a0200003901cc01c10000040f00000000030100190000006003300270000100740030019d0007000000010355000000010120018f000000000001042d0000007404000041000000740510009c000000000104801900000040011002100000000001310019000000740320009c000000000204801900000060022002100000000001210019000001cd0001042e0000007403000041000000740420009c0000000002038019000000740410009c000000000103801900000040011002100000006002200210000000000112019f000001ce00010430000000790310009c000001070000813d0000003f03100039000000200400008a000000000543016f000000400400003900000000030404330000000005530019000000000635004b000000000600001900000001060040390000007a0750009c000001070000213d0000000106600190000001070000c13d00000000005404350000000000130435000000000221004b0000010f0000213d00000006050003670000001f0410018f00000020023000390000000506100270000000000760004c000000f40000613d000000000700001900000005087002100000000009820019000000000885034f000000000808043b00000000008904350000000107700039000000000867004b000000ec0000413d000000000740004c000001030000613d0000000506600210000000000565034f00000000066200190000000304400210000000000706043300000000074701cf000000000747022f000000000505043b0000010004400089000000000545022f00000000044501cf000000000474019f0000000000460435000000000112001900000000000104350000000001030019000000000001042d0000007b0100004100000000001004350000004101000039000000040200003900000000001204350000002402000039000000000100001901cc00c90000040f0000000001000019000000000200001901cc00c90000040f0005000000000002000300000004001d000200000003001d000400000002001d000500000001001d000000000103043301cc01af0000040f000100000001001d000000000100041401cc01af0000040f0000000202000029000000400220021000000080022000410000008102200197000000010300002900000060033002100000008203300197000000000223019f000000c0011002100000008301100197000000000112019f00000084021001c70000000303000029000000000330004c000000000102c0190000000402000029000000770d200197000000050200002901cc01c60000040f000000000302001900000000020100190000006002200270000100740020019d000000740220019700070000000103550000000103300190000001880000613d0000003f012000390000008504100197000000400300003900000000010304330000000005410019000000000615004b000000000600001900000001060040390000007a0750009c000001a40000213d0000000106600190000001a40000c13d000000000053043500000000002104350000002003100039000000200640008a0000001f0460018f000000000500003100000006055003670000000506600270000000000760004c000001560000613d000000000700001900000005087002100000000009830019000000000885034f000000000808043b00000000008904350000000107700039000000000867004b0000014e0000413d000000000740004c000001650000613d0000000506600210000000000565034f00000000066300190000000304400210000000000706043300000000074701cf000000000747022f000000000505043b0000010004400089000000000545022f00000000044501cf000000000474019f000000000046043500000000002104350000000104000031000000000442004b000001ac0000213d00000007050003670000001f0420018f0000000502200270000000000620004c000001770000613d000000000600001900000005076002100000000008730019000000000775034f000000000707043b00000000007804350000000106600039000000000726004b0000016f0000413d000000000640004c000001860000613d0000000502200210000000000525034f00000000022300190000000303400210000000000402043300000000043401cf000000000434022f000000000505043b0000010003300089000000000535022f00000000033501cf000000000343019f00000000003204350000000500000005000000000001042d0000001f0420018f0000000503200270000000000530004c000001940000613d00000000050000190000000506500210000000000761034f000000000707043b00000000007604350000000105500039000000000635004b0000018d0000413d000000000540004c000001a20000613d00000003044002100000000503300210000000000503043300000000054501cf000000000545022f000000000131034f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000130435000000000100001901cc00c90000040f0000007b0100004100000000001004350000004101000039000000040200003900000000001204350000002402000039000000000100001901cc00c90000040f0000000001000019000000000200001901cc00c90000040f000000860210009c000001b20000813d000000000001042d000000400100003900000000010104330000004402100039000000870300004100000000003204350000002402100039000000080300003900000000003204350000007d020000410000000000210435000000040210003900000020030000390000000000320435000000640200003901cc00c90000040f000001c4002104210000000102000039000000000001042d0000000002000019000000000001042d000000000f0d0019000001ca002104290000000102000039000000000001042d0000000002000019000000000001042d000001cc00000432000001cd0001042e000001ce00010430000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff579952fc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff4e487b7100000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000008c379a00000000000000000000000000000000000000000000000000000000054686973206d6574686f6420726571756972652073797374656d2063616c6c20666c61670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000ffffffff000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000ffffffff000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001ffffffe000000000000000000000000000000000000000000000000000000001000000004f766572666c6f770000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000008003": "0x0005000000000002000500000000000200000000030100190000006003300270000000dc0430019700040000004103550003000000010355000000dc0030019d000200000002001f000100000000001f00000080010000390000004005000039000000000015043500000001012001900000007d0000c13d0000000001000031000000040110008c000002800000413d0000000301000367000000000101043b000000e001100270000000de0210009c000001630000613d000000df0210009c000000880000613d000000e00210009c000001860000613d000000e10210009c000000c30000613d000000e20210009c000001ba0000613d000000e30210009c000001dc0000613d000000e40210009c000000ed0000613d000000e50210009c000001080000613d000000e60210009c000001290000613d000000e70110009c000002800000c13d0000000001000416000000000110004c000002800000c13d000000040100008a0000000001100031000000e802000041000000400310008c00000000030000190000000003024019000000e801100197000000000410004c000000000200a019000000e80110009c00000000010300190000000001026019000000000110004c000002800000c13d000500000005001d000000010100003900000003020003670000002403200370000000000303043b000200000003001d0000000402200370000000000202043b000100000002001d0000000202000039000000020220018800000000020004110000004a0000c13d000000ea0120009c00000000010000190000000101004039000400000002001d036c03260000040f00000005010000290000000004010433000000f30100004100000000001404350000000401000029000000e90210019700000004034000390000000001000414000000000023043500000024030000390000000002040019000300000004001d036c02ba0000040f0000000104000031000000000110004c000002120000c13d00000004030003670000001f0240018f000000050100002900000000010104330000000504400270000000000540004c0000006c0000613d000000000500001900000005065002100000000007610019000000000663034f000000000606043b00000000006704350000000105500039000000000645004b000000640000413d000000000520004c0000007b0000613d0000000504400210000000000343034f00000000044100190000000302200210000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f00000000002404350000000102000031036c02f80000040f0000000001000416000000000110004c000002800000c13d000000200200003900000100010000390000000000210439000001200200003900000000000204390000004002000039000000dd03000041036c02ee0000040f0000000001000416000000000110004c000002800000c13d000000040100008a0000000001100031000000e802000041000000200310008c00000000030000190000000003024019000000e801100197000000000410004c000000000200a019000000e80110009c00000000010300190000000001026019000000000110004c000002800000c13d00000004010000390000000301100367000000000201043b000000e90120009c000002800000213d000400000002001d000500000005001d000000010100003900000002020000390000000202200188000000a80000c13d0000000001000411000000ea0110009c00000000010000190000000101004039036c03260000040f0000000001000411000080060110008c000002580000c13d000000040100002900000000001004350000002001000039000200000001001d00000000000104350000000001000019036c02db0000040f036c036a0000040f000300000001001d0000000401000029036c03110000040f00000000020100190000000301000029000000f201100041036c03680000040f0000000301000029000000800210027000000005010000290000000001010433000000000021043500000002020000290000000003000019036c02ee0000040f0000000001000416000000000110004c000002800000c13d000000040100008a0000000001100031000000e802000041000000200310008c00000000030000190000000003024019000000e801100197000000000410004c000000000200a019000000e80110009c00000000010300190000000001026019000000000110004c000002800000c13d0000000001000411000000000010043500000001010000390000002002000039000400000002001d00000000001204350000000001000019000500000005001d036c02db0000040f00000004020000390000000302200367000000000202043b0000000000200435000000040200002900000000001204350000000001000019036c02db0000040f036c036a0000040f000000050200002900000000020204330000000000120435000000000102001900000004020000290000000003000019036c02ee0000040f0000000001000416000000000110004c000002800000c13d000000040100008a0000000001100031000000e802000041000000200310008c00000000030000190000000003024019000000e801100197000000000410004c000000000200a019000000e80110009c00000000010300190000000001026019000000000110004c000002800000c13d000500000005001d036c03010000040f036c031d0000040f000000050200002900000000030204330000000000130435000000200200003900000000010300190000000003000019036c02ee0000040f0000000001000416000000000110004c000002800000c13d000000040100008a0000000001100031000000e802000041000000400310008c00000000030000190000000003024019000000e801100197000000000410004c000000000200a019000000e80110009c00000000010300190000000001026019000000000110004c000002800000c13d000500000005001d036c03010000040f00000024020000390000000302200367000000000202043b036c033b0000040f00000005020000290000000003020433000000000110004c0000000001000019000000010100c0390000000000130435000000200200003900000000010300190000000003000019036c02ee0000040f0000000001000416000000000110004c000002800000c13d000000040100008a0000000001100031000000e802000041000000200310008c00000000030000190000000003024019000000e801100197000000000410004c000000000200a019000000e80110009c00000000010300190000000001026019000000000110004c000002800000c13d000500000005001d000000010100003900000002020000390000000202200188000001430000c13d0000000001000411000000ea0110009c00000000010000190000000101004039036c03260000040f0000000001000411000300000001001d00000000001004350000002001000039000400000001001d00000000000104350000000001000019036c02db0000040f036c036a0000040f00000004020000390000000302200367000000000202043b0000000003010019000000eb01300197000000000121004b0000022e0000c13d00000003010000290000000000100435000000040100002900000000000104350000000001000019000500000003001d036c02db0000040f000000000201001900000005010000290000000101100039036c03680000040f000000000100001900000000020000190000000003000019036c02ee0000040f0000000001000416000000000110004c000002800000c13d000000040100008a0000000001100031000000e802000041000000200310008c00000000030000190000000003024019000000e801100197000000000410004c000000000200a019000000e80110009c00000000010300190000000001026019000000000110004c000002800000c13d000500000005001d036c03010000040f000000e90110019700000000001004350000002001000039000400000001001d00000000000104350000000001000019036c02db0000040f036c036a0000040f0000000502000029000000000202043300000080011002700000000000120435000000000102001900000004020000290000000003000019036c02ee0000040f0000000001000416000000000110004c000002800000c13d000000040100008a0000000001100031000000e802000041000000200310008c00000000030000190000000003024019000000e801100197000000000410004c000000000200a019000000e80110009c00000000010300190000000001026019000000000110004c000002800000c13d000500000005001d000000010100003900000004020000390000000302200367000000000202043b000400000002001d00000002020000390000000202200188000001a40000c13d0000000001000411000000ea0110009c00000000010000190000000101004039036c03260000040f0000000402000029000000ef0120009c0000023d0000413d000000050100002900000000010104330000006402100039000000f00300004100000000003204350000004402100039000000f1030000410000000000320435000000240210003900000030030000390000000000320435000000ed0200004100000000002104350000000402100039000000200300003900000000003204350000008402000039036c02f80000040f0000000001000416000000000110004c000002800000c13d000000040100008a0000000001100031000000e802000041000000200310008c00000000030000190000000003024019000000e801100197000000000410004c000000000200a019000000e80110009c00000000010300190000000001026019000000000110004c000002800000c13d000500000005001d036c03010000040f000000e90110019700000000001004350000002001000039000400000001001d00000000000104350000000001000019036c02db0000040f036c036a0000040f000000050200002900000000020204330000000000120435000000000102001900000004020000290000000003000019036c02ee0000040f0000000001000416000000000110004c000002800000c13d000000040100008a0000000001100031000000e802000041000000600310008c00000000030000190000000003024019000000e801100197000000000410004c000000000200a019000000e80110009c00000000010300190000000001026019000000000110004c000002800000c13d00000003020003670000000401200370000000000101043b000000e90310009c000002800000213d0000004403200370000000000403043b000000000340004c0000000003000019000000010300c039000000000334004b000002800000c13d000400000004001d000500000005001d0000002402200370000000000202043b036c033b0000040f000000000110004c000002630000c13d0000000401000029000000000110004c0000000501000029000002710000613d00000000010104330000004402100039000000ee03000041000000000032043500000024021000390000001d030000390000000000320435000000ed0200004100000000002104350000000402100039000000200300003900000000003204350000006402000039036c02f80000040f000000400140008c000000400100003900000000010440190000001f01100039000000e00210018f00000003050000290000000001520019000000000221004b00000000020000190000000102004039000000f40310009c000002260000213d0000000102200190000002260000c13d00000005020000290000000000120435000000400240008c000002800000413d000000f50210009c000002750000a13d000000f801000041000000000010043500000041010000390000000402000039000000000012043500000024020000390000000001000019036c02f80000040f000000050100002900000000010104330000004402100039000000ec03000041000000000032043500000024021000390000000f030000390000000000320435000000ed0200004100000000002104350000000402100039000000040300002900000000003204350000006402000039036c02f80000040f0000000001000411000100000001001d00000000001004350000002001000039000200000001001d00000000000104350000000001000019036c02db0000040f036c036a0000040f000300000001001d0000000101000029036c03110000040f000000040200002900000003030000290000000002230019000000000301001900000000010200190000000002030019036c03680000040f0000000301000029000000eb0210019700000005010000290000000001010433000000000021043500000002020000290000000003000019036c02ee0000040f00000005010000290000000001010433000000ed020000410000000000210435000000040210003900000020030000390000000000320435000000240210003900000000000204350000004402000039036c02f80000040f0000000401000029000000000110004c0000000501000029000002710000c13d0000000002010433000500000002001d000000ed0100004100000000001204350000000401200039036c03590000040f000000050300002900000000023100490000000001030019036c02f80000040f000000000100001900000000020000190000000003000019036c02ee0000040f0000004002100039000000050400002900000000002404350000000002050433000000010320008c000002800000213d000000000021043500000020025000390000000002020433000000010320008c000002830000a13d00000000010000190000000002000019036c02f80000040f000000200110003900000000002104350000000201000029000000000110004c000002960000c13d00000000010404330000004402100039000000f703000041000000000032043500000024021000390000001f030000390000000000320435000000ed0200004100000000002104350000000402100039000000200300003900000000003204350000006402000039036c02f80000040f000000000120004c000002af0000c13d0000000101000029000000000110004c000002af0000613d0000000101000029000000010210008a0000000401000029036c033b0000040f000000000110004c000002af0000c13d000000050100002900000000010104330000004402100039000000f6030000410000000000320435000000ed020000410000000000210435000000240210003900000020030000390000000000320435000000040210003900000000003204350000006402000039036c02f80000040f0000000401000029036c030a0000040f0000000102000029036c03170000040f00000000020100190000000201000029036c03680000040f000000000100001900000000020000190000000003000019036c02ee0000040f0001000000000002000100000004001d000000dc04000041000000dc0520009c00000000020480190000004002200210000000dc0530009c00000000030480190000006003300210000000000223019f000000dc0310009c0000000001048019000000c001100210000000000112019f0000800602000039036c03630000040f0000000106000029000000010220018f000000000300001900000005043002100000000005460019000000000441034f000000000404043b00000000004504350000000103300039000000020430008c000002cd0000413d00040000000103550000006001100270000100dc0010019d00000000010200190000000100000005000000000001042d000000dc020000410000000003000414000000dc0430009c0000000003028019000000dc0410009c00000000010280190000004001100210000000c002300210000000000112019f000000f9011001c70000801002000039036c03630000040f0000000102200190000002eb0000613d000000000101043b000000000001042d00000000010000190000000002000019036c02f80000040f000000dc04000041000000dc0510009c000000000104801900000040011002100000000001310019000000dc0320009c0000000002048019000000600220021000000000012100190000036d0001042e000000dc03000041000000dc0420009c0000000002038019000000dc0410009c000000000103801900000040011002100000006002200210000000000112019f0000036e0001043000000004010000390000000301100367000000000101043b000000fa0210009c000003070000813d000000000001042d00000000010000190000000002000019036c02f80000040f00000000001004350000000101000039000000200200003900000000001204350000000001000019036c02db0000040f000000000001042d0000000000100435000000200100003900000000000104350000000001000019036c02db0000040f000000000001042d0000000000200435000000200200003900000000001204350000000001000019036c02db0000040f000000000001042d000000e9011001970000000000100435000000200100003900000000000104350000000001000019036c02db0000040f036c036a0000040f000000eb01100197000000000001042d000000000110004c000003290000613d000000000001042d000000400100003900000000010104330000006402100039000000fb0300004100000000003204350000004402100039000000fc030000410000000000320435000000240210003900000024030000390000000000320435000000ed0200004100000000002104350000000402100039000000200300003900000000003204350000008402000039036c02f80000040f0002000000000002000200000002001d000100000001001d036c031d0000040f00000001020000390000000203000029000000000131004b000003560000213d0000000101000029000000e901100197000000000010043500000001010000390000002002000039000100000002001d00000000001204350000000001000019036c02db0000040f00000002020000290000000000200435000000010200002900000000001204350000000001000019036c02db0000040f036c036a0000040f000000000110004c0000000002000019000000010200c039000000010120018f0000000200000005000000000001042d0000004002100039000000fd03000041000000000032043500000020021000390000001c030000390000000000320435000000200200003900000000002104350000006001100039000000000001042d00000366002104230000000102000039000000000001042d0000000002000019000000000001042d000000000012041b000000000001042d000000000101041a000000000001042d0000036c000004320000036d0001042e0000036e00010430000000000000000000000000000000000000000000000000000000000000000000000000ffffffff000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fb1a9a5700000000000000000000000000000000000000000000000000000000306395c60000000000000000000000000000000000000000000000000000000038a780920000000000000000000000000000000000000000000000000000000055d35d18000000000000000000000000000000000000000000000000000000005aa9b6b5000000000000000000000000000000000000000000000000000000006ee1dc2000000000000000000000000000000000000000000000000000000000896909dc00000000000000000000000000000000000000000000000000000000cab7e8eb00000000000000000000000000000000000000000000000000000000e1239cd800000000000000000000000000000000000000000000000000000000155fd27a8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000ffffffffffffffffffffffffffffffff496e636f7272656374206e6f6e6365000000000000000000000000000000000008c379a000000000000000000000000000000000000000000000000000000000546865206e6f6e636520776173206e6f7420736574206173207573656400000000000000000000000000000000000000000000000000000000000001000000016f6e636520697320746f6f2068696768000000000000000000000000000000005468652076616c756520666f7220696e6372656d656e74696e6720746865206e00000000000000000000000000000001000000000000000000000000000000007b510fe800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff000000000000000000000000000000000000000000000000ffffffffffffffbf50726576696f7573206e6f6e636520686173206e6f74206265656e20757365644e6f6e63652076616c75652063616e206e6f742062652073657420746f2030004e487b710000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000400000000000000000000000000000000000000000000000010000000000000000000000000000000000000000666c61670000000000000000000000000000000000000000000000000000000054686973206d6574686f6420726571756972652073797374656d2063616c6c2052657573696e67207468652073616d65206e6f6e6365207477696365000000000000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000002": "0x00020000000000020002000000000002000100000001035500000060011002700000002b0010019d000000800300003900000040010000390000000000310435000000000300041600000001022001900000005e0000c13d000000000230004c000000680000c13d00000000020004120000002d022001970000000003000410000000000232004b000000680000c13d000000400200008a0000000004000031000000000224016f000000400320003900000080022000390000003f0540018f000000370550008c000000000a030019000000000a02201900000006053002700000000006000019000000010600203900000001030003670000001f0240018f00000000010104330000000504400270000000000740004c0000002d0000613d000000000700001900000005087002100000000009810019000000000883034f000000000808043b00000000008904350000000107700039000000000847004b000000250000413d0000000005650019000200000005001d000000000520004c0000003e0000613d0000000504400210000000000343034f00000000044100190000000302200210000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f000000000024043500000000021000310000002e0300004100000000003204350000000002a10019000000080220008a000000c30300003900000000033001ff0000000000320435000000800110008c0000000001000019000000010100603900010000000a001d00a600800000040f000000020100002900000007211000c900a600940000040f0000000202000029000000c00220021000000001030000290000001b033002100000002f03300197000000000223019f00000030022001c700000000030100190000000001020019000000000203001900a6008b0000040f00a6007a0000040f00000020020000390000000001000019000000000300001900a6006b0000040f000000000130004c000000680000c13d0000002002000039000001000100003900000000002104390000012002000039000000000002043900000040020000390000002c0300004100a6006b0000040f0000000001000019000000000200001900a600730000040f0000002b040000410000002b0510009c000000000104801900000040011002100000006002200210000000000121019f0000000001310019000000a70001042e0000002b030000410000002b0410009c000000000103801900000040011002100000006002200210000000000121019f000000a800010430000000000110004c0000007d0000613d000000000001042d0000000001000019000000000200001900a600730000040f000000000110004c000000830000613d000000000001042d000000310100004100000000001004350000000101000039000000040200003900000000001204350000002402000039000000000100001900a600730000040f0000002b022001970000000003000414000000000323004b000000910000413d0000000001210420000000000001042d0000000001000019000000000200001900a600730000040f000000320210009c000000970000813d000000000001042d0000004001000039000000000101043300000044021000390000003303000041000000000032043500000024021000390000000803000039000000000032043500000034020000410000000000210435000000040210003900000020030000390000000000320435000000640200003900a600730000040f000000a600000432000000a70001042e000000a80001043000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000200000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000000000000000000000000000000000000000000010000000000000000000000044e487b710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000004f766572666c6f7700000000000000000000000000000000000000000000000008c379a000000000000000000000000000000000000000000000000000000000", - "0x000000000000000000000000000000000000800c": "0x00020000000000020016000000000002000100000001035500000060011002700000026a0010019d000000800c00003900000040060000390000000000c604350000000101200190000000830000c13d0000000001000031000000040110008c000006380000413d0000000101000367000000000101043b0000026c011001970000026d0110009c000006380000c13d0000000001000416000000000110004c000006380000c13d000000040100008a00000000011000310000026e02000041000000200310008c000000000300001900000000030240190000026e04100197000000000540004c000000000200a0190000026e0440009c000000000203c019000000000220004c000006380000c13d000000010d0003670000000402d00370000000000502043b0000026f0250009c000006380000213d00000000015100490000026e02000041000002600310008c000000000300001900000000030240190000026e01100197000000000410004c000000000200a0190000026e0110009c00000000010300190000000001026019000000000110004c000006380000c13d000000040350003900000000013d034f000000000101043b000000000210004c000001040b500039000000a40a500039000000640950003900000044085000390000012407500039000001c402500039000000c404500039000b00000004001d0000014404500039000d00000004001d001400000006001d001600000003001d001500000002001d000e00000005001d001200000007001d001100000008001d001000000009001d000f0000000a001d000c0000000b001d0000008e0000c13d0000000001bd034f000000000101043b00130000000d035309a108b10000040f0000000f03000029000000130200035f000000000232034f000000000202043b000a00000001001d000000000102001909a108b10000040f0000001003000029000000130200035f000000000232034f000000000202043b000900000001001d000000000102001909a108b10000040f0000000002010019000000090100002909a1078d0000040f0000001102000029000000130300035f000000000223034f000000000202043b0000027302200197000900000001001d000000000102001909a108990000040f00000012020000290000000102200367000000000202043b000700000001001d000000000102001909a108b10000040f000800000001001d0000001601000029000000150200002909a107120000040f0000026f01200197000000010210008c0000016a0000c13d0000001601000029000000150200002909a107120000040f000000000220004c000001c80000c13d000002810100004100000000001004350000003201000039000000040200003900000000001204350000002402000039000000000100001909a106ff0000040f0000000001000416000000000110004c000006380000c13d0000002002000039000001000100003900000000002104390000012002000039000000000002043900000040020000390000026b0300004109a106f50000040f000000710410008c0000016e0000c13d000000000103001900130000000c001d09a107120000040f000000000300003109a1073f0000040f0000000002010433000000200110003909a106cf0000040f0000000e02000029000000140a000029000002040320003900000000040000310000000002240049000000230520008a0000000102000367000000000332034f000000000303043b0000026e06000041000000000753004b000000000700001900000000070680190000026e055001970000026e08300197000000000958004b0000000006008019000000000558013f0000026e0550009c00000000050700190000000005066019000000000b010019000000000150004c000006380000c13d00000016010000290000000001130019000000000312034f000000000503043b0000026f0350009c000006380000213d0000000503500210000000000434004900000020061000390000026e01000041000000000746004b000000000700001900000000070120190000026e044001970000026e08600197000000000948004b0000000001008019000000000448013f0000026e0440009c000000000107c019000000000110004c000006380000c13d00000000040a043300000020014000390000027605500197000000000750004c000000d50000613d000000000262034f000000000600001900000005076002100000000008710019000000000772034f000000000707043b00000000007804350000000106600039000000000756004b000000cd0000413d000000000200004c000000d70000613d00000000003404350000003f02300039000000200300008a000000000232016f0000000002240019000000000342004b000000000300001900000001030040390000026f0520009c000003b10000213d0000000103300190000003b10000c13d000000140300002900000000002304350000000002040433000a0000000b001d09a106cf0000040f000900000001001d0000000e010000290000022402100039000000160100002909a107120000040f000000000300003109a1073f0000040f0000000002010433000000200110003909a106cf0000040f0000000e04000029000000e4024000390000002403400039000000840440003900000001050003670000001006000029000000000665034f0000001107000029000000000775034f000000000835034f0000001203000029000000000935034f0000000c03000029000000000a35034f000000000225034f0000000b03000029000000000b35034f0000000f03000029000000000c35034f000000000d45034f0000001603000029000000000335034f000000000303043b000000000408043b000000000507043b000000000606043b00000000070d043b00000000080c043b000000000b0b043b000000000c02043b000000000a0a043b000000000909043b00000014020000290000000002020433000001c00d20003900000000001d0435000001a001200039000000090d0000290000000000d1043500000180012000390000000a0d0000290000000000d104350000016001200039000000000091043500000140012000390000000000a1043500000120012000390000000000c1043500000100012000390000000000b10435000000e0012000390000000000810435000000c0012000390000000000710435000000a0012000390000000000610435000000800120003900000000005104350000006001200039000000000041043500000040012000390000000000310435000001c0010000390000000000120435000002770300004100000020012000390000000000310435000002780320009c000003b10000213d000001e00320003900000014040000290000000000340435000000000202043309a106cf0000040f00000014020000290000000002020433000a00000002001d00000272020000410000000000200439000900000001001d09a106e60000040f00000279020000410000000a04000029000000600340003900000000002304350000027a0200004100000040034000390000000000230435000000800240003900000000001204350000027b02000041000000200140003900000000002104350000001302000029000000000024043500000000030400190000027c0240009c000003b10000213d000000a00230003900000014040000290000000000240435000000000203043309a106cf0000040f000000140200002900000000040204330000004202400039000000090300002900000000003204350000027d020000410000002003400039000400000003001d000000000023043500000022024000390000000000120435000000420100003900000000001404350000027e0140009c000003b10000213d0000008001400039000003910000013d09a108e60000040f00000001050003670000000002010019000001de0000013d000000020410008c000002720000c13d0000027201000041000000000010043909a106e60000040f09a108b10000040f000000010200036700130000000203530000000c03000029000000000232034f000000000202043b000a00000001001d000000000102001909a108b10000040f0000000b02000029000000130300035f000000000223034f000000000202043b000900000001001d000000000102001909a108b10000040f0000000f03000029000000130200035f000000000232034f000000000202043b000800000001001d000000000102001909a108b10000040f0000001002000029000000130300035f000000000223034f000000000202043b000700000001001d000000000102001909a108b10000040f0000001102000029000000130300035f000000000223034f000000000202043b0000027302200197001300000001001d000000000102001909a108990000040f00000012020000290000000102200367000000000202043b000600000001001d000000000102001909a108b10000040f00000000070100190000000a010000290000000902000029000000080300002900000007040000290000001305000029000000060600002909a108110000040f000a00000001001d0000001601000029000000150200002909a107120000040f0000026f01200197000000010210008c000002c40000c13d0000001601000029000000150200002909a107120000040f000000000220004c0000007b0000613d0000000101100367000000000101043b000000010200008a0000026e03000041000000000221004b000000000200001900000000020320190000026e011001970000026e0410009c00000000030080190000026e011001670000026e0110009c000000000102001900000000010360190000006002000039001300000002001d000000000110004c000002c60000c13d09a107b40000040f001300000001001d000002c60000013d0000000105000367000000000115034f000000000101043b000000010200008a0000026e03000041000000000221004b000000000200001900000000020320190000026e011001970000026e0410009c00000000030080190000026e011001670000026e0110009c000000000102001900000000010360190000006002000039000000000110004c000001de0000c13d001300000005035309a107b40000040f000000130500035f00000000020100190000000d01000029000000000115034f0000006004000039000000000101043b000000000110004c000500000002001d000002020000613d0000027201000041000000000010043909a106e60000040f09a108b10000040f00000014020000290000000002020433001300000002001d000000200220003909a107800000040f00000013040000290000027f02000041000000000021043500000000014100490000001e0210008a00000000002404350000002101100039000000200200008a000000000221016f0000000001420019000000000221004b000000000200001900000001020040390000026f0310009c000003b10000213d0000000102200190000003b10000c13d000000140200002900000000001204350000000502000029001300000004001d0000000001020433000600000001001d00000008010000290000000001010433000400000001001d00000007010000290000000001010433000300000001001d00000009010000290000000001010433000200000001001d0000000a010000290000000001010433000100000001001d0000001601000029000000150200002909a107120000040f00000002010000290000000103000029000000000131001900000003030000290000000001310019000000040300002900000000013100190000000603000029000000000131001900000000012100190000001302000029000000000202043300000000012100190000026f0110019709a1094a0000040f000400000001001d0000001601000029000000150200002909a107120000040f00000014030000290000000003030433000300000001001d000200000002001d000600000003001d00000020023000390000000401000029000400000002001d09a107800000040f00000000020100190000000a0100002909a107800000040f0000000002010019000000090100002909a107800000040f0000000002010019000000070100002909a107800000040f0000000002010019000000080100002909a107800000040f0000000002010019000000050100002909a107800000040f00000002080000290000001f0280018f000000030300002900000001033003670000000504800270000000000540004c0000024f0000613d000000000500001900000005065002100000000007610019000000000663034f000000000606043b00000000006704350000000105500039000000000645004b000002470000413d000000000520004c0000025e0000613d0000000504400210000000000343034f00000000044100190000000302200210000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f000000000024043500000000028100190000000000020435000000130100002909a107800000040f00000006040000290000000001410049000000200210008a00000000002404350000001f01100039000000200200008a000000000221016f0000000001420019000000000221004b000000000200001900000001020040390000026f0310009c000003b10000213d0000000102200190000003910000613d000003b10000013d000000010110008c000003240000c13d0000027201000041000000000010043909a106e60000040f09a108b10000040f000000010200036700130000000203530000000c03000029000000000232034f000000000202043b000a00000001001d000000000102001909a108b10000040f0000000f03000029000000130200035f000000000232034f000000000202043b000900000001001d000000000102001909a108b10000040f0000001002000029000000130300035f000000000223034f000000000202043b000800000001001d000000000102001909a108b10000040f0000001102000029000000130300035f000000000223034f000000000202043b0000027302200197001300000001001d000000000102001909a108990000040f00000012020000290000000102200367000000000202043b000700000001001d000000000102001909a108b10000040f00000000060100190000000a01000029000000090200002900000008030000290000001304000029000000070500002909a107da0000040f000a00000001001d0000001601000029000000150200002909a107120000040f0000026f01200197000000010210008c000003320000c13d0000001601000029000000150200002909a107120000040f000000000220004c0000007b0000613d0000000101100367000000000101043b000000010200008a0000026e03000041000000000221004b000000000200001900000000020320190000026e011001970000026e0410009c00000000030080190000026e011001670000026e0110009c000000000102001900000000010360190000006002000039001300000002001d000000000110004c000003340000c13d09a107b40000040f001300000001001d000003340000013d09a108e60000040f001300000001001d09a109380000040f000900000001001d0000000a010000290000000001010433000800000001001d0000001301000029001300000001001d0000000001010433000700000001001d0000001601000029000000150200002909a107120000040f00000008010000290000000703000029000000000113001900000000012100190000000902000029000000000202043300000000012100190000026f0110019709a1094a0000040f000500000001001d0000001601000029000000150200002909a107120000040f0000001403000029000000000403043300000275030000410000002005400039000400000005001d0000000000350435000800000001001d000700000002001d000600000004001d0000002102400039000000050100002909a107800000040f00000000020100190000000a0100002909a107800000040f0000000002010019000000130100002909a107800000040f00000007080000290000001f0280018f000000080300002900000001033003670000000504800270000000000540004c000003010000613d000000000500001900000005065002100000000007610019000000000663034f000000000606043b00000000006704350000000105500039000000000645004b000002f90000413d000000000520004c000003100000613d0000000504400210000000000343034f00000000044100190000000302200210000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f000000000024043500000000028100190000000000020435000000090100002909a107800000040f00000006040000290000000001410049000000200210008a00000000002404350000001f01100039000000200200008a000000000221016f0000000001420019000000000221004b000000000200001900000001020040390000026f0310009c000003b10000213d0000000102200190000003910000613d000003b10000013d000000000106043300000044021000390000027003000041000000000032043500000024021000390000001703000039000000000032043500000271020000410000000000210435000000040210003900000020030000390000000000320435000000640200003909a106ff0000040f09a108e60000040f001300000001001d09a109260000040f000900000001001d0000000a010000290000000001010433000800000001001d0000001301000029001300000001001d0000000001010433000700000001001d0000001601000029000000150200002909a107120000040f00000008010000290000000703000029000000000113001900000000012100190000000902000029000000000202043300000000012100190000026f0110019709a1094a0000040f000500000001001d0000001601000029000000150200002909a107120000040f0000001403000029000000000403043300000274030000410000002005400039000400000005001d0000000000350435000800000001001d000700000002001d000600000004001d0000002102400039000000050100002909a107800000040f00000000020100190000000a0100002909a107800000040f0000000002010019000000130100002909a107800000040f00000007080000290000001f0280018f000000080300002900000001033003670000000504800270000000000540004c0000036f0000613d000000000500001900000005065002100000000007610019000000000663034f000000000606043b00000000006704350000000105500039000000000645004b000003670000413d000000000520004c0000037e0000613d0000000504400210000000000343034f00000000044100190000000302200210000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f000000000024043500000000028100190000000000020435000000090100002909a107800000040f00000006040000290000000001410049000000200210008a00000000002404350000001f01100039000000200200008a000000000221016f0000000001420019000000000221004b000000000200001900000001020040390000026f0310009c000003b10000213d0000000102200190000003b10000c13d000000140200002900000000001204350000000002040433000000040100002909a106cf0000040f00000001050003670000001603000029000000000235034f0000000004010019000000000102043b000000710210008c001300000004001d000003b90000c13d0000000e01000029000001e402100039000000000103001909a107120000040f000000000300003109a1073f0000040f0000000002010433000000200110003909a106cf0000040f00000013030000290000001405000029000000000405043300000040024000390000000000120435000000000054043500000020014000390000000000310435000002820240009c000004000000a13d000002810100004100000000001004350000004101000039000000040200003900000000001204350000002402000039000000000100001909a106ff0000040f000000000210004c0000040e0000c13d0000000c01000029000000000115034f000000000101043b000c00000005035309a108b10000040f0000000f020000290000000c0300035f000000000223034f000000000202043b000f00000001001d000000000102001909a108b10000040f00000010020000290000000c0300035f000000000223034f000000000202043b001000000001001d000000000102001909a108b10000040f0000000002010019000000100100002909a1078d0000040f00000011020000290000000c0300035f000000000223034f000000000202043b0000027302200197001100000001001d000000000102001909a108990000040f00000012020000290000000102200367000000000202043b000c00000001001d000000000102001909a108b10000040f001000000001001d0000001601000029000000150200002909a107120000040f0000026f01200197000000010210008c000004680000c13d0000001601000029000000150200002909a107120000040f000000000220004c0000007b0000613d0000000101100367000000000101043b000000010200008a0000026e03000041000000000221004b000000000200001900000000020320190000026e011001970000026e0410009c00000000030080190000026e011001670000026e0110009c000000000102001900000000010360190000006002000039000b00000002001d000000000110004c0000046a0000c13d09a107b40000040f000b00000001001d0000046a0000013d000000600540003900000014020000290000000000520435000000000204043309a106cf0000040f0000001402000029000000000402043300000020034000390000001305000029000000000053043500000000001404350000000001040019000000000300001909a106f50000040f000000020210008c000005270000c13d0000027201000041000000000010043909a106e60000040f09a108b10000040f0000000103000367000d0000000303530000000c02000029000000000223034f000000000202043b000c00000001001d000000000102001909a108b10000040f0000000b020000290000000d0300035f000000000223034f000000000202043b000b00000001001d000000000102001909a108b10000040f0000000f020000290000000d0300035f000000000223034f000000000202043b000f00000001001d000000000102001909a108b10000040f00000010020000290000000d0300035f000000000223034f000000000202043b001000000001001d000000000102001909a108b10000040f00000011020000290000000d0300035f000000000223034f000000000202043b0000027302200197001100000001001d000000000102001909a108990000040f00000012020000290000000102200367000000000202043b001200000001001d000000000102001909a108b10000040f00000000070100190000000c010000290000000b020000290000000f0300002900000010040000290000001105000029000000120600002909a108110000040f001100000001001d0000001601000029000000150200002909a107120000040f0000026f01200197000000010210008c000005790000c13d0000001601000029000000150200002909a107120000040f000000000220004c0000007b0000613d0000000101100367000000000101043b000000010200008a0000026e03000041000000000221004b000000000200001900000000020320190000026e011001970000026e0410009c00000000030080190000026e011001670000026e0110009c000000000102001900000000010360190000006002000039001000000002001d000000000110004c0000057b0000c13d09a107b40000040f001000000001001d0000057b0000013d09a108e60000040f000b00000001001d0000000e01000029000001e4021000390000001601000029001200000002001d09a107120000040f000000200220008c000006380000413d0000000101100367000000000101043b09a108b10000040f000e00000001001d0000001601000029000000120200002909a107120000040f000000400220008c000006380000413d00000020011000390000000101100367000000000101043b09a108b10000040f000a00000001001d0000001601000029000000120200002909a107120000040f000000410220008c0000007b0000413d00000040011000390000000101100367000000000101043b000000f801100270001200000001001d0000001b0110008a000000020110008c0000000001000019000000010100403909a107c80000040f0000000d010000290000000101100367000000000101043b000000000110004c0000001201000029000004a50000613d0000027201000041000000000010043909a106e60000040f0000000102100210000000000310004c000004a00000613d000000090300008a000000000332004b000006530000213d00000000311200d9000000020110008c000006530000c13d000000120300002900000000012300190000000801100039000000000231004b000006530000413d09a108b10000040f001200000001001d0000000b01000029000b00000001001d0000000001010433000d00000001001d00000010010000290000000001010433000900000001001d0000000c010000290000000001010433000800000001001d0000000f010000290000000001010433000700000001001d00000011010000290000000001010433000600000001001d0000001601000029000000150200002909a107120000040f00000007010000290000000603000029000000000113001900000008030000290000000001310019000000090300002900000000013100190000000d03000029000000000131001900000000012100190000000e02000029000000000202043300000000012100190000000a02000029000000000202043300000000012100190000001202000029000000000202043300000000012100190000026f0110019709a1094a0000040f000800000001001d0000001601000029000000150200002909a107120000040f00000014030000290000000003030433000d00000001001d000900000002001d001600000003001d00000020023000390000000801000029001500000002001d09a107800000040f00000000020100190000000f0100002909a107800000040f0000000002010019000000110100002909a107800000040f00000000020100190000000c0100002909a107800000040f0000000002010019000000100100002909a107800000040f00000000020100190000000b0100002909a107800000040f00000009040000290000001f0240018f0000000d03000029000000010330036700000000080400190000000504400270000000000540004c000004fc0000613d000000000500001900000005065002100000000007610019000000000663034f000000000606043b00000000006704350000000105500039000000000645004b000004f40000413d000000000520004c0000050b0000613d0000000504400210000000000343034f00000000044100190000000302200210000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f000000000024043500000000028100190000000000020435000000120100002909a107800000040f00000000020100190000000e0100002909a107800000040f00000000020100190000000a0100002909a107800000040f00000016040000290000000001410049000000200210008a00000000002404350000001f01100039000000200200008a000000000221016f0000000005420019000000000225004b000000000200001900000001020040390000026f0350009c00000013030000290000001501000029000003b10000213d0000000102200190000004010000613d000003b10000013d000000010110008c000006190000c13d0000027201000041000000000010043909a106e60000040f09a108b10000040f0000000103000367000d0000000303530000000c02000029000000000223034f000000000202043b000c00000001001d000000000102001909a108b10000040f0000000f020000290000000d0300035f000000000223034f000000000202043b000f00000001001d000000000102001909a108b10000040f00000010020000290000000d0300035f000000000223034f000000000202043b001000000001001d000000000102001909a108b10000040f00000011020000290000000d0300035f000000000223034f000000000202043b0000027302200197001100000001001d000000000102001909a108990000040f00000012020000290000000102200367000000000202043b001200000001001d000000000102001909a108b10000040f00000000060100190000000c010000290000000f0200002900000010030000290000001104000029000000120500002909a107da0000040f001100000001001d0000001601000029000000150200002909a107120000040f0000026f01200197000000010210008c000006240000c13d0000001601000029000000150200002909a107120000040f000000000220004c0000007b0000613d0000000101100367000000000101043b000000010200008a0000026e03000041000000000221004b000000000200001900000000020320190000026e011001970000026e0410009c00000000030080190000026e011001670000026e0110009c000000000102001900000000010360190000006002000039001000000002001d000000000110004c000006260000c13d09a107b40000040f001000000001001d000006260000013d09a108e60000040f001000000001001d09a109380000040f000f00000001001d0000000e01000029000001e4021000390000001601000029001200000002001d09a107120000040f000000200220008c000006380000413d0000000101100367000000000101043b09a108b10000040f000e00000001001d0000001601000029000000120200002909a107120000040f000000400220008c000006380000413d00000020011000390000000101100367000000000101043b09a108b10000040f000d00000001001d0000001601000029000000120200002909a107120000040f000000410220008c0000007b0000413d00000040011000390000000101100367000000000101043b001200000001001d000000f8011002700000001b0110008a000c00000001001d000000020110008c0000000001000019000000010100403909a107c80000040f0000001201000029000002800110009c000006530000413d0000000c0100002909a108b10000040f001200000001001d00000011010000290000000001010433000c00000001001d0000001001000029001000000001001d0000000001010433000b00000001001d0000001601000029000000150200002909a107120000040f0000000c010000290000000b03000029000000000113001900000000012100190000000f02000029000000000202043300000000012100190000000e02000029000000000202043300000000012100190000000d02000029000000000202043300000000012100190000001202000029000000000202043300000000012100190000026f0110019709a1094a0000040f000a00000001001d0000001601000029000000150200002909a107120000040f0000001403000029000000000403043300000275030000410000002005400039001500000005001d0000000000350435000c00000001001d000b00000002001d001600000004001d00000021024000390000000a0100002909a107800000040f0000000002010019000000110100002909a107800000040f0000000002010019000000100100002909a107800000040f0000000b040000290000001f0240018f0000000c03000029000000010330036700000000080400190000000504400270000000000540004c000005eb0000613d000000000500001900000005065002100000000007610019000000000663034f000000000606043b00000000006704350000000105500039000000000645004b000005e30000413d000000000520004c000005fa0000613d0000000504400210000000000343034f00000000044100190000000302200210000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f0000000000240435000000000281001900000000000204350000000f0100002909a107800000040f0000000002010019000000120100002909a107800000040f00000000020100190000000e0100002909a107800000040f00000000020100190000000d0100002909a107800000040f00000016040000290000000001410049000000200210008a00000000002404350000001f01100039000000200200008a000000000221016f0000000005420019000000000225004b000000000200001900000001020040390000026f0350009c00000013030000290000001501000029000003b10000213d0000000102200190000004010000613d000003b10000013d00000014010000290000000002010433001600000002001d00000271010000410000000000120435000000040120003909a107080000040f00000016030000290000000002310049000000000103001909a106ff0000040f09a108e60000040f001000000001001d09a109260000040f000f00000001001d0000000e01000029000001e4021000390000001601000029001200000002001d09a107120000040f000000200220008c000006380000413d0000000101100367000000000101043b09a108b10000040f000e00000001001d0000001601000029000000120200002909a107120000040f000000400220008c0000063b0000813d0000000001000019000000000200001909a106ff0000040f00000020011000390000000101100367000000000101043b09a108b10000040f000d00000001001d0000001601000029000000120200002909a107120000040f000000410220008c0000007b0000413d00000040011000390000000101100367000000000101043b001200000001001d000000f8011002700000001b0110008a000c00000001001d000000020110008c0000000001000019000000010100403909a107c80000040f0000001201000029000002800110009c0000065b0000813d000002810100004100000000001004350000001101000039000000040200003900000000001204350000002402000039000000000100001909a106ff0000040f0000000c0100002909a108b10000040f001200000001001d00000011010000290000000001010433000c00000001001d0000001001000029001000000001001d0000000001010433000b00000001001d0000001601000029000000150200002909a107120000040f0000000c010000290000000b03000029000000000113001900000000012100190000000f02000029000000000202043300000000012100190000000e02000029000000000202043300000000012100190000000d02000029000000000202043300000000012100190000001202000029000000000202043300000000012100190000026f0110019709a1094a0000040f000a00000001001d0000001601000029000000150200002909a107120000040f0000001403000029000000000403043300000274030000410000002005400039001500000005001d0000000000350435000c00000001001d000b00000002001d001600000004001d00000021024000390000000a0100002909a107800000040f0000000002010019000000110100002909a107800000040f0000000002010019000000100100002909a107800000040f0000000b040000290000001f0240018f0000000c03000029000000010330036700000000080400190000000504400270000000000540004c000006a10000613d000000000500001900000005065002100000000007610019000000000663034f000000000606043b00000000006704350000000105500039000000000645004b000006990000413d000000000520004c000006b00000613d0000000504400210000000000343034f00000000044100190000000302200210000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f0000000000240435000000000281001900000000000204350000000f0100002909a107800000040f0000000002010019000000120100002909a107800000040f00000000020100190000000e0100002909a107800000040f00000000020100190000000d0100002909a107800000040f00000016040000290000000001410049000000200210008a00000000002404350000001f01100039000000200200008a000000000221016f0000000005420019000000000225004b000000000200001900000001020040390000026f0350009c00000013030000290000001501000029000003b10000213d0000000102200190000004010000613d000003b10000013d0000026a030000410000026a0410009c000000000103801900000040011002100000026a0420009c00000000020380190000006002200210000000000112019f00000000020004140000026a0420009c0000000002038019000000c002200210000000000112019f00000275011001c7000080100200003909a1099c0000040f0000000102200190000006e30000613d000000000101043b000000000001042d0000000001000019000000000200001909a106ff0000040f0000026a0100004100000000020004140000026a0320009c0000000001024019000000c00110021000000283011001c70000800b0200003909a1099c0000040f0000000102200190000006f20000613d000000000101043b000000000001042d0000000001000019000000000200001909a106ff0000040f0000026a040000410000026a0510009c0000000001048019000000400110021000000000013100190000026a0320009c000000000204801900000060022002100000000001210019000009a20001042e0000026a030000410000026a0420009c00000000020380190000026a0410009c000000000103801900000040011002100000006002200210000000000112019f000009a300010430000000400210003900000284030000410000000000320435000000200210003900000013030000390000000000320435000000200200003900000000002104350000006001100039000000000001042d000000000300003100000000041300490000001f0540008a0000000104000367000000000224034f000000000202043b0000026e06000041000000000752004b000000000700001900000000070640190000026e055001970000026e08200197000000000958004b000000000600a019000000000558013f0000026e0550009c00000000050700190000000005066019000000000550004c0000073c0000613d0000000001120019000000000214034f000000000202043b0000026f0420009c0000073c0000213d000000000323004900000020011000390000026e04000041000000000531004b000000000500001900000000050420190000026e033001970000026e06100197000000000736004b0000000004008019000000000336013f0000026e0330009c00000000030500190000000003046019000000000330004c0000073c0000c13d000000000001042d0000000001000019000000000200001909a106ff0000040f0000000004010019000002850120009c000007750000813d0000003f01200039000000200500008a000000000651016f000000400500003900000000010504330000000006610019000000000716004b000000000700001900000001070040390000026f0860009c000007750000213d0000000107700190000007750000c13d000000000065043500000000002104350000000005420019000000000335004b0000077d0000213d0000001f0520018f000000010440036700000020031000390000000506200270000000000760004c000007630000613d000000000700001900000005087002100000000009830019000000000884034f000000000808043b00000000008904350000000107700039000000000867004b0000075b0000413d000000000750004c000007720000613d0000000506600210000000000464034f00000000066300190000000305500210000000000706043300000000075701cf000000000757022f000000000404043b0000010005500089000000000454022f00000000045401cf000000000474019f000000000046043500000000022300190000000000020435000000000001042d000002810100004100000000001004350000004101000039000000040200003900000000001204350000002402000039000000000100001909a106ff0000040f0000000001000019000000000200001909a106ff0000040f00000000030104330000000004000019000000000534004b0000078a0000813d00000000052400190000002004400039000000000614001900000000060604330000000000650435000007820000013d00000000012300190000000000010435000000000001042d0003000000000002000300000002001d0000004002000039000100000002001d0000000002020433000200000002001d000000200220003909a107800000040f0000000002010019000000030100002909a107800000040f00000002040000290000000001410049000000200210008a00000000002404350000001f01100039000000200200008a000000000221016f0000000001420019000000000221004b000000000200001900000001020040390000026f0310009c000007ac0000213d0000000102200190000007ac0000c13d0000000102000029000000000012043500000000010400190000000300000005000000000001042d000002810100004100000000001004350000004101000039000000040200003900000000001204350000002402000039000000000100001909a106ff0000040f00000040020000390000000001020433000002860310009c000007c00000813d0000004003100039000000000032043500000020021000390000028703000041000000000032043500000001020000390000000000210435000000000001042d000002810100004100000000001004350000004101000039000000040200003900000000001204350000002402000039000000000100001909a106ff0000040f000000000110004c000007cb0000613d000000000001042d0000004001000039000000000101043300000044021000390000028803000041000000000032043500000024021000390000000f03000039000000000032043500000271020000410000000000210435000000040210003900000020030000390000000000320435000000640200003909a106ff0000040f0007000000000002000700000006001d000600000005001d000400000004001d000300000003001d000200000002001d0000004002000039000100000002001d0000000002020433000500000002001d000000200220003909a107800000040f0000000002010019000000020100002909a107800000040f0000000002010019000000030100002909a107800000040f0000000002010019000000040100002909a107800000040f0000000002010019000000060100002909a107800000040f0000000002010019000000070100002909a107800000040f00000005040000290000000001410049000000200210008a00000000002404350000001f01100039000000200200008a000000000221016f0000000001420019000000000221004b000000000200001900000001020040390000026f0310009c000008090000213d0000000102200190000008090000c13d0000000102000029000000000012043500000000010400190000000700000005000000000001042d000002810100004100000000001004350000004101000039000000040200003900000000001204350000002402000039000000000100001909a106ff0000040f0008000000000002000800000007001d000700000006001d000500000005001d000400000004001d000300000003001d000200000002001d0000004002000039000100000002001d0000000002020433000600000002001d000000200220003909a107800000040f0000000002010019000000020100002909a107800000040f0000000002010019000000030100002909a107800000040f0000000002010019000000040100002909a107800000040f0000000002010019000000050100002909a107800000040f0000000002010019000000070100002909a107800000040f0000000002010019000000080100002909a107800000040f00000006040000290000000001410049000000200210008a00000000002404350000001f01100039000000200200008a000000000221016f0000000001420019000000000221004b000000000200001900000001020040390000026f0310009c000008440000213d0000000102200190000008440000c13d0000000102000029000000000012043500000000010400190000000800000005000000000001042d000002810100004100000000001004350000004101000039000000040200003900000000001204350000002402000039000000000100001909a106ff0000040f00000040020000390000000001020433000002860310009c000008640000813d0000004003100039000000000032043500000001020000390000000000210435000000200210003900000000030000310000000103300367000000000400001900000005054002100000000006520019000000000553034f000000000505043b00000000005604350000000104400039000000000540004c000000000500001900000001050060390000000105500190000008580000c13d000000000001042d000002810100004100000000001004350000004101000039000000040200003900000000001204350000002402000039000000000100001909a106ff0000040f0000000002010019000002850120009c000008910000813d0000003f01200039000000200300008a000000000431016f000000400300003900000000010304330000000004410019000000000514004b000000000500001900000001050040390000026f0640009c000008910000213d0000000105500190000008910000c13d000000000043043500000000002104350000001f022000390000000502200270000000000320004c0000088e0000613d000000200310003900000000040000310000000104400367000000000500001900000005065002100000000007630019000000000664034f000000000606043b00000000006704350000000105500039000000000625004b000008860000413d000000000200004c000008900000613d000000000001042d000002810100004100000000001004350000004101000039000000040200003900000000001204350000002402000039000000000100001909a106ff0000040f000000000201001900000040030000390000000001030433000002860410009c000008a90000813d0000004004100039000000000043043500000020031000390000028904000041000000000043043500000060022002100000002103100039000000000023043500000015020000390000000000210435000000000001042d000002810100004100000000001004350000004101000039000000040200003900000000001204350000002402000039000000000100001909a106ff0000040f00020000000000020000007f0210008c000200000001001d000008ce0000a13d09a109800000040f000100000001001d000000020110003909a1086c0000040f0000000002010433000000000220004c000008de0000613d000000200210003900000000030204330000028a033001970000000105000029000000f804500210000000000334019f000002870330004100000000003204350000000302500210000000f802200089000000020300002900000000032301cf000000ff0220008c0000000002030019000000000200201900000021031000390000000000230435000008dc0000013d09a1084c0000040f0000000002010433000000000220004c000008de0000613d0000000204000029000000f8024002100000026e03000041000000000440004c0000000002036019000000200310003900000000040304330000028a04400197000000000224019f00000000002304350000000200000005000000000001042d000002810100004100000000001004350000003201000039000000040200003900000000001204350000002402000039000000000100001909a106ff0000040f000200000000000200000000030100190000026f01300197000000010210008c000009160000613d000000370210008c000009070000a13d000200000001001d09a109800000040f000100000001001d000000020110003909a1086c0000040f0000000002010433000000000220004c0000091e0000613d000000200210003900000000030204330000028a033001970000000105000029000000f804500210000000000334019f0000028b0330004100000000003204350000000302500210000000f802200089000000020300002900000000032301cf000000ff0220008c0000000002030019000000000200201900000021031000390000000000230435000009140000013d000200000003001d09a1084c0000040f0000000002010433000000000220004c0000091e0000613d0000000202000029000000f802200210000000200310003900000000040304330000028a04400197000000000224019f0000026e0220016700000000002304350000000200000005000000000001042d000002810100004100000000001004350000000101000039000000040200003900000000001204350000002402000039000000000100001909a106ff0000040f000002810100004100000000001004350000003201000039000000040200003900000000001204350000002402000039000000000100001909a106ff0000040f09a1084c0000040f0000000002010433000000000220004c000009300000613d000000200210003900000000030204330000028a033001970000028c033001c70000000000320435000000000001042d000002810100004100000000001004350000003201000039000000040200003900000000001204350000002402000039000000000100001909a106ff0000040f09a1084c0000040f0000000002010433000000000220004c000009420000613d000000200210003900000000030204330000028a033001970000028c033001c70000000000320435000000000001042d000002810100004100000000001004350000003201000039000000040200003900000000001204350000002402000039000000000100001909a106ff0000040f000200000000000200000000030100190000026f01300197000000370210008c000009690000a13d000200000001001d09a109800000040f000100000001001d000000020110003909a1086c0000040f0000000002010433000000000220004c000009780000613d000000200210003900000000030204330000028a033001970000000105000029000000f804500210000000000334019f0000028d0330004100000000003204350000000302500210000000f802200089000000020300002900000000032301cf000000ff0220008c0000000002030019000000000200201900000021031000390000000000230435000009760000013d000200000003001d09a1084c0000040f0000000002010433000000000220004c000009780000613d0000000202000029000000f802200210000000200310003900000000040304330000028a04400197000000000242019f0000028c0220004100000000002304350000000200000005000000000001042d000002810100004100000000001004350000003201000039000000040200003900000000001204350000002402000039000000000100001909a106ff0000040f00000080021002700000028e0310009c000000000201a0190000028e0110009c0000000001000019000000100100203900000008031001bf0000026f0420009c000000000103201900000040032002700000026f0420009c000000000203201900000004031001bf0000026a0420009c000000000103201900000020032002700000026a0420009c000000000203201900000002031001bf0000ffff0420008c000000000103201900000010032002700000000002032019000000ff0220008c000000000200001900000001020020390000000001210019000000000001042d0000099f002104230000000102000039000000000001042d0000000002000019000000000001042d000009a100000432000009a20001042e000009a300010430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000200000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000000ebe4a3d7000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff456e636f64696e6720756e737570706f7274656420747800000000000000000008c379a0000000000000000000000000000000000000000000000000000000009a8a0592ac89c5ad3bc6df8224c17b485976f597df104ee20d0df415241f670b000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff848e1bfa1ac4e3576b728bda6721b215c70a7799a5b4866282a71bab954baac8000000000000000000000000000000000000000000000000fffffffffffffe1fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a519b453ce45aaaaf3a300f5a9ec95869b4f28ab10430b572ee218c3a6a5e07d6fc2f8787176b8ac6bf7215b4adcc1e069bf4ab82d9ab1df05a57a91d425935b6e000000000000000000000000000000000000000000000000ffffffffffffff5f1901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff7f80800000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000004e487b7100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff9f0200000200000000000000000000000000000004000000000000000000000000556e737570706f727465642074782074797065000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000ffffffffffffffc08100000000000000000000000000000000000000000000000000000000000000496e76616c696420762076616c75650000000000000000000000000000000000940000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb800000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000f80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff", - "0x000000000000000000000000000000000000800d": "0x000d000000000002000b0000000c001f000a0000000b001f00090000000a001f000800000009001f000700000008001f000600000007001f000500000006001f000400000005001f000300000004001f000200000003001f000c0000000103550000006001100270000000330010019d000100000002001f000000800300003900000040010000390000000000310435000000000300041600000001022001900000002e0000c13d000000000230004c000000380000c13d000000020200003900000001022001880000003b0000c13d0000000002000411000000350220009c0000003b0000413d000000000101043300000064021000390000003603000041000000000032043500000044021000390000003703000041000000000032043500000024021000390000002403000039000000000032043500000038020000410000000000210435000000040210003900000020030000390000000000320435000000840200003900c5004a0000040f000000000130004c000000380000c13d000000200200003900000100010000390000000000210439000001200200003900000000000204390000004002000039000000340300004100c500420000040f0000000001000019000000000200001900c5004a0000040f000000000100003100c500510000040f000000600100003900000000020104330000008001000039000000000300001900c500420000040f000000400110021000000000013100190000003303000041000000330420009c000000000203801900000060022002100000000001210019000000c60001042e0000003303000041000000330410009c000000000103801900000040011002100000006002200210000000000121019f000000c70001043000050000000000020000000203000031000000050230008c0000009b0000813d000300000001001d000000200210021000000000012300190000000101100039000000000221004b000000930000413d0000000002000411000000000021041f000000010110008c000000610000c13d0000000500000005000000000001042d000000020100008a000200000001001d0000000002000019000100000003001d000000000123004b000000930000413d0000000001230049000000010110008c0000007b0000a13d00000001012001bf000500000002001d00c500ad0000040f0000000502000029000400000001001d0000000201000029000000000112004b000000930000613d0000000202200039000500000002001d000000000102001900c500ad0000040f000000050200002900000001030000290000000404000029000000000014041e000000650000013d00000001013001900000000001000019000000840000613d000000000103001900c500ad0000040f0000000c02000367000000000202043b000000000021041e0000002001000039000000410200008a0000000303000029000000000331004b0000005f0000813d00000020031000390000000c04000367000000000334034f000000000414034f000000000404043b000000000303043b000000000034041e0000004003100039000000000121004b0000000001030019000000850000a13d000000390100004100000000001004350000001101000039000000040200003900000000001204350000002402000039000000000100001900c5004a0000040f0000004001000039000000000101043300000064021000390000003a03000041000000000032043500000044021000390000003b03000041000000000032043500000024021000390000002103000039000000000032043500000038020000410000000000210435000000040210003900000020030000390000000000320435000000840200003900c5004a0000040f0000000a0210008c000000b30000813d0000000501100210000000200110011a0000000201010031000000000001042d0000004001000039000000000101043300000064021000390000003c03000041000000000032043500000044021000390000003d03000041000000000032043500000024021000390000002603000039000000000032043500000038020000410000000000210435000000040210003900000020030000390000000000320435000000840200003900c5004a0000040f000000c500000432000000c60001042e000000c700010430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000666c61670000000000000000000000000000000000000000000000000000000054686973206d6574686f6420726571756972652073797374656d2063616c6c2008c379a0000000000000000000000000000000000000000000000000000000004e487b710000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000004f6e6c79203420696e6465786564206669656c64732061726520616c6c6f77656973746572730000000000000000000000000000000000000000000000000000546865726520617265206f6e6c792031302061636365737369626c65207265670000000000000000000000000000000000000000000000000000000000000000" - } -} +{"entry_point_address":"0xc54e30abb6a3eed1b9dc0494d90c9c22d76fba7e","entry_point_code":[[0,4,0,0,0,0,0,2,0,10,0,0,0,0,0,2,0,0,0,0,3,1,0,25,0,0,0,96,4,48,2,112],[0,0,3,119,3,64,1,151,0,3,0,0,0,49,3,85,0,2,0,0,0,1,3,85,0,0,3,119,0,64,1,157],[0,0,0,1,2,32,1,144,0,0,0,93,0,0,193,61,0,0,0,128,2,0,0,57,0,0,0,64,0,32,4,63],[0,0,0,4,2,48,0,140,0,0,0,144,0,0,65,61,0,0,0,0,1,1,4,59,0,0,0,224,1,16,2,112],[0,0,3,201,2,16,0,156,0,0,2,111,0,0,161,61,0,0,3,202,2,16,0,156,0,0,2,136,0,0,33,61],[0,0,3,209,2,16,0,156,0,0,2,186,0,0,161,61,0,0,3,210,2,16,0,156,0,0,2,245,0,0,97,61],[0,0,3,211,2,16,0,156,0,0,2,227,0,0,97,61,0,0,3,212,1,16,0,156,0,0,5,32,0,0,193,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61,0,0,3,228,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,3,229,1,16,1,199,0,0,0,2,2,0,0,57],[13,214,13,209,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,3,119,3,48,1,151],[0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143],[0,0,0,5,4,64,2,114,0,0,0,58,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,70,0,75,0,0,0,51,0,0,65,61,0,0,0,0,6,5,0,75,0,0,0,72,0,0,97,61],[0,0,0,3,5,80,2,16,0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51,0,0,0,0,6,86,1,207],[0,0,0,0,6,86,2,47,0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137],[0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159,0,0,0,0,0,84,4,53],[0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,64,8,0,4,61,0,0,0,1,2,32,1,144],[0,0,3,184,0,0,97,61,0,0,0,0,1,0,4,51,0,0,3,230,1,16,1,103,0,0,0,64,2,128,0,57],[0,0,0,0,0,18,4,53,0,0,0,32,1,128,0,57,0,0,3,230,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,64,1,0,0,57,0,0,0,0,0,24,4,53,0,0,0,0,1,8,0,25,0,10,0,0,0,8,0,29],[13,214,7,244,0,0,4,15,0,0,0,10,1,0,0,41,13,214,10,230,0,0,4,15,0,0,0,0,1,0,0,25],[0,0,13,216,0,1,4,48,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61],[0,0,3,120,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,0,1,0,4,16,0,10,0,0,0,1,0,29],[0,0,0,4,0,16,4,67,0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,3,121,1,16,1,199,0,0,128,2,2,0,0,57],[13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61,0,0,3,122,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,0,10,1,0,0,41,0,0,0,4,0,16,4,67,0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,3,121,1,16,1,199],[0,0,128,2,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,3,123,1,16,0,156,0,0,5,32,0,0,193,61,0,0,3,124,1,0,0,65],[0,0,0,160,0,16,4,63,0,0,0,4,1,0,0,57,0,0,0,128,0,16,4,63,0,0,0,192,1,0,0,57],[0,0,0,64,0,16,4,63,0,0,0,0,1,0,4,20,0,0,0,10,2,0,0,41,0,0,0,4,3,32,0,140],[0,0,3,13,0,0,193,61,0,0,0,1,2,0,0,57,0,0,0,1,3,0,0,49,0,0,3,24,0,0,1,61],[0,0,0,0,1,3,0,75,0,0,5,32,0,0,193,61,0,0,3,129,1,0,0,65,0,0,0,0,2,1,4,26],[0,0,0,0,2,2,0,75,0,0,5,32,0,0,193,61,0,0,0,1,2,0,0,57,0,5,0,0,0,2,0,29],[0,0,0,0,0,33,4,27,0,0,0,0,1,0,4,18,0,0,3,130,1,16,1,151,0,0,0,0,2,0,4,16],[0,0,0,0,1,33,0,75,0,0,2,160,0,0,193,61,0,2,0,0,0,2,0,29,0,0,3,134,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57],[13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,1,1,0,75,0,0,3,37,0,0,193,61,0,0,3,136,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,3,119,3,0,0,65,0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156,0,0,0,0,1,3,128,25],[0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,10,2,0,0,57],[0,0,0,0,0,18,4,27,0,0,3,137,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,0,1,0,4,20],[0,0,3,119,2,16,0,156,0,0,3,119,1,0,128,65,0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199],[0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,9,2,0,0,57,0,0,0,0,3,2,4,26,0,0,3,138,3,48,1,151],[0,0,0,0,1,19,1,159,0,0,0,0,0,18,4,27,0,0,3,139,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,3,119,3,0,0,65,0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156,0,0,0,0,1,3,128,25],[0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,8,2,0,0,57],[0,0,0,0,0,18,4,27,0,0,3,140,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,0,1,0,4,20],[0,0,3,119,2,16,0,156,0,0,3,119,1,0,128,65,0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199],[0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,7,2,0,0,57,0,0,0,0,0,18,4,27,0,0,3,141,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,3,119,3,0,0,65,0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57],[13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,6,2,0,0,57,0,0,0,0,0,18,4,27,0,0,3,142,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156,0,0,3,119,1,0,128,65,0,0,0,192,1,16,2,16],[0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,5,147,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,3,2,0,0,57,0,0,0,0,0,18,4,27],[0,0,3,143,1,0,0,65,0,0,0,0,0,16,4,57,0,0,3,119,3,0,0,65,0,0,0,0,1,0,4,20],[0,0,3,119,2,16,0,156,0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199],[0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,3,130,1,16,1,151,0,0,0,4,2,0,0,57,0,0,0,0,3,2,4,26],[0,0,3,138,3,48,1,151,0,0,0,0,1,19,1,159,0,0,0,0,0,18,4,27,0,0,0,2,1,0,0,57],[0,0,0,0,2,1,4,26,0,0,3,144,2,32,1,151,0,0,0,2,3,0,3,103,0,0,0,0,3,3,4,59],[0,0,0,224,3,48,2,112,0,0,0,0,2,50,1,159,0,0,0,0,0,33,4,27,0,0,3,134,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156,0,0,3,119,1,0,128,65],[0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,5,2,0,0,57],[0,0,0,0,0,18,4,27,0,0,0,11,1,0,0,57,0,0,0,0,2,0,4,22,0,0,0,0,0,33,4,27],[0,0,0,0,1,0,4,20,0,1,0,0,0,1,0,29,0,0,0,64,1,0,4,61,0,0,0,0,5,1,0,25],[0,0,3,145,1,16,0,156,0,0,3,58,0,0,33,61,0,0,0,160,1,80,0,57,0,0,0,64,0,16,4,63],[0,0,0,128,1,80,0,57,0,0,3,146,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,96,1,80,0,57],[0,0,3,147,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,64,1,80,0,57,0,0,3,148,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,122,1,0,0,57,0,0,0,0,10,21,4,54,0,0,3,149,1,0,0,65],[0,0,0,0,0,26,4,53,0,4,128,16,0,0,0,61,0,8,0,0,0,0,0,29,0,10,0,0,0,5,0,29],[0,0,3,119,1,160,0,156,0,0,3,119,4,0,0,65,0,0,0,0,10,4,128,25,0,0,0,64,1,160,2,16],[0,0,0,0,2,5,4,51,0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,96,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,3,150,1,16,1,199,0,0,0,4,2,0,0,41],[13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,5,32,0,0,97,61,0,0,0,64,2,0,4,61],[0,0,0,0,1,1,4,59,0,9,0,0,0,1,0,29,0,0,0,10,6,0,0,41,0,0,0,0,1,6,4,51],[0,0,0,0,3,1,0,75,0,0,1,110,0,0,97,61,0,0,0,0,3,0,0,25,0,0,0,0,4,35,0,25],[0,0,0,32,3,48,0,57,0,0,0,0,5,99,0,25,0,0,0,0,5,5,4,51,0,0,0,0,0,84,4,53],[0,0,0,0,4,19,0,75,0,0,1,103,0,0,65,61,0,0,0,0,3,33,0,25,0,0,0,0,0,3,4,53],[0,0,3,119,3,32,0,156,0,0,3,119,4,0,0,65,0,0,0,0,2,4,128,25,0,0,0,64,2,32,2,16],[0,0,3,119,3,16,0,156,0,0,0,0,1,4,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159],[0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,0,2,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,5,3,0,25],[0,0,0,32,5,0,128,57,0,0,0,5,4,80,2,114,0,0,1,143,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,70,0,75,0,0,1,136,0,0,65,61,0,0,0,31,5,80,1,144],[0,0,1,157,0,0,97,61,0,0,0,3,5,80,2,16,0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51],[0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47,0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159],[0,0,0,0,0,84,4,53,0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,64,11,0,4,61],[0,0,0,1,2,32,1,144,0,0,3,251,0,0,97,61,0,0,0,0,2,0,4,51,0,0,0,32,12,176,0,57],[0,0,0,10,6,0,0,41,0,0,0,0,1,6,4,51,0,0,0,0,3,1,0,75,0,0,1,176,0,0,97,61],[0,0,0,0,3,0,0,25,0,0,0,0,4,195,0,25,0,0,0,32,3,48,0,57,0,0,0,0,5,99,0,25],[0,0,0,0,5,5,4,51,0,0,0,0,0,84,4,53,0,0,0,0,4,19,0,75,0,0,1,169,0,0,65,61],[0,0,0,9,2,32,1,79,0,0,0,0,3,193,0,25,0,0,0,0,0,35,4,53,0,0,0,32,3,16,0,57],[0,0,0,0,0,59,4,53,0,0,0,95,3,16,0,57,0,0,0,32,1,0,0,138,0,0,0,0,3,19,1,111],[0,0,0,0,13,179,0,25,0,0,0,0,3,61,0,75,0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57],[0,0,3,127,4,208,0,156,0,0,3,58,0,0,33,61,0,0,0,1,3,48,1,144,0,0,3,58,0,0,193,61],[0,0,0,64,0,208,4,63,0,0,0,12,10,0,0,57,0,0,0,0,3,10,4,26,0,0,3,127,4,48,0,156],[0,0,3,58,0,0,33,61,0,0,0,1,4,48,0,57,0,0,0,0,0,74,4,27,0,0,0,0,0,160,4,53],[0,0,3,151,3,48,0,65,0,0,0,0,0,35,4,27,0,0,0,0,3,10,4,26,0,0,0,0,4,3,0,75],[0,0,3,52,0,0,97,61,0,0,0,1,6,48,0,140,0,0,0,5,3,0,0,41,0,0,1,233,0,0,97,61],[0,0,0,0,3,10,4,26,0,0,0,0,4,99,0,75,0,0,5,3,0,0,161,61,0,0,0,1,4,96,0,138],[0,0,0,1,5,64,2,112,0,0,0,0,7,83,0,75,0,0,5,3,0,0,161,61,0,0,3,151,7,96,0,65],[0,0,0,0,9,7,4,26,0,0,0,0,0,160,4,53,0,0,3,151,6,80,0,65,0,0,0,0,8,6,4,26],[0,0,0,0,9,137,0,75,0,0,1,233,0,0,161,61,0,0,0,0,0,135,4,27,0,0,0,0,3,10,4,26],[0,0,0,0,3,83,0,75,0,0,5,3,0,0,161,61,0,0,0,0,0,38,4,27,0,0,0,2,3,64,0,140],[0,0,0,0,6,5,0,25,0,0,1,208,0,0,129,61,0,0,0,0,3,10,4,26,0,0,0,0,2,3,0,75],[0,0,3,52,0,0,97,61,0,0,0,1,2,48,0,138,0,0,0,0,2,35,1,112,0,0,1,245,0,0,193,61],[0,0,0,13,2,0,0,57,0,0,0,0,3,2,4,26,0,0,3,127,4,48,1,151,0,0,3,127,5,64,0,156],[0,0,3,52,0,0,97,61,0,0,3,152,3,48,1,151,0,0,0,1,4,64,0,57,0,0,0,0,3,52,1,159],[0,0,0,0,0,50,4,27,0,7,0,0,0,12,0,29,0,10,0,0,0,10,0,29,0,0,3,153,2,0,0,65],[0,0,0,0,0,45,4,53,0,0,0,4,2,208,0,57,0,0,0,32,3,0,0,57,0,3,0,0,0,3,0,29],[0,0,0,0,0,50,4,53,0,0,0,0,2,11,4,51,0,0,0,36,3,208,0,57,0,0,0,0,0,35,4,53],[0,0,0,68,3,208,0,57,0,0,0,0,4,2,0,75,0,0,2,11,0,0,97,61,0,0,0,0,4,0,0,25],[0,0,0,0,5,52,0,25,0,0,0,32,4,64,0,57,0,0,0,0,6,180,0,25,0,0,0,0,6,6,4,51],[0,0,0,0,0,101,4,53,0,0,0,0,5,36,0,75,0,0,2,4,0,0,65,61,0,9,0,0,0,11,0,29],[0,0,0,0,3,50,0,25,0,0,0,0,0,3,4,53,0,0,0,31,2,32,0,57,0,0,0,0,1,18,1,111],[0,0,3,119,2,208,0,156,0,0,3,119,4,0,0,65,0,0,0,0,2,4,0,25,0,0,0,0,2,13,64,25],[0,0,0,64,2,32,2,16,0,0,0,68,1,16,0,57,0,0,3,119,3,16,0,156,0,0,0,0,1,4,128,25],[0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156],[0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,128,8,2,0,0,57],[0,6,0,0,0,13,0,29,13,214,13,204,0,0,4,15,0,0,0,6,11,0,0,41,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25],[0,0,0,32,4,0,128,57,0,0,0,5,5,64,2,114,0,0,2,52,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,123,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,2,44,0,0,65,61],[0,0,0,31,6,64,1,144,0,0,0,10,9,0,0,41,0,0,0,7,10,0,0,41,0,0,2,69,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,7,81,3,79,0,0,0,0,5,91,0,25,0,0,0,3,6,96,2,16],[0,0,0,0,8,5,4,51,0,0,0,0,8,104,1,207,0,0,0,0,8,104,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,6,96,0,137,0,0,0,0,7,103,2,47,0,0,0,0,6,103,1,207,0,0,0,0,6,134,1,159],[0,0,0,0,0,101,4,53,0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144],[0,0,0,9,5,0,0,41,0,0,4,27,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,2,16,1,143],[0,0,0,0,1,178,0,25,0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57],[0,0,3,127,4,16,0,156,0,0,3,58,0,0,33,61,0,0,0,1,2,32,1,144,0,0,3,58,0,0,193,61],[0,0,0,64,0,16,4,63,0,0,0,32,2,48,0,140,0,0,5,32,0,0,65,61,0,0,0,8,3,0,0,41],[0,0,0,2,2,48,0,140,0,8,0,1,0,48,0,61,0,0,1,75,0,0,161,61,0,0,0,0,2,9,4,26],[0,0,0,0,3,2,0,75,0,0,4,60,0,0,193,61,0,0,0,68,2,16,0,57,0,0,3,198,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,1,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,3,131,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,3,3,0,0,41],[0,0,0,0,0,50,4,53,0,0,3,119,2,0,0,65,0,0,3,119,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,64,1,16,2,16,0,0,3,159,1,16,1,199,0,0,13,216,0,1,4,48,0,0,3,215,2,16,0,156],[0,0,2,149,0,0,161,61,0,0,3,216,2,16,0,156,0,0,2,179,0,0,161,61,0,0,3,217,2,16,0,156],[0,0,2,222,0,0,97,61,0,0,3,218,2,16,0,156,0,0,2,217,0,0,97,61,0,0,3,219,1,16,0,156],[0,0,5,32,0,0,193,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61],[0,0,0,12,1,0,0,57,0,0,0,0,5,1,4,26,0,0,0,0,2,5,0,75,0,0,3,107,0,0,193,61],[0,0,3,131,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63],[0,0,0,1,1,0,0,57,0,0,0,164,0,16,4,63,0,0,3,198,1,0,0,65,0,0,2,167,0,0,1,61],[0,0,3,203,2,16,0,156,0,0,2,196,0,0,161,61,0,0,3,204,2,16,0,156,0,0,2,251,0,0,97,61],[0,0,3,205,2,16,0,156,0,0,2,232,0,0,97,61,0,0,3,206,1,16,0,156,0,0,5,32,0,0,193,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61,0,0,0,4,1,0,0,57],[0,0,2,242,0,0,1,61,0,0,3,222,2,16,0,156,0,0,2,170,0,0,33,61,0,0,3,225,2,16,0,156],[0,0,2,205,0,0,97,61,0,0,3,226,1,16,0,156,0,0,5,32,0,0,193,61,0,0,0,0,1,0,4,22],[0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61,0,0,0,3,1,0,0,57,0,0,3,9,0,0,1,61],[0,0,3,131,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63],[0,0,0,16,1,0,0,57,0,0,0,164,0,16,4,63,0,0,3,132,1,0,0,65,0,0,0,196,0,16,4,63],[0,0,3,133,1,0,0,65,0,0,13,216,0,1,4,48,0,0,3,223,2,16,0,156,0,0,2,210,0,0,97,61],[0,0,3,224,1,16,0,156,0,0,5,32,0,0,193,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,5,32,0,0,193,61,0,0,0,6,1,0,0,57,0,0,3,9,0,0,1,61,0,0,3,220,2,16,0,156],[0,0,2,238,0,0,97,61,0,0,3,221,1,16,0,156,0,0,5,32,0,0,193,61,13,214,7,255,0,0,4,15],[0,0,0,0,1,0,0,25,0,0,13,215,0,1,4,46,0,0,3,213,2,16,0,156,0,0,3,0,0,0,97,61],[0,0,3,214,1,16,0,156,0,0,5,32,0,0,193,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,5,32,0,0,193,61,13,214,11,176,0,0,4,15,0,0,0,0,1,0,0,25,0,0,13,215,0,1,4,46],[0,0,3,207,2,16,0,156,0,0,3,5,0,0,97,61,0,0,3,208,1,16,0,156,0,0,5,32,0,0,193,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61,0,0,0,11,1,0,0,57],[0,0,3,9,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61],[0,0,0,0,1,0,4,26,0,0,2,243,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,5,32,0,0,193,61,0,0,0,2,1,0,0,57,0,0,0,0,1,1,4,26,0,0,0,224,1,16,2,16],[0,0,3,10,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61],[0,0,0,10,1,0,0,57,0,0,3,9,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,5,32,0,0,193,61,0,0,0,7,1,0,0,57,0,0,3,9,0,0,1,61,0,0,0,0,1,0,4,22],[0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61,0,0,3,124,1,0,0,65,0,0,3,10,0,0,1,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61,13,214,11,113,0,0,4,15],[0,0,0,0,1,0,0,25,0,0,13,215,0,1,4,46,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,5,32,0,0,193,61,0,0,0,9,1,0,0,57,0,0,0,0,1,1,4,26,0,0,3,130,1,16,1,151],[0,0,3,10,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61],[13,214,8,206,0,0,4,15,0,0,0,0,1,0,0,25,0,0,13,215,0,1,4,46,0,0,0,0,1,0,4,22],[0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61,0,0,0,5,1,0,0,57,0,0,3,9,0,0,1,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61,0,0,0,8,1,0,0,57],[0,0,3,9,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61],[0,0,0,1,1,0,0,57,0,0,0,0,1,1,4,26,0,0,0,128,0,16,4,63,0,0,3,227,1,0,0,65],[0,0,13,215,0,1,4,46,0,0,3,119,4,0,0,65,0,0,3,119,3,16,0,156,0,0,0,0,1,4,128,25],[0,0,0,192,1,16,2,16,0,0,3,125,1,16,1,199,13,214,13,204,0,0,4,15,0,0,0,1,2,32,1,143],[0,3,0,0,0,1,3,85,0,0,0,96,1,16,2,112,0,1,3,119,0,16,1,157,0,0,3,119,3,16,1,151],[0,0,0,96,1,0,0,57,0,0,0,0,4,3,0,75,0,0,3,56,0,0,193,61,0,0,0,0,2,2,0,75],[0,0,5,32,0,0,97,61,0,0,0,0,1,1,4,51,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61],[0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,3,128,1,0,0,65],[0,0,13,215,0,1,4,46,0,0,3,134,1,0,0,65,0,0,0,0,0,16,4,57,0,0,3,119,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,5,147,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,3,218,0,0,193,61],[0,0,3,199,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57,0,0,5,6,0,0,1,61],[0,0,3,126,1,48,0,156,0,0,3,62,0,0,65,61,0,0,3,199,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,65,1,0,0,57,0,0,5,6,0,0,1,61,0,0,0,31,1,48,0,57,0,0,0,32,4,0,0,138],[0,0,0,0,1,65,1,111,0,0,0,63,1,16,0,57,0,0,0,0,4,65,1,111,0,0,0,64,1,0,4,61],[0,0,0,0,4,65,0,25,0,0,0,0,5,20,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57],[0,0,3,127,6,64,0,156,0,0,3,58,0,0,33,61,0,0,0,1,5,80,1,144,0,0,3,58,0,0,193,61],[0,0,0,64,0,64,4,63,0,0,0,31,4,48,1,143,0,0,0,0,5,49,4,54,0,0,0,3,6,0,3,103],[0,0,0,5,3,48,2,114,0,0,3,91,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16],[0,0,0,0,9,133,0,25,0,0,0,0,8,134,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53],[0,0,0,1,7,112,0,57,0,0,0,0,8,55,0,75,0,0,3,83,0,0,65,61,0,0,0,0,7,4,0,75],[0,0,3,27,0,0,97,61,0,0,0,5,3,48,2,16,0,0,0,0,6,54,3,79,0,0,0,0,3,53,0,25],[0,0,0,3,4,64,2,16,0,0,0,0,5,3,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47],[0,0,0,0,6,6,4,59,0,0,1,0,4,64,0,137,0,0,0,0,6,70,2,47,0,0,0,0,4,70,1,207],[0,0,0,0,4,84,1,159,0,0,0,0,0,67,4,53,0,0,3,27,0,0,1,61,0,0,3,151,2,0,0,65],[0,0,0,1,3,0,0,57,0,0,3,157,4,0,0,65,0,0,3,119,0,0,1,61,0,0,0,1,6,0,0,138],[0,0,0,0,6,101,0,75,0,0,3,52,0,0,97,61,0,0,0,1,6,80,0,57,0,0,0,0,6,86,1,112],[0,0,3,174,0,0,97,61,0,0,0,0,6,5,0,75,0,0,3,249,0,0,97,61,0,0,3,154,6,80,0,65],[0,0,0,0,7,6,4,26,0,0,0,0,0,114,4,27,0,0,0,0,0,6,4,27,0,0,0,1,5,80,0,138],[0,0,0,0,0,81,4,27,0,0,0,2,6,80,0,140,0,0,3,114,0,0,65,61,0,0,0,0,8,3,0,25],[0,0,0,0,9,0,0,25,0,0,0,0,7,0,0,25,0,0,0,2,10,144,0,57,0,0,0,0,6,90,0,75],[0,0,0,0,6,8,0,25,0,0,3,141,0,0,129,61,0,0,3,155,6,144,0,65,0,0,0,0,6,6,4,26],[0,0,3,156,9,144,0,65,0,0,0,0,9,9,4,26,0,0,0,0,6,105,0,75,0,0,0,0,6,8,0,25],[0,0,0,0,6,10,64,25,0,0,0,0,8,101,0,75,0,0,5,3,0,0,161,61,0,0,3,151,8,96,0,65],[0,0,0,0,9,117,0,75,0,0,5,3,0,0,161,61,0,0,0,0,9,8,4,26,0,0,3,151,10,112,0,65],[0,0,0,0,7,10,4,26,0,0,0,0,11,121,0,75,0,0,3,111,0,0,161,61,0,0,0,0,0,154,4,27],[0,0,0,0,5,1,4,26,0,0,0,0,5,101,0,75,0,0,5,3,0,0,161,61,0,0,0,0,0,120,4,27],[0,0,0,0,5,6,0,75,0,0,0,0,5,0,0,25,0,0,0,0,5,4,64,25,0,0,3,157,7,96,1,151],[0,0,0,0,8,7,0,75,0,0,0,0,8,0,0,25,0,0,0,0,8,4,32,25,0,0,3,157,7,112,0,156],[0,0,0,0,8,5,192,25,0,0,0,0,5,8,0,75,0,0,3,52,0,0,193,61,0,0,0,0,5,1,4,26],[0,0,0,1,9,96,2,16,0,0,0,1,8,144,1,191,0,0,0,0,7,88,0,75,0,0,0,0,7,6,0,25],[0,0,3,130,0,0,65,61,0,0,3,111,0,0,1,61,0,0,0,13,6,0,0,57,0,0,0,0,7,6,4,26],[0,0,3,127,8,112,1,151,0,0,0,1,8,128,0,138,0,0,3,127,9,128,0,156,0,0,3,52,0,0,33,61],[0,0,3,152,7,112,1,151,0,0,0,0,7,120,1,159,0,0,0,0,0,118,4,27,0,0,3,117,0,0,1,61],[0,0,0,31,2,48,1,143,0,0,0,5,4,48,2,114,0,0,3,196,0,0,97,61,0,0,0,0,5,0,0,25],[0,0,0,5,6,80,2,16,0,0,0,0,7,104,0,25,0,0,0,0,6,97,3,79,0,0,0,0,6,6,4,59],[0,0,0,0,0,103,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,69,0,75,0,0,3,188,0,0,65,61],[0,0,0,0,5,2,0,75,0,0,3,211,0,0,97,61,0,0,0,5,4,64,2,16,0,0,0,0,1,65,3,79],[0,0,0,0,4,72,0,25,0,0,0,3,2,32,2,16,0,0,0,0,5,4,4,51,0,0,0,0,5,37,1,207],[0,0,0,0,5,37,2,47,0,0,0,0,1,1,4,59,0,0,1,0,2,32,0,137,0,0,0,0,1,33,2,47],[0,0,0,0,1,33,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,20,4,53,0,0,3,119,1,0,0,65],[0,0,3,119,2,128,0,156,0,0,0,0,8,1,128,25,0,0,0,64,1,128,2,16,0,0,0,96,2,48,2,16],[0,0,0,0,1,33,1,159,0,0,13,216,0,1,4,48,0,0,3,134,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,3,119,3,0,0,65,0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156,0,0,0,0,1,3,128,25],[0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61,0,0,0,0,1,1,4,59,0,10,0,0,0,1,0,29],[0,0,3,134,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156],[0,0,3,119,1,0,128,65,0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57],[13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61,0,0,0,10,2,0,0,41],[0,0,3,232,2,32,0,57,0,0,0,0,1,1,4,59,0,0,0,0,1,33,0,75,0,0,3,52,0,0,33,61],[0,0,0,174,0,0,1,61,0,0,0,0,0,16,4,53,0,0,2,128,0,0,1,61,0,0,0,31,2,48,1,143],[0,0,0,5,4,48,2,114,0,0,4,7,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16],[0,0,0,0,7,107,0,25,0,0,0,0,6,97,3,79,0,0,0,0,6,6,4,59,0,0,0,0,0,103,4,53],[0,0,0,1,5,80,0,57,0,0,0,0,6,69,0,75,0,0,3,255,0,0,65,61,0,0,0,0,5,2,0,75],[0,0,4,22,0,0,97,61,0,0,0,5,4,64,2,16,0,0,0,0,1,65,3,79,0,0,0,0,4,75,0,25],[0,0,0,3,2,32,2,16,0,0,0,0,5,4,4,51,0,0,0,0,5,37,1,207,0,0,0,0,5,37,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,2,32,0,137,0,0,0,0,1,33,2,47,0,0,0,0,1,33,1,207],[0,0,0,0,1,81,1,159,0,0,0,0,0,20,4,53,0,0,3,119,1,0,0,65,0,0,3,119,2,176,0,156],[0,0,0,0,11,1,128,25,0,0,0,64,1,176,2,16,0,0,3,215,0,0,1,61,0,0,0,64,2,0,4,61],[0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,4,40,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,4,32,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,4,55,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,3,119,1,0,0,65],[0,0,3,119,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,3,215,0,0,1,61],[0,0,3,154,3,32,0,65,0,0,0,0,4,3,4,26,0,0,3,151,5,0,0,65,0,0,0,0,0,69,4,27],[0,0,0,10,10,0,0,41,0,0,0,0,0,160,4,53,0,0,0,0,0,3,4,27,0,0,0,1,3,32,0,138],[0,0,0,0,0,58,4,27,0,0,0,2,2,48,0,140,0,0,4,122,0,0,65,61,0,0,0,1,6,0,0,57],[0,0,3,157,2,0,0,65,0,0,0,0,7,0,0,25,0,0,0,0,5,0,0,25,0,0,0,2,8,112,0,57],[0,0,0,0,4,56,0,75,0,0,0,0,4,6,0,25,0,0,4,86,0,0,129,61,0,0,3,155,4,112,0,65],[0,0,0,0,4,4,4,26,0,0,3,156,7,112,0,65,0,0,0,0,7,7,4,26,0,0,0,0,4,71,0,75],[0,0,0,0,4,6,0,25,0,0,0,0,4,8,64,25,0,0,0,0,6,67,0,75,0,0,5,3,0,0,161,61],[0,0,3,151,6,64,0,65,0,0,0,0,7,83,0,75,0,0,5,3,0,0,161,61,0,0,0,0,7,6,4,26],[0,0,0,0,0,160,4,53,0,0,3,151,8,80,0,65,0,0,0,0,5,8,4,26,0,0,0,0,9,87,0,75],[0,0,4,119,0,0,161,61,0,0,0,0,0,120,4,27,0,0,0,0,3,10,4,26,0,0,0,0,3,67,0,75],[0,0,5,3,0,0,161,61,0,0,0,0,0,86,4,27,0,0,0,0,3,4,0,75,0,0,0,0,3,0,0,25],[0,0,0,0,3,2,64,25,0,0,3,157,5,64,1,151,0,0,0,0,6,5,0,75,0,0,0,0,6,0,0,25],[0,0,0,0,6,2,32,25,0,0,3,157,5,80,0,156,0,0,0,0,6,3,192,25,0,0,0,0,3,6,0,75],[0,0,3,52,0,0,193,61,0,0,0,0,3,10,4,26,0,0,0,1,7,64,2,16,0,0,0,1,6,112,1,191],[0,0,0,0,5,54,0,75,0,0,0,0,5,4,0,25,0,0,4,75,0,0,65,61,0,0,0,1,2,0,0,138],[0,0,0,0,2,35,0,75,0,0,3,52,0,0,97,61,0,0,0,1,2,48,0,57,0,0,0,0,2,50,1,112],[0,0,4,134,0,0,193,61,0,0,0,13,2,0,0,57,0,0,0,0,3,2,4,26,0,0,3,127,4,48,1,151],[0,0,0,1,4,64,0,138,0,0,3,127,5,64,0,156,0,0,3,52,0,0,33,61,0,0,3,152,3,48,1,151],[0,0,0,0,3,52,1,159,0,0,0,0,0,50,4,27,0,0,0,0,3,0,4,20,0,8,0,0,0,3,0,29],[0,0,0,1,2,48,0,107,0,0,5,9,0,0,161,61,0,0,0,9,6,0,0,41,0,0,0,0,2,6,4,51],[0,0,0,0,3,2,0,75,0,0,4,150,0,0,97,61,0,0,0,0,3,0,0,25,0,0,0,0,4,19,0,25],[0,0,0,32,3,48,0,57,0,0,0,0,5,99,0,25,0,0,0,0,5,5,4,51,0,0,0,0,0,84,4,53],[0,0,0,0,4,35,0,75,0,0,4,143,0,0,65,61,0,0,0,0,3,18,0,25,0,0,0,0,0,3,4,53],[0,0,3,119,4,0,0,65,0,0,3,119,3,16,0,156,0,0,0,0,1,4,128,25,0,0,0,64,1,16,2,16],[0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,96,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,3,150,1,16,1,199,0,0,128,16,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,5,32,0,0,97,61,0,0,0,8,3,0,0,41,0,0,0,1,2,48,0,105],[0,0,0,0,5,1,4,59,0,0,0,64,1,0,4,61,0,0,0,0,0,33,4,53,0,0,0,0,2,0,4,20],[0,0,3,119,3,32,0,156,0,0,3,119,4,0,0,65,0,0,0,0,2,4,128,25,0,0,3,119,3,16,0,156],[0,0,0,0,1,4,128,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,3,160,1,16,1,199,0,0,128,13,2,0,0,57,0,0,0,2,3,0,0,57,0,0,3,161,4,0,0,65],[13,214,13,204,0,0,4,15,0,0,0,10,5,0,0,41,0,0,0,1,1,32,1,144,0,0,5,32,0,0,97,61],[0,0,0,64,2,0,4,61,0,0,3,162,1,32,0,156,0,0,3,58,0,0,33,61,0,0,0,192,1,32,0,57],[0,0,0,64,0,16,4,63,0,0,0,160,1,32,0,57,0,0,3,163,3,0,0,65,0,0,0,0,0,49,4,53],[0,0,0,128,3,32,0,57,0,0,3,164,1,0,0,65,0,0,0,0,0,19,4,53,0,0,0,96,3,32,0,57],[0,0,0,0,0,19,4,53,0,0,0,64,3,32,0,57,0,0,0,0,0,19,4,53,0,0,0,32,3,32,0,57],[0,0,0,0,0,19,4,53,0,0,0,135,3,0,0,57,0,0,0,0,0,50,4,53,0,0,0,64,2,0,4,61],[0,0,3,162,3,32,0,156,0,0,3,58,0,0,33,61,0,0,0,192,3,32,0,57,0,0,0,64,0,48,4,63],[0,0,0,160,3,32,0,57,0,0,3,165,4,0,0,65,0,0,0,0,0,67,4,53,0,0,0,128,3,32,0,57],[0,0,0,0,0,19,4,53,0,0,0,96,3,32,0,57,0,0,0,0,0,19,4,53,0,0,0,64,3,32,0,57],[0,0,0,0,0,19,4,53,0,0,0,32,3,32,0,57,0,0,0,0,0,19,4,53,0,0,0,136,1,0,0,57],[0,0,0,0,0,18,4,53,0,0,0,64,1,0,4,61,0,0,3,162,2,16,0,156,0,0,3,58,0,0,33,61],[0,0,0,192,2,16,0,57,0,0,0,64,0,32,4,63,0,0,0,160,2,16,0,57,0,0,3,166,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,128,2,16,0,57,0,0,3,164,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,96,2,16,0,57,0,0,0,0,0,50,4,53,0,0,0,64,2,16,0,57,0,0,0,0,0,50,4,53],[0,0,0,32,2,16,0,57,0,0,0,0,0,50,4,53,0,0,0,137,2,0,0,57,0,0,0,0,0,33,4,53],[0,0,0,0,1,5,4,26,0,9,0,0,0,1,0,29,0,0,0,0,1,1,0,75,0,0,5,15,0,0,193,61],[0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,3,197,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,24,3,0,0,57,0,0,2,99,0,0,1,61,0,0,3,199,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,50,1,0,0,57,0,0,0,4,0,16,4,63,0,0,3,200,1,0,0,65],[0,0,13,216,0,1,4,48,0,0,0,68,2,16,0,57,0,0,3,158,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,18,3,0,0,57,0,0,2,99,0,0,1,61,0,0,3,120,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,0,2,1,0,0,41,0,0,0,4,0,16,4,67,0,0,3,119,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,3,121,1,16,1,199,0,0,128,2,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,5,147,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,5,34,0,0,193,61],[0,0,0,0,1,0,0,25,0,0,13,216,0,1,4,48,0,0,0,64,2,0,4,61,0,0,3,167,1,0,0,65],[0,8,0,0,0,2,0,29,0,0,0,0,0,18,4,53,0,0,0,0,1,0,4,20,0,0,0,2,2,0,0,41],[0,0,0,4,2,32,0,140,0,0,5,60,0,0,97,61,0,0,3,119,2,0,0,65,0,0,3,119,3,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,8,4,0,0,41,0,0,3,119,3,64,0,156,0,0,0,0,2,4,64,25],[0,0,0,64,2,32,2,16,0,0,0,192,1,16,2,16,0,0,0,0,1,33,1,159,0,0,3,168,1,16,1,199],[0,0,0,2,2,0,0,41,13,214,13,204,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,1,3,119,0,48,1,157,0,3,0,0,0,1,3,85,0,0,0,1,1,32,1,144,0,0,5,82,0,0,97,61],[0,0,0,8,1,0,0,41,0,0,3,127,1,16,0,156,0,0,3,58,0,0,33,61,0,0,0,8,3,0,0,41],[0,0,0,64,0,48,4,63,0,0,0,68,1,48,0,57,0,0,3,196,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,36,1,48,0,57,0,0,0,23,2,0,0,57,0,0,0,0,0,33,4,53,0,0,3,131,1,0,0,65],[0,0,0,0,0,19,4,53,0,0,0,4,1,48,0,57,0,0,0,3,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,3,119,1,0,0,65,0,0,3,119,2,48,0,156,0,0,0,0,3,1,128,25,0,0,0,64,1,48,2,16],[0,0,3,159,1,16,1,199,0,0,13,216,0,1,4,48,0,0,0,10,1,0,0,41,0,0,0,0,1,1,4,26],[0,0,0,9,1,16,0,108,0,0,5,148,0,0,193,61,0,0,3,120,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,0,2,1,0,0,41,0,0,0,4,0,16,4,67,0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,3,121,1,16,1,199],[0,0,128,2,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,5,32,0,0,97,61,0,0,0,64,4,0,4,61],[0,0,3,170,1,0,0,65,0,0,0,0,0,20,4,53,0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25,0,0,3,119,3,64,0,156,0,10,0,0,0,4,0,29],[0,0,0,0,1,4,64,25,0,9,0,64,0,16,2,24,0,0,0,192,1,32,2,16,0,0,0,9,1,16,1,175],[0,0,3,168,1,16,1,199,0,0,0,2,2,0,0,41,13,214,13,204,0,0,4,15,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,1,3,119,0,48,1,157,0,3,0,0,0,1,3,85,0,0,0,1,1,32,1,144],[0,0,5,155,0,0,97,61,0,0,0,10,1,0,0,41,0,0,3,127,1,16,0,156,0,0,3,58,0,0,33,61],[0,0,0,10,3,0,0,41,0,0,0,64,0,48,4,63,0,0,0,100,1,48,0,57,0,0,3,193,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,68,1,48,0,57,0,0,3,194,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,36,1,48,0,57,0,0,0,38,2,0,0,57,0,0,0,0,0,33,4,53,0,0,3,131,1,0,0,65],[0,0,0,0,0,19,4,53,0,0,0,4,1,48,0,57,0,0,0,3,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,0,9,1,0,0,41,0,0,3,195,1,16,1,199,0,0,13,216,0,1,4,48,0,0,0,0,0,1,4,47],[0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,3,169,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,27,3,0,0,57,0,0,2,99,0,0,1,61,0,0,0,64,1,0,4,61],[0,0,3,171,2,16,0,156,0,0,3,58,0,0,33,61,0,0,0,96,2,16,0,57,0,0,0,64,0,32,4,63],[0,0,3,172,2,0,0,65,0,0,0,0,2,33,4,54,0,0,0,64,4,0,4,61,0,0,3,173,3,64,0,156],[0,0,3,58,0,0,33,61,0,0,0,128,3,64,0,57,0,0,0,64,0,48,4,63,0,0,0,96,3,64,0,57],[0,0,3,174,5,0,0,65,0,0,0,0,0,83,4,53,0,0,0,64,3,64,0,57,0,0,3,175,5,0,0,65],[0,0,0,0,0,83,4,53,0,0,0,32,3,64,0,57,0,0,3,176,5,0,0,65,0,0,0,0,0,83,4,53],[0,0,0,65,3,0,0,57,0,9,0,0,0,3,0,29,0,0,0,0,0,52,4,53,0,0,0,64,3,16,0,57],[0,0,3,177,5,0,0,65,0,0,0,0,0,83,4,53,0,0,0,0,0,66,4,53,0,0,0,64,4,0,4,61],[0,10,0,0,0,4,0,29,0,0,3,171,4,64,0,156,0,0,3,58,0,0,33,61,0,0,0,10,5,0,0,41],[0,0,0,96,4,80,0,57,0,0,0,64,0,64,4,63,0,0,3,178,4,0,0,65,0,0,0,0,4,69,4,54],[0,8,0,0,0,4,0,29,0,0,0,64,4,0,4,61,0,0,3,173,5,64,0,156,0,0,3,58,0,0,33,61],[0,0,0,128,5,64,0,57,0,0,0,64,0,80,4,63,0,0,0,96,5,64,0,57,0,0,3,174,6,0,0,65],[0,0,0,0,0,101,4,53,0,0,0,64,5,64,0,57,0,0,3,179,6,0,0,65,0,0,0,0,0,101,4,53],[0,0,0,32,5,64,0,57,0,0,3,180,6,0,0,65,0,0,0,0,0,101,4,53,0,0,0,9,5,0,0,41],[0,0,0,0,0,84,4,53,0,0,0,10,5,0,0,41,0,0,0,64,6,80,0,57,0,0,3,181,5,0,0,65],[0,7,0,0,0,6,0,29,0,0,0,0,0,86,4,53,0,0,0,8,5,0,0,41,0,0,0,0,0,69,4,53],[0,0,0,0,2,2,4,51,0,0,0,0,84,2,4,52,0,0,0,65,4,64,0,140,0,0,5,32,0,0,193,61],[0,0,0,65,4,32,0,57,0,0,0,0,4,4,4,51,0,0,0,255,4,64,1,143,0,0,0,27,6,64,0,138],[0,0,0,1,6,96,0,140,0,0,5,32,0,0,33,61,0,0,0,0,3,3,4,51,0,6,0,0,0,3,0,29],[0,0,0,0,1,1,4,51,0,0,0,0,3,5,4,51,0,0,0,64,2,32,0,57,0,0,0,0,2,2,4,51],[0,0,0,64,5,0,4,61,0,0,0,96,6,80,0,57,0,0,0,0,0,38,4,53,0,0,0,64,2,80,0,57],[0,0,0,0,0,50,4,53,0,0,0,32,2,80,0,57,0,0,0,0,0,66,4,53,0,0,0,0,0,21,4,53],[0,0,0,0,0,0,4,53,0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,3,119,3,80,0,156,0,0,0,0,5,1,128,25,0,0,0,64,1,80,2,16],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,3,182,1,16,1,199,0,0,0,1,2,0,0,57],[13,214,13,209,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,3,119,3,48,1,151],[0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143],[0,0,0,5,4,64,2,114,0,0,6,14,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,70,0,75,0,0,6,7,0,0,65,61,0,0,0,0,6,5,0,75,0,0,6,28,0,0,97,61],[0,0,0,3,5,80,2,16,0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51,0,0,0,0,6,86,1,207],[0,0,0,0,6,86,2,47,0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137],[0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159,0,0,0,0,0,84,4,53],[0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144,0,0,7,64,0,0,97,61],[0,0,0,0,1,0,4,51,0,0,0,6,1,16,1,79,0,0,3,130,1,16,1,152,0,0,5,32,0,0,193,61],[0,0,0,8,1,0,0,41,0,0,0,0,1,1,4,51,0,0,0,0,50,1,4,52,0,0,0,65,2,32,0,140],[0,0,5,32,0,0,193,61,0,0,0,65,2,16,0,57,0,0,0,0,2,2,4,51,0,0,0,255,2,32,1,143],[0,0,0,27,4,32,0,138,0,0,0,1,4,64,0,140,0,0,5,32,0,0,33,61,0,0,0,7,4,0,0,41],[0,0,0,0,4,4,4,51,0,8,0,0,0,4,0,29,0,0,0,10,4,0,0,41,0,0,0,0,4,4,4,51],[0,0,0,0,3,3,4,51,0,0,0,64,1,16,0,57,0,0,0,0,1,1,4,51,0,0,0,64,5,0,4,61],[0,0,0,96,6,80,0,57,0,0,0,0,0,22,4,53,0,0,0,64,1,80,0,57,0,0,0,0,0,49,4,53],[0,0,0,32,1,80,0,57,0,0,0,0,0,33,4,53,0,0,0,0,0,69,4,53,0,0,0,0,0,0,4,53],[0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,3,119,3,80,0,156,0,0,0,0,5,1,128,25,0,0,0,64,1,80,2,16,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,3,182,1,16,1,199,0,0,0,1,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,4,64,2,114],[0,0,6,93,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,113,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,70,0,75],[0,0,6,86,0,0,65,61,0,0,0,0,6,5,0,75,0,0,6,107,0,0,97,61,0,0,0,3,5,80,2,16],[0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47],[0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159,0,0,0,0,0,84,4,53,0,1,0,0,0,3,0,31],[0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144,0,0,7,93,0,0,97,61,0,0,0,0,1,0,4,51],[0,0,0,8,1,16,1,79,0,0,3,130,1,16,1,152,0,0,5,32,0,0,193,61,0,0,0,64,1,0,4,61],[0,0,3,171,2,16,0,156,0,0,3,58,0,0,33,61,0,0,0,96,2,16,0,57,0,0,0,64,0,32,4,63],[0,0,0,0,5,1,4,54,0,0,0,64,2,0,4,61,0,0,3,173,3,32,0,156,0,0,3,58,0,0,33,61],[0,0,0,128,3,32,0,57,0,0,0,64,0,48,4,63,0,0,0,96,3,32,0,57,0,0,3,174,4,0,0,65],[0,0,0,0,0,67,4,53,0,0,0,64,3,32,0,57,0,0,3,183,4,0,0,65,0,0,0,0,0,67,4,53],[0,0,0,32,4,32,0,57,0,0,3,184,6,0,0,65,0,0,0,0,0,100,4,53,0,0,0,9,6,0,0,41],[0,0,0,0,0,98,4,53,0,0,0,64,6,16,0,57,0,0,3,185,7,0,0,65,0,0,0,0,0,118,4,53],[0,0,0,0,0,37,4,53,0,0,0,0,5,2,4,51,0,0,0,65,5,80,0,140,0,0,5,32,0,0,193,61],[0,0,0,65,2,32,0,57,0,0,0,0,2,2,4,51,0,0,0,255,2,32,1,143,0,0,0,27,5,32,0,138],[0,0,0,1,5,80,0,140,0,0,5,32,0,0,33,61,0,0,0,0,1,1,4,51,0,0,0,0,4,4,4,51],[0,0,0,0,3,3,4,51,0,0,0,64,5,0,4,61,0,0,0,96,6,80,0,57,0,0,0,0,0,54,4,53],[0,0,0,64,3,80,0,57,0,0,0,0,0,67,4,53,0,0,0,32,3,80,0,57,0,0,0,0,0,35,4,53],[0,0,0,0,0,21,4,53,0,0,0,0,0,0,4,53,0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25,0,0,3,119,3,80,0,156,0,0,0,0,5,1,128,25],[0,0,0,64,1,80,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,3,182,1,16,1,199],[0,0,0,1,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57],[0,0,0,31,5,64,1,143,0,0,0,5,4,64,2,114,0,0,6,191,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,70,0,75,0,0,6,184,0,0,65,61,0,0,0,0,6,5,0,75],[0,0,6,205,0,0,97,61,0,0,0,3,5,80,2,16,0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51],[0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47,0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159],[0,0,0,0,0,84,4,53,0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144],[0,0,7,122,0,0,97,61,0,0,0,0,1,0,4,51,0,0,3,130,1,16,1,151,0,0,3,185,1,16,0,156],[0,0,5,32,0,0,193,61,0,0,0,64,1,0,4,61,0,0,3,171,2,16,0,156,0,0,3,58,0,0,33,61],[0,0,0,96,2,16,0,57,0,0,0,64,0,32,4,63,0,0,3,186,2,0,0,65,0,0,0,0,5,33,4,54],[0,0,0,64,2,0,4,61,0,0,3,173,3,32,0,156,0,0,3,58,0,0,33,61,0,0,0,128,3,32,0,57],[0,0,0,64,0,48,4,63,0,0,0,96,3,32,0,57,0,0,3,187,4,0,0,65,0,0,0,0,0,67,4,53],[0,0,0,64,3,32,0,57,0,0,3,188,4,0,0,65,0,0,0,0,0,67,4,53,0,0,0,32,4,32,0,57],[0,0,3,189,6,0,0,65,0,0,0,0,0,100,4,53,0,0,0,9,6,0,0,41,0,0,0,0,0,98,4,53],[0,0,0,0,0,37,4,53,0,0,0,64,5,16,0,57,0,0,0,0,0,5,4,53,0,0,0,0,5,2,4,51],[0,0,0,65,5,80,0,140,0,0,5,32,0,0,193,61,0,0,0,65,2,32,0,57,0,0,0,0,2,2,4,51],[0,0,0,255,2,32,1,143,0,0,0,27,5,32,0,138,0,0,0,1,5,80,0,140,0,0,5,32,0,0,33,61],[0,0,0,0,1,1,4,51,0,0,0,0,4,4,4,51,0,0,0,0,3,3,4,51,0,0,0,64,5,0,4,61],[0,0,0,96,6,80,0,57,0,0,0,0,0,54,4,53,0,0,0,64,3,80,0,57,0,0,0,0,0,67,4,53],[0,0,0,32,3,80,0,57,0,0,0,0,0,35,4,53,0,0,0,0,0,21,4,53,0,0,0,0,0,0,4,53],[0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,3,119,3,80,0,156,0,0,0,0,5,1,128,25,0,0,0,64,1,80,2,16,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,3,182,1,16,1,199,0,0,0,1,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,4,64,2,114],[0,0,7,33,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,113,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,70,0,75],[0,0,7,26,0,0,65,61,0,0,0,0,6,5,0,75,0,0,7,47,0,0,97,61,0,0,0,3,5,80,2,16],[0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47],[0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159,0,0,0,0,0,84,4,53,0,1,0,0,0,3,0,31],[0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144,0,0,7,151,0,0,97,61,0,0,0,0,1,0,4,51],[0,0,3,130,1,16,1,152,0,0,5,32,0,0,193,61,0,0,0,0,3,0,4,22,0,0,3,119,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,3,119,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,0,0,2,3,0,75,0,0,7,180,0,0,193,61,0,0,3,190,2,0,0,65,0,0,7,184,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,7,77,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,7,69,0,0,65,61,0,0,0,0,6,4,0,75,0,0,7,92,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,4,55,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114],[0,0,7,106,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,7,98,0,0,65,61,0,0,0,0,6,4,0,75,0,0,7,121,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,4,55,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143],[0,0,0,5,5,48,2,114,0,0,7,135,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,7,127,0,0,65,61,0,0,0,0,6,4,0,75],[0,0,7,150,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25],[0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,4,55,0,0,1,61,0,0,0,64,2,0,4,61],[0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,7,164,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,7,156,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,7,179,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,4,55,0,0,1,61],[0,0,3,150,1,16,1,199,0,0,128,9,2,0,0,57,0,0,3,190,4,0,0,65,0,0,0,0,5,0,0,25],[13,214,13,204,0,0,4,15,0,3,0,0,0,1,3,85,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,1,3,119,0,48,1,157,0,0,3,119,5,48,1,152,0,0,7,231,0,0,97,61,0,0,0,63,3,80,0,57],[0,0,3,191,3,48,1,151,0,0,0,64,4,0,4,61,0,0,0,0,3,52,0,25,0,0,0,0,6,67,0,75],[0,0,0,0,6,0,0,25,0,0,0,1,6,0,64,57,0,0,3,127,7,48,0,156,0,0,3,58,0,0,33,61],[0,0,0,1,6,96,1,144,0,0,3,58,0,0,193,61,0,0,0,64,0,48,4,63,0,0,0,31,3,80,1,143],[0,0,0,0,4,84,4,54,0,0,0,5,5,80,2,114,0,0,7,216,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,116,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,7,208,0,0,65,61],[0,0,0,0,6,3,0,75,0,0,7,231,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,4,84,0,25,0,0,0,3,3,48,2,16,0,0,0,0,5,4,4,51,0,0,0,0,5,53,1,207],[0,0,0,0,5,53,2,47,0,0,0,0,1,1,4,59,0,0,1,0,3,48,0,137,0,0,0,0,1,49,2,47],[0,0,0,0,1,49,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,20,4,53,0,0,0,1,1,32,1,144],[0,0,7,237,0,0,97,61,0,0,3,129,1,0,0,65,0,0,0,0,0,1,4,27,0,0,0,0,1,0,0,25],[0,0,13,215,0,1,4,46,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,3,192,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,20,3,0,0,57,0,0,2,99,0,0,1,61],[0,0,3,231,2,16,0,156,0,0,7,249,0,0,129,61,0,0,0,96,1,16,0,57,0,0,0,64,0,16,4,63],[0,0,0,0,0,1,4,45,0,0,3,199,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,3,200,1,0,0,65,0,0,13,216,0,1,4,48,0,1,0,0,0,0,0,2],[0,0,0,0,1,0,0,50,0,0,8,204,0,0,193,61,0,0,3,134,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,8,197,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75],[0,0,8,62,0,0,97,61,0,0,3,134,1,0,0,65,0,0,0,0,0,16,4,57,0,0,3,119,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,8,197,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,8,198,0,0,97,61],[0,0,3,134,1,0,0,65,0,0,0,0,0,16,4,57,0,0,3,119,3,0,0,65,0,0,0,0,1,0,4,20],[0,0,3,119,2,16,0,156,0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199],[0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,8,197,0,0,97,61],[0,0,0,0,1,1,4,59,0,1,0,0,0,1,0,29,0,0,3,134,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156,0,0,3,119,1,0,128,65,0,0,0,192,1,16,2,16],[0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,8,197,0,0,97,61,0,0,0,1,2,0,0,41,0,0,3,232,2,32,0,57,0,0,0,0,1,1,4,59],[0,0,0,0,1,33,0,75,0,0,8,198,0,0,33,61,0,0,3,136,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,3,119,3,0,0,65,0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156,0,0,0,0,1,3,128,25],[0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,8,197,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,10,2,0,0,57],[0,0,0,0,0,18,4,27,0,0,3,137,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,0,1,0,4,20],[0,0,3,119,2,16,0,156,0,0,3,119,1,0,128,65,0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199],[0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,8,197,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,9,2,0,0,57,0,0,0,0,3,2,4,26,0,0,3,138,3,48,1,151],[0,0,0,0,1,19,1,159,0,0,0,0,0,18,4,27,0,0,3,139,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,3,119,3,0,0,65,0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156,0,0,0,0,1,3,128,25],[0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,8,197,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,8,2,0,0,57],[0,0,0,0,0,18,4,27,0,0,3,140,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,0,1,0,4,20],[0,0,3,119,2,16,0,156,0,0,3,119,1,0,128,65,0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199],[0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,8,197,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,7,2,0,0,57,0,0,0,0,0,18,4,27,0,0,3,141,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,3,119,3,0,0,65,0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57],[13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,8,197,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,6,2,0,0,57,0,0,0,0,0,18,4,27,0,0,3,142,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156,0,0,3,119,1,0,128,65,0,0,0,192,1,16,2,16],[0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,8,197,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,3,2,0,0,57,0,0,0,0,0,18,4,27],[0,0,3,143,1,0,0,65,0,0,0,0,0,16,4,57,0,0,3,119,3,0,0,65,0,0,0,0,1,0,4,20],[0,0,3,119,2,16,0,156,0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199],[0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,8,197,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,3,130,1,16,1,151,0,0,0,4,2,0,0,57,0,0,0,0,3,2,4,26],[0,0,3,138,3,48,1,151,0,0,0,0,1,19,1,159,0,0,0,0,0,18,4,27,0,0,0,2,1,0,0,57],[0,0,0,0,2,1,4,26,0,0,3,144,2,32,1,151,0,0,0,2,3,0,3,103,0,0,0,0,3,3,4,59],[0,0,0,224,3,48,2,112,0,0,0,0,2,50,1,159,0,0,0,0,0,33,4,27,0,0,3,134,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156,0,0,3,119,1,0,128,65],[0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,8,197,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,5,2,0,0,57],[0,0,0,0,0,18,4,27,0,0,0,11,1,0,0,57,0,0,0,0,2,0,4,22,0,0,0,0,0,33,4,27],[0,0,0,0,0,1,4,45,0,0,0,0,0,1,4,47,0,0,3,199,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,17,1,0,0,57,0,0,0,4,0,16,4,63,0,0,3,200,1,0,0,65,0,0,13,216,0,1,4,48],[0,0,0,0,1,0,0,25,0,0,13,216,0,1,4,48,0,8,0,0,0,0,0,2,0,0,0,0,1,0,4,20],[0,1,0,0,0,1,0,29,0,0,0,64,5,0,4,61,0,0,3,232,1,80,0,156,0,0,10,130,0,0,129,61],[0,0,0,160,1,80,0,57,0,0,0,64,0,16,4,63,0,0,0,128,1,80,0,57,0,0,3,146,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,96,1,80,0,57,0,0,3,147,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,64,1,80,0,57,0,0,3,148,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,122,1,0,0,57],[0,0,0,0,9,21,4,54,0,0,3,149,1,0,0,65,0,0,0,0,0,25,4,53,0,3,128,16,0,0,0,61],[0,0,0,0,3,0,0,25,0,8,0,0,0,5,0,29,0,6,0,0,0,3,0,29,0,0,3,119,1,144,0,156],[0,0,3,119,4,0,0,65,0,0,0,0,9,4,128,25,0,0,0,64,1,144,2,16,0,0,0,0,2,5,4,51],[0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,96,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,3,150,1,16,1,199,0,0,0,3,2,0,0,41,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,10,138,0,0,97,61,0,0,0,64,2,0,4,61,0,0,0,0,1,1,4,59],[0,7,0,0,0,1,0,29,0,0,0,8,6,0,0,41,0,0,0,0,1,6,4,51,0,0,0,0,3,1,0,75],[0,0,9,9,0,0,97,61,0,0,0,0,3,0,0,25,0,0,0,0,4,35,0,25,0,0,0,32,3,48,0,57],[0,0,0,0,5,99,0,25,0,0,0,0,5,5,4,51,0,0,0,0,0,84,4,53,0,0,0,0,4,19,0,75],[0,0,9,2,0,0,65,61,0,0,0,0,3,33,0,25,0,0,0,0,0,3,4,53,0,0,3,119,3,32,0,156],[0,0,3,119,4,0,0,65,0,0,0,0,2,4,128,25,0,0,0,64,2,32,2,16,0,0,3,119,3,16,0,156],[0,0,0,0,1,4,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20],[0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,0,2,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,5,3,0,25,0,0,0,32,5,0,128,57],[0,0,0,5,4,80,2,114,0,0,9,42,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,70,0,75,0,0,9,35,0,0,65,61,0,0,0,31,5,80,1,144,0,0,9,56,0,0,97,61],[0,0,0,3,5,80,2,16,0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51,0,0,0,0,6,86,1,207],[0,0,0,0,6,86,2,47,0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137],[0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159,0,0,0,0,0,84,4,53],[0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,64,10,0,4,61,0,0,0,1,2,32,1,144],[0,0,10,140,0,0,97,61,0,0,0,0,2,0,4,51,0,0,0,32,12,160,0,57,0,0,0,8,6,0,0,41],[0,0,0,0,1,6,4,51,0,0,0,0,3,1,0,75,0,0,9,75,0,0,97,61,0,0,0,0,3,0,0,25],[0,0,0,0,4,195,0,25,0,0,0,32,3,48,0,57,0,0,0,0,5,99,0,25,0,0,0,0,5,5,4,51],[0,0,0,0,0,84,4,53,0,0,0,0,4,19,0,75,0,0,9,68,0,0,65,61,0,0,0,7,2,32,1,79],[0,0,0,0,3,193,0,25,0,0,0,0,0,35,4,53,0,0,0,32,3,16,0,57,0,0,0,0,0,58,4,53],[0,0,0,95,3,16,0,57,0,0,0,32,1,0,0,138,0,0,0,0,3,19,1,111,0,0,0,0,13,163,0,25],[0,0,0,0,3,61,0,75,0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57,0,0,3,127,4,208,0,156],[0,0,10,130,0,0,33,61,0,0,0,1,3,48,1,144,0,0,10,130,0,0,193,61,0,0,0,64,0,208,4,63],[0,0,0,12,11,0,0,57,0,0,0,0,3,11,4,26,0,0,3,127,4,48,0,156,0,0,10,130,0,0,33,61],[0,0,0,1,4,48,0,57,0,0,0,0,0,75,4,27,0,0,0,0,0,176,4,53,0,0,3,151,3,48,0,65],[0,0,0,0,0,35,4,27,0,0,0,0,4,11,4,26,0,0,0,0,3,4,0,75,0,0,10,134,0,0,97,61],[0,0,0,1,3,0,0,57,0,0,0,1,6,64,0,140,0,0,9,132,0,0,97,61,0,0,0,0,3,11,4,26],[0,0,0,0,4,99,0,75,0,0,10,124,0,0,161,61,0,0,0,1,4,96,0,138,0,0,0,1,5,64,2,112],[0,0,0,0,7,83,0,75,0,0,10,124,0,0,161,61,0,0,3,151,7,96,0,65,0,0,0,0,9,7,4,26],[0,0,0,0,0,176,4,53,0,0,3,151,6,80,0,65,0,0,0,0,8,6,4,26,0,0,0,0,9,137,0,75],[0,0,9,132,0,0,161,61,0,0,0,0,0,135,4,27,0,0,0,0,3,11,4,26,0,0,0,0,3,83,0,75],[0,0,10,124,0,0,161,61,0,0,0,0,0,38,4,27,0,0,0,2,3,64,0,140,0,0,0,0,6,5,0,25],[0,0,9,107,0,0,129,61,0,0,0,0,3,11,4,26,0,0,0,0,2,3,0,75,0,0,10,134,0,0,97,61],[0,0,0,1,2,48,0,138,0,0,0,0,2,35,1,112,0,0,9,144,0,0,193,61,0,0,0,13,2,0,0,57],[0,0,0,0,3,2,4,26,0,0,3,127,4,48,1,151,0,0,3,127,5,64,0,156,0,0,10,134,0,0,97,61],[0,0,3,152,3,48,1,151,0,0,0,1,4,64,0,57,0,0,0,0,3,52,1,159,0,0,0,0,0,50,4,27],[0,5,0,0,0,12,0,29,0,7,0,0,0,11,0,29,0,0,3,153,2,0,0,65,0,0,0,0,0,45,4,53],[0,0,0,4,2,208,0,57,0,0,0,32,3,0,0,57,0,2,0,0,0,3,0,29,0,0,0,0,0,50,4,53],[0,0,0,0,2,10,4,51,0,0,0,36,3,208,0,57,0,0,0,0,0,35,4,53,0,0,0,68,3,208,0,57],[0,0,0,0,4,2,0,75,0,0,9,166,0,0,97,61,0,0,0,0,4,0,0,25,0,0,0,0,5,52,0,25],[0,0,0,32,4,64,0,57,0,0,0,0,6,164,0,25,0,0,0,0,6,6,4,51,0,0,0,0,0,101,4,53],[0,0,0,0,5,36,0,75,0,0,9,159,0,0,65,61,0,8,0,0,0,10,0,29,0,0,0,0,3,50,0,25],[0,0,0,0,0,3,4,53,0,0,0,31,2,32,0,57,0,0,0,0,1,18,1,111,0,0,3,119,2,208,0,156],[0,0,3,119,4,0,0,65,0,0,0,0,2,4,0,25,0,0,0,0,2,13,64,25,0,0,0,64,2,32,2,16],[0,0,0,68,1,16,0,57,0,0,3,119,3,16,0,156,0,0,0,0,1,4,128,25,0,0,0,96,1,16,2,16],[0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,128,8,2,0,0,57,0,4,0,0,0,13,0,29],[13,214,13,204,0,0,4,15,0,0,0,4,12,0,0,41,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57],[0,0,0,5,5,64,2,114,0,0,9,207,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,124,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,9,199,0,0,65,61,0,0,0,31,6,64,1,144],[0,0,0,7,11,0,0,41,0,0,0,5,9,0,0,41,0,0,9,224,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,7,81,3,79,0,0,0,0,5,92,0,25,0,0,0,3,6,96,2,16,0,0,0,0,8,5,4,51],[0,0,0,0,8,104,1,207,0,0,0,0,8,104,2,47,0,0,0,0,7,7,4,59,0,0,1,0,6,96,0,137],[0,0,0,0,7,103,2,47,0,0,0,0,6,103,1,207,0,0,0,0,6,134,1,159,0,0,0,0,0,101,4,53],[0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144,0,0,0,8,10,0,0,41],[0,0,10,172,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,2,16,1,143,0,0,0,0,1,194,0,25],[0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,3,127,4,16,0,156],[0,0,10,130,0,0,33,61,0,0,0,1,2,32,1,144,0,0,10,130,0,0,193,61,0,0,0,64,0,16,4,63],[0,0,0,32,2,48,0,140,0,0,10,138,0,0,65,61,0,0,0,6,3,0,0,41,0,0,0,2,2,48,0,140],[0,0,0,1,3,48,0,57,0,0,0,0,5,10,0,25,0,0,8,229,0,0,161,61,0,0,0,0,2,11,4,26],[0,0,0,0,3,2,0,75,0,0,10,207,0,0,97,61,0,0,3,154,3,32,0,65,0,0,0,0,4,3,4,26],[0,0,3,151,5,0,0,65,0,0,0,0,0,69,4,27,0,0,0,0,0,176,4,53,0,0,0,0,0,3,4,27],[0,0,0,1,3,32,0,138,0,0,0,0,0,59,4,27,0,0,0,2,2,48,0,140,0,0,10,55,0,0,65,61],[0,0,0,1,6,0,0,57,0,0,3,157,2,0,0,65,0,0,0,0,7,0,0,25,0,0,0,0,5,0,0,25],[0,0,0,2,8,112,0,57,0,0,0,0,4,56,0,75,0,0,0,0,4,6,0,25,0,0,10,19,0,0,129,61],[0,0,3,155,4,112,0,65,0,0,0,0,4,4,4,26,0,0,3,156,7,112,0,65,0,0,0,0,7,7,4,26],[0,0,0,0,4,71,0,75,0,0,0,0,4,6,0,25,0,0,0,0,4,8,64,25,0,0,0,0,6,67,0,75],[0,0,10,124,0,0,161,61,0,0,3,151,6,64,0,65,0,0,0,0,7,83,0,75,0,0,10,124,0,0,161,61],[0,0,0,0,7,6,4,26,0,0,0,0,0,176,4,53,0,0,3,151,8,80,0,65,0,0,0,0,5,8,4,26],[0,0,0,0,9,87,0,75,0,0,10,52,0,0,161,61,0,0,0,0,0,120,4,27,0,0,0,0,3,11,4,26],[0,0,0,0,3,67,0,75,0,0,10,124,0,0,161,61,0,0,0,0,0,86,4,27,0,0,0,0,3,4,0,75],[0,0,0,0,3,0,0,25,0,0,0,0,3,2,64,25,0,0,3,157,5,64,1,151,0,0,0,0,6,5,0,75],[0,0,0,0,6,0,0,25,0,0,0,0,6,2,32,25,0,0,3,157,5,80,0,156,0,0,0,0,6,3,192,25],[0,0,0,0,3,6,0,75,0,0,10,134,0,0,193,61,0,0,0,0,3,11,4,26,0,0,0,1,7,64,2,16],[0,0,0,1,6,112,1,191,0,0,0,0,5,54,0,75,0,0,0,0,5,4,0,25,0,0,10,8,0,0,65,61],[0,0,0,1,2,0,0,138,0,0,0,0,2,35,0,75,0,0,10,134,0,0,97,61,0,0,0,1,2,48,0,57],[0,0,0,0,2,50,1,112,0,0,10,67,0,0,193,61,0,0,0,13,2,0,0,57,0,0,0,0,3,2,4,26],[0,0,3,127,4,48,1,151,0,0,0,1,4,64,0,138,0,0,3,127,5,64,0,156,0,0,10,134,0,0,33,61],[0,0,3,152,3,48,1,151,0,0,0,0,3,52,1,159,0,0,0,0,0,50,4,27,0,0,0,0,3,0,4,20],[0,0,0,1,2,48,0,107,0,0,10,213,0,0,161,61,0,7,0,0,0,3,0,29,0,0,0,0,2,10,4,51],[0,0,0,0,3,2,0,75,0,0,10,82,0,0,97,61,0,0,0,0,3,0,0,25,0,0,0,0,4,19,0,25],[0,0,0,32,3,48,0,57,0,0,0,0,5,163,0,25,0,0,0,0,5,5,4,51,0,0,0,0,0,84,4,53],[0,0,0,0,4,35,0,75,0,0,10,75,0,0,65,61,0,0,0,0,3,18,0,25,0,0,0,0,0,3,4,53],[0,0,3,119,4,0,0,65,0,0,3,119,3,16,0,156,0,0,0,0,1,4,128,25,0,0,0,64,1,16,2,16],[0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,96,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,3,150,1,16,1,199,0,0,128,16,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,10,138,0,0,97,61,0,0,0,7,3,0,0,41,0,0,0,1,2,48,0,105],[0,0,0,0,5,1,4,59,0,0,0,64,1,0,4,61,0,0,0,0,0,33,4,53,0,0,0,0,2,0,4,20],[0,0,3,119,3,32,0,156,0,0,3,119,4,0,0,65,0,0,0,0,2,4,128,25,0,0,3,119,3,16,0,156],[0,0,0,0,1,4,128,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,3,160,1,16,1,199,0,0,128,13,2,0,0,57,0,0,0,2,3,0,0,57,0,0,3,161,4,0,0,65],[13,214,13,204,0,0,4,15,0,0,0,1,1,32,1,144,0,0,10,138,0,0,97,61,0,0,0,0,0,1,4,45],[0,0,3,199,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,50,1,0,0,57,0,0,0,4,0,16,4,63],[0,0,3,200,1,0,0,65,0,0,13,216,0,1,4,48,0,0,3,199,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,65,1,0,0,57,0,0,10,127,0,0,1,61,0,0,3,199,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,17,1,0,0,57,0,0,10,127,0,0,1,61,0,0,0,0,1,0,0,25,0,0,13,216,0,1,4,48],[0,0,0,31,2,48,1,143,0,0,0,5,4,48,2,114,0,0,10,152,0,0,97,61,0,0,0,0,5,0,0,25],[0,0,0,5,6,80,2,16,0,0,0,0,7,106,0,25,0,0,0,0,6,97,3,79,0,0,0,0,6,6,4,59],[0,0,0,0,0,103,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,69,0,75,0,0,10,144,0,0,65,61],[0,0,0,0,5,2,0,75,0,0,10,167,0,0,97,61,0,0,0,5,4,64,2,16,0,0,0,0,1,65,3,79],[0,0,0,0,4,74,0,25,0,0,0,3,2,32,2,16,0,0,0,0,5,4,4,51,0,0,0,0,5,37,1,207],[0,0,0,0,5,37,2,47,0,0,0,0,1,1,4,59,0,0,1,0,2,32,0,137,0,0,0,0,1,33,2,47],[0,0,0,0,1,33,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,20,4,53,0,0,3,119,1,0,0,65],[0,0,3,119,2,160,0,156,0,0,0,0,10,1,128,25,0,0,0,64,1,160,2,16,0,0,10,204,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,10,185,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,10,177,0,0,65,61,0,0,0,0,6,4,0,75,0,0,10,200,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,3,119,1,0,0,65,0,0,3,119,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16],[0,0,0,96,2,48,2,16,0,0,0,0,1,33,1,159,0,0,13,216,0,1,4,48,0,0,0,68,2,16,0,57],[0,0,3,198,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,1,3,0,0,57],[0,0,10,218,0,0,1,61,0,0,0,68,2,16,0,57,0,0,3,158,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,18,3,0,0,57,0,0,0,0,0,50,4,53,0,0,3,131,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,2,3,0,0,41,0,0,0,0,0,50,4,53],[0,0,3,119,2,0,0,65,0,0,3,119,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16],[0,0,3,159,1,16,1,199,0,0,13,216,0,1,4,48,0,1,0,0,0,0,0,2,0,0,0,64,7,0,4,61],[0,0,3,153,2,0,0,65,0,0,0,0,0,39,4,53,0,0,0,4,2,112,0,57,0,0,0,32,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,0,0,2,1,4,51,0,0,0,36,3,112,0,57,0,0,0,0,0,35,4,53],[0,0,0,68,3,112,0,57,0,0,0,0,4,2,0,75,0,0,10,251,0,0,97,61,0,0,0,0,4,0,0,25],[0,0,0,0,5,52,0,25,0,0,0,32,4,64,0,57,0,0,0,0,6,20,0,25,0,0,0,0,6,6,4,51],[0,0,0,0,0,101,4,53,0,0,0,0,5,36,0,75,0,0,10,244,0,0,65,61,0,0,0,0,1,50,0,25],[0,0,0,0,0,1,4,53,0,0,0,31,1,32,0,57,0,0,0,32,2,0,0,138,0,0,0,0,1,33,1,111],[0,0,3,119,2,0,0,65,0,0,3,119,3,112,0,156,0,0,0,0,3,2,0,25,0,0,0,0,3,7,64,25],[0,0,0,64,3,48,2,16,0,0,0,68,1,16,0,57,0,0,3,119,4,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,96,1,16,2,16,0,0,0,0,1,49,1,159,0,0,0,0,3,0,4,20,0,0,3,119,4,48,0,156],[0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16,0,0,0,0,1,18,1,159,0,0,128,8,2,0,0,57],[0,1,0,0,0,7,0,29,13,214,13,204,0,0,4,15,0,0,0,1,10,0,0,41,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25],[0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114,0,0,11,37,0,0,97,61],[0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,138,0,25,0,0,0,0,8,129,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75],[0,0,11,29,0,0,65,61,0,0,0,0,7,5,0,75,0,0,11,52,0,0,97,61,0,0,0,5,6,96,2,16],[0,0,0,0,7,97,3,79,0,0,0,0,6,106,0,25,0,0,0,3,5,80,2,16,0,0,0,0,8,6,4,51],[0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137],[0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53],[0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144,0,0,11,70,0,0,97,61],[0,0,0,31,1,64,0,57,0,0,0,96,2,16,1,143,0,0,0,0,1,162,0,25,0,0,0,0,2,33,0,75],[0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,3,127,4,16,0,156,0,0,11,105,0,0,33,61],[0,0,0,1,2,32,1,144,0,0,11,105,0,0,193,61,0,0,0,64,0,16,4,63,0,0,0,32,1,48,0,140],[0,0,11,111,0,0,65,61,0,0,0,0,0,1,4,45,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143],[0,0,0,5,5,48,2,114,0,0,11,83,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,11,75,0,0,65,61,0,0,0,0,6,4,0,75],[0,0,11,98,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25],[0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,3,119,1,0,0,65,0,0,3,119,4,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,0,96,2,48,2,16,0,0,0,0,1,33,1,159],[0,0,13,216,0,1,4,48,0,0,3,199,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,3,200,1,0,0,65,0,0,13,216,0,1,4,48,0,0,0,0,1,0,0,25],[0,0,13,216,0,1,4,48,0,0,0,64,2,0,4,61,0,0,3,233,1,32,0,156,0,0,11,170,0,0,129,61],[0,0,0,192,1,32,0,57,0,0,0,64,0,16,4,63,0,0,0,160,1,32,0,57,0,0,3,163,3,0,0,65],[0,0,0,0,0,49,4,53,0,0,0,128,3,32,0,57,0,0,3,164,1,0,0,65,0,0,0,0,0,19,4,53],[0,0,0,96,3,32,0,57,0,0,0,0,0,19,4,53,0,0,0,64,3,32,0,57,0,0,0,0,0,19,4,53],[0,0,0,32,3,32,0,57,0,0,0,0,0,19,4,53,0,0,0,135,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,0,64,2,0,4,61,0,0,3,162,3,32,0,156,0,0,11,170,0,0,33,61,0,0,0,192,3,32,0,57],[0,0,0,64,0,48,4,63,0,0,0,160,3,32,0,57,0,0,3,165,4,0,0,65,0,0,0,0,0,67,4,53],[0,0,0,128,3,32,0,57,0,0,0,0,0,19,4,53,0,0,0,96,3,32,0,57,0,0,0,0,0,19,4,53],[0,0,0,64,3,32,0,57,0,0,0,0,0,19,4,53,0,0,0,32,3,32,0,57,0,0,0,0,0,19,4,53],[0,0,0,136,1,0,0,57,0,0,0,0,0,18,4,53,0,0,0,64,1,0,4,61,0,0,3,162,2,16,0,156],[0,0,11,170,0,0,33,61,0,0,0,192,2,16,0,57,0,0,0,64,0,32,4,63,0,0,0,160,2,16,0,57],[0,0,3,166,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,128,2,16,0,57,0,0,3,164,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,96,2,16,0,57,0,0,0,0,0,50,4,53,0,0,0,64,2,16,0,57],[0,0,0,0,0,50,4,53,0,0,0,32,2,16,0,57,0,0,0,0,0,50,4,53,0,0,0,137,2,0,0,57],[0,0,0,0,0,33,4,53,0,0,0,0,0,1,4,45,0,0,3,199,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,65,1,0,0,57,0,0,0,4,0,16,4,63,0,0,3,200,1,0,0,65,0,0,13,216,0,1,4,48],[0,5,0,0,0,0,0,2,0,0,0,64,1,0,4,61,0,0,3,231,2,16,0,156,0,0,13,75,0,0,129,61],[0,0,0,96,2,16,0,57,0,0,0,64,0,32,4,63,0,0,3,172,2,0,0,65,0,0,0,0,2,33,4,54],[0,0,0,64,4,0,4,61,0,0,3,173,3,64,0,156,0,0,13,75,0,0,33,61,0,0,0,128,3,64,0,57],[0,0,0,64,0,48,4,63,0,0,0,96,3,64,0,57,0,0,3,174,5,0,0,65,0,0,0,0,0,83,4,53],[0,0,0,64,3,64,0,57,0,0,3,175,5,0,0,65,0,0,0,0,0,83,4,53,0,0,0,32,3,64,0,57],[0,0,3,176,5,0,0,65,0,0,0,0,0,83,4,53,0,0,0,65,7,0,0,57,0,0,0,0,0,116,4,53],[0,0,0,64,3,16,0,57,0,0,3,177,5,0,0,65,0,0,0,0,0,83,4,53,0,0,0,0,0,66,4,53],[0,0,0,64,8,0,4,61,0,0,3,171,4,128,0,156,0,0,13,75,0,0,33,61,0,0,0,96,4,128,0,57],[0,0,0,64,0,64,4,63,0,0,3,178,4,0,0,65,0,0,0,0,9,72,4,54,0,0,0,64,4,0,4,61],[0,0,3,173,5,64,0,156,0,0,13,75,0,0,33,61,0,0,0,128,5,64,0,57,0,0,0,64,0,80,4,63],[0,0,0,96,5,64,0,57,0,0,3,174,6,0,0,65,0,0,0,0,0,101,4,53,0,0,0,64,5,64,0,57],[0,0,3,179,6,0,0,65,0,0,0,0,0,101,4,53,0,0,0,32,5,64,0,57,0,0,3,180,6,0,0,65],[0,0,0,0,0,101,4,53,0,5,0,0,0,7,0,29,0,0,0,0,0,116,4,53,0,0,0,64,6,128,0,57],[0,0,3,181,5,0,0,65,0,1,0,0,0,6,0,29,0,0,0,0,0,86,4,53,0,0,0,0,0,73,4,53],[0,0,0,0,2,2,4,51,0,0,0,0,84,2,4,52,0,0,0,65,4,64,0,140,0,0,13,73,0,0,193,61],[0,0,0,65,4,32,0,57,0,0,0,0,4,4,4,51,0,0,0,255,4,64,1,143,0,0,0,27,6,64,0,138],[0,0,0,1,6,96,0,140,0,0,13,73,0,0,33,61,0,3,0,0,0,9,0,29,0,4,0,0,0,8,0,29],[0,0,0,0,3,3,4,51,0,2,0,0,0,3,0,29,0,0,0,0,1,1,4,51,0,0,0,0,3,5,4,51],[0,0,0,64,2,32,0,57,0,0,0,0,2,2,4,51,0,0,0,64,5,0,4,61,0,0,0,96,6,80,0,57],[0,0,0,0,0,38,4,53,0,0,0,64,2,80,0,57,0,0,0,0,0,50,4,53,0,0,0,32,2,80,0,57],[0,0,0,0,0,66,4,53,0,0,0,0,0,21,4,53,0,0,0,0,0,0,4,53,0,0,3,119,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25,0,0,3,119,3,80,0,156],[0,0,0,0,5,1,128,25,0,0,0,64,1,80,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,3,182,1,16,1,199,0,0,0,1,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25],[0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,4,64,2,114,0,0,12,32,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59],[0,0,0,0,0,135,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,70,0,75,0,0,12,25,0,0,65,61],[0,0,0,0,6,5,0,75,0,0,12,46,0,0,97,61,0,0,0,3,5,80,2,16,0,0,0,5,4,64,2,16],[0,0,0,0,6,4,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47,0,0,0,0,7,65,3,79],[0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207],[0,0,0,0,5,101,1,159,0,0,0,0,0,84,4,53,0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85],[0,0,0,1,2,32,1,144,0,0,0,4,5,0,0,41,0,0,0,3,2,0,0,41,0,0,13,81,0,0,97,61],[0,0,0,0,1,0,4,51,0,0,0,2,1,16,1,79,0,0,3,130,1,16,1,152,0,0,13,73,0,0,193,61],[0,0,0,0,1,2,4,51,0,0,0,0,50,1,4,52,0,0,0,65,2,32,0,140,0,0,13,73,0,0,193,61],[0,0,0,65,2,16,0,57,0,0,0,0,2,2,4,51,0,0,0,255,2,32,1,143,0,0,0,27,4,32,0,138],[0,0,0,1,4,64,0,140,0,0,13,73,0,0,33,61,0,0,0,1,4,0,0,41,0,0,0,0,4,4,4,51],[0,3,0,0,0,4,0,29,0,0,0,0,4,5,4,51,0,0,0,0,3,3,4,51,0,0,0,64,1,16,0,57],[0,0,0,0,1,1,4,51,0,0,0,64,5,0,4,61,0,0,0,96,6,80,0,57,0,0,0,0,0,22,4,53],[0,0,0,64,1,80,0,57,0,0,0,0,0,49,4,53,0,0,0,32,1,80,0,57,0,0,0,0,0,33,4,53],[0,0,0,0,0,69,4,53,0,0,0,0,0,0,4,53,0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25,0,0,3,119,3,80,0,156,0,0,0,0,5,1,128,25],[0,0,0,64,1,80,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,3,182,1,16,1,199],[0,0,0,1,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57],[0,0,0,31,5,64,1,143,0,0,0,5,4,64,2,114,0,0,12,111,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,70,0,75,0,0,12,104,0,0,65,61,0,0,0,0,6,5,0,75],[0,0,12,125,0,0,97,61,0,0,0,3,5,80,2,16,0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51],[0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47,0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159],[0,0,0,0,0,84,4,53,0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144],[0,0,13,110,0,0,97,61,0,0,0,0,1,0,4,51,0,0,0,3,1,16,1,79,0,0,3,130,1,16,1,152],[0,0,13,73,0,0,193,61,0,0,0,64,1,0,4,61,0,0,3,171,2,16,0,156,0,0,0,5,7,0,0,41],[0,0,13,75,0,0,33,61,0,0,0,96,2,16,0,57,0,0,0,64,0,32,4,63,0,0,0,0,5,1,4,54],[0,0,0,64,2,0,4,61,0,0,3,173,3,32,0,156,0,0,13,75,0,0,33,61,0,0,0,128,3,32,0,57],[0,0,0,64,0,48,4,63,0,0,0,96,3,32,0,57,0,0,3,174,4,0,0,65,0,0,0,0,0,67,4,53],[0,0,0,64,3,32,0,57,0,0,3,183,4,0,0,65,0,0,0,0,0,67,4,53,0,0,0,32,4,32,0,57],[0,0,3,184,6,0,0,65,0,0,0,0,0,100,4,53,0,0,0,0,0,114,4,53,0,0,0,64,6,16,0,57],[0,0,3,185,7,0,0,65,0,0,0,0,0,118,4,53,0,0,0,0,0,37,4,53,0,0,0,0,5,2,4,51],[0,0,0,65,5,80,0,140,0,0,13,73,0,0,193,61,0,0,0,65,2,32,0,57,0,0,0,0,2,2,4,51],[0,0,0,255,2,32,1,143,0,0,0,27,5,32,0,138,0,0,0,1,5,80,0,140,0,0,13,73,0,0,33,61],[0,0,0,0,1,1,4,51,0,0,0,0,4,4,4,51,0,0,0,0,3,3,4,51,0,0,0,64,5,0,4,61],[0,0,0,96,6,80,0,57,0,0,0,0,0,54,4,53,0,0,0,64,3,80,0,57,0,0,0,0,0,67,4,53],[0,0,0,32,3,80,0,57,0,0,0,0,0,35,4,53,0,0,0,0,0,21,4,53,0,0,0,0,0,0,4,53],[0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,3,119,3,80,0,156,0,0,0,0,5,1,128,25,0,0,0,64,1,80,2,16,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,3,182,1,16,1,199,0,0,0,1,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,4,64,2,114],[0,0,12,209,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,113,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,70,0,75],[0,0,12,202,0,0,65,61,0,0,0,0,6,5,0,75,0,0,12,223,0,0,97,61,0,0,0,3,5,80,2,16],[0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47],[0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159,0,0,0,0,0,84,4,53,0,1,0,0,0,3,0,31],[0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144,0,0,13,139,0,0,97,61,0,0,0,0,1,0,4,51],[0,0,3,130,1,16,1,151,0,0,3,185,1,16,0,156,0,0,13,73,0,0,193,61,0,0,0,64,1,0,4,61],[0,0,3,171,2,16,0,156,0,0,0,5,7,0,0,41,0,0,13,75,0,0,33,61,0,0,0,96,2,16,0,57],[0,0,0,64,0,32,4,63,0,0,3,186,2,0,0,65,0,0,0,0,5,33,4,54,0,0,0,64,2,0,4,61],[0,0,3,173,3,32,0,156,0,0,13,75,0,0,33,61,0,0,0,128,3,32,0,57,0,0,0,64,0,48,4,63],[0,0,0,96,3,32,0,57,0,0,3,187,4,0,0,65,0,0,0,0,0,67,4,53,0,0,0,64,3,32,0,57],[0,0,3,188,4,0,0,65,0,0,0,0,0,67,4,53,0,0,0,32,4,32,0,57,0,0,3,189,6,0,0,65],[0,0,0,0,0,100,4,53,0,0,0,0,0,114,4,53,0,0,0,0,0,37,4,53,0,0,0,64,5,16,0,57],[0,0,0,0,0,5,4,53,0,0,0,0,5,2,4,51,0,0,0,65,5,80,0,140,0,0,13,73,0,0,193,61],[0,0,0,65,2,32,0,57,0,0,0,0,2,2,4,51,0,0,0,255,2,32,1,143,0,0,0,27,5,32,0,138],[0,0,0,1,5,80,0,140,0,0,13,73,0,0,33,61,0,0,0,0,1,1,4,51,0,0,0,0,4,4,4,51],[0,0,0,0,3,3,4,51,0,0,0,64,5,0,4,61,0,0,0,96,6,80,0,57,0,0,0,0,0,54,4,53],[0,0,0,64,3,80,0,57,0,0,0,0,0,67,4,53,0,0,0,32,3,80,0,57,0,0,0,0,0,35,4,53],[0,0,0,0,0,21,4,53,0,0,0,0,0,0,4,53,0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25,0,0,3,119,3,80,0,156,0,0,0,0,5,1,128,25],[0,0,0,64,1,80,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,3,182,1,16,1,199],[0,0,0,1,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57],[0,0,0,31,5,64,1,143,0,0,0,5,4,64,2,114,0,0,13,51,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,70,0,75,0,0,13,44,0,0,65,61,0,0,0,0,6,5,0,75],[0,0,13,65,0,0,97,61,0,0,0,3,5,80,2,16,0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51],[0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47,0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159],[0,0,0,0,0,84,4,53,0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144],[0,0,13,168,0,0,97,61,0,0,0,0,1,0,4,51,0,0,3,130,1,16,1,152,0,0,13,73,0,0,193,61],[0,0,0,0,0,1,4,45,0,0,0,0,1,0,0,25,0,0,13,216,0,1,4,48,0,0,3,199,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57,0,0,0,4,0,16,4,63,0,0,3,200,1,0,0,65],[0,0,13,216,0,1,4,48,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114],[0,0,13,94,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,13,86,0,0,65,61,0,0,0,0,6,4,0,75,0,0,13,196,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,13,196,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143],[0,0,0,5,5,48,2,114,0,0,13,123,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,13,115,0,0,65,61,0,0,0,0,6,4,0,75],[0,0,13,138,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25],[0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,13,196,0,0,1,61,0,0,0,64,2,0,4,61],[0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,13,152,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,13,144,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,13,167,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,13,196,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,13,181,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,13,173,0,0,65,61,0,0,0,0,6,4,0,75,0,0,13,196,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,3,119,1,0,0,65,0,0,3,119,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16],[0,0,0,96,2,48,2,16,0,0,0,0,1,33,1,159,0,0,13,216,0,1,4,48,0,0,0,0,0,1,4,47],[0,0,13,207,0,33,4,33,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25],[0,0,0,0,0,1,4,45,0,0,13,212,0,33,4,35,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45],[0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,13,214,0,0,4,50,0,0,13,215,0,1,4,46],[0,0,13,216,0,1,4,48,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[24,6,170,24,150,187,242,101,104,232,132,167,55,75,65,224,2,80,9,98,202,186,106,21,2,58,141,144,232,80,139,131],[2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[224,63,225,119,187,5,10,64,234,27,62,205,100,18,26,63,160,99,169,75,109,64,75,47,69,198,70,151,85,94,254,14],[197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112],[153,58,4,183,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,160,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,1,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,255,255,255,255,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[142,148,254,212,66,57,235,35,20,171,122,64,99,69,230,197,168,240,204,237,243,182,0,222,61,0,78,103,44,51,171,244],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[8,195,121,160,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],[105,110,32,100,101,108,101,103,97,116,101,32,99,97,108,108,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,0,0,0,100,0,0,0,128,0,0,0,0,0,0,0,0],[66,203,177,92,205,195,202,214,38,107,14,122,8,192,69,75,35,191,41,220,45,247,75,111,60,32,158,147,54,70,91,209],[2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0],[25,202,228,98,154,45,215,137,0,54,208,209,246,168,39,66,132,91,119,139,113,132,227,141,91,235,253,76,206,59,24,30],[166,174,10,172,21,139,45,92,154,156,146,133,116,52,25,214,42,50,246,114,122,100,9,85,228,206,142,228,21,3,199,132],[255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[120,119,167,151,254,109,202,67,33,243,63,217,84,20,218,7,154,183,142,105,141,118,21,20,192,28,237,146,17,175,38,126],[254,23,59,151,237,154,162,99,35,108,82,250,62,179,52,208,119,65,173,217,94,151,45,23,53,45,118,129,107,74,174,163],[154,138,5,146,172,137,197,173,59,198,223,130,36,193,123,72,89,118,245,151,223,16,78,226,13,13,244,21,36,31,103,11],[121,107,137,185,22,68,188,152,205,147,149,142,76,144,56,39,93,98,33,131,226,90,197,175,8,204,107,93,149,83,145,50],[147,139,95,50,153,161,243,177,142,69,133,100,239,187,149,7,51,34,96,20,238,206,38,250,225,144,18,216,80,180,141,131],[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,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,255,255,255,255,255,255,255,95],[116,104,101,32,105,110,100,117,115,116,114,121,39,115,32,115,116,97,110,100,97,114,100,46,46,46,0,0,0,0,0,0],[32,105,110,100,117,115,116,114,121,46,32,76,111,114,101,109,32,73,112,115,117,109,32,104,97,115,32,98,101,101,110,32],[32,111,102,32,116,104,101,32,112,114,105,110,116,105,110,103,32,97,110,100,32,116,121,112,101,115,101,116,116,105,110,103],[76,111,114,101,109,32,73,112,115,117,109,32,105,115,32,115,105,109,112,108,121,32,100,117,109,109,121,32,116,101,120,116],[2,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],[223,105,102,201,113,5,28,61,84,236,89,22,38,6,83,20,147,165,20,4,160,2,132,47,86,0,157,126,92,244,168,199],[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0],[98,248,75,36,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],[223,105,102,201,113,5,28,61,84,236,89,22,38,6,83,20,147,165,20,4,160,2,132,47,86,0,157,126,92,244,168,198],[223,105,102,201,113,5,28,61,84,236,89,22,38,6,83,20,147,165,20,4,160,2,132,47,86,0,157,126,92,244,168,201],[223,105,102,201,113,5,28,61,84,236,89,22,38,6,83,20,147,165,20,4,160,2,132,47,86,0,157,126,92,244,168,200],[128,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],[83,111,109,101,32,101,114,114,111,114,32,109,101,115,115,97,103,101,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,0,100,0,0,0,0,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[133,189,45,42,160,229,82,140,202,50,72,223,177,233,146,208,17,58,85,56,2,215,146,79,223,4,154,233,237,29,91,48],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,63],[97,97,97,97,97,97,97,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],[97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97],[97,97,97,97,97,97,97,97,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[97,97,97,97,97,97,97,97,97,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[102,3,194,241,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0],[72,101,97,112,32,115,104,111,117,108,100,32,110,111,116,32,98,101,32,109,111,100,105,102,105,101,100,0,0,0,0,0],[171,37,105,15,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,159],[20,67,19,57,18,139,210,95,44,127,147,186,166,17,227,103,71,32,72,117,127,74,214,127,109,113,165,202,13,165,80,245],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,127],[28,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],[70,234,191,53,104,3,40,226,110,244,87,156,175,138,235,44,249,236,224,93,191,103,164,243,209,242,140,123,29,14,53,70],[81,228,219,187,206,186,222,105,90,63,15,223,16,190,184,181,248,63,218,22,30,26,49,5,161,76,65,22,139,243,220,224],[0,0,0,0,0,0,0,0,0,0,0,0,127,139,59,4,191,52,97,143,74,23,35,251,169,107,93,178,17,39,154,43],[224,104,47,212,162,96,50,175,255,59,24,5,58,12,51,210,166,196,101,192,225,156,177,228,193,14,176,169,73,242,130,124],[11,219,95,10,199,157,26,126,253,194,85,243,153,160,69,3,140,27,67,62,157,6,193,177,171,213,138,95,202,171,51,241],[196,108,220,80,166,111,77,7,198,233,161,39,167,39,126,136,47,178,27,207,181,176,104,242,181,140,127,114,131,153,59,121],[0,0,0,0,0,0,0,0,0,0,0,0,8,101,167,125,77,104,199,227,205,210,25,212,49,207,238,146,113,144,80,116],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0],[46,56,93,100,142,59,225,148,212,95,187,31,114,41,239,16,197,183,238,28,124,48,20,90,164,221,249,56,14,171,90,3],[155,55,233,20,69,233,43,20,35,53,72,37,170,51,216,65,216,60,172,253,216,149,211,22,174,136,218,188,49,115,105,150],[0,0,0,0,0,0,0,0,0,0,0,0,158,21,153,225,16,206,239,79,21,232,238,112,106,217,205,74,91,142,198,237],[221,105,233,149,15,82,221,220,188,103,81,253,187,105,73,120,124,193,184,74,196,2,10,176,97,126,200,173,149,14,85,74],[27,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],[64,104,245,181,230,196,180,66,232,63,203,123,98,144,82,14,187,94,7,124,209,13,59,216,108,244,49,202,75,100,1,98],[176,9,134,216,187,82,238,122,203,6,202,191,166,194,192,153,216,144,76,124,141,86,112,122,38,125,219,175,215,174,208,112],[0,0,0,0,0,0,0,0,0,0,0,0,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238],[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,1,255,255,255,224],[102,97,105,108,101,100,32,116,114,97,110,115,102,101,114,32,99,97,108,108,0,0,0,0,0,0,0,0,0,0,0,0],[102,97,105,108,101,100,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],[115,101,110,100,105,110,103,32,108,49,32,109,101,115,115,97,103,101,115,32,116,101,115,116,32,115,104,111,117,108,100,32],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,0,0],[104,101,97,112,32,116,101,115,116,32,115,104,111,117,108,100,32,102,97,105,108,101,100,0,0,0,0,0,0,0,0,0],[72,101,97,112,32,115,104,111,117,108,100,32,110,111,116,32,98,101,32,101,109,112,116,121,0,0,0,0,0,0,0,0],[119,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],[78,72,123,113,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,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,0,0,0,0,0,0,0,0,119,55,221,230],[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,175,100,13,14],[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,198,249,104,131],[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,198,249,104,132],[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,230,246,42,184],[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,251,56,170,86],[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,175,100,13,15],[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,190,139,17,32],[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,135,78,143,142],[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,135,78,143,143],[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,153,58,4,183],[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,171,37,105,15],[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,119,55,221,231],[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,127,213,148,97],[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,72,64,160,80],[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,89,48,143,14],[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,89,48,143,15],[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,94,254,75,180],[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,102,3,194,241],[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,72,64,160,81],[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,87,154,227,236],[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,34,132,79,187],[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,34,132,79,188],[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,42,187,215,72],[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,2,208,93,63],[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,25,216,172,97],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,128,0,0,0,0,0,0,0,0],[84,101,115,116,32,109,101,115,115,97,103,101,32,50,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,0,0,0,0,0,14,0,0,0,128,0,0,0,0,0,0,0,0],[62,169,138,246,227,81,65,251,202,204,23,36,225,79,93,118,185,181,142,65,246,195,93,14,138,226,226,4,230,102,149,235],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,160],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,96],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,64],[214,157,133,29,132,62,228,160,250,200,14,30,42,137,20,209,16,252,193,75,95,47,89,133,35,162,110,88,69,252,146,234]],"default_account_code":[[0,4,0,0,0,0,0,2,0,12,0,0,0,0,0,2,0,0,0,0,3,1,0,25,0,0,0,96,7,48,2,112],[0,0,5,2,6,112,1,151,0,3,0,0,0,97,3,85,0,2,0,0,0,1,3,85,0,0,5,2,0,112,1,157],[0,0,0,128,4,0,0,57,0,0,0,64,0,64,4,63,0,0,0,1,2,32,1,144,0,0,0,44,0,0,193,61],[0,0,0,4,2,96,0,140,0,0,0,52,0,0,65,61,0,0,0,0,2,1,4,59,0,0,0,224,2,32,2,112],[0,0,5,4,3,32,0,156,0,0,0,68,0,0,161,61,0,0,5,5,3,32,0,156,0,0,0,150,0,0,97,61],[0,0,5,6,3,32,0,156,0,0,0,197,0,0,97,61,0,0,5,7,2,32,0,156,0,0,0,54,0,0,193,61],[0,0,0,4,2,96,0,138,0,0,0,32,3,32,0,140,0,0,1,39,0,0,65,61,0,0,0,4,1,16,3,112],[0,0,0,0,1,1,4,59,0,0,5,10,3,16,0,156,0,0,1,39,0,0,33,61,0,0,0,0,1,18,0,73],[0,0,5,11,2,0,0,65,0,0,2,96,3,16,0,140,0,0,0,0,3,0,0,25,0,0,0,0,3,2,64,25],[0,0,5,11,1,16,1,151,0,0,0,0,4,1,0,75,0,0,0,0,2,0,160,25,0,0,5,11,1,16,0,156],[0,0,0,0,2,3,192,25,0,0,0,0,1,2,0,75,0,0,3,118,0,0,97,61,0,0,1,39,0,0,1,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,1,39,0,0,193,61,0,0,0,32,1,0,0,57],[0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,5,3,1,0,0,65,0,0,20,2,0,1,4,46],[0,0,0,0,1,6,0,75,0,0,3,118,0,0,97,61,0,0,0,0,1,0,4,18,0,0,5,12,1,16,1,151],[0,0,0,0,2,0,4,16,0,0,0,0,1,33,0,75,0,0,3,118,0,0,193,61,0,0,0,0,1,0,4,17],[0,0,128,1,1,16,0,140,0,0,3,118,0,0,193,61,0,0,5,88,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,1,1,0,0,57,0,0,0,4,0,16,4,63,0,0,5,89,1,0,0,65,0,0,20,3,0,1,4,48],[0,0,5,8,3,32,0,156,0,0,1,17,0,0,97,61,0,10,0,0,0,4,0,29,0,0,5,9,2,32,0,156],[0,0,0,54,0,0,193,61,0,0,0,4,2,96,0,138,0,0,0,96,2,32,0,140,0,0,1,39,0,0,65,61],[0,0,0,68,2,16,3,112,0,0,0,0,3,2,4,59,0,0,5,10,2,48,0,156,0,0,1,39,0,0,33,61],[0,0,0,4,4,48,0,57,0,0,0,0,5,70,0,73,0,0,5,11,2,0,0,65,0,0,2,96,7,80,0,140],[0,0,0,0,7,0,0,25,0,0,0,0,7,2,64,25,0,0,5,11,8,80,1,151,0,0,0,0,9,8,0,75],[0,0,0,0,2,0,160,25,0,0,5,11,8,128,0,156,0,0,0,0,2,7,192,25,0,0,0,0,2,2,0,75],[0,0,1,39,0,0,193,61,0,0,0,0,2,0,4,17,0,0,128,1,2,32,0,140,0,0,3,118,0,0,193,61],[0,0,0,0,2,0,4,18,0,0,5,12,7,32,1,151,0,0,0,0,2,0,4,16,0,0,0,0,7,39,0,75],[0,0,3,118,0,0,193,61,0,0,2,36,3,48,0,57,0,0,0,0,7,49,3,79,0,0,0,0,7,7,4,59],[0,0,0,31,5,80,0,138,0,0,5,11,8,0,0,65,0,0,0,0,9,87,0,75,0,0,0,0,9,0,0,25],[0,0,0,0,9,8,128,25,0,0,5,11,5,80,1,151,0,0,5,11,10,112,1,151,0,0,0,0,11,90,0,75],[0,0,0,0,8,0,128,25,0,0,0,0,5,90,1,63,0,0,5,11,5,80,0,156,0,0,0,0,8,9,192,25],[0,0,0,0,5,8,0,75,0,0,1,39,0,0,193,61,0,0,0,0,5,71,0,25,0,0,0,0,4,81,3,79],[0,0,0,0,4,4,4,59,0,0,5,10,7,64,0,156,0,0,1,39,0,0,33,61,0,0,0,0,7,70,0,73],[0,0,0,32,5,80,0,57,0,0,5,11,8,0,0,65,0,0,0,0,9,117,0,75,0,0,0,0,9,0,0,25],[0,0,0,0,9,8,32,25,0,0,5,11,7,112,1,151,0,0,5,11,10,80,1,151,0,0,0,0,11,122,0,75],[0,0,0,0,8,0,128,25,0,0,0,0,7,122,1,63,0,0,5,11,7,112,0,156,0,0,0,0,8,9,192,25],[0,0,0,0,7,8,0,75,0,0,1,39,0,0,193,61,0,0,0,3,7,64,0,140,0,0,2,87,0,0,33,61],[0,0,5,16,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63],[0,0,0,58,1,0,0,57,0,0,0,164,0,16,4,63,0,0,5,50,1,0,0,65,0,0,0,196,0,16,4,63],[0,0,5,51,1,0,0,65,0,0,2,103,0,0,1,61,0,0,0,4,2,96,0,138,0,0,0,96,2,32,0,140],[0,0,1,39,0,0,65,61,0,0,0,68,2,16,3,112,0,0,0,0,3,2,4,59,0,0,5,10,2,48,0,156],[0,0,1,39,0,0,33,61,0,0,0,4,2,48,0,57,0,0,0,0,5,38,0,73,0,0,5,11,4,0,0,65],[0,0,2,96,8,80,0,140,0,0,0,0,8,0,0,25,0,0,0,0,8,4,64,25,0,0,5,11,9,80,1,151],[0,0,0,0,10,9,0,75,0,0,0,0,4,0,160,25,0,0,5,11,9,144,0,156,0,0,0,0,4,8,192,25],[0,0,0,0,4,4,0,75,0,0,1,39,0,0,193,61,0,0,0,0,4,0,4,17,0,0,128,1,4,64,0,140],[0,0,3,118,0,0,193,61,0,0,0,0,4,0,4,18,0,0,5,12,4,64,1,151,0,0,0,0,8,0,4,16],[0,0,0,0,4,132,0,75,0,0,3,118,0,0,193,61,0,0,0,68,4,48,0,57,0,0,0,0,4,65,3,79],[0,0,1,36,8,48,0,57,0,0,0,0,3,129,3,79,0,0,0,0,4,4,4,59,0,0,5,12,4,64,1,151],[0,0,0,0,3,3,4,59,0,0,5,18,9,48,0,156,0,0,1,248,0,0,65,61,0,0,5,16,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,8,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,5,27,1,0,0,65,0,0,0,196,0,16,4,63,0,0,5,28,1,0,0,65],[0,0,20,3,0,1,4,48,0,0,0,4,3,96,0,138,0,0,0,96,2,48,0,140,0,0,1,39,0,0,65,61],[0,0,0,68,2,16,3,112,0,0,0,0,2,2,4,59,0,0,5,10,4,32,0,156,0,0,1,39,0,0,33,61],[0,0,0,0,3,35,0,73,0,0,5,11,4,0,0,65,0,0,2,96,5,48,0,140,0,0,0,0,5,0,0,25],[0,0,0,0,5,4,64,25,0,0,5,11,3,48,1,151,0,0,0,0,6,3,0,75,0,0,0,0,4,0,160,25],[0,0,5,11,3,48,0,156,0,0,0,0,4,5,192,25,0,0,0,0,3,4,0,75,0,0,1,39,0,0,193,61],[0,0,0,0,3,0,4,17,0,0,128,1,3,48,0,140,0,0,3,118,0,0,193,61,0,0,0,0,3,0,4,18],[0,0,5,12,3,48,1,151,0,0,0,0,4,0,4,16,0,0,0,0,3,67,0,75,0,0,3,118,0,0,193,61],[0,0,0,164,3,32,0,57,0,0,0,0,3,49,3,79,0,0,0,100,2,32,0,57,0,0,0,0,1,33,3,79],[0,0,0,0,1,1,4,59,0,0,0,0,2,3,4,59,0,0,0,0,3,2,0,75,0,0,1,224,0,0,193,61],[0,0,0,0,4,0,4,21,0,0,0,12,4,64,0,138,0,0,0,32,4,64,0,201,0,0,0,0,1,0,4,20],[0,12,0,0,0,0,0,29,0,10,0,0,0,4,0,29,0,0,5,2,2,0,0,65,0,0,5,2,3,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,192,1,16,2,16,0,0,128,1,2,0,0,57,20,1,19,237,0,0,4,15],[0,0,0,10,3,0,0,41,0,3,0,0,0,1,3,85,0,0,0,96,1,16,2,112,0,1,5,2,0,16,1,157],[0,0,0,5,1,48,2,112,0,0,0,1,1,32,1,149,0,0,0,1,1,32,1,144,0,0,3,118,0,0,193,61],[0,0,0,64,1,0,4,61,0,0,0,100,2,16,0,57,0,0,5,14,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,68,2,16,0,57,0,0,5,15,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,37,3,0,0,57,0,0,0,0,0,50,4,53,0,0,5,16,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53,0,0,5,2,2,0,0,65],[0,0,5,2,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,5,17,1,16,1,199],[0,0,20,3,0,1,4,48,0,0,0,4,2,96,0,138,0,0,0,96,2,32,0,140,0,0,1,39,0,0,65,61],[0,0,0,68,2,16,3,112,0,0,0,0,2,2,4,59,0,10,0,0,0,2,0,29,0,0,5,10,2,32,0,156],[0,0,1,39,0,0,33,61,0,0,0,10,2,0,0,41,0,9,0,4,0,32,0,61,0,0,0,9,2,96,0,106],[0,0,5,11,3,0,0,65,0,0,2,96,4,32,0,140,0,0,0,0,4,0,0,25,0,0,0,0,4,3,64,25],[0,0,5,11,2,32,1,151,0,0,0,0,5,2,0,75,0,0,0,0,3,0,160,25,0,0,5,11,2,32,0,156],[0,0,0,0,3,4,192,25,0,0,0,0,2,3,0,75,0,0,1,41,0,0,97,61,0,0,0,0,1,0,0,25],[0,0,20,3,0,1,4,48,0,0,0,36,2,16,3,112,0,0,0,0,2,2,4,59,0,8,0,0,0,2,0,29],[0,0,0,0,2,0,4,17,0,0,128,1,2,32,0,140,0,0,3,118,0,0,193,61,0,0,0,0,2,0,4,18],[0,0,5,12,2,32,1,151,0,0,0,0,3,0,4,16,0,7,0,0,0,3,0,29,0,0,0,0,2,50,0,75],[0,0,3,118,0,0,193,61,0,0,0,0,2,0,4,20,0,0,5,52,3,0,0,65,0,0,0,160,0,48,4,63],[0,0,0,10,3,0,0,41,0,6,1,4,0,48,0,61,0,0,0,6,1,16,3,96,0,0,0,0,1,1,4,59],[0,0,0,164,0,16,4,63,0,0,0,36,1,0,0,57,0,0,0,128,0,16,4,63,0,0,0,224,1,0,0,57],[0,0,0,64,0,16,4,63,0,0,0,192,1,32,2,16,0,0,5,24,1,16,1,151,0,0,5,53,1,16,1,199],[0,0,128,3,2,0,0,57,0,0,0,0,3,0,0,25,0,0,0,0,4,0,0,25,0,0,0,0,5,0,0,25],[0,0,0,0,6,0,0,25,20,1,19,237,0,0,4,15,0,3,0,0,0,1,3,85,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,1,5,2,0,48,1,157,0,0,5,2,8,48,1,151,0,0,0,63,3,128,0,57],[0,0,5,54,4,48,1,151,0,0,0,64,6,0,4,61,0,0,0,0,3,100,0,25,0,0,0,0,4,67,0,75],[0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57,0,0,5,10,5,48,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,4,64,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,48,4,63,0,0,0,0,7,134,4,54],[0,0,0,2,3,0,3,103,0,0,0,0,4,0,0,49,0,0,0,0,5,67,3,79,0,0,0,31,9,128,0,57],[0,0,0,5,9,144,2,114,0,0,1,107,0,0,97,61,0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16],[0,0,0,0,12,183,0,25,0,0,0,0,11,181,3,79,0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53],[0,0,0,1,10,160,0,57,0,0,0,0,11,154,0,75,0,0,1,99,0,0,65,61,0,0,0,0,9,0,0,75],[0,0,1,109,0,0,97,61,0,0,0,31,9,128,1,143,0,0,0,5,8,128,2,114,0,0,1,121,0,0,97,61],[0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16,0,0,0,0,12,183,0,25,0,0,0,0,11,177,3,79],[0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53,0,0,0,1,10,160,0,57,0,0,0,0,11,138,0,75],[0,0,1,113,0,0,65,61,0,0,0,0,10,9,0,75,0,0,1,136,0,0,97,61,0,0,0,5,8,128,2,16],[0,0,0,0,1,129,3,79,0,0,0,0,8,135,0,25,0,0,0,3,9,144,2,16,0,0,0,0,10,8,4,51],[0,0,0,0,10,154,1,207,0,0,0,0,10,154,2,47,0,0,0,0,1,1,4,59,0,0,1,0,9,144,0,137],[0,0,0,0,1,145,2,47,0,0,0,0,1,145,1,207,0,0,0,0,1,161,1,159,0,0,0,0,0,24,4,53],[0,0,0,1,1,32,1,144,0,0,2,77,0,0,97,61,0,0,0,8,1,0,0,107,0,0,16,183,0,0,193,61],[0,0,0,6,1,0,0,41,0,0,1,0,1,16,0,138,0,0,0,0,1,19,3,79,0,0,0,0,1,1,4,59],[0,0,0,0,2,1,0,75,0,0,2,106,0,0,193,61,0,0,0,6,1,48,3,96,0,0,0,64,9,0,4,61],[0,0,0,0,1,1,4,59,0,0,0,128,2,16,0,140,0,8,0,0,0,9,0,29,0,0,2,161,0,0,65,61],[0,0,0,128,2,16,2,112,0,0,5,60,6,16,0,156,0,0,0,0,2,1,160,25,0,0,5,60,6,16,0,156],[0,0,0,0,6,0,0,25,0,0,0,16,6,0,32,57,0,0,0,8,7,96,1,191,0,0,5,10,8,32,0,156],[0,0,0,0,7,6,160,25,0,0,0,64,6,32,2,112,0,0,5,10,8,32,0,156,0,0,0,0,6,2,160,25],[0,0,0,4,8,112,1,191,0,0,5,2,2,96,0,156,0,0,0,0,8,7,160,25,0,0,0,32,7,96,2,112],[0,0,5,2,2,96,0,156,0,0,0,0,7,6,160,25,0,0,0,2,2,128,1,191,0,0,255,255,6,112,0,140],[0,0,0,0,2,8,160,25,0,0,0,16,6,112,2,112,0,0,0,0,6,7,160,25,0,0,0,255,6,96,0,140],[0,0,0,1,2,32,32,57,0,0,0,32,6,0,0,138,0,0,0,65,7,32,0,57,0,0,0,0,6,103,1,111],[0,0,0,0,6,105,0,25,0,0,0,0,7,150,0,75,0,0,0,0,7,0,0,25,0,0,0,1,7,0,64,57],[0,0,5,10,8,96,0,156,0,0,18,165,0,0,33,61,0,0,0,1,7,112,1,144,0,0,18,165,0,0,193,61],[0,0,0,64,0,96,4,63,0,0,0,2,6,32,0,57,0,0,0,8,7,0,0,41,0,0,0,0,6,103,4,54],[0,0,0,33,7,32,0,57,0,0,0,5,7,112,2,114,0,0,1,204,0,0,97,61,0,0,0,0,8,0,0,25],[0,0,0,5,9,128,2,16,0,0,0,0,10,150,0,25,0,0,0,0,9,149,3,79,0,0,0,0,9,9,4,59],[0,0,0,0,0,154,4,53,0,0,0,1,8,128,0,57,0,0,0,0,9,120,0,75,0,0,1,196,0,0,65,61],[0,0,0,0,7,0,0,75,0,0,1,206,0,0,97,61,0,0,0,8,7,0,0,41,0,0,0,0,7,7,4,51],[0,0,0,0,7,7,0,75,0,0,12,17,0,0,97,61,0,0,0,0,7,6,4,51,0,0,5,59,7,112,1,151],[0,0,0,248,8,32,2,16,0,0,0,0,7,120,1,159,0,0,5,61,7,112,0,65,0,0,0,0,0,118,4,53],[0,0,0,3,2,32,2,16,0,0,0,248,2,32,0,137,0,0,0,0,1,33,1,207,0,0,0,255,2,32,0,140],[0,0,0,0,1,0,32,25,0,0,0,8,2,0,0,41,0,0,0,33,2,32,0,57,0,0,2,178,0,0,1,61],[0,0,0,0,67,18,0,169,0,0,0,0,66,35,0,217,0,0,0,0,1,18,0,75,0,0,16,208,0,0,193,61],[0,0,0,0,4,0,4,21,0,0,0,11,4,64,0,138,0,0,0,32,4,64,0,201,0,0,0,0,1,0,4,20],[0,11,0,0,0,0,0,29,0,0,0,0,2,3,0,75,0,0,0,237,0,0,97,61,0,0,5,2,2,0,0,65],[0,0,5,2,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,192,1,16,2,16,0,0,5,13,1,16,1,199],[0,0,128,9,2,0,0,57,0,0,128,1,4,0,0,57,0,0,0,0,5,0,0,25,20,1,19,237,0,0,4,15],[0,0,0,0,3,0,4,21,0,0,0,11,3,48,0,138,0,0,0,32,3,48,0,201,0,0,0,245,0,0,1,61],[0,0,0,160,8,128,0,57,0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,31,5,80,0,138],[0,0,5,11,9,0,0,65,0,0,0,0,10,88,0,75,0,0,0,0,10,0,0,25,0,0,0,0,10,9,128,25],[0,0,5,11,5,80,1,151,0,0,5,11,11,128,1,151,0,0,0,0,12,91,0,75,0,0,0,0,9,0,128,25],[0,0,0,0,5,91,1,63,0,0,5,11,5,80,0,156,0,0,0,0,9,10,192,25,0,0,0,0,5,9,0,75],[0,0,1,39,0,0,193,61,0,0,0,0,2,40,0,25,0,0,0,0,5,33,3,79,0,0,0,0,8,5,4,59],[0,0,5,10,5,128,0,156,0,0,1,39,0,0,33,61,0,0,0,0,5,134,0,73,0,0,0,32,9,32,0,57],[0,0,5,11,2,0,0,65,0,0,0,0,10,89,0,75,0,0,0,0,10,0,0,25,0,0,0,0,10,2,32,25],[0,0,5,11,5,80,1,151,0,0,5,11,11,144,1,151,0,0,0,0,12,91,0,75,0,0,0,0,2,0,128,25],[0,0,0,0,5,91,1,63,0,0,5,11,5,80,0,156,0,0,0,0,2,10,192,25,0,0,0,0,2,2,0,75],[0,0,1,39,0,0,193,61,0,0,0,0,2,0,4,20,0,0,5,2,5,32,0,156,0,0,0,187,0,0,33,61],[0,0,128,6,5,64,0,140,0,0,0,0,5,0,0,25,0,0,2,52,0,0,193,61,0,0,0,4,5,128,0,140],[0,0,0,0,5,0,0,25,0,0,2,52,0,0,65,61,0,0,0,0,10,145,3,79,0,0,0,1,5,0,0,57],[0,0,0,0,10,10,4,59,0,0,5,19,10,160,1,151,0,0,5,20,11,160,0,156,0,0,2,51,0,0,97,61],[0,0,5,21,11,160,0,156,0,0,2,51,0,0,97,61,0,0,5,22,11,160,0,156,0,0,2,51,0,0,97,61],[0,0,5,23,5,160,0,156,0,0,0,0,5,0,0,25,0,0,0,1,5,0,96,57,0,0,0,1,5,80,1,143],[0,0,0,0,10,152,0,25,0,0,0,0,6,166,0,75,0,0,0,0,6,0,0,25,0,0,0,1,6,0,64,57],[0,0,0,0,8,138,0,75,0,0,0,1,6,96,65,191,0,0,5,2,8,144,1,151,0,0,0,0,1,129,3,79],[0,0,0,0,8,3,0,75,0,0,3,99,0,0,193,61,0,0,0,1,3,96,1,144,0,0,16,208,0,0,193,61],[0,0,5,25,3,0,0,65,0,0,5,26,6,0,0,65,0,0,0,0,5,5,0,75,0,0,0,0,6,3,192,25],[0,0,0,192,2,32,2,16,0,0,5,24,2,32,1,151,0,0,0,0,2,38,1,159,0,0,0,0,3,167,0,73],[0,0,5,2,3,48,1,151,0,0,0,0,1,49,3,223,0,0,0,0,1,33,3,175,0,0,0,0,2,4,0,25],[0,0,3,110,0,0,1,61,0,0,0,0,1,6,4,51,0,0,5,2,2,0,0,65,0,0,5,2,3,16,0,156],[0,0,0,0,1,2,128,25,0,0,5,2,3,112,0,156,0,0,0,0,7,2,128,25,0,0,0,64,2,112,2,16],[0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,20,3,0,1,4,48,0,0,0,0,7,81,3,79],[0,0,0,0,7,7,4,59,0,0,5,19,7,112,1,151,0,0,5,29,8,112,0,156,0,0,2,255,0,0,193,61],[0,0,0,67,4,64,0,140,0,0,3,120,0,0,33,61,0,0,5,16,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,64,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,5,47,1,0,0,65,0,0,0,196,0,16,4,63,0,0,5,48,1,0,0,65,0,0,0,228,0,16,4,63],[0,0,5,49,1,0,0,65,0,0,20,3,0,1,4,48,0,0,0,113,2,16,0,140,0,0,3,9,0,0,193,61],[0,0,0,10,2,0,0,41,0,0,1,196,1,32,0,57,0,0,0,0,1,19,3,79,0,0,0,0,2,36,0,73],[0,0,0,35,2,32,0,138,0,0,0,0,1,1,4,59,0,0,5,11,5,0,0,65,0,0,0,0,6,33,0,75],[0,0,0,0,6,0,0,25,0,0,0,0,6,5,128,25,0,0,5,11,2,32,1,151,0,0,5,11,7,16,1,151],[0,0,0,0,8,39,0,75,0,0,0,0,5,0,128,25,0,0,0,0,2,39,1,63,0,0,5,11,2,32,0,156],[0,0,0,0,5,6,192,25,0,0,0,0,2,5,0,75,0,0,1,39,0,0,193,61,0,0,0,9,1,16,0,41],[0,0,0,0,2,19,3,79,0,0,0,0,2,2,4,59,0,0,5,10,5,32,0,156,0,0,1,39,0,0,33,61],[0,0,0,0,5,36,0,73,0,0,0,32,1,16,0,57,0,0,5,11,6,0,0,65,0,0,0,0,7,81,0,75],[0,0,0,0,7,0,0,25,0,0,0,0,7,6,32,25,0,0,5,11,5,80,1,151,0,0,5,11,8,16,1,151],[0,0,0,0,9,88,0,75,0,0,0,0,6,0,128,25,0,0,0,0,5,88,1,63,0,0,5,11,5,80,0,156],[0,0,0,0,6,7,192,25,0,0,0,0,5,6,0,75,0,0,1,39,0,0,193,61,0,0,0,0,5,18,0,26],[0,0,0,0,2,0,4,20,0,0,16,208,0,0,65,61,0,0,0,0,6,84,0,75,0,0,16,208,0,0,65,61],[0,0,5,67,6,32,0,156,0,0,6,77,0,0,65,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57],[0,0,5,27,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,8,3,0,0,57],[0,0,4,110,0,0,1,61,0,0,5,58,2,144,0,156,0,0,18,165,0,0,33,61,0,0,0,8,6,0,0,41],[0,0,0,64,2,96,0,57,0,0,0,64,0,32,4,63,0,0,0,1,2,0,0,58,0,0,0,0,2,38,4,54],[0,0,0,0,6,80,3,80,0,0,0,0,6,6,4,59,0,0,0,0,0,98,4,53,0,0,12,17,0,0,97,61],[0,0,0,248,7,16,2,16,0,0,5,11,8,0,0,65,0,0,0,0,1,1,0,75,0,0,0,0,8,7,192,25],[0,0,5,59,1,96,1,151,0,0,0,0,1,129,1,159,0,0,0,0,0,18,4,53,0,0,0,64,1,0,4,61],[0,0,0,6,2,0,0,41,0,0,0,96,2,32,0,138,0,0,0,0,6,35,3,79,0,0,0,0,6,6,4,59],[0,0,0,128,7,96,0,140,0,0,3,241,0,0,65,61,0,0,0,128,7,96,2,112,0,0,5,60,8,96,0,156],[0,0,0,0,7,6,160,25,0,0,5,60,8,96,0,156,0,0,0,0,8,0,0,25,0,0,0,16,8,0,32,57],[0,0,0,8,9,128,1,191,0,0,5,10,10,112,0,156,0,0,0,0,9,8,160,25,0,0,0,64,8,112,2,112],[0,0,5,10,10,112,0,156,0,0,0,0,8,7,160,25,0,0,0,4,10,144,1,191,0,0,5,2,7,128,0,156],[0,0,0,0,10,9,160,25,0,0,0,32,9,128,2,112,0,0,5,2,7,128,0,156,0,0,0,0,9,8,160,25],[0,0,0,2,7,160,1,191,0,0,255,255,8,144,0,140,0,0,0,0,7,10,160,25,0,0,0,16,8,144,2,112],[0,0,0,0,8,9,160,25,0,0,0,255,8,128,0,140,0,0,0,1,7,112,32,57,0,0,0,32,8,0,0,138],[0,0,0,65,9,112,0,57,0,0,0,0,8,137,1,111,0,0,0,0,8,129,0,25,0,0,0,0,9,24,0,75],[0,0,0,0,9,0,0,25,0,0,0,1,9,0,64,57,0,0,5,10,10,128,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,9,144,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,128,4,63,0,0,0,2,8,112,0,57],[0,0,0,0,8,129,4,54,0,0,0,33,9,112,0,57,0,0,0,5,9,144,2,114,0,0,2,237,0,0,97,61],[0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16,0,0,0,0,12,184,0,25,0,0,0,0,11,181,3,79],[0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53,0,0,0,1,10,160,0,57,0,0,0,0,11,154,0,75],[0,0,2,229,0,0,65,61,0,0,0,0,9,0,0,75,0,0,2,239,0,0,97,61,0,0,0,0,9,1,4,51],[0,0,0,0,9,9,0,75,0,0,12,17,0,0,97,61,0,0,0,0,9,8,4,51,0,0,5,59,9,144,1,151],[0,0,0,248,10,112,2,16,0,0,0,0,9,154,1,159,0,0,5,61,9,144,0,65,0,0,0,0,0,152,4,53],[0,0,0,3,7,112,2,16,0,0,0,248,7,112,0,137,0,0,0,0,6,118,1,207,0,0,0,255,7,112,0,140],[0,0,0,0,6,0,32,25,0,0,0,33,7,16,0,57,0,0,4,1,0,0,1,61,0,0,5,30,1,112,0,156],[0,0,3,118,0,0,97,61,0,0,5,16,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,132,0,16,4,63,0,0,0,26,1,0,0,57,0,0,0,164,0,16,4,63,0,0,5,31,1,0,0,65],[0,0,0,194,0,0,1,61,0,0,0,2,2,16,0,140,0,0,3,151,0,0,193,61,0,0,5,56,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,5,2,1,0,0,65,0,0,0,0,2,0,4,20,0,0,5,2,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,57,1,16,1,199,0,0,128,11,2,0,0,57],[20,1,19,242,0,0,4,15,0,0,0,1,2,32,1,144,0,0,16,244,0,0,97,61,0,0,0,64,3,0,4,61],[0,0,0,0,4,1,4,59,0,0,0,128,1,64,0,140,0,0,4,122,0,0,65,61,0,0,0,128,1,64,2,112],[0,0,5,60,2,64,0,156,0,0,0,0,1,4,160,25,0,0,5,60,2,64,0,156,0,0,0,0,2,0,0,25],[0,0,0,16,2,0,32,57,0,0,0,8,5,32,1,191,0,0,5,10,6,16,0,156,0,0,0,0,5,2,160,25],[0,0,0,64,2,16,2,112,0,0,5,10,6,16,0,156,0,0,0,0,2,1,160,25,0,0,0,4,1,80,1,191],[0,0,5,2,6,32,0,156,0,0,0,0,1,5,160,25,0,0,0,32,6,32,2,112,0,0,5,2,5,32,0,156],[0,0,0,0,6,2,160,25,0,0,0,2,5,16,1,191,0,0,255,255,2,96,0,140,0,0,0,0,5,1,160,25],[0,0,0,16,1,96,2,112,0,0,0,0,1,6,160,25,0,0,0,255,1,16,0,140,0,0,0,1,5,80,32,57],[0,0,0,32,1,0,0,138,0,0,0,65,2,80,0,57,0,0,0,0,1,18,1,111,0,0,0,0,1,19,0,25],[0,0,0,0,2,49,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,5,10,6,16,0,156],[0,0,18,165,0,0,33,61,0,0,0,1,2,32,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,16,4,63],[0,0,0,2,1,80,0,57,0,0,0,0,6,19,4,54,0,0,0,2,1,0,3,103,0,0,0,0,2,0,0,49],[0,0,0,33,7,80,0,57,0,0,0,5,7,112,2,114,0,0,3,81,0,0,97,61,0,0,0,0,8,33,3,79],[0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16,0,0,0,0,11,166,0,25,0,0,0,0,10,168,3,79],[0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75],[0,0,3,73,0,0,65,61,0,0,0,0,7,0,0,75,0,0,3,83,0,0,97,61,0,0,0,0,7,3,4,51],[0,0,0,0,7,7,0,75,0,0,12,17,0,0,97,61,0,0,0,0,7,6,4,51,0,0,5,59,7,112,1,151],[0,0,0,248,8,80,2,16,0,0,0,0,7,120,1,159,0,0,5,61,7,112,0,65,0,0,0,0,0,118,4,53],[0,0,0,3,5,80,2,16,0,0,0,248,5,80,0,137,0,0,0,0,4,84,1,207,0,0,0,255,5,80,0,140],[0,0,0,0,4,0,32,25,0,0,0,33,5,48,0,57,0,0,4,141,0,0,1,61,0,0,0,1,6,96,1,144],[0,0,16,208,0,0,193,61,0,0,0,0,6,167,0,73,0,0,5,2,6,96,1,151,0,0,0,0,1,97,3,223],[0,0,0,192,2,32,2,16,0,0,5,24,2,32,1,151,0,0,5,25,2,32,1,199,0,0,0,0,1,33,3,175],[0,0,128,9,2,0,0,57,0,0,0,0,6,0,0,25,20,1,19,247,0,0,4,15,0,3,0,0,0,1,3,85],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,1,5,2,0,48,1,157,0,0,5,2,3,48,1,151],[0,0,0,1,2,32,1,144,0,0,4,77,0,0,97,61,0,0,0,0,1,0,0,25,0,0,20,2,0,1,4,46],[0,0,0,4,4,80,0,57,0,0,0,0,5,65,3,79,0,0,0,0,5,5,4,59,0,9,0,0,0,5,0,29],[0,0,5,12,5,80,0,156,0,0,1,39,0,0,33,61,0,0,1,64,3,48,0,138,0,0,0,0,3,49,3,79],[0,0,0,32,4,64,0,57,0,0,0,0,4,65,3,79,0,0,0,0,4,4,4,59,0,8,0,0,0,4,0,29],[0,0,0,0,3,3,4,59,0,0,5,32,4,0,0,65,0,0,0,128,0,64,4,63,0,0,5,12,2,32,1,151],[0,6,0,0,0,2,0,29,0,0,0,132,0,32,4,63,0,0,5,12,2,48,1,151,0,7,0,0,0,2,0,29],[0,0,0,164,0,32,4,63,0,0,0,0,2,0,4,20,0,0,0,9,3,0,0,41,0,0,0,4,3,48,0,140],[0,0,4,217,0,0,193,61,0,0,0,0,1,97,3,79,0,0,0,1,3,0,0,49,0,0,0,32,2,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,5,5,0,0,1,61,0,0,0,1,1,16,0,140],[0,0,4,104,0,0,193,61,0,0,5,56,1,0,0,65,0,0,0,0,0,16,4,57,0,0,5,2,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,5,2,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,5,57,1,16,1,199,0,0,128,11,2,0,0,57,20,1,19,242,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,16,244,0,0,97,61,0,0,0,64,3,0,4,61,0,0,0,0,4,1,4,59,0,0,0,128,1,64,0,140],[0,0,5,45,0,0,65,61,0,0,0,128,1,64,2,112,0,0,5,60,2,64,0,156,0,0,0,0,1,4,160,25],[0,0,5,60,2,64,0,156,0,0,0,0,2,0,0,25,0,0,0,16,2,0,32,57,0,0,0,8,5,32,1,191],[0,0,5,10,6,16,0,156,0,0,0,0,5,2,160,25,0,0,0,64,2,16,2,112,0,0,5,10,6,16,0,156],[0,0,0,0,2,1,160,25,0,0,0,4,1,80,1,191,0,0,5,2,6,32,0,156,0,0,0,0,1,5,160,25],[0,0,0,32,6,32,2,112,0,0,5,2,5,32,0,156,0,0,0,0,6,2,160,25,0,0,0,2,5,16,1,191],[0,0,255,255,2,96,0,140,0,0,0,0,5,1,160,25,0,0,0,16,1,96,2,112,0,0,0,0,1,6,160,25],[0,0,0,255,1,16,0,140,0,0,0,1,5,80,32,57,0,0,0,32,1,0,0,138,0,0,0,65,2,80,0,57],[0,0,0,0,1,18,1,111,0,0,0,0,1,19,0,25,0,0,0,0,2,49,0,75,0,0,0,0,2,0,0,25],[0,0,0,1,2,0,64,57,0,0,5,10,6,16,0,156,0,0,18,165,0,0,33,61,0,0,0,1,2,32,1,144],[0,0,18,165,0,0,193,61,0,0,0,64,0,16,4,63,0,0,0,2,1,80,0,57,0,0,0,0,6,19,4,54],[0,0,0,2,1,0,3,103,0,0,0,0,2,0,0,49,0,0,0,33,7,80,0,57,0,0,0,5,7,112,2,114],[0,0,3,223,0,0,97,61,0,0,0,0,8,33,3,79,0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16],[0,0,0,0,11,166,0,25,0,0,0,0,10,168,3,79,0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53],[0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75,0,0,3,215,0,0,65,61,0,0,0,0,7,0,0,75],[0,0,3,225,0,0,97,61,0,0,0,0,7,3,4,51,0,0,0,0,7,7,0,75,0,0,12,17,0,0,97,61],[0,0,0,0,7,6,4,51,0,0,5,59,7,112,1,151,0,0,0,248,8,80,2,16,0,0,0,0,7,120,1,159],[0,0,5,61,7,112,0,65,0,0,0,0,0,118,4,53,0,0,0,3,5,80,2,16,0,0,0,248,5,80,0,137],[0,0,0,0,4,84,1,207,0,0,0,255,5,80,0,140,0,0,0,0,4,0,32,25,0,0,0,33,5,48,0,57],[0,0,5,64,0,0,1,61,0,0,5,58,7,16,0,156,0,0,18,165,0,0,33,61,0,0,0,64,7,16,0,57],[0,0,0,64,0,112,4,63,0,0,0,1,7,0,0,58,0,0,0,0,7,113,4,54,0,0,0,0,8,80,3,80],[0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,12,17,0,0,97,61,0,0,0,248,9,96,2,16],[0,0,5,11,10,0,0,65,0,0,0,0,6,6,0,75,0,0,0,0,10,9,192,25,0,0,5,59,6,128,1,151],[0,0,0,0,6,166,1,159,0,0,0,0,0,103,4,53,0,0,0,64,2,32,0,138,0,0,0,0,6,35,3,79],[0,0,0,64,2,0,4,61,0,0,0,0,6,6,4,59,0,0,0,128,7,96,0,140,0,0,5,140,0,0,65,61],[0,0,0,128,7,96,2,112,0,0,5,60,8,96,0,156,0,0,0,0,7,6,160,25,0,0,5,60,8,96,0,156],[0,0,0,0,8,0,0,25,0,0,0,16,8,0,32,57,0,0,0,8,9,128,1,191,0,0,5,10,10,112,0,156],[0,0,0,0,9,8,160,25,0,0,0,64,8,112,2,112,0,0,5,10,10,112,0,156,0,0,0,0,8,7,160,25],[0,0,0,4,10,144,1,191,0,0,5,2,7,128,0,156,0,0,0,0,10,9,160,25,0,0,0,32,9,128,2,112],[0,0,5,2,7,128,0,156,0,0,0,0,9,8,160,25,0,0,0,2,7,160,1,191,0,0,255,255,8,144,0,140],[0,0,0,0,7,10,160,25,0,0,0,16,8,144,2,112,0,0,0,0,8,9,160,25,0,0,0,255,8,128,0,140],[0,0,0,1,7,112,32,57,0,0,0,32,8,0,0,138,0,0,0,65,9,112,0,57,0,0,0,0,8,137,1,111],[0,0,0,0,8,130,0,25,0,0,0,0,9,40,0,75,0,0,0,0,9,0,0,25,0,0,0,1,9,0,64,57],[0,0,5,10,10,128,0,156,0,0,18,165,0,0,33,61,0,0,0,1,9,144,1,144,0,0,18,165,0,0,193,61],[0,0,0,64,0,128,4,63,0,0,0,2,8,112,0,57,0,0,0,0,8,130,4,54,0,0,0,33,9,112,0,57],[0,0,0,5,9,144,2,114,0,0,4,59,0,0,97,61,0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16],[0,0,0,0,12,184,0,25,0,0,0,0,11,181,3,79,0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53],[0,0,0,1,10,160,0,57,0,0,0,0,11,154,0,75,0,0,4,51,0,0,65,61,0,0,0,0,9,0,0,75],[0,0,4,61,0,0,97,61,0,0,0,0,9,2,4,51,0,0,0,0,9,9,0,75,0,0,12,17,0,0,97,61],[0,0,0,0,9,8,4,51,0,0,5,59,9,144,1,151,0,0,0,248,10,112,2,16,0,0,0,0,9,154,1,159],[0,0,5,61,9,144,0,65,0,0,0,0,0,152,4,53,0,0,0,3,7,112,2,16,0,0,0,248,7,112,0,137],[0,0,0,0,6,118,1,207,0,0,0,255,7,112,0,140,0,0,0,0,6,0,32,25,0,0,0,33,7,32,0,57],[0,0,5,156,0,0,1,61,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114,0,0,4,88,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75,0,0,4,81,0,0,65,61],[0,0,0,0,5,4,0,75,0,0,4,102,0,0,97,61,0,0,0,3,4,64,2,16,0,0,0,5,2,32,2,16],[0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47,0,0,0,0,1,33,3,79],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16,0,0,20,3,0,1,4,48],[0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,5,55,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,23,3,0,0,57,0,0,0,0,0,50,4,53,0,0,5,16,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,5,2,2,0,0,65,0,0,5,2,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16],[0,0,5,46,1,16,1,199,0,0,20,3,0,1,4,48,0,0,5,58,1,48,0,156,0,0,18,165,0,0,33,61],[0,0,0,64,1,48,0,57,0,0,0,64,0,16,4,63,0,0,0,1,1,0,0,58,0,0,0,0,5,19,4,54],[0,0,0,0,2,0,0,49,0,0,0,2,1,0,3,103,0,0,0,0,6,33,3,79,0,0,0,0,6,96,3,80],[0,0,0,0,6,6,4,59,0,0,0,0,0,101,4,53,0,0,12,17,0,0,97,61,0,0,0,248,7,64,2,16],[0,0,5,11,8,0,0,65,0,0,0,0,4,4,0,75,0,0,0,0,8,7,192,25,0,0,5,59,4,96,1,151],[0,0,0,0,4,132,1,159,0,0,0,0,0,69,4,53,0,0,0,6,5,16,3,96,0,0,0,64,4,0,4,61],[0,0,0,0,5,5,4,59,0,0,0,128,6,80,0,140,0,0,8,32,0,0,65,61,0,0,0,128,6,80,2,112],[0,0,5,60,7,80,0,156,0,0,0,0,6,5,160,25,0,0,5,60,7,80,0,156,0,0,0,0,7,0,0,25],[0,0,0,16,7,0,32,57,0,0,0,8,8,112,1,191,0,0,5,10,9,96,0,156,0,0,0,0,8,7,160,25],[0,0,0,64,7,96,2,112,0,0,5,10,9,96,0,156,0,0,0,0,7,6,160,25,0,0,0,4,9,128,1,191],[0,0,5,2,6,112,0,156,0,0,0,0,9,8,160,25,0,0,0,32,8,112,2,112,0,0,5,2,6,112,0,156],[0,0,0,0,8,7,160,25,0,0,0,2,6,144,1,191,0,0,255,255,7,128,0,140,0,0,0,0,6,9,160,25],[0,0,0,16,7,128,2,112,0,0,0,0,7,8,160,25,0,0,0,255,7,112,0,140,0,0,0,1,6,96,32,57],[0,0,0,32,7,0,0,138,0,0,0,65,8,96,0,57,0,0,0,0,7,120,1,111,0,0,0,0,7,116,0,25],[0,0,0,0,8,71,0,75,0,0,0,0,8,0,0,25,0,0,0,1,8,0,64,57,0,0,5,10,9,112,0,156],[0,0,18,165,0,0,33,61,0,0,0,1,8,128,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,112,4,63],[0,0,0,2,7,96,0,57,0,0,0,0,7,116,4,54,0,0,0,33,8,96,0,57,0,0,0,5,8,128,2,114],[0,0,4,199,0,0,97,61,0,0,0,0,9,33,3,79,0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16],[0,0,0,0,12,183,0,25,0,0,0,0,11,185,3,79,0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53],[0,0,0,1,10,160,0,57,0,0,0,0,11,138,0,75,0,0,4,191,0,0,65,61,0,0,0,0,8,0,0,75],[0,0,4,201,0,0,97,61,0,0,0,0,8,4,4,51,0,0,0,0,8,8,0,75,0,0,12,17,0,0,97,61],[0,0,0,0,8,7,4,51,0,0,5,59,8,128,1,151,0,0,0,248,9,96,2,16,0,0,0,0,8,137,1,159],[0,0,5,61,8,128,0,65,0,0,0,0,0,135,4,53,0,0,0,3,6,96,2,16,0,0,0,248,6,96,0,137],[0,0,0,0,5,101,1,207,0,0,0,255,6,96,0,140,0,0,0,0,5,0,32,25,0,0,0,33,6,64,0,57],[0,0,8,49,0,0,1,61,0,0,5,2,1,0,0,65,0,0,5,2,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,5,33,1,16,1,199,0,0,0,9,2,0,0,41,20,1,19,242,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,5,2,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114],[0,0,4,242,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,129,3,79],[0,0,0,0,9,9,4,59,0,0,0,128,8,128,0,57,0,0,0,0,0,152,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,103,0,75,0,0,4,234,0,0,65,61,0,0,0,0,7,5,0,75,0,0,5,1,0,0,97,61],[0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,3,5,80,2,16,0,0,0,128,6,96,0,57],[0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159],[0,0,0,0,0,86,4,53,0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144],[0,0,6,42,0,0,97,61,0,0,0,31,2,64,0,57,0,0,0,96,5,32,1,143,0,0,0,128,2,80,1,191],[0,0,0,64,0,32,4,63,0,0,0,32,4,48,0,140,0,0,1,39,0,0,65,61,0,0,0,128,4,0,4,61],[0,0,0,8,4,64,0,108,0,0,3,118,0,0,129,61,0,0,0,160,4,80,0,57,0,0,5,34,6,0,0,65],[0,0,0,0,0,100,4,53,0,0,0,164,6,80,0,57,0,0,0,7,7,0,0,41,0,0,0,0,0,118,4,53],[0,0,0,196,6,80,0,57,0,0,0,0,0,6,4,53,0,0,0,68,6,0,0,57,0,1,0,0,0,6,0,29],[0,0,0,0,0,98,4,53,0,0,1,64,6,80,0,57,0,0,0,64,0,96,4,63,0,0,1,32,7,80,0,57],[0,0,5,35,6,0,0,65,0,3,0,0,0,7,0,29,0,0,0,0,0,103,4,53,0,0,1,0,6,80,1,191],[0,0,0,32,5,0,0,57,0,4,0,0,0,5,0,29,0,2,0,0,0,6,0,29,0,0,0,0,0,86,4,53],[0,0,0,0,5,2,4,51,0,0,0,0,2,0,4,20,0,0,0,9,6,0,0,41,0,0,0,4,6,96,0,140],[0,0,8,127,0,0,193,61,0,0,0,1,2,0,0,57,0,0,5,10,4,48,0,156,0,0,18,165,0,0,33,61],[0,0,8,147,0,0,1,61,0,0,5,58,1,48,0,156,0,0,18,165,0,0,33,61,0,0,0,64,1,48,0,57],[0,0,0,64,0,16,4,63,0,0,0,1,1,0,0,58,0,0,0,0,5,19,4,54,0,0,0,0,2,0,0,49],[0,0,0,2,1,0,3,103,0,0,0,0,6,33,3,79,0,0,0,0,6,96,3,80,0,0,0,0,6,6,4,59],[0,0,0,0,0,101,4,53,0,0,12,17,0,0,97,61,0,0,0,248,7,64,2,16,0,0,5,11,8,0,0,65],[0,0,0,0,4,4,0,75,0,0,0,0,8,7,192,25,0,0,5,59,4,96,1,151,0,0,0,0,4,132,1,159],[0,0,0,0,0,69,4,53,0,0,0,6,5,16,3,96,0,0,0,64,4,0,4,61,0,0,0,0,5,5,4,59],[0,0,0,128,6,80,0,140,0,0,8,225,0,0,65,61,0,0,0,128,6,80,2,112,0,0,5,60,7,80,0,156],[0,0,0,0,6,5,160,25,0,0,5,60,7,80,0,156,0,0,0,0,7,0,0,25,0,0,0,16,7,0,32,57],[0,0,0,8,8,112,1,191,0,0,5,10,9,96,0,156,0,0,0,0,8,7,160,25,0,0,0,64,7,96,2,112],[0,0,5,10,9,96,0,156,0,0,0,0,7,6,160,25,0,0,0,4,9,128,1,191,0,0,5,2,6,112,0,156],[0,0,0,0,9,8,160,25,0,0,0,32,8,112,2,112,0,0,5,2,6,112,0,156,0,0,0,0,8,7,160,25],[0,0,0,2,6,144,1,191,0,0,255,255,7,128,0,140,0,0,0,0,6,9,160,25,0,0,0,16,7,128,2,112],[0,0,0,0,7,8,160,25,0,0,0,255,7,112,0,140,0,0,0,1,6,96,32,57,0,0,0,32,7,0,0,138],[0,0,0,65,8,96,0,57,0,0,0,0,7,120,1,111,0,0,0,0,7,116,0,25,0,0,0,0,8,71,0,75],[0,0,0,0,8,0,0,25,0,0,0,1,8,0,64,57,0,0,5,10,9,112,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,8,128,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,112,4,63,0,0,0,2,7,96,0,57],[0,0,0,0,7,116,4,54,0,0,0,33,8,96,0,57,0,0,0,5,8,128,2,114,0,0,5,122,0,0,97,61],[0,0,0,0,9,33,3,79,0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16,0,0,0,0,12,183,0,25],[0,0,0,0,11,185,3,79,0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53,0,0,0,1,10,160,0,57],[0,0,0,0,11,138,0,75,0,0,5,114,0,0,65,61,0,0,0,0,8,0,0,75,0,0,5,124,0,0,97,61],[0,0,0,0,8,4,4,51,0,0,0,0,8,8,0,75,0,0,12,17,0,0,97,61,0,0,0,0,8,7,4,51],[0,0,5,59,8,128,1,151,0,0,0,248,9,96,2,16,0,0,0,0,8,137,1,159,0,0,5,61,8,128,0,65],[0,0,0,0,0,135,4,53,0,0,0,3,6,96,2,16,0,0,0,248,6,96,0,137,0,0,0,0,5,101,1,207],[0,0,0,255,6,96,0,140,0,0,0,0,5,0,32,25,0,0,0,33,6,64,0,57,0,0,8,242,0,0,1,61],[0,0,5,58,7,32,0,156,0,0,18,165,0,0,33,61,0,0,0,64,7,32,0,57,0,0,0,64,0,112,4,63],[0,0,0,1,7,0,0,58,0,0,0,0,7,114,4,54,0,0,0,0,8,80,3,80,0,0,0,0,8,8,4,59],[0,0,0,0,0,135,4,53,0,0,12,17,0,0,97,61,0,0,0,248,9,96,2,16,0,0,5,11,10,0,0,65],[0,0,0,0,6,6,0,75,0,0,0,0,10,9,192,25,0,0,5,59,6,128,1,151,0,0,0,0,6,166,1,159],[0,0,0,0,0,103,4,53,0,0,0,64,6,0,4,61,0,6,0,0,0,6,0,29,0,0,0,32,7,96,0,57],[0,0,0,0,6,1,4,51,0,0,0,0,8,6,0,75,0,0,5,171,0,0,97,61,0,0,0,0,8,0,0,25],[0,0,0,0,9,120,0,25,0,0,0,32,8,128,0,57,0,0,0,0,10,24,0,25,0,0,0,0,10,10,4,51],[0,0,0,0,0,169,4,53,0,0,0,0,9,104,0,75,0,0,5,164,0,0,65,61,0,0,0,0,1,118,0,25],[0,0,0,0,0,1,4,53,0,0,0,0,7,2,4,51,0,0,0,0,8,7,0,75,0,0,5,184,0,0,97,61],[0,0,0,0,8,0,0,25,0,0,0,0,9,24,0,25,0,0,0,32,8,128,0,57,0,0,0,0,10,40,0,25],[0,0,0,0,10,10,4,51,0,0,0,0,0,169,4,53,0,0,0,0,9,120,0,75,0,0,5,177,0,0,65,61],[0,0,0,0,1,23,0,25,0,0,0,0,0,1,4,53,0,0,0,0,1,103,0,25,0,0,0,6,6,0,0,41],[0,0,0,0,0,22,4,53,0,0,0,63,1,16,0,57,0,2,0,32,0,0,0,146,0,0,0,2,1,16,1,127],[0,0,0,0,2,97,0,25,0,0,0,0,1,18,0,75,0,0,0,0,1,0,0,25,0,0,0,1,1,0,64,57],[0,5,0,0,0,2,0,29,0,0,5,10,2,32,0,156,0,0,18,165,0,0,33,61,0,0,0,1,1,16,1,144],[0,0,18,165,0,0,193,61,0,0,0,5,1,0,0,41,0,0,0,64,0,16,4,63,0,0,5,58,1,16,0,156],[0,0,18,165,0,0,33,61,0,0,0,10,7,0,0,41,0,0,0,68,1,112,0,57,0,0,0,0,1,19,3,79],[0,0,0,0,1,1,4,59,0,0,0,5,8,0,0,41,0,0,0,64,2,128,0,57,0,0,0,64,0,32,4,63],[0,0,0,32,2,128,0,57,0,0,5,62,6,0,0,65,0,0,0,0,0,98,4,53,0,0,0,21,2,0,0,57],[0,0,0,0,0,40,4,53,0,0,0,96,1,16,2,16,0,0,0,33,2,128,0,57,0,0,0,0,0,18,4,53],[0,0,1,36,1,112,0,57,0,0,0,0,2,19,3,79,0,0,0,64,6,0,4,61,0,4,0,0,0,6,0,29],[0,0,0,0,2,2,4,59,0,0,0,128,6,32,0,140,0,0,9,223,0,0,65,61,0,0,0,128,6,32,2,112],[0,0,5,60,7,32,0,156,0,0,0,0,6,2,160,25,0,0,5,60,7,32,0,156,0,0,0,0,7,0,0,25],[0,0,0,16,7,0,32,57,0,0,0,8,8,112,1,191,0,0,5,10,9,96,0,156,0,0,0,0,8,7,160,25],[0,0,0,64,7,96,2,112,0,0,5,10,9,96,0,156,0,0,0,0,7,6,160,25,0,0,0,4,9,128,1,191],[0,0,5,2,6,112,0,156,0,0,0,0,9,8,160,25,0,0,0,32,8,112,2,112,0,0,5,2,6,112,0,156],[0,0,0,0,8,7,160,25,0,0,0,2,6,144,1,191,0,0,255,255,7,128,0,140,0,0,0,0,6,9,160,25],[0,0,0,16,7,128,2,112,0,0,0,0,7,8,160,25,0,0,0,255,7,112,0,140,0,0,0,1,6,96,32,57],[0,0,0,65,7,96,0,57,0,0,0,2,7,112,1,127,0,0,0,4,7,112,0,41,0,0,0,4,8,112,0,108],[0,0,0,0,8,0,0,25,0,0,0,1,8,0,64,57,0,0,5,10,9,112,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,8,128,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,112,4,63,0,0,0,2,7,96,0,57],[0,0,0,4,8,0,0,41,0,0,0,0,7,120,4,54,0,0,0,33,8,96,0,57,0,0,0,5,8,128,2,114],[0,0,6,22,0,0,97,61,0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16,0,0,0,0,11,167,0,25],[0,0,0,0,10,165,3,79,0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57],[0,0,0,0,10,137,0,75,0,0,6,14,0,0,65,61,0,0,0,0,8,0,0,75,0,0,6,24,0,0,97,61],[0,0,0,4,8,0,0,41,0,0,0,0,8,8,4,51,0,0,0,0,8,8,0,75,0,0,12,17,0,0,97,61],[0,0,0,0,8,7,4,51,0,0,5,59,8,128,1,151,0,0,0,248,9,96,2,16,0,0,0,0,8,137,1,159],[0,0,5,61,8,128,0,65,0,0,0,0,0,135,4,53,0,0,0,3,6,96,2,16,0,0,0,248,6,96,0,137],[0,0,0,0,2,98,1,207,0,0,0,255,6,96,0,140,0,0,0,0,2,0,32,25,0,0,0,4,6,0,0,41],[0,0,0,33,6,96,0,57,0,0,9,241,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143],[0,0,0,5,5,48,2,114,0,0,6,55,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,6,47,0,0,65,61,0,0,0,0,6,4,0,75],[0,0,6,70,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25],[0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,5,2,1,0,0,65,0,0,5,2,4,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,0,96,2,48,2,16,0,0,0,0,1,33,1,159],[0,0,20,3,0,1,4,48,0,0,5,2,1,16,1,151,0,0,0,0,1,19,3,79,0,0,0,0,3,84,0,73],[0,0,5,2,3,48,1,151,0,0,0,0,1,49,3,223,0,0,0,192,2,32,2,16,0,0,5,24,2,32,1,151],[0,0,5,26,2,32,1,199,0,0,0,0,1,33,3,175,0,0,128,16,2,0,0,57,20,1,19,252,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,1,5,2,0,48,1,157,0,0,5,2,5,48,1,151],[0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144,0,0,9,64,0,0,97,61,0,0,0,63,2,80,0,57],[0,0,5,54,2,32,1,151,0,0,0,64,6,0,4,61,0,0,0,0,2,38,0,25,0,0,0,0,3,98,0,75],[0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57,0,0,5,10,4,32,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,3,48,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,32,4,63,0,0,0,0,4,86,4,54],[0,0,0,2,2,0,3,103,0,0,0,0,3,0,0,49,0,0,0,31,7,80,0,57,0,0,0,5,7,112,2,114],[0,0,6,123,0,0,97,61,0,0,0,0,8,50,3,79,0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16],[0,0,0,0,11,164,0,25,0,0,0,0,10,168,3,79,0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53],[0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75,0,0,6,115,0,0,65,61,0,0,0,0,7,0,0,75],[0,0,6,125,0,0,97,61,0,0,0,31,7,80,1,143,0,0,0,5,5,80,2,114,0,0,6,137,0,0,97,61],[0,0,0,0,8,0,0,25,0,0,0,5,9,128,2,16,0,0,0,0,10,148,0,25,0,0,0,0,9,145,3,79],[0,0,0,0,9,9,4,59,0,0,0,0,0,154,4,53,0,0,0,1,8,128,0,57,0,0,0,0,9,88,0,75],[0,0,6,129,0,0,65,61,0,0,0,0,8,7,0,75,0,0,6,152,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,84,0,25,0,0,0,3,7,112,2,16,0,0,0,0,8,5,4,51],[0,0,0,0,8,120,1,207,0,0,0,0,8,120,2,47,0,0,0,0,1,1,4,59,0,0,1,0,7,112,0,137],[0,0,0,0,1,113,2,47,0,0,0,0,1,113,1,207,0,0,0,0,1,129,1,159,0,0,0,0,0,21,4,53],[0,0,0,0,1,6,4,51,0,0,0,32,1,16,0,140,0,0,9,216,0,0,193,61,0,0,0,10,6,0,0,41],[0,0,0,0,1,99,0,73,0,0,0,35,5,16,0,138,0,8,2,4,0,96,0,61,0,0,0,8,1,32,3,96],[0,0,0,0,1,1,4,59,0,0,5,11,6,0,0,65,0,0,0,0,7,81,0,75,0,0,0,0,7,0,0,25],[0,0,0,0,7,6,128,25,0,0,5,11,5,80,1,151,0,0,5,11,8,16,1,151,0,0,0,0,9,88,0,75],[0,0,0,0,6,0,128,25,0,0,0,0,5,88,1,63,0,0,5,11,5,80,0,156,0,0,0,0,6,7,192,25],[0,0,0,0,5,6,0,75,0,0,1,39,0,0,193,61,0,0,0,0,4,4,4,51,0,5,0,0,0,4,0,29],[0,0,0,9,1,16,0,41,0,0,0,0,4,18,3,79,0,0,0,0,5,4,4,59,0,0,5,10,4,80,0,156],[0,0,1,39,0,0,33,61,0,0,0,5,4,80,2,16,0,0,0,0,3,67,0,73,0,0,0,32,6,16,0,57],[0,0,5,11,1,0,0,65,0,0,0,0,7,54,0,75,0,0,0,0,7,0,0,25,0,0,0,0,7,1,32,25],[0,0,5,11,3,48,1,151,0,0,5,11,8,96,1,151,0,0,0,0,9,56,0,75,0,0,0,0,1,0,128,25],[0,0,0,0,3,56,1,63,0,0,5,11,3,48,0,156,0,0,0,0,1,7,192,25,0,0,0,0,1,1,0,75],[0,0,1,39,0,0,193,61,0,0,0,64,1,0,4,61,0,0,0,32,3,16,0,57,0,0,5,68,5,80,1,152],[0,0,6,211,0,0,97,61,0,0,0,0,2,98,3,79,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,115,0,25,0,0,0,0,7,114,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,6,203,0,0,65,61,0,0,0,0,2,0,0,75],[0,0,6,213,0,0,97,61,0,0,0,0,0,65,4,53,0,0,0,63,2,64,0,57,0,0,0,32,4,0,0,138],[0,0,0,0,2,66,1,111,0,0,0,0,2,33,0,25,0,0,0,0,4,18,0,75,0,0,0,0,4,0,0,25],[0,0,0,1,4,0,64,57,0,0,5,10,5,32,0,156,0,0,18,165,0,0,33,61,0,0,0,1,4,64,1,144],[0,0,18,165,0,0,193,61,0,0,0,64,0,32,4,63,0,0,5,2,2,0,0,65,0,0,5,2,4,48,0,156],[0,0,0,0,3,2,128,25,0,0,0,64,3,48,2,16,0,0,0,0,1,1,4,51,0,0,5,2,4,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,49,1,159,0,0,0,0,3,0,4,20],[0,0,5,2,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16,0,0,0,0,1,18,1,159],[0,0,5,13,1,16,1,199,0,0,128,16,2,0,0,57,20,1,19,242,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,1,39,0,0,97,61,0,0,0,0,2,0,0,49,0,0,0,10,3,32,0,106,0,0,0,35,5,48,0,138],[0,0,0,8,3,0,0,41,0,0,0,32,4,48,0,57,0,0,0,2,3,0,3,103,0,0,0,0,4,67,3,79],[0,0,0,0,4,4,4,59,0,0,5,11,6,0,0,65,0,0,0,0,7,84,0,75,0,0,0,0,7,0,0,25],[0,0,0,0,7,6,128,25,0,0,5,11,5,80,1,151,0,0,5,11,8,64,1,151,0,0,0,0,9,88,0,75],[0,0,0,0,6,0,128,25,0,0,0,0,5,88,1,63,0,0,5,11,5,80,0,156,0,0,0,0,6,7,192,25],[0,0,0,0,1,1,4,59,0,8,0,0,0,1,0,29,0,0,0,0,1,6,0,75,0,0,1,39,0,0,193,61],[0,0,0,9,1,64,0,41,0,0,0,0,4,19,3,79,0,0,0,0,4,4,4,59,0,0,5,10,5,64,0,156],[0,0,1,39,0,0,33,61,0,0,0,0,5,66,0,73,0,0,0,32,1,16,0,57,0,0,5,11,6,0,0,65],[0,0,0,0,7,81,0,75,0,0,0,0,7,0,0,25,0,0,0,0,7,6,32,25,0,0,5,11,5,80,1,151],[0,0,5,11,8,16,1,151,0,0,0,0,9,88,0,75,0,0,0,0,6,0,128,25,0,0,0,0,5,88,1,63],[0,0,5,11,5,80,0,156,0,0,0,0,6,7,192,25,0,0,0,0,5,6,0,75,0,0,1,39,0,0,193,61],[0,0,0,0,5,20,0,26,0,0,0,0,4,0,4,20,0,0,16,208,0,0,65,61,0,0,0,0,6,82,0,75],[0,0,16,208,0,0,65,61,0,0,5,2,6,64,0,156,0,0,2,154,0,0,33,61,0,0,5,2,1,16,1,151],[0,0,0,0,1,19,3,79,0,0,0,0,2,82,0,73,0,0,5,2,2,32,1,151,0,0,0,0,1,33,3,223],[0,0,0,192,2,64,2,16,0,0,5,24,2,32,1,151,0,0,5,26,2,32,1,199,0,0,0,0,1,33,3,175],[0,0,128,16,2,0,0,57,20,1,19,252,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,1,5,2,0,48,1,157,0,0,5,2,3,48,1,151,0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144],[0,0,17,218,0,0,97,61,0,0,0,63,2,48,0,57,0,0,5,54,2,32,1,151,0,0,0,64,5,0,4,61],[0,0,0,0,2,37,0,25,0,0,0,0,4,82,0,75,0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57],[0,0,5,10,6,32,0,156,0,0,18,165,0,0,33,61,0,0,0,1,4,64,1,144,0,0,18,165,0,0,193,61],[0,0,0,64,0,32,4,63,0,0,0,0,2,53,4,54,0,0,0,2,4,0,3,103,0,0,0,31,6,48,0,57],[0,0,0,5,6,96,2,114,0,0,7,84,0,0,97,61,0,0,0,0,7,64,3,104,0,0,0,0,8,0,0,25],[0,0,0,5,9,128,2,16,0,0,0,0,10,146,0,25,0,0,0,0,9,151,3,79,0,0,0,0,9,9,4,59],[0,0,0,0,0,154,4,53,0,0,0,1,8,128,0,57,0,0,0,0,9,104,0,75,0,0,7,76,0,0,65,61],[0,0,0,0,6,0,0,75,0,0,7,86,0,0,97,61,0,0,0,31,6,48,1,143,0,0,0,5,3,48,2,114],[0,0,7,98,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,130,0,25],[0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,55,0,75,0,0,7,90,0,0,65,61,0,0,0,0,7,6,0,75,0,0,7,113,0,0,97,61],[0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79,0,0,0,0,3,50,0,25,0,0,0,3,6,96,2,16],[0,0,0,0,7,3,4,51,0,0,0,0,7,103,1,207,0,0,0,0,7,103,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,6,96,0,137,0,0,0,0,1,97,2,47,0,0,0,0,1,97,1,207,0,0,0,0,1,113,1,159],[0,0,0,0,0,19,4,53,0,0,0,0,1,5,4,51,0,0,0,32,1,16,0,140,0,0,9,216,0,0,193,61],[0,0,0,10,12,0,0,41,0,0,0,100,1,192,0,57,0,0,0,0,1,20,3,79,0,0,0,68,3,192,0,57],[0,0,0,0,5,52,3,79,0,0,0,36,3,192,0,57,0,0,0,0,6,52,3,79,0,0,1,36,3,192,0,57],[0,0,0,0,7,52,3,79,0,0,0,6,8,64,3,96,0,0,0,228,3,192,0,57,0,0,0,0,9,52,3,79],[0,0,0,196,3,192,0,57,0,0,0,0,10,52,3,79,0,0,0,164,3,192,0,57,0,0,0,0,11,52,3,79],[0,0,0,132,3,192,0,57,0,0,0,0,12,52,3,79,0,0,0,9,3,64,3,96,0,0,0,0,3,3,4,59],[0,0,0,0,4,6,4,59,0,0,0,0,5,5,4,59,0,0,0,0,6,1,4,59,0,0,0,0,12,12,4,59],[0,0,0,0,11,11,4,59,0,0,0,0,10,10,4,59,0,0,0,0,9,9,4,59,0,0,0,0,8,8,4,59],[0,0,0,0,7,7,4,59,0,0,0,0,2,2,4,51,0,0,0,64,1,0,4,61,0,0,1,192,13,16,0,57],[0,0,0,0,0,45,4,53,0,0,1,160,2,16,0,57,0,0,0,8,13,0,0,41,0,0,0,0,0,210,4,53],[0,0,1,128,2,16,0,57,0,0,0,5,13,0,0,41,0,0,0,0,0,210,4,53,0,0,1,96,2,16,0,57],[0,0,0,0,0,114,4,53,0,0,1,64,2,16,0,57,0,0,0,0,0,130,4,53,0,0,1,32,2,16,0,57],[0,0,0,0,0,146,4,53,0,0,1,0,2,16,0,57,0,0,0,0,0,162,4,53,0,0,0,224,2,16,0,57],[0,0,0,0,0,178,4,53,0,0,0,192,2,16,0,57,0,0,0,0,0,194,4,53,0,0,0,160,2,16,0,57],[0,0,0,0,0,98,4,53,0,0,0,128,2,16,0,57,0,0,0,0,0,82,4,53,0,0,0,96,2,16,0,57],[0,0,0,0,0,66,4,53,0,0,0,64,2,16,0,57,0,0,0,0,0,50,4,53,0,0,0,32,2,16,0,57],[0,0,5,70,3,0,0,65,0,0,0,0,0,50,4,53,0,0,1,192,3,0,0,57,0,0,0,0,0,49,4,53],[0,0,5,71,3,16,0,156,0,0,18,165,0,0,33,61,0,0,1,224,3,16,0,57,0,0,0,64,0,48,4,63],[0,0,5,2,4,0,0,65,0,0,5,2,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,64,2,32,2,16],[0,0,0,0,1,1,4,51,0,0,5,2,3,16,0,156,0,0,0,0,1,4,128,25,0,0,0,96,1,16,2,16],[0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20,0,0,5,2,3,32,0,156,0,0,0,0,2,4,128,25],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,13,1,16,1,199,0,0,128,16,2,0,0,57],[20,1,19,242,0,0,4,15,0,0,0,1,2,32,1,144,0,0,1,39,0,0,97,61,0,0,0,0,1,1,4,59],[0,6,0,0,0,1,0,29,0,0,0,64,1,0,4,61,0,8,0,0,0,1,0,29,0,0,5,56,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,0,0,1,0,4,20,0,0,5,2,2,16,0,156,0,0,5,2,1,0,128,65],[0,0,0,192,1,16,2,16,0,0,5,57,1,16,1,199,0,0,128,11,2,0,0,57,20,1,19,242,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,16,244,0,0,97,61,0,0,0,8,4,0,0,41,0,0,0,32,2,64,0,57],[0,0,0,0,1,1,4,59,0,0,5,72,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,128,3,64,0,57],[0,0,0,0,0,19,4,53,0,0,0,96,1,64,0,57,0,0,5,73,3,0,0,65,0,0,0,0,0,49,4,53],[0,0,0,64,1,64,0,57,0,0,5,74,3,0,0,65,0,0,0,0,0,49,4,53,0,0,0,128,1,0,0,57],[0,0,0,0,0,20,4,53,0,0,5,75,1,64,0,156,0,0,18,165,0,0,33,61,0,0,0,8,4,0,0,41],[0,0,0,160,1,64,0,57,0,0,0,64,0,16,4,63,0,0,5,2,1,0,0,65,0,0,5,2,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,64,2,32,2,16,0,0,0,0,3,4,4,51,0,0,5,2,4,48,0,156],[0,0,0,0,3,1,128,25,0,0,0,96,3,48,2,16,0,0,0,0,2,35,1,159,0,0,0,0,3,0,4,20],[0,0,5,2,4,48,0,156,0,0,0,0,3,1,128,25,0,0,0,192,1,48,2,16,0,0,0,0,1,33,1,159],[0,0,5,13,1,16,1,199,0,0,128,16,2,0,0,57,20,1,19,242,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,1,39,0,0,97,61,0,0,0,0,3,1,4,59,0,0,0,64,1,0,4,61,0,0,0,66,2,16,0,57],[0,0,0,6,4,0,0,41,0,0,0,0,0,66,4,53,0,0,0,32,2,16,0,57,0,0,5,76,4,0,0,65],[0,0,0,0,0,66,4,53,0,0,0,34,4,16,0,57,0,0,0,0,0,52,4,53,0,0,0,66,3,0,0,57],[0,0,0,0,0,49,4,53,0,0,5,41,3,16,0,156,0,0,18,165,0,0,33,61,0,0,0,128,3,16,0,57],[0,0,0,64,0,48,4,63,0,0,5,2,3,0,0,65,0,0,5,2,4,32,0,156,0,0,0,0,2,3,128,25],[0,0,0,64,2,32,2,16,0,0,0,0,1,1,4,51,0,0,5,2,4,16,0,156,0,0,0,0,1,3,128,25],[0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20,0,0,5,2,4,32,0,156],[0,0,0,0,2,3,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,16,175,0,0,1,61],[0,0,5,58,6,64,0,156,0,0,18,165,0,0,33,61,0,0,0,64,6,64,0,57,0,0,0,64,0,96,4,63],[0,0,0,0,7,33,3,79,0,0,0,1,6,0,0,58,0,0,0,0,6,100,4,54,0,0,0,0,7,112,3,80],[0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,12,17,0,0,97,61,0,0,0,248,8,80,2,16],[0,0,5,11,9,0,0,65,0,0,0,0,5,5,0,75,0,0,0,0,9,8,192,25,0,0,5,59,5,112,1,151],[0,0,0,0,5,149,1,159,0,0,0,0,0,86,4,53,0,0,0,64,5,0,4,61,0,0,0,6,6,0,0,41],[0,0,0,64,7,96,0,138,0,0,0,0,6,113,3,79,0,0,0,0,6,6,4,59,0,0,0,128,8,96,0,140],[0,0,9,122,0,0,65,61,0,0,0,128,8,96,2,112,0,0,5,60,9,96,0,156,0,0,0,0,8,6,160,25],[0,0,5,60,9,96,0,156,0,0,0,0,9,0,0,25,0,0,0,16,9,0,32,57,0,0,0,8,10,144,1,191],[0,0,5,10,11,128,0,156,0,0,0,0,10,9,160,25,0,0,0,64,9,128,2,112,0,0,5,10,11,128,0,156],[0,0,0,0,9,8,160,25,0,0,0,4,11,160,1,191,0,0,5,2,8,144,0,156,0,0,0,0,11,10,160,25],[0,0,0,32,10,144,2,112,0,0,5,2,8,144,0,156,0,0,0,0,10,9,160,25,0,0,0,2,8,176,1,191],[0,0,255,255,9,160,0,140,0,0,0,0,8,11,160,25,0,0,0,16,9,160,2,112,0,0,0,0,9,10,160,25],[0,0,0,255,9,144,0,140,0,0,0,1,8,128,32,57,0,0,0,32,9,0,0,138,0,0,0,65,10,128,0,57],[0,0,0,0,9,154,1,111,0,0,0,0,9,149,0,25,0,0,0,0,10,89,0,75,0,0,0,0,10,0,0,25],[0,0,0,1,10,0,64,57,0,0,5,10,11,144,0,156,0,0,18,165,0,0,33,61,0,0,0,1,10,160,1,144],[0,0,18,165,0,0,193,61,0,0,0,64,0,144,4,63,0,0,0,2,9,128,0,57,0,0,0,0,9,149,4,54],[0,0,0,33,10,128,0,57,0,0,0,5,10,160,2,114,0,0,8,109,0,0,97,61,0,0,0,0,11,33,3,79],[0,0,0,0,12,0,0,25,0,0,0,5,13,192,2,16,0,0,0,0,14,217,0,25,0,0,0,0,13,219,3,79],[0,0,0,0,13,13,4,59,0,0,0,0,0,222,4,53,0,0,0,1,12,192,0,57,0,0,0,0,13,172,0,75],[0,0,8,101,0,0,65,61,0,0,0,0,10,0,0,75,0,0,8,111,0,0,97,61,0,0,0,0,10,5,4,51],[0,0,0,0,10,10,0,75,0,0,12,17,0,0,97,61,0,0,0,0,10,9,4,51,0,0,5,59,10,160,1,151],[0,0,0,248,11,128,2,16,0,0,0,0,10,171,1,159,0,0,5,61,10,160,0,65,0,0,0,0,0,169,4,53],[0,0,0,3,8,128,2,16,0,0,0,248,8,128,0,137,0,0,0,0,6,134,1,207,0,0,0,255,8,128,0,140],[0,0,0,0,6,0,32,25,0,0,0,33,8,80,0,57,0,0,9,139,0,0,1,61,0,0,5,2,1,0,0,65],[0,0,5,2,3,80,0,156,0,0,0,0,5,1,128,25,0,0,0,96,3,80,2,16,0,0,0,64,4,64,2,16],[0,0,0,0,3,67,1,159,0,0,5,2,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,0,0,1,19,1,159,0,0,0,9,2,0,0,41,20,1,19,237,0,0,4,15,0,5,0,96,0,0,0,61],[0,0,0,1,2,32,1,143,0,3,0,0,0,1,3,85,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,1,5,2,0,48,1,157,0,0,5,2,3,48,1,152,0,0,8,191,0,0,97,61,0,0,0,63,4,48,0,57],[0,0,0,32,5,0,0,138,0,0,0,0,4,84,1,111,0,0,0,64,5,0,4,61,0,0,0,0,4,69,0,25],[0,5,0,0,0,5,0,29,0,0,0,0,5,84,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57],[0,0,5,10,6,64,0,156,0,0,18,165,0,0,33,61,0,0,0,1,5,80,1,144,0,0,18,165,0,0,193,61],[0,0,0,64,0,64,4,63,0,0,0,31,4,48,1,143,0,0,0,5,5,0,0,41,0,0,0,0,8,53,4,54],[0,0,0,5,3,48,2,114,0,0,8,175,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16],[0,0,0,0,7,104,0,25,0,0,0,0,6,97,3,79,0,0,0,0,6,6,4,59,0,0,0,0,0,103,4,53],[0,0,0,1,5,80,0,57,0,0,0,0,6,53,0,75,0,0,8,167,0,0,65,61,0,10,0,0,0,8,0,29],[0,0,0,0,5,4,0,75,0,0,8,191,0,0,97,61,0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79],[0,0,0,10,3,48,0,41,0,0,0,3,4,64,2,16,0,0,0,0,5,3,4,51,0,0,0,0,5,69,1,207],[0,0,0,0,5,69,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,19,4,53,0,0,0,5,1,0,0,41],[0,0,0,0,1,1,4,51,0,0,0,0,2,2,0,75,0,0,9,91,0,0,193,61,0,0,0,0,2,1,0,75],[0,0,8,217,0,0,193,61,0,0,0,64,4,0,4,61,0,10,0,0,0,4,0,29,0,0,5,16,1,0,0,65],[0,0,0,0,0,20,4,53,0,0,0,4,1,64,0,57,0,0,0,4,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,0,2,1,0,0,41,0,0,0,0,3,1,4,51,0,9,0,0,0,3,0,29,0,0,0,36,1,64,0,57],[0,0,0,0,0,49,4,53,0,0,0,68,2,64,0,57,0,0,0,3,1,0,0,41,20,1,19,223,0,0,4,15],[0,0,0,9,1,0,0,41,0,0,0,31,1,16,0,57,0,0,0,32,2,0,0,138,0,0,0,0,1,33,1,111],[0,0,0,68,1,16,0,57,0,0,5,2,2,0,0,65,0,0,5,2,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,10,4,0,0,41,0,0,5,2,3,64,0,156,0,0,0,0,4,2,128,25,0,0,0,64,2,64,2,16],[0,0,2,84,0,0,1,61,0,0,5,58,6,64,0,156,0,0,18,165,0,0,33,61,0,0,0,64,6,64,0,57],[0,0,0,64,0,96,4,63,0,0,0,0,7,33,3,79,0,0,0,1,6,0,0,58,0,0,0,0,6,100,4,54],[0,0,0,0,7,112,3,80,0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,12,17,0,0,97,61],[0,0,0,248,8,80,2,16,0,0,5,11,9,0,0,65,0,0,0,0,5,5,0,75,0,0,0,0,9,8,192,25],[0,0,5,59,5,112,1,151,0,0,0,0,5,149,1,159,0,0,0,0,0,86,4,53,0,0,0,64,5,0,4,61],[0,0,0,6,6,0,0,41,0,0,0,96,6,96,0,138,0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59],[0,0,0,128,8,112,0,140,0,0,10,55,0,0,65,61,0,0,0,128,8,112,2,112,0,0,5,60,9,112,0,156],[0,0,0,0,8,7,160,25,0,0,5,60,9,112,0,156,0,0,0,0,9,0,0,25,0,0,0,16,9,0,32,57],[0,0,0,8,10,144,1,191,0,0,5,10,11,128,0,156,0,0,0,0,10,9,160,25,0,0,0,64,9,128,2,112],[0,0,5,10,11,128,0,156,0,0,0,0,9,8,160,25,0,0,0,4,11,160,1,191,0,0,5,2,8,144,0,156],[0,0,0,0,11,10,160,25,0,0,0,32,10,144,2,112,0,0,5,2,8,144,0,156,0,0,0,0,10,9,160,25],[0,0,0,2,8,176,1,191,0,0,255,255,9,160,0,140,0,0,0,0,8,11,160,25,0,0,0,16,9,160,2,112],[0,0,0,0,9,10,160,25,0,0,0,255,9,144,0,140,0,0,0,1,8,128,32,57,0,0,0,32,9,0,0,138],[0,0,0,65,10,128,0,57,0,0,0,0,9,154,1,111,0,0,0,0,9,149,0,25,0,0,0,0,10,89,0,75],[0,0,0,0,10,0,0,25,0,0,0,1,10,0,64,57,0,0,5,10,11,144,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,10,160,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,144,4,63,0,0,0,2,9,128,0,57],[0,0,0,0,9,149,4,54,0,0,0,33,10,128,0,57,0,0,0,5,10,160,2,114,0,0,9,46,0,0,97,61],[0,0,0,0,11,33,3,79,0,0,0,0,12,0,0,25,0,0,0,5,13,192,2,16,0,0,0,0,14,217,0,25],[0,0,0,0,13,219,3,79,0,0,0,0,13,13,4,59,0,0,0,0,0,222,4,53,0,0,0,1,12,192,0,57],[0,0,0,0,13,172,0,75,0,0,9,38,0,0,65,61,0,0,0,0,10,0,0,75,0,0,9,48,0,0,97,61],[0,0,0,0,10,5,4,51,0,0,0,0,10,10,0,75,0,0,12,17,0,0,97,61,0,0,0,0,10,9,4,51],[0,0,5,59,10,160,1,151,0,0,0,248,11,128,2,16,0,0,0,0,10,171,1,159,0,0,5,61,10,160,0,65],[0,0,0,0,0,169,4,53,0,0,0,3,8,128,2,16,0,0,0,248,8,128,0,137,0,0,0,0,7,135,1,207],[0,0,0,255,8,128,0,140,0,0,0,0,7,0,32,25,0,0,0,33,8,80,0,57,0,0,10,72,0,0,1,61],[0,0,0,31,3,80,1,143,0,0,0,5,2,80,2,114,0,0,9,75,0,0,97,61,0,0,0,0,4,0,0,25],[0,0,0,5,6,64,2,16,0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53],[0,0,0,1,4,64,0,57,0,0,0,0,6,36,0,75,0,0,9,68,0,0,65,61,0,0,0,0,4,3,0,75],[0,0,9,89,0,0,97,61,0,0,0,3,3,48,2,16,0,0,0,5,2,32,2,16,0,0,0,0,4,2,4,51],[0,0,0,0,4,52,1,207,0,0,0,0,4,52,2,47,0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59],[0,0,1,0,3,48,0,137,0,0,0,0,1,49,2,47,0,0,0,0,1,49,1,207,0,0,0,0,1,65,1,159],[0,0,0,0,0,18,4,53,0,0,0,96,1,80,2,16,0,0,20,3,0,1,4,48,0,0,0,0,2,1,0,75],[0,0,10,248,0,0,193,61,0,0,5,36,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,9,1,0,0,41],[0,0,0,4,0,16,4,67,0,0,5,2,1,0,0,65,0,0,0,0,2,0,4,20,0,0,5,2,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,37,1,16,1,199,0,0,128,2,2,0,0,57],[20,1,19,242,0,0,4,15,0,0,0,1,2,32,1,144,0,0,16,244,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,1,1,0,75,0,0,10,244,0,0,193,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57],[0,0,5,45,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,29,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,5,16,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57],[0,0,0,4,3,0,0,41,0,0,4,115,0,0,1,61,0,0,5,58,8,80,0,156,0,0,18,165,0,0,33,61],[0,0,0,64,8,80,0,57,0,0,0,64,0,128,4,63,0,0,0,0,9,33,3,79,0,0,0,1,8,0,0,58],[0,0,0,0,8,133,4,54,0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59,0,0,0,0,0,152,4,53],[0,0,12,17,0,0,97,61,0,0,0,248,10,96,2,16,0,0,5,11,11,0,0,65,0,0,0,0,6,6,0,75],[0,0,0,0,11,10,192,25,0,0,5,59,6,144,1,151,0,0,0,0,6,182,1,159,0,0,0,0,0,104,4,53],[0,0,0,64,6,0,4,61,0,0,0,32,7,112,0,138,0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59],[0,0,0,128,9,128,0,140,0,0,10,149,0,0,65,61,0,0,0,128,9,128,2,112,0,0,5,60,10,128,0,156],[0,0,0,0,9,8,160,25,0,0,5,60,10,128,0,156,0,0,0,0,10,0,0,25,0,0,0,16,10,0,32,57],[0,0,0,8,11,160,1,191,0,0,5,10,12,144,0,156,0,0,0,0,11,10,160,25,0,0,0,64,10,144,2,112],[0,0,5,10,12,144,0,156,0,0,0,0,10,9,160,25,0,0,0,4,12,176,1,191,0,0,5,2,9,160,0,156],[0,0,0,0,12,11,160,25,0,0,0,32,11,160,2,112,0,0,5,2,9,160,0,156,0,0,0,0,11,10,160,25],[0,0,0,2,9,192,1,191,0,0,255,255,10,176,0,140,0,0,0,0,9,12,160,25,0,0,0,16,10,176,2,112],[0,0,0,0,10,11,160,25,0,0,0,255,10,160,0,140,0,0,0,1,9,144,32,57,0,0,0,32,10,0,0,138],[0,0,0,65,11,144,0,57,0,0,0,0,10,171,1,111,0,0,0,0,10,166,0,25,0,0,0,0,11,106,0,75],[0,0,0,0,11,0,0,25,0,0,0,1,11,0,64,57,0,0,5,10,12,160,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,11,176,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,160,4,63,0,0,0,2,10,144,0,57],[0,0,0,0,10,166,4,54,0,0,0,33,11,144,0,57,0,0,0,5,11,176,2,114,0,0,9,198,0,0,97,61],[0,0,0,0,12,33,3,79,0,0,0,0,13,0,0,25,0,0,0,5,14,208,2,16,0,0,0,0,15,234,0,25],[0,0,0,0,14,236,3,79,0,0,0,0,14,14,4,59,0,0,0,0,0,239,4,53,0,0,0,1,13,208,0,57],[0,0,0,0,14,189,0,75,0,0,9,190,0,0,65,61,0,0,0,0,11,0,0,75,0,0,9,200,0,0,97,61],[0,0,0,0,11,6,4,51,0,0,0,0,11,11,0,75,0,0,12,17,0,0,97,61,0,0,0,0,11,10,4,51],[0,0,5,59,11,176,1,151,0,0,0,248,12,144,2,16,0,0,0,0,11,188,1,159,0,0,5,61,11,176,0,65],[0,0,0,0,0,186,4,53,0,0,0,3,9,144,2,16,0,0,0,248,9,144,0,137,0,0,0,0,8,152,1,207],[0,0,0,255,9,144,0,140,0,0,0,0,8,0,32,25,0,0,0,33,9,96,0,57,0,0,10,166,0,0,1,61],[0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,5,69,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,31,3,0,0,57,0,0,4,110,0,0,1,61,0,0,0,4,6,0,0,41],[0,0,5,58,6,96,0,156,0,0,18,165,0,0,33,61,0,0,0,4,7,0,0,41,0,0,0,64,6,112,0,57],[0,0,0,64,0,96,4,63,0,0,0,1,6,0,0,58,0,0,0,0,6,103,4,54,0,0,0,0,7,80,3,80],[0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,12,17,0,0,97,61,0,0,0,248,8,32,2,16],[0,0,5,11,9,0,0,65,0,0,0,0,2,2,0,75,0,0,0,0,9,8,192,25,0,0,5,59,2,112,1,151],[0,0,0,0,2,146,1,159,0,0,0,0,0,38,4,53,0,0,0,9,6,64,0,106,0,0,0,160,1,16,0,57],[0,0,0,0,2,19,3,79,0,0,0,0,2,2,4,59,0,0,0,31,6,96,0,138,0,0,5,11,7,96,1,151],[0,0,5,11,8,32,1,151,0,0,5,11,9,0,0,65,0,0,0,0,10,120,0,75,0,0,0,0,10,0,0,25],[0,0,0,0,10,9,64,25,0,0,0,0,7,120,1,63,0,0,0,0,8,98,0,75,0,0,0,0,9,0,64,25],[0,0,5,11,7,112,0,156,0,0,0,0,10,9,192,25,0,0,0,0,7,10,0,75,0,0,1,39,0,0,193,61],[0,0,0,9,8,32,0,41,0,0,0,0,7,131,3,79,0,0,0,0,7,7,4,59,0,0,5,10,9,112,0,156],[0,0,1,39,0,0,33,61,0,0,0,0,9,116,0,73,0,0,0,32,8,128,0,57,0,0,5,11,10,0,0,65],[0,0,0,0,11,152,0,75,0,0,0,0,11,0,0,25,0,0,0,0,11,10,32,25,0,0,5,11,9,144,1,151],[0,0,5,11,12,128,1,151,0,0,0,0,13,156,0,75,0,0,0,0,10,0,128,25,0,0,0,0,9,156,1,63],[0,0,5,11,9,144,0,156,0,0,0,0,10,11,192,25,0,0,0,0,9,10,0,75,0,0,1,39,0,0,193,61],[0,0,0,1,9,112,0,140,0,0,12,62,0,0,193,61,0,0,0,0,5,131,3,79,0,0,0,0,5,5,4,59],[0,0,0,1,7,0,0,138,0,0,5,11,8,0,0,65,0,0,0,0,7,117,0,75,0,0,0,0,7,0,0,25],[0,0,0,0,7,8,32,25,0,0,5,11,5,80,1,151,0,0,5,11,9,80,0,156,0,0,0,0,8,0,128,25],[0,0,5,11,5,80,1,103,0,0,5,11,5,80,0,156,0,0,0,0,8,7,192,25,0,3,0,96,0,0,0,61],[0,0,0,0,5,8,0,75,0,0,13,164,0,0,193,61,0,0,0,64,5,0,4,61,0,3,0,0,0,5,0,29],[0,0,5,58,5,80,0,156,0,0,18,165,0,0,33,61,0,0,0,3,8,0,0,41,0,0,0,64,5,128,0,57],[0,0,0,64,0,80,4,63,0,0,0,32,5,128,0,57,0,0,5,61,7,0,0,65,0,0,0,0,0,117,4,53],[0,0,0,1,5,0,0,57,0,0,0,0,0,88,4,53,0,0,13,164,0,0,1,61,0,0,5,58,8,80,0,156],[0,0,18,165,0,0,33,61,0,0,0,64,8,80,0,57,0,0,0,64,0,128,4,63,0,0,0,0,9,33,3,79],[0,0,0,1,8,0,0,58,0,0,0,0,8,133,4,54,0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59],[0,0,0,0,0,152,4,53,0,0,12,17,0,0,97,61,0,0,0,248,10,112,2,16,0,0,5,11,11,0,0,65],[0,0,0,0,7,7,0,75,0,0,0,0,11,10,192,25,0,0,5,59,7,144,1,151,0,0,0,0,7,183,1,159],[0,0,0,0,0,120,4,53,0,0,0,64,7,0,4,61,0,0,0,64,6,96,0,138,0,0,0,0,8,97,3,79],[0,0,0,0,8,8,4,59,0,0,0,128,9,128,0,140,0,0,11,46,0,0,65,61,0,0,0,128,9,128,2,112],[0,0,5,60,10,128,0,156,0,0,0,0,9,8,160,25,0,0,5,60,10,128,0,156,0,0,0,0,10,0,0,25],[0,0,0,16,10,0,32,57,0,0,0,8,11,160,1,191,0,0,5,10,12,144,0,156,0,0,0,0,11,10,160,25],[0,0,0,64,10,144,2,112,0,0,5,10,12,144,0,156,0,0,0,0,10,9,160,25,0,0,0,4,12,176,1,191],[0,0,5,2,9,160,0,156,0,0,0,0,12,11,160,25,0,0,0,32,11,160,2,112,0,0,5,2,9,160,0,156],[0,0,0,0,11,10,160,25,0,0,0,2,9,192,1,191,0,0,255,255,10,176,0,140,0,0,0,0,9,12,160,25],[0,0,0,16,10,176,2,112,0,0,0,0,10,11,160,25,0,0,0,255,10,160,0,140,0,0,0,1,9,144,32,57],[0,0,0,32,10,0,0,138,0,0,0,65,11,144,0,57,0,0,0,0,10,171,1,111,0,0,0,0,10,167,0,25],[0,0,0,0,11,122,0,75,0,0,0,0,11,0,0,25,0,0,0,1,11,0,64,57,0,0,5,10,12,160,0,156],[0,0,18,165,0,0,33,61,0,0,0,1,11,176,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,160,4,63],[0,0,0,2,10,144,0,57,0,0,0,0,10,167,4,54,0,0,0,33,11,144,0,57,0,0,0,5,11,176,2,114],[0,0,10,131,0,0,97,61,0,0,0,0,12,33,3,79,0,0,0,0,13,0,0,25,0,0,0,5,14,208,2,16],[0,0,0,0,15,234,0,25,0,0,0,0,14,236,3,79,0,0,0,0,14,14,4,59,0,0,0,0,0,239,4,53],[0,0,0,1,13,208,0,57,0,0,0,0,14,189,0,75,0,0,10,123,0,0,65,61,0,0,0,0,11,0,0,75],[0,0,10,133,0,0,97,61,0,0,0,0,11,7,4,51,0,0,0,0,11,11,0,75,0,0,12,17,0,0,97,61],[0,0,0,0,11,10,4,51,0,0,5,59,11,176,1,151,0,0,0,248,12,144,2,16,0,0,0,0,11,188,1,159],[0,0,5,61,11,176,0,65,0,0,0,0,0,186,4,53,0,0,0,3,9,144,2,16,0,0,0,248,9,144,0,137],[0,0,0,0,8,152,1,207,0,0,0,255,9,144,0,140,0,0,0,0,8,0,32,25,0,0,0,33,9,112,0,57],[0,0,11,63,0,0,1,61,0,0,5,58,9,96,0,156,0,0,18,165,0,0,33,61,0,0,0,64,9,96,0,57],[0,0,0,64,0,144,4,63,0,0,0,0,10,33,3,79,0,0,0,1,9,0,0,58,0,0,0,0,9,150,4,54],[0,0,0,0,10,160,3,80,0,0,0,0,10,10,4,59,0,0,0,0,0,169,4,53,0,0,12,17,0,0,97,61],[0,0,0,248,11,128,2,16,0,0,5,11,12,0,0,65,0,0,0,0,8,8,0,75,0,0,0,0,12,11,192,25],[0,0,5,59,8,160,1,151,0,0,0,0,8,200,1,159,0,0,0,0,0,137,4,53,0,0,0,64,8,0,4,61],[0,8,0,64,0,112,0,146,0,0,0,8,9,16,3,96,0,0,0,0,9,9,4,59,0,0,0,128,10,144,0,140],[0,0,12,6,0,0,65,61,0,0,0,128,10,144,2,112,0,0,5,60,11,144,0,156,0,0,0,0,10,9,160,25],[0,0,5,60,11,144,0,156,0,0,0,0,11,0,0,25,0,0,0,16,11,0,32,57,0,0,0,8,12,176,1,191],[0,0,5,10,13,160,0,156,0,0,0,0,12,11,160,25,0,0,0,64,11,160,2,112,0,0,5,10,13,160,0,156],[0,0,0,0,11,10,160,25,0,0,0,4,13,192,1,191,0,0,5,2,10,176,0,156,0,0,0,0,13,12,160,25],[0,0,0,32,12,176,2,112,0,0,5,2,10,176,0,156,0,0,0,0,12,11,160,25,0,0,0,2,10,208,1,191],[0,0,255,255,11,192,0,140,0,0,0,0,10,13,160,25,0,0,0,16,11,192,2,112,0,0,0,0,11,12,160,25],[0,0,0,255,11,176,0,140,0,0,0,1,10,160,32,57,0,0,0,32,11,0,0,138,0,0,0,65,12,160,0,57],[0,0,0,0,11,188,1,111,0,0,0,0,11,184,0,25,0,0,0,0,12,139,0,75,0,0,0,0,12,0,0,25],[0,0,0,1,12,0,64,57,0,0,5,10,13,176,0,156,0,0,18,165,0,0,33,61,0,0,0,1,12,192,1,144],[0,0,18,165,0,0,193,61,0,0,0,64,0,176,4,63,0,0,0,2,11,160,0,57,0,0,0,0,11,184,4,54],[0,0,0,33,12,160,0,57,0,0,0,5,12,192,2,114,0,0,10,225,0,0,97,61,0,0,0,0,13,33,3,79],[0,0,0,0,14,0,0,25,0,0,0,5,15,224,2,16,0,0,0,0,7,251,0,25,0,0,0,0,15,253,3,79],[0,0,0,0,15,15,4,59,0,0,0,0,0,247,4,53,0,0,0,1,14,224,0,57,0,0,0,0,7,206,0,75],[0,0,10,217,0,0,65,61,0,0,0,0,7,0,0,75,0,0,10,227,0,0,97,61,0,0,0,0,7,8,4,51],[0,0,0,0,7,7,0,75,0,0,12,17,0,0,97,61,0,0,0,0,7,11,4,51,0,0,5,59,7,112,1,151],[0,0,0,248,12,160,2,16,0,0,0,0,7,124,1,159,0,0,5,61,7,112,0,65,0,0,0,0,0,123,4,53],[0,0,0,3,7,160,2,16,0,0,0,248,7,112,0,137,0,0,0,0,9,121,1,207,0,0,0,255,7,112,0,140],[0,0,0,0,9,0,32,25,0,0,0,33,7,128,0,57,0,0,0,0,0,151,4,53,0,0,13,48,0,0,1,61],[0,0,0,5,1,0,0,41,0,0,0,0,1,1,4,51,0,0,0,0,2,1,0,75,0,0,11,27,0,0,97,61],[0,0,5,11,2,0,0,65,0,0,0,32,3,16,0,140,0,0,0,0,3,0,0,25,0,0,0,0,3,2,64,25],[0,0,5,11,1,16,1,151,0,0,0,0,4,1,0,75,0,0,0,0,2,0,160,25,0,0,5,11,1,16,0,156],[0,0,0,0,2,3,192,25,0,0,0,0,1,2,0,75,0,0,1,39,0,0,193,61,0,0,0,10,1,0,0,41],[0,0,0,0,1,1,4,51,0,0,0,0,2,1,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,192,57],[0,0,0,0,2,33,0,75,0,0,1,39,0,0,193,61,0,0,0,0,1,1,0,75,0,0,11,27,0,0,193,61],[0,0,0,64,1,0,4,61,0,0,0,100,2,16,0,57,0,0,5,43,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,68,2,16,0,57,0,0,5,44,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,42,3,0,0,57,0,0,0,0,0,50,4,53,0,0,5,16,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,4,2,16,0,57,0,0,0,4,3,0,0,41,0,0,1,10,0,0,1,61,0,0,0,64,3,0,4,61],[0,0,0,36,1,48,0,57,0,0,0,7,2,0,0,41,0,0,0,0,0,33,4,53,0,0,5,32,1,0,0,65],[0,0,0,0,0,19,4,53,0,10,0,0,0,3,0,29,0,0,0,4,1,48,0,57,0,0,0,6,2,0,0,41],[0,0,0,0,0,33,4,53,0,0,0,0,1,0,4,20,0,0,0,9,2,0,0,41,0,0,0,4,2,32,0,140],[0,0,11,159,0,0,193,61,0,0,0,1,3,0,0,49,0,0,0,32,1,48,0,140,0,0,0,0,4,3,0,25],[0,0,0,32,4,0,128,57,0,0,11,209,0,0,1,61,0,0,5,58,9,112,0,156,0,0,18,165,0,0,33,61],[0,0,0,64,9,112,0,57,0,0,0,64,0,144,4,63,0,0,0,0,10,33,3,79,0,0,0,1,9,0,0,58],[0,0,0,0,9,151,4,54,0,0,0,0,10,160,3,80,0,0,0,0,10,10,4,59,0,0,0,0,0,169,4,53],[0,0,12,17,0,0,97,61,0,0,0,248,11,128,2,16,0,0,5,11,12,0,0,65,0,0,0,0,8,8,0,75],[0,0,0,0,12,11,192,25,0,0,5,59,8,160,1,151,0,0,0,0,8,200,1,159,0,0,0,0,0,137,4,53],[0,0,0,64,9,0,4,61,0,0,5,58,8,144,0,156,0,0,18,165,0,0,33,61,0,0,0,32,8,96,0,138],[0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,64,10,144,0,57,0,0,0,64,0,160,4,63],[0,0,0,32,10,144,0,57,0,0,5,62,11,0,0,65,0,0,0,0,0,186,4,53,0,0,0,21,10,0,0,57],[0,0,0,0,0,169,4,53,0,0,0,96,8,128,2,16,0,0,0,33,10,144,0,57,0,0,0,0,0,138,4,53],[0,0,0,192,6,96,0,57,0,0,0,0,6,97,3,79,0,0,0,64,8,0,4,61,0,0,0,0,6,6,4,59],[0,8,0,0,0,6,0,29,0,0,0,128,10,96,0,140,0,0,12,105,0,0,65,61,0,0,0,8,6,0,0,41],[0,0,0,128,10,96,2,112,0,0,5,60,11,96,0,156,0,0,0,0,10,6,160,25,0,0,5,60,11,96,0,156],[0,0,0,0,11,0,0,25,0,0,0,16,11,0,32,57,0,0,0,8,12,176,1,191,0,0,5,10,13,160,0,156],[0,0,0,0,12,11,160,25,0,0,0,64,11,160,2,112,0,0,5,10,13,160,0,156,0,0,0,0,11,10,160,25],[0,0,0,4,13,192,1,191,0,0,5,2,10,176,0,156,0,0,0,0,13,12,160,25,0,0,0,32,12,176,2,112],[0,0,5,2,10,176,0,156,0,0,0,0,12,11,160,25,0,0,0,2,10,208,1,191,0,0,255,255,11,192,0,140],[0,0,0,0,10,13,160,25,0,0,0,16,11,192,2,112,0,0,0,0,11,12,160,25,0,0,0,255,11,176,0,140],[0,0,0,1,10,160,32,57,0,0,0,32,11,0,0,138,0,0,0,65,12,160,0,57,0,0,0,0,11,188,1,111],[0,0,0,0,11,184,0,25,0,0,0,0,12,139,0,75,0,0,0,0,12,0,0,25,0,0,0,1,12,0,64,57],[0,0,5,10,13,176,0,156,0,0,18,165,0,0,33,61,0,0,0,1,12,192,1,144,0,0,18,165,0,0,193,61],[0,0,0,64,0,176,4,63,0,0,0,2,11,160,0,57,0,0,0,0,11,184,4,54,0,0,0,33,12,160,0,57],[0,0,0,5,12,192,2,114,0,0,11,140,0,0,97,61,0,0,0,0,13,33,3,79,0,0,0,0,14,0,0,25],[0,0,0,5,15,224,2,16,0,0,0,0,6,251,0,25,0,0,0,0,15,253,3,79,0,0,0,0,15,15,4,59],[0,0,0,0,0,246,4,53,0,0,0,1,14,224,0,57,0,0,0,0,6,206,0,75,0,0,11,132,0,0,65,61],[0,0,0,0,6,0,0,75,0,0,11,142,0,0,97,61,0,0,0,0,6,8,4,51,0,0,0,0,6,6,0,75],[0,0,12,17,0,0,97,61,0,0,0,0,6,11,4,51,0,0,5,59,6,96,1,151,0,0,0,248,12,160,2,16],[0,0,0,0,6,108,1,159,0,0,5,61,6,96,0,65,0,0,0,0,0,107,4,53,0,0,0,3,6,160,2,16],[0,0,0,248,6,96,0,137,0,0,0,8,10,96,1,239,0,0,0,255,6,96,0,140,0,0,0,0,10,0,32,25],[0,0,0,33,6,128,0,57,0,0,0,0,0,166,4,53,0,0,12,124,0,0,1,61,0,0,5,2,2,0,0,65],[0,0,5,2,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,10,4,0,0,41,0,0,5,2,3,64,0,156],[0,0,0,0,2,4,64,25,0,0,0,64,2,32,2,16,0,0,0,192,1,16,2,16,0,0,0,0,1,33,1,159],[0,0,5,38,1,16,1,199,0,0,0,9,2,0,0,41,20,1,19,242,0,0,4,15,0,0,0,10,10,0,0,41],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,5,2,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114],[0,0,11,190,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,138,0,25],[0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,103,0,75,0,0,11,182,0,0,65,61,0,0,0,0,7,5,0,75,0,0,11,205,0,0,97,61],[0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,10,6,96,0,41,0,0,0,3,5,80,2,16],[0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159],[0,0,0,0,0,86,4,53,0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144],[0,0,12,21,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,2,16,1,143,0,0,0,10,1,32,0,41],[0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,5,10,4,16,0,156],[0,0,18,165,0,0,33,61,0,0,0,1,2,32,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,16,4,63],[0,0,0,32,2,48,0,140,0,0,1,39,0,0,65,61,0,0,0,68,4,16,0,57,0,0,0,36,5,16,0,57],[0,0,0,10,2,0,0,41,0,0,0,0,2,2,4,51,0,0,0,0,2,2,0,75,0,0,12,50,0,0,193,61],[0,0,0,32,2,16,0,57,0,0,5,34,6,0,0,65,0,0,0,0,0,98,4,53,0,0,0,7,6,0,0,41],[0,0,0,0,0,101,4,53,0,0,0,8,5,0,0,41,0,0,0,0,0,84,4,53,0,0,0,1,4,0,0,41],[0,0,0,0,0,65,4,53,0,0,5,41,4,16,0,156,0,0,18,165,0,0,33,61,0,0,0,128,4,16,0,57],[0,10,0,0,0,4,0,29,0,0,0,64,0,64,4,63,0,0,5,42,4,16,0,156,0,0,18,165,0,0,33,61],[0,0,0,192,4,16,0,57,0,0,0,64,0,64,4,63,0,0,0,4,4,0,0,41,0,0,0,10,5,0,0,41],[0,0,0,0,0,69,4,53,0,0,0,160,5,16,0,57,0,0,5,35,4,0,0,65,0,7,0,0,0,5,0,29],[0,0,0,0,0,69,4,53,0,0,0,0,4,1,4,51,0,0,0,0,1,0,4,20,0,0,0,9,5,0,0,41],[0,0,0,4,5,80,0,140,0,0,15,43,0,0,193,61,0,0,0,1,2,0,0,57,0,0,5,10,1,48,0,156],[0,0,18,165,0,0,33,61,0,0,15,65,0,0,1,61,0,0,5,58,7,128,0,156,0,0,18,165,0,0,33,61],[0,0,0,64,7,128,0,57,0,0,0,64,0,112,4,63,0,0,0,0,7,33,3,79,0,0,0,1,10,0,0,58],[0,0,0,0,10,168,4,54,0,0,0,0,7,112,3,80,0,0,0,0,11,7,4,59,0,0,0,0,0,186,4,53],[0,0,13,41,0,0,193,61,0,0,5,88,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,50,1,0,0,57],[0,0,0,65,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114],[0,0,12,34,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,12,26,0,0,65,61,0,0,0,0,6,4,0,75,0,0,12,49,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,6,70,0,0,1,61,0,0,5,16,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,4,2,16,0,57,0,0,0,4,3,0,0,41,0,0,0,0,0,50,4,53,0,0,0,54,2,0,0,57],[0,0,0,0,0,37,4,53,0,0,5,39,2,0,0,65,0,0,0,0,0,36,4,53,0,0,0,100,2,16,0,57],[0,0,5,40,3,0,0,65,0,0,1,10,0,0,1,61,0,0,0,64,8,0,4,61,0,3,0,0,0,8,0,29],[0,0,0,56,8,112,0,140,0,0,13,147,0,0,65,61,0,0,0,32,9,112,2,112,0,0,5,2,8,112,0,156],[0,0,0,0,9,7,160,25,0,0,5,2,8,112,0,156,0,0,0,0,10,0,0,25,0,0,0,4,10,0,32,57],[0,0,0,2,8,160,1,191,0,0,255,255,11,144,0,140,0,0,0,0,8,10,160,25,0,0,0,16,10,144,2,112],[0,0,0,0,10,9,160,25,0,0,0,255,9,160,0,140,0,0,0,0,9,0,0,25,0,0,0,1,9,0,32,57],[0,0,0,3,10,0,0,41,0,0,5,58,10,160,0,156,0,0,18,165,0,0,33,61,0,0,0,0,8,152,1,159],[0,0,0,3,10,0,0,41,0,0,0,64,9,160,0,57,0,0,0,64,0,144,4,63,0,0,0,2,9,128,0,58],[0,0,0,0,9,154,4,54,0,0,0,0,5,80,3,80,0,0,0,0,5,5,4,59,0,0,0,0,0,89,4,53],[0,0,12,17,0,0,97,61,0,0,5,59,5,80,1,151,0,0,0,248,10,128,2,16,0,0,0,0,5,90,1,159],[0,0,5,63,5,80,1,199,0,0,0,0,0,89,4,53,0,0,0,3,5,128,2,16,0,0,0,248,5,80,1,95],[0,0,0,0,5,87,1,207,0,0,0,3,7,0,0,41,0,0,0,33,7,112,0,57,0,0,0,0,0,87,4,53],[0,0,13,164,0,0,1,61,0,0,5,58,6,128,0,156,0,0,18,165,0,0,33,61,0,0,0,64,6,128,0,57],[0,0,0,64,0,96,4,63,0,0,0,0,6,33,3,79,0,0,0,1,10,0,0,58,0,0,0,0,10,168,4,54],[0,0,0,0,6,96,3,80,0,0,0,0,11,6,4,59,0,0,0,0,0,186,4,53,0,0,12,17,0,0,97,61],[0,0,0,8,13,0,0,41,0,0,0,248,6,208,2,16,0,0,5,11,12,0,0,65,0,0,0,0,13,13,0,75],[0,0,0,0,12,6,192,25,0,0,5,59,6,176,1,151,0,0,0,0,6,198,1,159,0,0,0,0,0,106,4,53],[0,0,0,64,6,0,4,61,0,0,0,32,11,96,0,57,0,0,0,0,10,3,4,51,0,0,0,0,12,10,0,75],[0,0,12,137,0,0,97,61,0,0,0,0,12,0,0,25,0,0,0,0,13,188,0,25,0,0,0,32,12,192,0,57],[0,0,0,0,14,60,0,25,0,0,0,0,14,14,4,51,0,0,0,0,0,237,4,53,0,0,0,0,13,172,0,75],[0,0,12,130,0,0,65,61,0,0,0,0,3,186,0,25,0,0,0,0,0,3,4,53,0,0,0,0,3,106,0,25],[0,0,0,32,11,48,0,57,0,0,0,0,10,4,4,51,0,0,0,0,12,10,0,75,0,0,12,152,0,0,97,61],[0,0,0,0,12,0,0,25,0,0,0,0,13,188,0,25,0,0,0,32,12,192,0,57,0,0,0,0,14,76,0,25],[0,0,0,0,14,14,4,51,0,0,0,0,0,237,4,53,0,0,0,0,13,172,0,75,0,0,12,145,0,0,65,61],[0,0,0,0,4,186,0,25,0,0,0,0,0,4,4,53,0,0,0,0,3,58,0,25,0,0,0,32,10,48,0,57],[0,0,0,0,4,5,4,51,0,0,0,0,11,4,0,75,0,0,12,167,0,0,97,61,0,0,0,0,11,0,0,25],[0,0,0,0,12,171,0,25,0,0,0,32,11,176,0,57,0,0,0,0,13,91,0,25,0,0,0,0,13,13,4,51],[0,0,0,0,0,220,4,53,0,0,0,0,12,75,0,75,0,0,12,160,0,0,65,61,0,0,0,0,5,164,0,25],[0,0,0,0,0,5,4,53,0,0,0,0,3,52,0,25,0,0,0,32,5,48,0,57,0,0,0,0,4,7,4,51],[0,0,0,0,10,4,0,75,0,0,12,182,0,0,97,61,0,0,0,0,10,0,0,25,0,0,0,0,11,90,0,25],[0,0,0,32,10,160,0,57,0,0,0,0,12,122,0,25,0,0,0,0,12,12,4,51,0,0,0,0,0,203,4,53],[0,0,0,0,11,74,0,75,0,0,12,175,0,0,65,61,0,0,0,0,5,84,0,25,0,0,0,0,0,5,4,53],[0,0,0,0,3,52,0,25,0,0,0,32,5,48,0,57,0,0,0,0,4,9,4,51,0,0,0,0,7,4,0,75],[0,0,12,197,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,0,10,87,0,25,0,0,0,32,7,112,0,57],[0,0,0,0,11,151,0,25,0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53,0,0,0,0,10,71,0,75],[0,0,12,190,0,0,65,61,0,0,0,0,5,84,0,25,0,0,0,0,0,5,4,53,0,0,0,0,3,52,0,25],[0,0,0,32,5,48,0,57,0,0,0,0,4,8,4,51,0,0,0,0,7,4,0,75,0,0,12,212,0,0,97,61],[0,0,0,0,7,0,0,25,0,0,0,0,9,87,0,25,0,0,0,32,7,112,0,57,0,0,0,0,10,135,0,25],[0,0,0,0,10,10,4,51,0,0,0,0,0,169,4,53,0,0,0,0,9,71,0,75,0,0,12,205,0,0,65,61],[0,0,0,0,5,84,0,25,0,0,0,0,0,5,4,53,0,0,0,0,3,99,0,73,0,0,0,0,3,52,0,25],[0,0,0,0,0,54,4,53,0,0,0,63,4,48,0,57,0,0,0,32,3,0,0,138,0,0,0,0,4,52,1,111],[0,0,0,0,7,100,0,25,0,0,0,0,4,71,0,75,0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57],[0,0,5,10,5,112,0,156,0,0,18,165,0,0,33,61,0,0,0,1,4,64,1,144,0,0,18,165,0,0,193,61],[0,0,0,64,0,112,4,63,0,0,0,10,5,0,0,41,0,0,1,196,4,80,0,57,0,0,0,0,4,65,3,79],[0,0,0,0,5,82,0,73,0,0,0,35,5,80,0,138,0,0,0,0,4,4,4,59,0,0,5,11,8,0,0,65],[0,0,0,0,9,84,0,75,0,0,0,0,9,0,0,25,0,0,0,0,9,8,128,25,0,0,5,11,5,80,1,151],[0,0,5,11,10,64,1,151,0,0,0,0,11,90,0,75,0,0,0,0,8,0,128,25,0,0,0,0,5,90,1,63],[0,0,5,11,5,80,0,156,0,0,0,0,8,9,192,25,0,0,0,0,5,8,0,75,0,0,1,39,0,0,193,61],[0,0,0,9,5,64,0,41,0,0,0,0,4,81,3,79,0,0,0,0,4,4,4,59,0,0,5,10,8,64,0,156],[0,0,1,39,0,0,33,61,0,0,0,0,8,66,0,73,0,0,0,32,5,80,0,57,0,0,5,11,9,0,0,65],[0,0,0,0,10,133,0,75,0,0,0,0,10,0,0,25,0,0,0,0,10,9,32,25,0,0,5,11,8,128,1,151],[0,0,5,11,11,80,1,151,0,0,0,0,12,139,0,75,0,0,0,0,9,0,128,25,0,0,0,0,8,139,1,63],[0,0,5,11,8,128,0,156,0,0,0,0,9,10,192,25,0,0,0,0,8,9,0,75,0,0,1,39,0,0,193,61],[0,0,0,1,8,64,0,140,0,0,17,245,0,0,193,61,0,0,0,0,8,81,3,79,0,0,0,0,8,8,4,59],[0,0,0,1,9,0,0,138,0,0,5,11,10,0,0,65,0,0,0,0,9,152,0,75,0,0,0,0,9,0,0,25],[0,0,0,0,9,10,32,25,0,0,5,11,8,128,1,151,0,0,5,11,11,128,0,156,0,0,0,0,10,0,128,25],[0,0,5,11,8,128,1,103,0,0,5,11,8,128,0,156,0,0,0,0,10,9,192,25,0,0,0,96,8,0,0,57],[0,0,0,0,9,10,0,75,0,0,18,86,0,0,193,61,0,0,5,58,8,112,0,156,0,0,18,165,0,0,33,61],[0,0,0,64,8,112,0,57,0,0,0,64,0,128,4,63,0,0,0,32,8,112,0,57,0,0,5,61,9,0,0,65],[0,0,0,0,0,152,4,53,0,0,0,1,8,0,0,57,0,0,0,0,0,135,4,53,0,0,0,0,8,7,0,25],[0,0,18,86,0,0,1,61,0,0,0,248,7,144,2,16,0,0,5,11,12,0,0,65,0,0,0,0,9,9,0,75],[0,0,0,0,12,7,192,25,0,0,5,59,7,176,1,151,0,0,0,0,7,199,1,159,0,0,0,0,0,122,4,53],[0,0,0,64,10,0,4,61,0,0,5,58,7,160,0,156,0,0,18,165,0,0,33,61,0,0,0,8,12,0,0,41],[0,0,0,32,7,192,0,138,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,64,9,160,0,57],[0,0,0,64,0,144,4,63,0,0,0,32,9,160,0,57,0,0,5,62,11,0,0,65,0,0,0,0,0,185,4,53],[0,0,0,21,9,0,0,57,0,0,0,0,0,154,4,53,0,0,0,96,7,112,2,16,0,0,0,33,9,160,0,57],[0,0,0,0,0,121,4,53,0,0,0,192,7,192,0,57,0,0,0,0,7,113,3,79,0,0,0,64,9,0,4,61],[0,0,0,0,7,7,4,59,0,8,0,0,0,7,0,29,0,0,0,128,11,112,0,140,0,0,14,5,0,0,65,61],[0,0,0,8,7,0,0,41,0,0,0,128,11,112,2,112,0,0,5,60,12,112,0,156,0,0,0,0,11,7,160,25],[0,0,5,60,12,112,0,156,0,0,0,0,12,0,0,25,0,0,0,16,12,0,32,57,0,0,0,8,13,192,1,191],[0,0,5,10,14,176,0,156,0,0,0,0,13,12,160,25,0,0,0,64,12,176,2,112,0,0,5,10,14,176,0,156],[0,0,0,0,12,11,160,25,0,0,0,4,14,208,1,191,0,0,5,2,11,192,0,156,0,0,0,0,14,13,160,25],[0,0,0,32,13,192,2,112,0,0,5,2,11,192,0,156,0,0,0,0,13,12,160,25,0,0,0,2,7,224,1,191],[0,0,255,255,12,208,0,140,0,0,0,0,7,14,160,25,0,0,0,16,12,208,2,112,0,0,0,0,12,13,160,25],[0,0,0,255,12,192,0,140,0,0,0,1,7,112,32,57,0,0,0,32,12,0,0,138,0,6,0,0,0,7,0,29],[0,0,0,65,13,112,0,57,0,0,0,0,12,205,1,111,0,0,0,0,12,201,0,25,0,0,0,0,13,156,0,75],[0,0,0,0,13,0,0,25,0,0,0,1,13,0,64,57,0,0,5,10,14,192,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,13,208,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,192,4,63,0,0,0,6,7,0,0,41],[0,0,0,2,12,112,0,57,0,0,0,0,12,201,4,54,0,0,0,33,13,112,0,57,0,0,0,5,13,208,2,114],[0,0,13,127,0,0,97,61,0,0,0,0,14,33,3,79,0,0,0,0,15,0,0,25,0,0,0,5,7,240,2,16],[0,0,0,0,11,124,0,25,0,0,0,0,7,126,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,123,4,53],[0,0,0,1,15,240,0,57,0,0,0,0,7,223,0,75,0,0,13,119,0,0,65,61,0,0,0,0,7,0,0,75],[0,0,13,129,0,0,97,61,0,0,0,0,7,9,4,51,0,0,0,0,7,7,0,75,0,0,12,17,0,0,97,61],[0,0,0,0,7,12,4,51,0,0,5,59,7,112,1,151,0,0,0,6,13,0,0,41,0,0,0,248,11,208,2,16],[0,0,0,0,7,123,1,159,0,0,5,61,7,112,0,65,0,0,0,0,0,124,4,53,0,0,0,3,7,208,2,16],[0,0,0,248,7,112,0,137,0,0,0,8,11,112,1,239,0,0,0,255,7,112,0,140,0,0,0,0,11,0,32,25],[0,0,0,33,7,144,0,57,0,0,0,0,0,183,4,53,0,0,14,24,0,0,1,61,0,0,0,3,8,0,0,41],[0,0,5,58,8,128,0,156,0,0,18,165,0,0,33,61,0,0,0,3,9,0,0,41,0,0,0,64,8,144,0,57],[0,0,0,64,0,128,4,63,0,0,0,1,8,0,0,58,0,0,0,0,8,137,4,54,0,0,0,0,5,80,3,80],[0,0,0,0,5,5,4,59,0,0,0,0,0,88,4,53,0,0,12,17,0,0,97,61,0,0,0,248,7,112,2,16],[0,0,5,59,5,80,1,151,0,0,0,0,5,117,1,159,0,0,5,11,5,80,1,103,0,0,0,0,0,88,4,53],[0,0,0,128,1,16,0,138,0,0,0,0,5,19,3,79,0,0,0,96,1,0,0,57,0,0,0,0,5,5,4,59],[0,0,0,0,5,5,0,75,0,0,14,212,0,0,193,61,0,0,5,11,5,0,0,65,0,0,0,0,7,98,0,75],[0,0,0,0,7,0,0,25,0,0,0,0,7,5,128,25,0,0,5,11,6,96,1,151,0,0,5,11,8,32,1,151],[0,0,0,0,9,104,0,75,0,0,0,0,5,0,128,25,0,0,0,0,6,104,1,63,0,0,5,11,6,96,0,156],[0,0,0,0,5,7,192,25,0,0,0,0,5,5,0,75,0,0,1,39,0,0,193,61,0,0,0,8,5,0,0,41],[0,0,0,0,6,5,4,51,0,0,0,6,5,0,0,41,0,0,0,0,7,5,4,51,0,0,0,5,5,0,0,41],[0,0,0,0,8,5,4,51,0,0,0,4,5,0,0,41,0,0,0,0,9,5,4,51,0,0,0,3,5,0,0,41],[0,0,0,0,10,5,4,51,0,0,0,9,5,32,0,41,0,0,0,0,2,83,3,79,0,0,0,0,2,2,4,59],[0,0,5,10,11,32,0,156,0,0,1,39,0,0,33,61,0,0,0,0,11,36,0,73,0,0,0,32,5,80,0,57],[0,0,5,11,12,0,0,65,0,0,0,0,13,181,0,75,0,0,0,0,13,0,0,25,0,0,0,0,13,12,32,25],[0,0,5,11,11,176,1,151,0,0,5,11,14,80,1,151,0,0,0,0,15,190,0,75,0,0,0,0,12,0,128,25],[0,0,0,0,11,190,1,63,0,0,5,11,11,176,0,156,0,0,0,0,12,13,192,25,0,0,0,0,11,12,0,75],[0,0,1,39,0,0,193,61,0,0,0,0,6,103,0,25,0,0,0,0,6,134,0,25,0,0,0,0,6,150,0,25],[0,0,0,0,6,166,0,25,0,0,0,0,6,38,0,25,0,0,0,0,7,1,4,51,0,0,0,0,6,118,0,25],[0,0,0,64,7,0,4,61,0,0,5,10,6,96,1,151,0,0,0,56,8,96,0,140,0,0,15,246,0,0,65,61],[0,0,0,32,9,96,2,112,0,0,5,2,8,96,0,156,0,0,0,0,9,6,160,25,0,0,5,2,8,96,0,156],[0,0,0,0,10,0,0,25,0,0,0,4,10,0,32,57,0,0,0,2,8,160,1,191,0,0,255,255,11,144,0,140],[0,0,0,0,8,10,160,25,0,0,0,16,10,144,2,112,0,0,0,0,10,9,160,25,0,0,0,255,9,160,0,140],[0,0,0,0,9,0,0,25,0,0,0,1,9,0,32,57,0,0,5,58,10,112,0,156,0,0,18,165,0,0,33,61],[0,0,0,0,8,152,1,159,0,0,0,64,9,112,0,57,0,0,0,64,0,144,4,63,0,0,0,0,9,67,3,79],[0,0,0,2,4,128,0,58,0,0,0,0,4,71,4,54,0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59],[0,0,0,0,0,148,4,53,0,0,12,17,0,0,97,61,0,0,5,59,9,144,1,151,0,0,0,248,10,128,2,16],[0,0,0,0,9,154,1,159,0,0,5,65,9,144,1,199,0,0,0,0,0,148,4,53,0,0,0,3,4,128,2,16],[0,0,0,248,4,64,1,95,0,0,0,0,4,70,1,207,0,0,0,33,6,112,0,57,0,0,0,0,0,70,4,53],[0,0,16,6,0,0,1,61,0,0,5,58,7,144,0,156,0,0,18,165,0,0,33,61,0,0,0,64,7,144,0,57],[0,0,0,64,0,112,4,63,0,0,0,0,7,33,3,79,0,0,0,1,11,0,0,58,0,0,0,0,11,185,4,54],[0,0,0,0,7,112,3,80,0,0,0,0,12,7,4,59,0,0,0,0,0,203,4,53,0,0,12,17,0,0,97,61],[0,0,0,8,14,0,0,41,0,0,0,248,7,224,2,16,0,0,5,11,13,0,0,65,0,0,0,0,14,14,0,75],[0,0,0,0,13,7,192,25,0,0,5,59,7,192,1,151,0,0,0,0,7,215,1,159,0,0,0,0,0,123,4,53],[0,0,0,64,7,0,4,61,0,0,0,32,12,112,0,57,0,0,0,0,11,3,4,51,0,0,0,0,13,11,0,75],[0,0,14,37,0,0,97,61,0,0,0,0,13,0,0,25,0,0,0,0,14,205,0,25,0,0,0,32,13,208,0,57],[0,0,0,0,15,61,0,25,0,0,0,0,15,15,4,51,0,0,0,0,0,254,4,53,0,0,0,0,14,189,0,75],[0,0,14,30,0,0,65,61,0,0,0,0,3,203,0,25,0,0,0,0,0,3,4,53,0,0,0,0,3,123,0,25],[0,0,0,32,12,48,0,57,0,0,0,0,11,4,4,51,0,0,0,0,13,11,0,75,0,0,14,52,0,0,97,61],[0,0,0,0,13,0,0,25,0,0,0,0,14,205,0,25,0,0,0,32,13,208,0,57,0,0,0,0,15,77,0,25],[0,0,0,0,15,15,4,51,0,0,0,0,0,254,4,53,0,0,0,0,14,189,0,75,0,0,14,45,0,0,65,61],[0,0,0,0,4,203,0,25,0,0,0,0,0,4,4,53,0,0,0,0,3,59,0,25,0,0,0,32,11,48,0,57],[0,0,0,0,4,5,4,51,0,0,0,0,12,4,0,75,0,0,14,67,0,0,97,61,0,0,0,0,12,0,0,25],[0,0,0,0,13,188,0,25,0,0,0,32,12,192,0,57,0,0,0,0,14,92,0,25,0,0,0,0,14,14,4,51],[0,0,0,0,0,237,4,53,0,0,0,0,13,76,0,75,0,0,14,60,0,0,65,61,0,0,0,0,5,180,0,25],[0,0,0,0,0,5,4,53,0,0,0,0,3,52,0,25,0,0,0,32,5,48,0,57,0,0,0,0,4,6,4,51],[0,0,0,0,11,4,0,75,0,0,14,82,0,0,97,61,0,0,0,0,11,0,0,25,0,0,0,0,12,91,0,25],[0,0,0,32,11,176,0,57,0,0,0,0,13,107,0,25,0,0,0,0,13,13,4,51,0,0,0,0,0,220,4,53],[0,0,0,0,12,75,0,75,0,0,14,75,0,0,65,61,0,0,0,0,5,84,0,25,0,0,0,0,0,5,4,53],[0,0,0,0,3,52,0,25,0,0,0,32,5,48,0,57,0,0,0,0,4,8,4,51,0,0,0,0,6,4,0,75],[0,0,14,97,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,0,11,86,0,25,0,0,0,32,6,96,0,57],[0,0,0,0,12,134,0,25,0,0,0,0,12,12,4,51,0,0,0,0,0,203,4,53,0,0,0,0,11,70,0,75],[0,0,14,90,0,0,65,61,0,0,0,0,5,84,0,25,0,0,0,0,0,5,4,53,0,0,0,0,3,52,0,25],[0,0,0,32,5,48,0,57,0,0,0,0,4,10,4,51,0,0,0,0,6,4,0,75,0,0,14,112,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,0,8,86,0,25,0,0,0,32,6,96,0,57,0,0,0,0,11,166,0,25],[0,0,0,0,11,11,4,51,0,0,0,0,0,184,4,53,0,0,0,0,8,70,0,75,0,0,14,105,0,0,65,61],[0,0,0,0,5,84,0,25,0,0,0,0,0,5,4,53,0,0,0,0,3,52,0,25,0,0,0,32,5,48,0,57],[0,0,0,0,4,9,4,51,0,0,0,0,6,4,0,75,0,0,14,127,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,0,8,86,0,25,0,0,0,32,6,96,0,57,0,0,0,0,10,150,0,25,0,0,0,0,10,10,4,51],[0,0,0,0,0,168,4,53,0,0,0,0,8,70,0,75,0,0,14,120,0,0,65,61,0,0,0,0,5,84,0,25],[0,0,0,0,0,5,4,53,0,0,0,0,3,115,0,73,0,0,0,0,3,52,0,25,0,0,0,0,0,55,4,53],[0,0,0,63,4,48,0,57,0,0,0,32,3,0,0,138,0,0,0,0,4,52,1,111,0,0,0,0,6,116,0,25],[0,0,0,0,4,70,0,75,0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57,0,0,5,10,5,96,0,156],[0,0,18,165,0,0,33,61,0,0,0,1,4,64,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,96,4,63],[0,0,0,10,5,0,0,41,0,0,1,196,4,80,0,57,0,0,0,0,4,65,3,79,0,0,0,0,5,82,0,73],[0,0,0,35,5,80,0,138,0,0,0,0,4,4,4,59,0,0,5,11,8,0,0,65,0,0,0,0,9,84,0,75],[0,0,0,0,9,0,0,25,0,0,0,0,9,8,128,25,0,0,5,11,5,80,1,151,0,0,5,11,10,64,1,151],[0,0,0,0,11,90,0,75,0,0,0,0,8,0,128,25,0,0,0,0,5,90,1,63,0,0,5,11,5,80,0,156],[0,0,0,0,8,9,192,25,0,0,0,0,5,8,0,75,0,0,1,39,0,0,193,61,0,0,0,9,5,64,0,41],[0,0,0,0,4,81,3,79,0,0,0,0,4,4,4,59,0,0,5,10,8,64,0,156,0,0,1,39,0,0,33,61],[0,0,0,0,8,66,0,73,0,0,0,32,5,80,0,57,0,0,5,11,9,0,0,65,0,0,0,0,10,133,0,75],[0,0,0,0,10,0,0,25,0,0,0,0,10,9,32,25,0,0,5,11,8,128,1,151,0,0,5,11,11,80,1,151],[0,0,0,0,12,139,0,75,0,0,0,0,9,0,128,25,0,0,0,0,8,139,1,63,0,0,5,11,8,128,0,156],[0,0,0,0,9,10,192,25,0,0,0,0,8,9,0,75,0,0,1,39,0,0,193,61,0,0,0,1,8,64,0,140],[0,0,18,29,0,0,193,61,0,0,0,0,8,81,3,79,0,0,0,0,8,8,4,59,0,0,0,1,9,0,0,138],[0,0,5,11,10,0,0,65,0,0,0,0,9,152,0,75,0,0,0,0,9,0,0,25,0,0,0,0,9,10,32,25],[0,0,5,11,8,128,1,151,0,0,5,11,11,128,0,156,0,0,0,0,10,0,128,25,0,0,5,11,8,128,1,103],[0,0,5,11,8,128,0,156,0,0,0,0,10,9,192,25,0,0,0,96,8,0,0,57,0,0,0,0,9,10,0,75],[0,0,18,162,0,0,193,61,0,0,5,58,8,96,0,156,0,0,18,165,0,0,33,61,0,0,0,64,8,96,0,57],[0,0,0,64,0,128,4,63,0,0,0,32,8,96,0,57,0,0,5,61,9,0,0,65,0,0,0,0,0,152,4,53],[0,0,0,1,8,0,0,57,0,0,0,0,0,134,4,53,0,0,0,0,8,6,0,25,0,0,18,162,0,0,1,61],[0,0,5,56,1,0,0,65,0,0,0,0,0,16,4,57,0,0,5,2,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,5,2,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,57,1,16,1,199],[0,0,128,11,2,0,0,57,20,1,19,242,0,0,4,15,0,0,0,1,2,32,1,144,0,0,16,244,0,0,97,61],[0,0,0,64,2,0,4,61,0,0,0,0,1,1,4,59,0,0,0,128,3,16,0,140,0,0,15,141,0,0,65,61],[0,0,0,128,3,16,2,112,0,0,5,60,4,16,0,156,0,0,0,0,3,1,160,25,0,0,5,60,4,16,0,156],[0,0,0,0,4,0,0,25,0,0,0,16,4,0,32,57,0,0,0,8,5,64,1,191,0,0,5,10,6,48,0,156],[0,0,0,0,5,4,160,25,0,0,0,64,4,48,2,112,0,0,5,10,6,48,0,156,0,0,0,0,4,3,160,25],[0,0,0,4,3,80,1,191,0,0,5,2,6,64,0,156,0,0,0,0,3,5,160,25,0,0,0,32,6,64,2,112],[0,0,5,2,5,64,0,156,0,0,0,0,6,4,160,25,0,0,0,2,5,48,1,191,0,0,255,255,4,96,0,140],[0,0,0,0,5,3,160,25,0,0,0,16,3,96,2,112,0,0,0,0,3,6,160,25,0,0,0,255,3,48,0,140],[0,0,0,1,5,80,32,57,0,0,0,65,3,80,0,57,0,0,0,2,3,48,1,127,0,0,0,0,3,50,0,25],[0,0,0,0,4,35,0,75,0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57,0,0,5,10,6,48,0,156],[0,0,18,165,0,0,33,61,0,0,0,1,4,64,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,48,4,63],[0,0,0,2,3,80,0,57,0,0,0,0,6,50,4,54,0,0,0,2,3,0,3,103,0,0,0,0,4,0,0,49],[0,0,0,33,7,80,0,57,0,0,0,5,7,112,2,114,0,0,15,25,0,0,97,61,0,0,0,0,8,67,3,79],[0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16,0,0,0,0,11,166,0,25,0,0,0,0,10,168,3,79],[0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75],[0,0,15,17,0,0,65,61,0,0,0,0,7,0,0,75,0,0,15,27,0,0,97,61,0,0,0,0,7,2,4,51],[0,0,0,0,7,7,0,75,0,0,12,17,0,0,97,61,0,0,0,0,7,6,4,51,0,0,5,59,7,112,1,151],[0,0,0,248,8,80,2,16,0,0,0,0,7,120,1,159,0,0,5,61,7,112,0,65,0,0,0,0,0,118,4,53],[0,0,0,3,5,80,2,16,0,0,0,248,5,80,0,137,0,0,0,0,1,81,1,207,0,0,0,255,5,80,0,140],[0,0,0,0,1,0,32,25,0,0,0,33,5,32,0,57,0,0,15,160,0,0,1,61,0,0,5,2,3,0,0,65],[0,0,5,2,5,32,0,156,0,0,0,0,2,3,128,25,0,0,0,64,2,32,2,16,0,0,5,2,5,64,0,156],[0,0,0,0,4,3,128,25,0,0,0,96,4,64,2,16,0,0,0,0,2,36,1,159,0,0,5,2,4,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,0,0,1,18,1,159,0,0,0,9,2,0,0,41],[20,1,19,237,0,0,4,15,0,8,0,96,0,0,0,61,0,6,0,128,0,0,0,61,0,0,0,1,2,32,1,143],[0,3,0,0,0,1,3,85,0,0,0,96,1,16,2,112,0,1,5,2,0,16,1,157,0,0,5,2,3,16,1,152],[0,0,15,110,0,0,97,61,0,0,0,63,1,48,0,57,0,0,0,32,4,0,0,138,0,0,0,0,1,65,1,111],[0,0,0,64,4,0,4,61,0,0,0,0,1,20,0,25,0,8,0,0,0,4,0,29,0,0,0,0,4,65,0,75],[0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57,0,0,5,10,5,16,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,4,64,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,16,4,63,0,0,0,31,1,48,1,143],[0,0,0,8,4,0,0,41,0,0,0,0,8,52,4,54,0,0,0,3,4,0,3,103,0,0,0,5,3,48,2,114],[0,0,15,94,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,104,0,25],[0,0,0,0,6,100,3,79,0,0,0,0,6,6,4,59,0,0,0,0,0,103,4,53,0,0,0,1,5,80,0,57],[0,0,0,0,6,53,0,75,0,0,15,86,0,0,65,61,0,6,0,0,0,8,0,29,0,0,0,0,5,1,0,75],[0,0,15,110,0,0,97,61,0,0,0,5,3,48,2,16,0,0,0,0,4,52,3,79,0,0,0,6,3,48,0,41],[0,0,0,3,1,16,2,16,0,0,0,0,5,3,4,51,0,0,0,0,5,21,1,207,0,0,0,0,5,21,2,47],[0,0,0,0,4,4,4,59,0,0,1,0,1,16,0,137,0,0,0,0,4,20,2,47,0,0,0,0,1,20,1,207],[0,0,0,0,1,81,1,159,0,0,0,0,0,19,4,53,0,0,0,8,1,0,0,41,0,0,0,0,1,1,4,51],[0,0,0,0,2,2,0,75,0,0,15,197,0,0,193,61,0,0,0,0,2,1,0,75,0,0,15,241,0,0,193,61],[0,0,0,64,4,0,4,61,0,9,0,0,0,4,0,29,0,0,5,16,1,0,0,65,0,0,0,0,0,20,4,53],[0,0,0,4,1,64,0,57,0,0,0,4,2,0,0,41,0,0,0,0,0,33,4,53,0,0,0,10,1,0,0,41],[0,0,0,0,3,1,4,51,0,10,0,0,0,3,0,29,0,0,0,36,1,64,0,57,0,0,0,0,0,49,4,53],[0,0,0,68,2,64,0,57,0,0,0,7,1,0,0,41,20,1,19,223,0,0,4,15,0,0,0,10,1,0,0,41],[0,0,0,31,1,16,0,57,0,0,0,32,2,0,0,138,0,0,0,0,1,33,1,111,0,0,0,68,1,16,0,57],[0,0,5,2,2,0,0,65,0,0,5,2,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,9,4,0,0,41],[0,0,8,221,0,0,1,61,0,0,5,58,3,32,0,156,0,0,18,165,0,0,33,61,0,0,0,64,3,32,0,57],[0,0,0,64,0,48,4,63,0,0,0,1,3,0,0,58,0,0,0,0,5,50,4,54,0,0,0,0,4,0,0,49],[0,0,0,2,3,0,3,103,0,0,0,0,6,67,3,79,0,0,0,0,6,96,3,80,0,0,0,0,6,6,4,59],[0,0,0,0,0,101,4,53,0,0,12,17,0,0,97,61,0,0,0,248,7,16,2,16,0,0,5,11,8,0,0,65],[0,0,0,0,1,1,0,75,0,0,0,0,8,7,192,25,0,0,5,59,1,96,1,151,0,0,0,0,1,129,1,159],[0,0,0,0,0,21,4,53,0,0,0,64,1,0,4,61,0,0,0,32,6,16,0,57,0,0,0,0,5,2,4,51],[0,0,0,0,7,5,0,75,0,0,15,174,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,0,8,103,0,25],[0,0,0,32,7,112,0,57,0,0,0,0,9,39,0,25,0,0,0,0,9,9,4,51,0,0,0,0,0,152,4,53],[0,0,0,0,8,87,0,75,0,0,15,167,0,0,65,61,0,0,0,0,2,101,0,25,0,0,5,77,6,0,0,65],[0,0,0,0,0,98,4,53,0,0,0,2,2,80,0,57,0,0,0,0,0,33,4,53,0,0,0,65,2,80,0,57],[0,0,0,2,5,32,1,127,0,0,0,0,2,21,0,25,0,0,0,0,5,82,0,75,0,0,0,0,5,0,0,25],[0,0,0,1,5,0,64,57,0,0,5,10,6,32,0,156,0,0,18,165,0,0,33,61,0,0,0,1,5,80,1,144],[0,0,18,165,0,0,193,61,0,0,0,10,6,0,0,41,0,0,1,196,5,96,0,57,0,0,0,64,0,32,4,63],[0,0,0,0,2,83,3,79,0,0,0,0,5,100,0,73,0,0,0,35,6,80,0,138,0,0,0,0,2,2,4,59],[0,0,13,170,0,0,1,61,0,0,0,0,2,1,0,75,0,0,15,220,0,0,193,61,0,0,5,36,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,0,9,1,0,0,41,0,0,0,4,0,16,4,67,0,0,5,2,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,5,2,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,5,37,1,16,1,199,0,0,128,2,2,0,0,57,20,1,19,242,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,16,244,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,9,110,0,0,97,61],[0,0,0,8,1,0,0,41,0,0,0,0,1,1,4,51,0,0,0,0,2,1,0,75,0,0,3,118,0,0,97,61],[0,0,5,11,2,0,0,65,0,0,0,32,3,16,0,140,0,0,0,0,3,0,0,25,0,0,0,0,3,2,64,25],[0,0,5,11,1,16,1,151,0,0,0,0,4,1,0,75,0,0,0,0,2,0,160,25,0,0,5,11,1,16,0,156],[0,0,0,0,2,3,192,25,0,0,0,0,1,2,0,75,0,0,1,39,0,0,193,61,0,0,0,6,1,0,0,41],[0,0,0,0,1,1,4,51,0,0,0,0,2,1,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,192,57],[0,0,0,0,2,33,0,75,0,0,1,39,0,0,193,61,0,0,0,0,1,1,0,75,0,0,3,118,0,0,193,61],[0,0,11,12,0,0,1,61,0,0,5,2,2,0,0,65,0,0,5,2,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,6,4,0,0,41,0,0,8,221,0,0,1,61,0,0,5,58,8,112,0,156,0,0,18,165,0,0,33,61],[0,0,0,64,8,112,0,57,0,0,0,64,0,128,4,63,0,0,0,0,8,67,3,79,0,0,0,1,4,0,0,58],[0,0,0,0,4,71,4,54,0,0,0,0,8,128,3,80,0,0,0,0,8,8,4,59,0,0,0,0,0,132,4,53],[0,0,12,17,0,0,97,61,0,0,5,59,8,128,1,151,0,0,0,248,6,96,2,16,0,0,0,0,6,134,1,159],[0,0,5,64,6,96,0,65,0,0,0,0,0,100,4,53,0,0,0,64,4,0,4,61,0,0,0,32,6,64,0,57],[0,0,0,0,8,7,4,51,0,0,0,0,9,8,0,75,0,0,16,19,0,0,97,61,0,0,0,0,9,0,0,25],[0,0,0,0,10,105,0,25,0,0,0,32,9,144,0,57,0,0,0,0,11,121,0,25,0,0,0,0,11,11,4,51],[0,0,0,0,0,186,4,53,0,0,0,0,10,137,0,75,0,0,16,12,0,0,65,61,0,0,0,0,7,104,0,25],[0,0,0,0,0,7,4,53,0,0,0,0,7,72,0,25,0,0,0,32,9,112,0,57,0,0,0,8,8,0,0,41],[0,0,0,0,8,8,4,51,0,0,0,0,10,8,0,75,0,0,16,35,0,0,97,61,0,0,0,0,10,0,0,25],[0,0,0,0,11,154,0,25,0,0,0,32,10,160,0,57,0,0,0,8,12,160,0,41,0,0,0,0,12,12,4,51],[0,0,0,0,0,203,4,53,0,0,0,0,11,138,0,75,0,0,16,28,0,0,65,61,0,0,0,0,9,152,0,25],[0,0,0,0,0,9,4,53,0,0,0,0,7,120,0,25,0,0,0,32,9,112,0,57,0,0,0,6,8,0,0,41],[0,0,0,0,8,8,4,51,0,0,0,0,10,8,0,75,0,0,16,51,0,0,97,61,0,0,0,0,10,0,0,25],[0,0,0,0,11,154,0,25,0,0,0,32,10,160,0,57,0,0,0,6,12,160,0,41,0,0,0,0,12,12,4,51],[0,0,0,0,0,203,4,53,0,0,0,0,11,138,0,75,0,0,16,44,0,0,65,61,0,0,0,0,9,152,0,25],[0,0,0,0,0,9,4,53,0,0,0,0,7,120,0,25,0,0,0,32,9,112,0,57,0,0,0,5,8,0,0,41],[0,0,0,0,8,8,4,51,0,0,0,0,10,8,0,75,0,0,16,67,0,0,97,61,0,0,0,0,10,0,0,25],[0,0,0,0,11,154,0,25,0,0,0,32,10,160,0,57,0,0,0,5,12,160,0,41,0,0,0,0,12,12,4,51],[0,0,0,0,0,203,4,53,0,0,0,0,11,138,0,75,0,0,16,60,0,0,65,61,0,0,0,0,9,152,0,25],[0,0,0,0,0,9,4,53,0,0,0,0,7,120,0,25,0,0,0,32,9,112,0,57,0,0,0,4,8,0,0,41],[0,0,0,0,8,8,4,51,0,0,0,0,10,8,0,75,0,0,16,83,0,0,97,61,0,0,0,0,10,0,0,25],[0,0,0,0,11,154,0,25,0,0,0,32,10,160,0,57,0,0,0,4,12,160,0,41,0,0,0,0,12,12,4,51],[0,0,0,0,0,203,4,53,0,0,0,0,11,138,0,75,0,0,16,76,0,0,65,61,0,0,0,0,9,152,0,25],[0,0,0,0,0,9,4,53,0,0,0,0,7,120,0,25,0,0,0,32,9,112,0,57,0,0,0,3,8,0,0,41],[0,0,0,0,8,8,4,51,0,0,0,0,10,8,0,75,0,0,16,99,0,0,97,61,0,0,0,0,10,0,0,25],[0,0,0,0,11,154,0,25,0,0,0,32,10,160,0,57,0,0,0,3,12,160,0,41,0,0,0,0,12,12,4,51],[0,0,0,0,0,203,4,53,0,0,0,0,11,138,0,75,0,0,16,92,0,0,65,61,0,0,0,0,9,152,0,25],[0,0,0,0,0,9,4,53,0,0,0,0,5,83,3,79,0,0,0,0,3,120,0,25,0,0,0,31,7,32,1,143],[0,0,0,32,8,48,0,57,0,0,0,5,9,32,2,114,0,0,16,116,0,0,97,61,0,0,0,0,10,0,0,25],[0,0,0,5,11,160,2,16,0,0,0,0,12,184,0,25,0,0,0,0,11,181,3,79,0,0,0,0,11,11,4,59],[0,0,0,0,0,188,4,53,0,0,0,1,10,160,0,57,0,0,0,0,11,154,0,75,0,0,16,108,0,0,65,61],[0,0,0,0,10,7,0,75,0,0,16,131,0,0,97,61,0,0,0,5,9,144,2,16,0,0,0,0,5,149,3,79],[0,0,0,0,8,152,0,25,0,0,0,3,7,112,2,16,0,0,0,0,9,8,4,51,0,0,0,0,9,121,1,207],[0,0,0,0,9,121,2,47,0,0,0,0,5,5,4,59,0,0,1,0,7,112,0,137,0,0,0,0,5,117,2,47],[0,0,0,0,5,117,1,207,0,0,0,0,5,149,1,159,0,0,0,0,0,88,4,53,0,0,0,0,2,35,0,25],[0,0,0,32,5,32,0,57,0,0,0,0,0,5,4,53,0,0,0,0,3,1,4,51,0,0,0,0,7,3,0,75],[0,0,16,145,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,0,8,87,0,25,0,0,0,32,7,112,0,57],[0,0,0,0,9,23,0,25,0,0,0,0,9,9,4,51,0,0,0,0,0,152,4,53,0,0,0,0,8,55,0,75],[0,0,16,138,0,0,65,61,0,0,0,0,1,83,0,25,0,0,0,0,0,1,4,53,0,0,0,0,1,66,0,73],[0,0,0,0,1,19,0,25,0,0,0,0,0,20,4,53,0,0,0,63,1,16,0,57,0,0,0,2,2,16,1,127],[0,0,0,0,1,66,0,25,0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57],[0,0,5,10,3,16,0,156,0,0,18,165,0,0,33,61,0,0,0,1,2,32,1,144,0,0,18,165,0,0,193,61],[0,0,0,64,0,16,4,63,0,0,5,2,1,0,0,65,0,0,5,2,2,96,0,156,0,0,0,0,6,1,128,25],[0,0,0,64,2,96,2,16,0,0,0,0,3,4,4,51,0,0,5,2,4,48,0,156,0,0,0,0,3,1,128,25],[0,0,0,96,3,48,2,16,0,0,0,0,2,35,1,159,0,0,0,0,3,0,4,20,0,0,5,2,4,48,0,156],[0,0,0,0,3,1,128,25,0,0,0,192,1,48,2,16,0,0,0,0,1,33,1,159,0,0,5,13,1,16,1,199],[0,0,128,16,2,0,0,57,20,1,19,242,0,0,4,15,0,0,0,1,2,32,1,144,0,0,1,39,0,0,97,61],[0,0,0,2,3,0,3,103,0,0,0,0,1,1,4,59,0,8,0,0,0,1,0,29,0,0,0,10,1,0,0,41],[0,0,0,228,4,16,0,57,0,0,0,0,1,67,3,79,0,0,0,0,1,1,4,59,0,0,5,12,1,16,1,152],[0,5,0,0,0,4,0,29,0,0,16,212,0,0,193,61,0,0,0,128,1,64,0,138,0,0,0,0,2,19,3,79],[0,0,0,64,1,64,0,138,0,0,0,0,5,19,3,79,0,0,0,0,4,2,4,59,0,0,0,0,5,5,4,59],[0,0,0,0,98,69,0,169,0,0,0,0,6,5,0,75,0,0,16,202,0,0,97,61,0,0,0,0,101,82,0,217],[0,0,0,0,4,69,0,75,0,0,16,208,0,0,193,61,0,0,0,128,1,16,0,57,0,0,0,0,1,19,3,79],[0,0,0,0,1,1,4,59,0,6,0,0,0,33,0,30,0,0,16,208,0,0,65,61,0,0,16,217,0,0,1,61],[0,0,5,88,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57,0,0,0,65,0,0,1,61],[0,0,0,10,1,0,0,41,0,0,1,36,1,16,0,57,0,0,0,0,1,19,3,79,0,0,0,0,1,1,4,59],[0,6,0,0,0,1,0,29,0,0,5,78,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,7,1,0,0,41],[0,0,0,4,0,16,4,67,0,0,5,2,1,0,0,65,0,0,0,0,2,0,4,20,0,0,5,2,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,37,1,16,1,199,0,0,128,10,2,0,0,57],[20,1,19,242,0,0,4,15,0,0,0,1,2,32,1,144,0,0,16,244,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,6,1,16,0,107,0,0,16,245,0,0,161,61,0,0,0,64,1,0,4,61,0,0,0,100,2,16,0,57],[0,0,5,86,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,68,2,16,0,57,0,0,5,87,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,34,3,0,0,57,0,0,1,5,0,0,1,61],[0,0,0,0,0,1,4,47,0,0,0,0,4,0,0,49,0,0,0,10,1,64,0,106,0,0,0,35,2,16,0,138],[0,0,0,5,1,0,0,41,0,0,1,0,1,16,0,57,0,0,0,2,3,0,3,103,0,0,0,0,1,19,3,79],[0,0,0,0,1,1,4,59,0,0,5,11,5,0,0,65,0,0,0,0,6,33,0,75,0,0,0,0,6,0,0,25],[0,0,0,0,6,5,128,25,0,0,5,11,2,32,1,151,0,0,5,11,7,16,1,151,0,0,0,0,8,39,0,75],[0,0,0,0,5,0,128,25,0,0,0,0,2,39,1,63,0,0,5,11,2,32,0,156,0,0,0,0,5,6,192,25],[0,0,0,0,2,5,0,75,0,0,1,39,0,0,193,61,0,0,0,9,2,16,0,41,0,0,0,0,1,35,3,79],[0,0,0,0,1,1,4,59,0,0,5,10,5,16,0,156,0,0,1,39,0,0,33,61,0,0,0,0,5,20,0,73],[0,0,0,32,6,32,0,57,0,0,5,11,2,0,0,65,0,0,0,0,7,86,0,75,0,0,0,0,7,0,0,25],[0,0,0,0,7,2,32,25,0,0,5,11,5,80,1,151,0,0,5,11,8,96,1,151,0,0,0,0,9,88,0,75],[0,0,0,0,2,0,128,25,0,0,0,0,5,88,1,63,0,0,5,11,5,80,0,156,0,0,0,0,2,7,192,25],[0,0,0,0,2,2,0,75,0,0,1,39,0,0,193,61,0,0,0,63,2,16,0,57,0,0,0,32,5,0,0,138],[0,0,0,0,5,82,1,111,0,0,0,64,2,0,4,61,0,0,0,0,5,82,0,25,0,0,0,0,7,37,0,75],[0,0,0,0,7,0,0,25,0,0,0,1,7,0,64,57,0,0,5,10,8,80,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,7,112,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,80,4,63,0,0,0,0,5,18,4,54],[0,0,0,0,7,97,0,25,0,0,0,0,4,71,0,75,0,0,1,39,0,0,33,61,0,0,0,0,4,99,3,79],[0,0,0,31,3,16,1,143,0,0,0,5,6,16,2,114,0,0,17,60,0,0,97,61,0,0,0,0,7,0,0,25],[0,0,0,5,8,112,2,16,0,0,0,0,9,133,0,25,0,0,0,0,8,132,3,79,0,0,0,0,8,8,4,59],[0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,17,52,0,0,65,61],[0,0,0,0,7,3,0,75,0,0,17,75,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,4,100,3,79],[0,0,0,0,6,101,0,25,0,0,0,3,3,48,2,16,0,0,0,0,7,6,4,51,0,0,0,0,7,55,1,207],[0,0,0,0,7,55,2,47,0,0,0,0,4,4,4,59,0,0,1,0,3,48,0,137,0,0,0,0,4,52,2,47],[0,0,0,0,3,52,1,207,0,0,0,0,3,115,1,159,0,0,0,0,0,54,4,53,0,0,0,0,1,21,0,25],[0,0,0,0,0,1,4,53,0,0,0,64,1,0,4,61,0,0,0,0,3,2,4,51,0,0,0,65,3,48,0,140],[0,0,17,94,0,0,193,61,0,0,0,65,3,32,0,57,0,0,0,0,3,3,4,51,0,0,0,255,3,48,1,143],[0,0,0,29,4,48,0,138,0,0,0,3,6,0,0,138,0,0,0,0,4,100,0,75,0,0,17,100,0,0,33,61],[0,0,0,68,2,16,0,57,0,0,5,85,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,22,3,0,0,57,0,0,4,110,0,0,1,61,0,0,0,68,2,16,0,57,0,0,5,79,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,29,3,0,0,57,0,0,4,110,0,0,1,61],[0,0,0,0,4,5,4,51,0,0,0,64,2,32,0,57,0,0,0,0,2,2,4,51,0,0,5,80,5,32,0,156],[0,0,17,111,0,0,65,61,0,0,0,68,2,16,0,57,0,0,5,84,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,9,3,0,0,57,0,0,4,110,0,0,1,61,0,0,0,96,5,16,0,57],[0,0,0,0,0,37,4,53,0,0,0,64,2,16,0,57,0,0,0,0,0,66,4,53,0,0,0,32,2,16,0,57],[0,0,0,0,0,50,4,53,0,0,0,8,2,0,0,41,0,0,0,0,0,33,4,53,0,0,0,0,0,0,4,53],[0,0,5,2,2,0,0,65,0,0,0,0,3,0,4,20,0,0,5,2,4,48,0,156,0,0,0,0,3,2,128,25],[0,0,5,2,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,0,192,2,48,2,16],[0,0,0,0,1,18,1,159,0,0,5,81,1,16,1,199,0,0,0,1,2,0,0,57,20,1,19,242,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,5,2,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,4,64,2,114],[0,0,17,149,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,113,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,70,0,75],[0,0,17,142,0,0,65,61,0,0,0,0,6,5,0,75,0,0,17,163,0,0,97,61,0,0,0,3,5,80,2,16],[0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47],[0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159,0,0,0,0,0,84,4,53,0,1,0,0,0,3,0,31],[0,3,0,0,0,1,3,85,0,0,0,64,4,0,4,61,0,0,0,1,2,32,1,144,0,0,17,186,0,0,97,61],[0,0,0,0,1,0,4,51,0,0,5,12,1,16,1,151,0,0,0,7,2,16,0,108,0,0,0,0,2,0,0,25],[0,0,0,1,2,0,192,57,0,0,0,0,1,1,0,75,0,0,0,0,1,0,0,25,0,0,0,1,1,0,96,57],[0,0,0,0,1,18,1,160,0,0,5,82,1,0,0,65,0,0,0,0,1,0,192,25,0,0,0,0,0,20,4,53],[0,0,5,2,1,0,0,65,0,0,5,2,2,64,0,156,0,0,0,0,4,1,128,25,0,0,0,64,1,64,2,16],[0,0,5,83,1,16,1,199,0,0,20,2,0,1,4,46,0,0,0,31,2,48,1,143,0,0,0,5,5,48,2,114],[0,0,17,198,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,116,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,17,190,0,0,65,61,0,0,0,0,6,2,0,75,0,0,17,213,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,84,0,25,0,0,0,3,2,32,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,38,1,207,0,0,0,0,6,38,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,2,32,0,137,0,0,0,0,1,33,2,47,0,0,0,0,1,33,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,5,2,1,0,0,65,0,0,5,2,2,64,0,156,0,0,0,0,4,1,128,25],[0,0,0,64,1,64,2,16,0,0,6,74,0,0,1,61,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114],[0,0,17,229,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75],[0,0,17,222,0,0,65,61,0,0,0,0,5,4,0,75,0,0,17,243,0,0,97,61,0,0,0,3,4,64,2,16],[0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47],[0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16],[0,0,20,3,0,1,4,48,0,0,0,56,8,64,0,140,0,0,18,69,0,0,65,61,0,0,0,32,9,64,2,112],[0,0,5,2,8,64,0,156,0,0,0,0,9,4,160,25,0,0,5,2,8,64,0,156,0,0,0,0,10,0,0,25],[0,0,0,4,10,0,32,57,0,0,0,2,8,160,1,191,0,0,255,255,11,144,0,140,0,0,0,0,8,10,160,25],[0,0,0,16,10,144,2,112,0,0,0,0,10,9,160,25,0,0,0,255,9,160,0,140,0,0,0,0,9,0,0,25],[0,0,0,1,9,0,32,57,0,0,5,58,10,112,0,156,0,0,18,165,0,0,33,61,0,0,0,0,8,152,1,159],[0,0,0,64,9,112,0,57,0,0,0,64,0,144,4,63,0,0,0,0,10,33,3,79,0,0,0,2,9,128,0,58],[0,0,0,0,9,151,4,54,0,0,0,0,10,160,3,80,0,0,0,0,10,10,4,59,0,0,0,0,0,169,4,53],[0,0,12,17,0,0,97,61,0,0,5,59,10,160,1,151,0,0,0,248,11,128,2,16,0,0,0,0,10,171,1,159],[0,0,5,63,10,160,1,199,0,0,0,0,0,169,4,53,0,0,0,3,8,128,2,16,0,0,0,248,8,128,1,95],[0,0,0,0,8,132,1,207,0,0,0,33,9,112,0,57,0,0,0,0,0,137,4,53,0,0,0,0,8,7,0,25],[0,0,18,86,0,0,1,61,0,0,0,56,8,64,0,140,0,0,18,145,0,0,65,61,0,0,0,32,9,64,2,112],[0,0,5,2,8,64,0,156,0,0,0,0,9,4,160,25,0,0,5,2,8,64,0,156,0,0,0,0,10,0,0,25],[0,0,0,4,10,0,32,57,0,0,0,2,8,160,1,191,0,0,255,255,11,144,0,140,0,0,0,0,8,10,160,25],[0,0,0,16,10,144,2,112,0,0,0,0,10,9,160,25,0,0,0,255,9,160,0,140,0,0,0,0,9,0,0,25],[0,0,0,1,9,0,32,57,0,0,5,58,10,96,0,156,0,0,18,165,0,0,33,61,0,0,0,0,8,152,1,159],[0,0,0,64,9,96,0,57,0,0,0,64,0,144,4,63,0,0,0,0,10,33,3,79,0,0,0,2,9,128,0,58],[0,0,0,0,9,150,4,54,0,0,0,0,10,160,3,80,0,0,0,0,10,10,4,59,0,0,0,0,0,169,4,53],[0,0,12,17,0,0,97,61,0,0,5,59,10,160,1,151,0,0,0,248,11,128,2,16,0,0,0,0,10,171,1,159],[0,0,5,63,10,160,1,199,0,0,0,0,0,169,4,53,0,0,0,3,8,128,2,16,0,0,0,248,8,128,1,95],[0,0,0,0,8,132,1,207,0,0,0,33,9,96,0,57,0,0,0,0,0,137,4,53,0,0,0,0,8,6,0,25],[0,0,18,162,0,0,1,61,0,0,5,58,8,112,0,156,0,0,18,165,0,0,33,61,0,0,0,64,8,112,0,57],[0,0,0,64,0,128,4,63,0,0,0,0,9,33,3,79,0,0,0,1,8,0,0,58,0,0,0,0,8,135,4,54],[0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59,0,0,0,0,0,152,4,53,0,0,12,17,0,0,97,61],[0,0,0,248,10,64,2,16,0,0,5,59,9,144,1,151,0,0,0,0,9,169,1,159,0,0,5,11,9,144,1,103],[0,0,0,0,0,152,4,53,0,0,0,0,8,7,0,25,0,0,0,64,7,0,4,61,0,0,5,58,9,112,0,156],[0,0,18,165,0,0,33,61,0,0,0,64,9,112,0,57,0,0,0,64,0,144,4,63,0,0,0,0,2,33,3,79],[0,0,0,1,12,0,0,58,0,0,0,0,9,199,4,54,0,0,0,0,2,32,3,80,0,0,0,0,11,2,4,59],[0,0,0,0,0,185,4,53,0,0,12,17,0,0,97,61,0,0,5,59,2,176,1,151,0,0,5,64,10,32,1,199],[0,0,0,0,0,169,4,53,0,0,0,0,9,6,4,51,0,0,0,0,9,73,0,25,0,0,0,0,10,8,4,51],[0,0,0,0,9,169,0,25,0,0,0,0,10,7,4,51,0,0,0,0,9,169,0,25,0,0,0,64,10,0,4,61],[0,0,5,10,9,144,1,151,0,0,0,56,13,144,0,140,0,0,18,225,0,0,65,61,0,0,0,32,13,144,2,112],[0,0,5,2,12,144,0,156,0,0,0,0,13,9,160,25,0,0,5,2,12,144,0,156,0,0,0,0,14,0,0,25],[0,0,0,4,14,0,32,57,0,0,0,2,12,224,1,191,0,0,255,255,15,208,0,140,0,0,0,0,12,14,160,25],[0,0,0,16,14,208,2,112,0,0,0,0,14,13,160,25,0,0,0,255,13,224,0,140,0,0,0,0,13,0,0,25],[0,0,0,1,13,0,32,57,0,0,5,58,14,160,0,156,0,0,18,165,0,0,33,61,0,0,0,0,12,220,1,159],[0,0,0,64,13,160,0,57,0,0,0,64,0,208,4,63,0,0,0,32,13,160,0,57,0,0,0,0,0,189,4,53],[0,0,0,2,11,192,0,58,0,0,0,0,0,186,4,53,0,0,12,17,0,0,97,61,0,0,0,248,11,192,2,16],[0,0,0,0,2,43,1,159,0,0,5,65,2,32,1,199,0,0,0,0,0,45,4,53,0,0,0,3,2,192,2,16],[0,0,0,248,2,32,1,95,0,0,0,0,2,41,1,207,0,0,0,33,9,160,0,57,0,0,0,0,0,41,4,53],[0,0,18,238,0,0,1,61,0,0,5,58,8,96,0,156,0,0,18,165,0,0,33,61,0,0,0,64,8,96,0,57],[0,0,0,64,0,128,4,63,0,0,0,0,9,33,3,79,0,0,0,1,8,0,0,58,0,0,0,0,8,134,4,54],[0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59,0,0,0,0,0,152,4,53,0,0,12,17,0,0,97,61],[0,0,0,248,10,64,2,16,0,0,5,59,9,144,1,151,0,0,0,0,9,169,1,159,0,0,5,11,9,144,1,103],[0,0,0,0,0,152,4,53,0,0,0,0,8,6,0,25,0,0,0,64,6,0,4,61,0,0,5,58,9,96,0,156],[0,0,18,169,0,0,161,61,0,0,5,88,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57],[0,0,0,65,0,0,1,61,0,0,0,64,9,96,0,57,0,0,0,64,0,144,4,63,0,0,0,0,2,33,3,79],[0,0,0,1,12,0,0,58,0,0,0,0,9,198,4,54,0,0,0,0,2,32,3,80,0,0,0,0,11,2,4,59],[0,0,0,0,0,185,4,53,0,0,12,17,0,0,97,61,0,0,5,59,2,176,1,151,0,0,5,64,10,32,1,199],[0,0,0,0,0,169,4,53,0,0,0,0,9,7,4,51,0,0,0,0,9,73,0,25,0,0,0,0,10,8,4,51],[0,0,0,0,9,169,0,25,0,0,0,0,10,6,4,51,0,0,0,0,9,169,0,25,0,0,0,64,10,0,4,61],[0,0,5,10,9,144,1,151,0,0,0,56,13,144,0,140,0,0,19,91,0,0,65,61,0,0,0,32,13,144,2,112],[0,0,5,2,12,144,0,156,0,0,0,0,13,9,160,25,0,0,5,2,12,144,0,156,0,0,0,0,14,0,0,25],[0,0,0,4,14,0,32,57,0,0,0,2,12,224,1,191,0,0,255,255,15,208,0,140,0,0,0,0,12,14,160,25],[0,0,0,16,14,208,2,112,0,0,0,0,14,13,160,25,0,0,0,255,13,224,0,140,0,0,0,0,13,0,0,25],[0,0,0,1,13,0,32,57,0,0,5,58,14,160,0,156,0,0,18,165,0,0,33,61,0,0,0,0,12,220,1,159],[0,0,0,64,13,160,0,57,0,0,0,64,0,208,4,63,0,0,0,32,13,160,0,57,0,0,0,0,0,189,4,53],[0,0,0,2,11,192,0,58,0,0,0,0,0,186,4,53,0,0,12,17,0,0,97,61,0,0,0,248,11,192,2,16],[0,0,0,0,2,43,1,159,0,0,5,65,2,32,1,199,0,0,0,0,0,45,4,53,0,0,0,3,2,192,2,16],[0,0,0,248,2,32,1,95,0,0,0,0,2,41,1,207,0,0,0,33,9,160,0,57,0,0,0,0,0,41,4,53],[0,0,19,104,0,0,1,61,0,0,5,58,13,160,0,156,0,0,18,165,0,0,33,61,0,0,0,64,13,160,0,57],[0,0,0,64,0,208,4,63,0,0,0,32,13,160,0,57,0,0,0,0,0,189,4,53,0,0,0,0,0,202,4,53],[0,0,0,0,11,12,0,75,0,0,12,17,0,0,97,61,0,0,0,248,9,144,2,16,0,0,0,0,2,41,1,159],[0,0,5,64,2,32,0,65,0,0,0,0,0,45,4,53,0,0,0,64,2,0,4,61,0,0,0,32,9,32,0,57],[0,0,5,66,11,0,0,65,0,0,0,0,0,185,4,53,0,0,0,33,12,32,0,57,0,0,0,0,11,10,4,51],[0,0,0,0,13,11,0,75,0,0,18,254,0,0,97,61,0,0,0,0,13,0,0,25,0,0,0,0,14,205,0,25],[0,0,0,32,13,208,0,57,0,0,0,0,15,173,0,25,0,0,0,0,15,15,4,51,0,0,0,0,0,254,4,53],[0,0,0,0,14,189,0,75,0,0,18,247,0,0,65,61,0,0,0,0,10,203,0,25,0,0,0,0,0,10,4,53],[0,0,0,0,10,43,0,25,0,0,0,33,12,160,0,57,0,0,0,0,11,6,4,51,0,0,0,0,13,11,0,75],[0,0,19,13,0,0,97,61,0,0,0,0,13,0,0,25,0,0,0,0,14,205,0,25,0,0,0,32,13,208,0,57],[0,0,0,0,15,109,0,25,0,0,0,0,15,15,4,51,0,0,0,0,0,254,4,53,0,0,0,0,14,189,0,75],[0,0,19,6,0,0,65,61,0,0,0,0,6,203,0,25,0,0,0,0,0,6,4,53,0,0,0,0,6,171,0,25],[0,0,0,33,11,96,0,57,0,0,0,0,10,8,4,51,0,0,0,0,12,10,0,75,0,0,19,28,0,0,97,61],[0,0,0,0,12,0,0,25,0,0,0,0,13,188,0,25,0,0,0,32,12,192,0,57,0,0,0,0,14,140,0,25],[0,0,0,0,14,14,4,51,0,0,0,0,0,237,4,53,0,0,0,0,13,172,0,75,0,0,19,21,0,0,65,61],[0,0,0,0,8,186,0,25,0,0,0,0,0,8,4,53,0,0,0,0,5,81,3,79,0,0,0,0,1,106,0,25],[0,0,0,31,6,64,1,143,0,0,0,33,8,16,0,57,0,0,0,5,10,64,2,114,0,0,19,45,0,0,97,61],[0,0,0,0,11,0,0,25,0,0,0,5,12,176,2,16,0,0,0,0,13,200,0,25,0,0,0,0,12,197,3,79],[0,0,0,0,12,12,4,59,0,0,0,0,0,205,4,53,0,0,0,1,11,176,0,57,0,0,0,0,12,171,0,75],[0,0,19,37,0,0,65,61,0,0,0,0,11,6,0,75,0,0,19,60,0,0,97,61,0,0,0,5,10,160,2,16],[0,0,0,0,5,165,3,79,0,0,0,0,8,168,0,25,0,0,0,3,6,96,2,16,0,0,0,0,10,8,4,51],[0,0,0,0,10,106,1,207,0,0,0,0,10,106,2,47,0,0,0,0,5,5,4,59,0,0,1,0,6,96,0,137],[0,0,0,0,5,101,2,47,0,0,0,0,5,101,1,207,0,0,0,0,5,165,1,159,0,0,0,0,0,88,4,53],[0,0,0,0,1,65,0,25,0,0,0,33,5,16,0,57,0,0,0,0,0,5,4,53,0,0,0,0,4,7,4,51],[0,0,0,0,6,4,0,75,0,0,19,74,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,0,8,86,0,25],[0,0,0,32,6,96,0,57,0,0,0,0,10,118,0,25,0,0,0,0,10,10,4,51,0,0,0,0,0,168,4,53],[0,0,0,0,8,70,0,75,0,0,19,67,0,0,65,61,0,0,0,0,5,84,0,25,0,0,0,0,0,5,4,53],[0,0,0,0,1,33,0,73,0,0,0,0,1,20,0,25,0,0,0,1,4,16,0,57,0,0,0,0,0,66,4,53],[0,0,0,64,1,16,0,57,0,0,0,0,3,49,1,111,0,0,0,0,1,35,0,25,0,0,0,0,3,49,0,75],[0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57,0,0,5,10,4,16,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,3,48,1,144,0,0,19,212,0,0,97,61,0,0,18,165,0,0,1,61,0,0,5,58,13,160,0,156],[0,0,18,165,0,0,33,61,0,0,0,64,13,160,0,57,0,0,0,64,0,208,4,63,0,0,0,32,13,160,0,57],[0,0,0,0,0,189,4,53,0,0,0,0,0,202,4,53,0,0,0,0,11,12,0,75,0,0,12,17,0,0,97,61],[0,0,0,248,9,144,2,16,0,0,0,0,2,41,1,159,0,0,5,64,2,32,0,65,0,0,0,0,0,45,4,53],[0,0,0,64,2,0,4,61,0,0,0,32,9,32,0,57,0,0,5,13,11,0,0,65,0,0,0,0,0,185,4,53],[0,0,0,33,12,32,0,57,0,0,0,0,11,10,4,51,0,0,0,0,13,11,0,75,0,0,19,120,0,0,97,61],[0,0,0,0,13,0,0,25,0,0,0,0,14,205,0,25,0,0,0,32,13,208,0,57,0,0,0,0,15,173,0,25],[0,0,0,0,15,15,4,51,0,0,0,0,0,254,4,53,0,0,0,0,14,189,0,75,0,0,19,113,0,0,65,61],[0,0,0,0,10,203,0,25,0,0,0,0,0,10,4,53,0,0,0,0,10,43,0,25,0,0,0,33,12,160,0,57],[0,0,0,0,11,7,4,51,0,0,0,0,13,11,0,75,0,0,19,135,0,0,97,61,0,0,0,0,13,0,0,25],[0,0,0,0,14,205,0,25,0,0,0,32,13,208,0,57,0,0,0,0,15,125,0,25,0,0,0,0,15,15,4,51],[0,0,0,0,0,254,4,53,0,0,0,0,14,189,0,75,0,0,19,128,0,0,65,61,0,0,0,0,7,203,0,25],[0,0,0,0,0,7,4,53,0,0,0,0,7,171,0,25,0,0,0,33,11,112,0,57,0,0,0,0,10,8,4,51],[0,0,0,0,12,10,0,75,0,0,19,150,0,0,97,61,0,0,0,0,12,0,0,25,0,0,0,0,13,188,0,25],[0,0,0,32,12,192,0,57,0,0,0,0,14,140,0,25,0,0,0,0,14,14,4,51,0,0,0,0,0,237,4,53],[0,0,0,0,13,172,0,75,0,0,19,143,0,0,65,61,0,0,0,0,8,186,0,25,0,0,0,0,0,8,4,53],[0,0,0,0,5,81,3,79,0,0,0,0,1,122,0,25,0,0,0,31,7,64,1,143,0,0,0,33,8,16,0,57],[0,0,0,5,10,64,2,114,0,0,19,167,0,0,97,61,0,0,0,0,11,0,0,25,0,0,0,5,12,176,2,16],[0,0,0,0,13,200,0,25,0,0,0,0,12,197,3,79,0,0,0,0,12,12,4,59,0,0,0,0,0,205,4,53],[0,0,0,1,11,176,0,57,0,0,0,0,12,171,0,75,0,0,19,159,0,0,65,61,0,0,0,0,11,7,0,75],[0,0,19,182,0,0,97,61,0,0,0,5,10,160,2,16,0,0,0,0,5,165,3,79,0,0,0,0,8,168,0,25],[0,0,0,3,7,112,2,16,0,0,0,0,10,8,4,51,0,0,0,0,10,122,1,207,0,0,0,0,10,122,2,47],[0,0,0,0,5,5,4,59,0,0,1,0,7,112,0,137,0,0,0,0,5,117,2,47,0,0,0,0,5,117,1,207],[0,0,0,0,5,165,1,159,0,0,0,0,0,88,4,53,0,0,0,0,1,65,0,25,0,0,0,33,5,16,0,57],[0,0,0,0,0,5,4,53,0,0,0,0,4,6,4,51,0,0,0,0,7,4,0,75,0,0,19,196,0,0,97,61],[0,0,0,0,7,0,0,25,0,0,0,0,8,87,0,25,0,0,0,32,7,112,0,57,0,0,0,0,10,103,0,25],[0,0,0,0,10,10,4,51,0,0,0,0,0,168,4,53,0,0,0,0,8,71,0,75,0,0,19,189,0,0,65,61],[0,0,0,0,5,84,0,25,0,0,0,0,0,5,4,53,0,0,0,0,1,33,0,73,0,0,0,0,1,20,0,25],[0,0,0,1,4,16,0,57,0,0,0,0,0,66,4,53,0,0,0,64,1,16,0,57,0,0,0,0,3,49,1,111],[0,0,0,0,1,35,0,25,0,0,0,0,3,49,0,75,0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57],[0,0,5,10,4,16,0,156,0,0,18,165,0,0,33,61,0,0,0,1,3,48,1,144,0,0,18,165,0,0,193,61],[0,0,0,64,0,16,4,63,0,0,5,2,1,0,0,65,0,0,5,2,3,144,0,156,0,0,0,0,9,1,128,25],[0,0,0,64,3,144,2,16,0,0,0,0,2,2,4,51,0,0,5,2,4,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,96,2,32,2,16,0,0,0,0,2,50,1,159,0,0,16,170,0,0,1,61,0,0,0,0,4,3,0,75],[0,0,19,233,0,0,97,61,0,0,0,0,4,0,0,25,0,0,0,0,5,36,0,25,0,0,0,0,6,20,0,25],[0,0,0,0,6,6,4,51,0,0,0,0,0,101,4,53,0,0,0,32,4,64,0,57,0,0,0,0,5,52,0,75],[0,0,19,226,0,0,65,61,0,0,0,0,1,35,0,25,0,0,0,0,0,1,4,53,0,0,0,0,0,1,4,45],[0,0,0,0,0,1,4,47,0,0,19,240,0,33,4,33,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45],[0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,19,245,0,33,4,35,0,0,0,1,2,0,0,57],[0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,19,250,0,33,4,33],[0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45],[0,0,19,255,0,33,4,35,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25],[0,0,0,0,0,1,4,45,0,0,20,1,0,0,4,50,0,0,20,2,0,1,4,46,0,0,20,3,0,1,4,48],[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],[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,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,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,0,0,0,0,0,223,156,21,136],[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,223,156,21,137],[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,226,243,24,227],[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,238,184,203,9],[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,32,43,204,231],[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,162,140,26,238],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255],[128,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,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[2,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],[114,97,116,111,114,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],[70,97,105,108,101,100,32,116,111,32,112,97,121,32,116,104,101,32,102,101,101,32,116,111,32,116,104,101,32,111,112,101],[8,195,121,160,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,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,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[255,255,255,255,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],[236,249,91,138,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],[156,77,83,91,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],[60,218,51,81,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],[93,56,39,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,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[1,0,0,1,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,1,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],[79,118,101,114,102,108,111,119,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,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,128,0,0,0,0,0,0,0,0],[148,148,49,220,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],[140,90,52,69,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],[85,110,115,117,112,112,111,114,116,101,100,32,112,97,121,109,97,115,116,101,114,32,102,108,111,119,0,0,0,0,0,0],[221,98,237,62,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,0,0,0,128,0,0,0,0,0,0,0,0],[9,94,167,179,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],[83,97,102,101,69,82,67,50,48,58,32,108,111,119,45,108,101,118,101,108,32,99,97,108,108,32,102,97,105,108,101,100],[24,6,170,24,150,187,242,101,104,232,132,167,55,75,65,224,2,80,9,98,202,186,106,21,2,58,141,144,232,80,139,131],[2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,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,68,0,0,0,0,0,0,0,0,0,0,0,0],[83,97,102,101,69,82,67,50,48,58,32,97,112,112,114,111,118,101,32,102,114,111,109,32,110,111,110,45,122,101,114,111],[32,116,111,32,110,111,110,45,122,101,114,111,32,97,108,108,111,119,97,110,99,101,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,0,0,255,255,255,255,255,255,255,127],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,63],[111,116,32,115,117,99,99,101,101,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[83,97,102,101,69,82,67,50,48,58,32,69,82,67,50,48,32,111,112,101,114,97,116,105,111,110,32,100,105,100,32,110],[65,100,100,114,101,115,115,58,32,99,97,108,108,32,116,111,32,110,111,110,45,99,111,110,116,114,97,99,116,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0],[84,104,101,32,97,112,112,114,111,118,97,108,66,97,115,101,100,32,112,97,121,109,97,115,116,101,114,32,105,110,112,117],[116,32,109,117,115,116,32,98,101,32,97,116,32,108,101,97,115,116,32,54,56,32,98,121,116,101,115,32,108,111,110,103],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[84,104,101,32,115,116,97,110,100,97,114,100,32,112,97,121,109,97,115,116,101,114,32,105,110,112,117,116,32,109,117,115],[116,32,98,101,32,97,116,32,108,101,97,115,116,32,52,32,98,121,116,101,115,32,108,111,110,103,0,0,0,0,0,0],[225,35,156,216,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],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,160,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,0,0,0,1,255,255,255,224],[69,110,99,111,100,105,110,103,32,117,110,115,117,112,112,111,114,116,101,100,32,116,120,0,0,0,0,0,0,0,0,0],[154,138,5,146,172,137,197,173,59,198,223,130,36,193,123,72,89,118,245,151,223,16,78,226,13,13,244,21,36,31,103,11],[2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,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,0,0,0,0,255,255,255,255,255,255,255,191],[0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[129,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],[148,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],[184,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],[192,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],[248,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],[1,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,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,1,0,0,0,0],[7,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[107,101,99,99,97,107,50,53,54,32,114,101,116,117,114,110,101,100,32,105,110,118,97,108,105,100,32,100,97,116,97,0],[132,142,27,250,26,196,227,87,107,114,139,218,103,33,178,21,199,10,119,153,165,180,134,98,130,167,27,171,149,75,170,200],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,254,31],[194,248,120,113,118,184,172,107,247,33,91,74,220,193,224,105,191,74,184,45,154,177,223,5,165,122,145,212,37,147,91,110],[173,124,91,239,2,120,22,168,0,218,23,54,68,79,181,138,128,126,244,201,96,59,120,72,103,63,126,58,104,235,20,165],[25,180,83,206,69,170,170,243,163,0,245,169,236,149,134,155,79,40,171,16,67,11,87,46,226,24,195,166,165,224,125,111],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,95],[25,1,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],[128,128,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],[156,199,247,8,175,198,89,68,130,155,212,135,185,11,114,83,107,25,81,134,79,191,193,78,18,95,201,114,166,80,127,57],[83,105,103,110,97,116,117,114,101,32,108,101,110,103,116,104,32,105,115,32,105,110,99,111,114,114,101,99,116,0,0,0],[127,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,93,87,110,115,87,164,80,29,223,233,47,70,104,27,32,161],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0],[32,43,204,231,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[73,110,118,97,108,105,100,32,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[118,32,105,115,32,110,101,105,116,104,101,114,32,50,55,32,110,111,114,32,50,56,0,0,0,0,0,0,0,0,0,0],[117,101,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],[78,111,116,32,101,110,111,117,103,104,32,98,97,108,97,110,99,101,32,102,111,114,32,102,101,101,32,43,32,118,97,108],[78,72,123,113,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[205,226,41,223,135,157,189,123,19,91,210,22,87,91,13,13,139,233,20,214,167,167,41,134,204,148,77,212,186,226,50,198]],"predeployed_contracts":{"0x0000000000000000000000000000000000000001":[[0,0,0,1,2,32,1,144,0,0,0,32,0,0,193,61,0,0,0,96,2,16,3,112,0,0,0,0,2,2,4,59],[0,0,0,12,5,32,0,65,0,0,0,64,3,16,3,112,0,0,0,0,3,3,4,59,0,0,0,12,6,48,0,65],[0,0,0,32,4,16,3,112,0,0,0,0,4,4,4,59,0,0,0,29,7,64,0,138,0,0,0,2,8,0,0,138],[0,0,0,0,7,135,0,75,0,0,0,30,0,0,65,61,0,0,0,13,6,96,0,156,0,0,0,30,0,0,65,61],[0,0,0,12,5,80,0,156,0,0,0,30,0,0,161,61,0,0,0,0,1,1,4,59,0,0,0,0,0,16,4,53],[0,0,0,27,1,64,0,138,0,0,0,32,0,16,4,63,0,0,0,64,0,48,4,63,0,0,0,96,0,32,4,63],[0,0,4,88,1,0,0,57,0,0,0,14,2,0,0,65,0,0,0,0,1,18,4,32,0,0,0,0,2,0,4,51],[0,0,0,0,1,18,1,112,0,0,0,37,0,0,193,61,0,0,0,0,1,0,0,25,0,0,0,40,0,1,4,46],[0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,0,11,1,0,0,65],[0,0,0,40,0,1,4,46,0,0,0,15,1,0,0,65,0,0,0,40,0,1,4,46,0,0,0,39,0,0,4,50],[0,0,0,40,0,1,4,46,0,0,0,41,0,1,4,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,69,81,35,25,80,183,95,196,64,45,161,115,47,201,190,191],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,69,81,35,25,80,183,95,196,64,45,161,115,47,201,190,192],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,4,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,32,0,0,0,0,0,0,0,0],[205,76,193,251,171,13,182,237,9,254,102,184,97,34,209,59,23,93,45,253,17,17,77,105,136,160,250,31,151,204,138,222]],"0x0000000000000000000000000000000000000006":[[0,4,0,0,0,0,0,2,0,0,0,1,2,32,1,144,0,0,0,17,0,0,193,61,0,0,0,96,2,16,3,112],[0,0,0,0,2,2,4,59,0,0,0,64,3,16,3,112,0,0,0,0,3,3,4,59,0,0,0,0,5,50,1,159],[0,0,0,0,20,1,4,60,0,0,0,0,1,1,4,59,0,0,0,0,6,65,1,159,0,0,0,0,7,101,1,160],[0,0,0,22,0,0,193,61,0,0,0,0,0,0,4,53,0,0,0,32,0,0,4,63,0,0,0,141,1,0,0,65],[0,0,2,8,0,1,4,46,0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67],[0,0,0,131,1,0,0,65,0,0,2,8,0,1,4,46,0,0,0,0,7,5,0,75,0,0,0,87,0,0,97,61],[0,0,0,0,7,6,0,75,0,0,0,87,0,0,193,61,0,0,0,132,1,48,0,156,0,0,0,30,0,0,33,61],[0,0,0,132,1,32,0,156,0,0,0,32,0,0,161,61,0,0,0,0,1,0,4,20,0,0,0,0,1,16,4,32],[0,0,0,0,1,3,0,75,0,0,0,133,65,48,0,209,0,0,0,1,4,64,192,57,0,0,0,134,81,48,0,209],[0,0,0,135,81,16,0,209,0,0,0,0,1,84,0,25,0,0,0,136,4,16,0,65,0,0,0,132,5,16,0,156],[0,0,0,0,4,1,160,25,0,0,0,0,81,68,0,170,0,0,0,1,5,80,192,57,0,0,0,137,97,16,0,209],[0,0,0,135,97,16,0,209,0,0,0,0,1,101,0,25,0,0,0,136,5,16,0,65,0,0,0,132,6,16,0,156],[0,0,0,0,5,1,160,25,0,0,0,0,65,69,0,170,0,0,0,1,4,64,192,57,0,0,0,0,5,2,0,75],[0,0,0,133,101,32,0,209,0,0,0,1,6,96,192,57,0,0,0,134,117,32,0,209,0,0,0,135,117,80,0,209],[0,0,0,0,5,118,0,25,0,0,0,136,6,80,0,65,0,0,0,132,7,80,0,156,0,0,0,0,6,5,160,25],[0,0,0,0,101,102,0,170,0,0,0,1,6,96,192,57,0,0,0,137,113,16,0,209,0,0,0,137,117,80,0,209],[0,0,0,135,113,16,0,209,0,0,0,0,1,116,0,25,0,0,0,135,84,80,0,209,0,0,0,0,4,86,0,25],[0,0,0,136,5,16,0,65,0,0,0,132,6,16,0,156,0,0,0,0,5,1,160,25,0,0,0,136,1,64,0,65],[0,0,0,132,6,64,0,156,0,0,0,0,1,4,160,25,0,0,0,138,4,0,0,65,0,0,0,139,6,0,0,65],[0,0,0,140,7,80,0,156,0,0,0,0,6,4,160,25,0,0,0,0,4,86,0,25,0,0,0,0,1,65,0,75],[0,0,0,83,0,0,97,61,0,0,0,0,1,0,4,20,0,0,0,0,1,16,4,32,0,0,0,0,0,48,4,53],[0,0,0,32,0,32,4,63,0,0,0,141,1,0,0,65,0,0,2,8,0,1,4,46,0,0,0,132,7,16,0,156],[0,0,0,0,7,0,0,25,0,0,0,1,7,0,32,57,0,0,0,132,8,64,0,156,0,0,0,1,7,112,33,191],[0,0,0,0,6,6,0,75,0,0,0,153,0,0,97,61,0,0,0,0,5,5,0,75,0,0,0,153,0,0,193,61],[0,0,0,1,2,112,1,144,0,0,0,100,0,0,97,61,0,0,0,0,2,0,4,20,0,0,0,0,2,32,4,32],[0,0,0,0,2,4,0,75,0,0,0,133,50,64,0,209,0,0,0,1,3,48,192,57,0,0,0,134,82,64,0,209],[0,0,0,135,82,32,0,209,0,0,0,0,2,83,0,25,0,0,0,136,3,32,0,65,0,0,0,132,5,32,0,156],[0,0,0,0,3,2,160,25,0,0,0,0,82,51,0,170,0,0,0,1,5,80,192,57,0,0,0,137,98,32,0,209],[0,0,0,135,98,32,0,209,0,0,0,0,2,101,0,25,0,0,0,136,5,32,0,65,0,0,0,132,6,32,0,156],[0,0,0,0,5,2,160,25,0,0,0,0,50,53,0,170,0,0,0,1,3,48,192,57,0,0,0,0,5,1,0,75],[0,0,0,133,101,16,0,209,0,0,0,1,6,96,192,57,0,0,0,134,117,16,0,209,0,0,0,135,117,80,0,209],[0,0,0,0,5,118,0,25,0,0,0,136,6,80,0,65,0,0,0,132,7,80,0,156,0,0,0,0,6,5,160,25],[0,0,0,0,101,102,0,170,0,0,0,1,6,96,192,57,0,0,0,137,114,32,0,209,0,0,0,137,117,80,0,209],[0,0,0,135,114,32,0,209,0,0,0,0,2,115,0,25,0,0,0,135,83,80,0,209,0,0,0,0,3,86,0,25],[0,0,0,136,5,32,0,65,0,0,0,132,6,32,0,156,0,0,0,0,5,2,160,25,0,0,0,136,2,48,0,65],[0,0,0,132,6,48,0,156,0,0,0,0,2,3,160,25,0,0,0,138,3,0,0,65,0,0,0,139,6,0,0,65],[0,0,0,140,7,80,0,156,0,0,0,0,6,3,160,25,0,0,0,0,3,86,0,25,0,0,0,0,2,50,0,75],[0,0,0,151,0,0,97,61,0,0,0,0,2,0,4,20,0,0,0,0,2,32,4,32,0,0,0,0,0,64,4,53],[0,0,1,193,0,0,1,61,0,0,0,1,5,112,1,144,0,0,0,157,0,0,97,61,0,0,0,0,5,0,4,20],[0,0,0,0,5,80,4,32,0,0,0,132,5,48,0,156,0,0,0,161,0,0,33,61,0,0,0,135,5,32,0,156],[0,0,0,163,0,0,65,61,0,0,0,0,5,0,4,20,0,0,0,0,5,80,4,32,0,0,0,135,5,0,0,65],[0,0,0,0,6,21,0,73,0,0,0,135,103,96,1,42,0,0,0,0,7,52,0,75,0,0,0,241,0,0,193,61],[0,0,0,0,6,38,0,75,0,0,0,241,0,0,193,61,0,0,0,0,3,4,0,75,0,0,0,133,83,64,0,209],[0,0,0,1,5,80,192,57,0,0,0,134,67,64,0,209,0,0,0,135,67,48,0,209,0,0,0,0,3,69,0,25],[0,0,0,136,4,48,0,65,0,0,0,132,5,48,0,156,0,0,0,0,4,3,160,25,0,0,0,0,83,68,0,170],[0,0,0,1,5,80,192,57,0,0,0,137,99,48,0,209,0,0,0,135,99,48,0,209,0,0,0,0,3,101,0,25],[0,0,0,136,5,48,0,65,0,0,0,132,6,48,0,156,0,0,0,0,5,3,160,25,0,0,0,0,52,69,0,170],[0,0,0,1,3,48,192,57,0,0,0,0,5,2,0,75,0,0,0,133,101,32,0,209,0,0,0,1,6,96,192,57],[0,0,0,134,82,32,0,209,0,0,0,135,82,32,0,209,0,0,0,0,2,86,0,25,0,0,0,136,5,32,0,65],[0,0,0,132,6,32,0,156,0,0,0,0,5,2,160,25,0,0,0,0,82,85,0,170,0,0,0,1,5,80,192,57],[0,0,0,0,6,1,0,75,0,0,0,133,118,16,0,209,0,0,0,1,7,112,192,57,0,0,0,134,97,16,0,209],[0,0,0,135,97,16,0,209,0,0,0,0,1,103,0,25,0,0,0,136,6,16,0,65,0,0,0,132,7,16,0,156],[0,0,0,0,6,1,160,25,0,0,0,0,97,102,0,170,0,0,0,1,6,96,192,57,0,0,0,137,116,64,0,209],[0,0,0,137,114,32,0,209,0,0,0,135,114,32,0,209,0,0,0,0,2,117,0,25,0,0,0,137,21,16,0,209],[0,0,0,135,65,64,0,209,0,0,0,0,1,67,0,25,0,0,0,136,3,16,0,65,0,0,0,132,4,16,0,156],[0,0,0,0,3,1,160,25,0,0,0,136,1,32,0,65,0,0,0,132,4,32,0,156,0,0,0,0,1,2,160,25],[0,0,0,135,66,80,0,209,0,0,0,0,2,70,0,25,0,0,0,136,4,32,0,65,0,0,0,132,5,32,0,156],[0,0,0,0,4,2,160,25,0,0,0,138,2,0,0,65,0,0,0,139,5,0,0,65,0,0,0,140,6,48,0,156],[0,0,0,0,5,2,160,25,0,0,0,0,2,53,0,25,0,0,0,0,3,36,0,75,0,0,0,238,0,0,193,61],[0,0,0,0,1,33,0,75,0,0,0,13,0,0,97,61,0,0,0,0,1,0,4,20,0,0,0,0,1,16,4,32],[0,0,0,13,0,0,1,61,0,0,0,0,5,37,0,73,0,0,0,135,86,80,1,42,0,0,0,0,6,52,0,75],[0,0,0,251,0,0,193,61,0,0,0,0,5,81,0,75,0,0,0,251,0,0,97,61,0,0,0,0,5,33,0,75],[0,0,0,251,0,0,97,61,0,0,0,0,5,0,4,20,0,0,0,0,5,80,4,32,0,0,0,0,5,4,0,75],[0,0,0,133,101,64,0,209,0,0,0,1,6,96,192,57,0,0,0,134,117,64,0,209,0,0,0,135,117,80,0,209],[0,0,0,0,5,118,0,25,0,0,0,136,12,80,0,65,0,0,0,132,6,80,0,156,0,0,0,0,12,5,160,25],[0,0,0,0,101,204,0,170,0,0,0,1,6,96,192,57,0,0,0,137,117,80,0,209,0,0,0,135,117,80,0,209],[0,0,0,0,5,118,0,25,0,0,0,136,6,80,0,65,0,0,0,132,7,80,0,156,0,0,0,0,6,5,160,25],[0,0,0,0,101,198,0,170,0,0,0,1,6,96,192,57,0,0,0,0,7,1,0,75,0,0,0,133,135,16,0,209],[0,0,0,1,8,128,192,57,0,0,0,134,151,16,0,209,0,0,0,135,151,112,0,209,0,0,0,0,7,152,0,25],[0,0,0,136,13,112,0,65,0,0,0,132,8,112,0,156,0,0,0,0,13,7,160,25,0,0,0,0,135,221,0,170],[0,0,0,1,8,128,192,57,0,0,0,137,149,80,0,209,0,0,0,137,151,112,0,209,0,0,0,135,149,80,0,209],[0,0,0,0,5,150,0,25,0,0,0,135,118,112,0,209,0,0,0,0,6,120,0,25,0,0,0,136,8,80,0,65],[0,0,0,132,7,80,0,156,0,0,0,0,8,5,160,25,0,0,0,136,5,96,0,65,0,0,0,132,7,96,0,156],[0,0,0,0,5,6,160,25,0,0,0,138,7,0,0,65,0,0,0,139,6,0,0,65,0,0,0,140,9,128,0,156],[0,0,0,0,9,7,0,25,0,0,0,0,9,6,32,25,0,0,0,0,8,137,0,25,0,0,0,0,4,52,0,75],[0,4,0,0,0,12,0,29,0,0,1,96,0,0,193,61,0,0,0,0,1,33,0,75,0,0,1,96,0,0,193,61],[0,3,0,0,0,13,0,29,0,0,0,0,1,133,0,75,0,0,1,53,0,0,97,61,0,0,0,0,1,0,4,20],[0,0,0,0,1,16,4,32,0,0,0,0,1,12,0,25,0,0,0,0,2,12,0,25,2,7,1,204,0,0,4,15],[0,0,0,135,33,16,1,42,0,0,0,1,1,32,2,16,0,0,0,135,49,16,1,42,0,0,0,0,1,35,0,25],[0,0,0,135,18,16,1,42,0,0,0,3,2,0,0,41,0,0,0,135,50,32,1,42,0,0,0,1,2,48,2,16],[0,0,0,135,35,32,1,42,2,7,1,213,0,0,4,15,0,2,0,0,0,1,0,29,0,0,0,0,2,1,0,25],[2,7,1,204,0,0,4,15,0,0,0,4,2,0,0,41,0,0,0,135,50,32,1,42,0,0,0,1,2,48,2,16],[0,0,0,135,66,32,1,42,0,0,0,135,5,0,0,65,0,0,0,0,2,69,0,73,0,0,0,135,66,32,1,42],[0,0,0,135,33,16,1,42,0,0,0,0,1,66,0,25,0,0,0,135,33,16,1,42,0,4,0,0,0,2,0,29],[0,0,0,0,1,37,0,73,0,0,0,135,33,16,1,42,0,0,0,0,1,50,0,25,0,0,0,135,33,16,1,42],[0,0,0,2,1,0,0,41,2,7,1,204,0,0,4,15,0,2,0,0,0,1,0,29,0,0,0,4,1,0,0,41],[2,7,1,196,0,0,4,15,0,0,0,135,3,0,0,65,0,0,0,3,2,48,0,106,0,0,0,135,50,32,1,42],[0,0,0,2,2,0,0,41,0,0,0,135,66,32,1,42,0,0,0,0,2,52,0,25,0,0,1,187,0,0,1,61],[0,0,0,0,1,3,0,75,0,0,0,133,65,48,0,209,0,0,0,1,4,64,192,57,0,0,0,134,49,48,0,209],[0,0,0,135,49,16,0,209,0,0,0,0,1,52,0,25,0,0,0,136,3,16,0,65,0,0,0,132,4,16,0,156],[0,0,0,0,3,1,160,25,0,0,0,0,65,51,0,170,0,0,0,1,4,64,192,57,0,0,0,137,145,16,0,209],[0,0,0,135,145,16,0,209,0,0,0,0,1,148,0,25,0,0,0,136,4,16,0,65,0,0,0,132,9,16,0,156],[0,0,0,0,4,1,160,25,0,0,0,0,148,52,0,170,0,0,0,1,9,144,192,57,0,0,0,0,1,2,0,75],[0,0,0,133,161,32,0,209,0,0,0,1,10,160,192,57,0,0,0,134,33,32,0,209,0,0,0,135,33,16,0,209],[0,0,0,0,2,42,0,25,0,0,0,136,1,32,0,65,0,0,0,132,10,32,0,156,0,0,0,0,1,2,160,25],[0,0,0,0,162,17,0,170,0,0,0,1,10,160,192,57,0,0,0,137,180,64,0,209,0,0,0,137,178,32,0,209],[0,0,0,135,180,64,0,209,0,0,0,0,4,185,0,25,0,0,0,135,146,32,0,209,0,0,0,0,9,154,0,25],[0,0,0,136,2,64,0,65,0,0,0,132,10,64,0,156,0,0,0,0,2,4,160,25,0,0,0,136,4,144,0,65],[0,0,0,132,10,144,0,156,0,0,0,0,4,9,160,25,0,0,0,140,9,32,0,156,0,0,0,0,6,7,160,25],[0,0,0,0,5,133,0,75,0,0,1,145,0,0,193,61,0,0,0,0,2,38,0,25,0,0,0,0,2,36,0,75],[0,0,1,147,0,0,97,61,0,0,0,0,2,0,4,20,0,0,0,0,2,32,4,32,0,0,0,135,5,0,0,65],[0,0,0,0,2,213,0,73,0,0,0,135,66,32,1,42,0,3,0,0,0,4,0,29,0,0,0,135,33,16,1,42],[0,0,0,0,1,66,0,25,0,0,0,135,18,16,1,42,0,0,0,0,2,197,0,73,0,0,0,135,66,32,1,42],[0,0,0,135,50,48,1,42,0,1,0,0,0,3,0,29,0,0,0,0,2,67,0,25,0,0,0,135,35,32,1,42],[2,7,1,213,0,0,4,15,0,2,0,0,0,1,0,29,0,0,0,0,2,1,0,25,2,7,1,204,0,0,4,15],[0,0,0,4,2,0,0,41,0,0,0,135,50,32,1,42,0,0,0,1,2,48,0,41,0,0,0,135,66,32,1,42],[0,0,0,135,5,0,0,65,0,0,0,0,2,69,0,73,0,0,0,135,66,32,1,42,0,0,0,135,33,16,1,42],[0,0,0,0,1,66,0,25,0,0,0,135,33,16,1,42,0,4,0,0,0,2,0,29,0,0,0,0,1,37,0,73],[0,0,0,135,33,16,1,42,0,0,0,0,1,50,0,25,0,0,0,135,33,16,1,42,0,0,0,2,1,0,0,41],[2,7,1,204,0,0,4,15,0,2,0,0,0,1,0,29,0,0,0,4,1,0,0,41,2,7,1,196,0,0,4,15],[0,0,0,2,2,0,0,41,0,0,0,135,50,32,1,42,0,0,0,3,2,48,0,41,0,0,0,135,35,32,1,42],[0,4,0,0,0,1,0,29,0,0,0,0,1,2,0,25,2,7,1,196,0,0,4,15,0,0,0,4,2,0,0,41],[0,0,0,0,0,32,4,53,0,0,0,32,0,16,4,63,0,0,0,141,1,0,0,65,0,0,2,8,0,1,4,46],[0,0,0,0,2,1,0,75,0,0,0,137,33,16,0,209,0,0,0,135,33,16,0,209,0,0,0,1,2,32,192,57],[0,0,0,136,1,32,0,65,0,0,0,132,3,32,0,156,0,0,0,0,1,2,160,25,0,0,0,0,0,1,4,45],[0,0,0,0,33,18,0,170,0,0,0,1,2,32,192,57,0,0,0,137,49,16,0,209,0,0,0,135,49,16,0,209],[0,0,0,0,2,50,0,25,0,0,0,136,1,32,0,65,0,0,0,132,3,32,0,156,0,0,0,0,1,2,160,25],[0,0,0,0,0,1,4,45,0,0,0,133,3,0,0,65,0,0,0,1,4,32,0,140,0,0,1,254,0,0,97,61],[0,0,0,135,4,0,0,65,0,0,0,133,3,0,0,65,0,0,0,0,5,0,0,25,0,0,0,1,6,32,1,144],[0,0,1,227,0,0,193,61,0,0,0,1,6,48,1,144,0,0,0,135,3,48,192,65,0,0,0,2,6,32,1,144],[0,0,0,1,2,32,2,112,0,0,0,1,3,48,2,112,0,0,1,221,0,0,97,61,0,0,0,1,6,64,1,144],[0,0,1,235,0,0,193,61,0,0,0,1,6,80,1,144,0,0,0,135,5,80,192,65,0,0,0,2,6,64,1,144],[0,0,0,1,4,64,2,112,0,0,0,1,5,80,2,112,0,0,1,229,0,0,97,61,0,0,0,0,6,36,0,75],[0,0,1,243,0,0,161,61,0,0,0,135,6,80,0,65,0,0,0,0,7,53,0,75,0,0,0,0,6,5,128,25],[0,0,0,0,5,54,0,73,0,0,0,0,4,36,0,73,0,0,1,248,0,0,1,61,0,0,0,135,6,48,0,65],[0,0,0,0,7,83,0,75,0,0,0,0,6,3,128,25,0,0,0,0,3,86,0,73,0,0,0,0,2,66,0,73],[0,0,0,1,6,32,0,140,0,0,1,252,0,0,97,61,0,0,0,1,6,64,0,140,0,0,1,219,0,0,193,61],[0,0,0,1,2,32,0,140,0,0,0,0,3,5,192,25,0,0,0,0,33,19,0,170,0,0,0,1,2,32,192,57],[0,0,0,137,49,16,0,209,0,0,0,135,49,16,0,209,0,0,0,0,2,50,0,25,0,0,0,136,1,32,0,65],[0,0,0,132,3,32,0,156,0,0,0,0,1,2,160,25,0,0,0,0,0,1,4,45,0,0,2,7,0,0,4,50],[0,0,2,8,0,1,4,46,0,0,2,9,0,1,4,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[48,100,78,114,225,49,160,41,184,80,69,182,129,129,88,93,151,129,106,145,104,113,202,141,60,32,140,22,216,124,253,70],[6,216,159,113,202,184,53,31,71,171,30,255,10,65,127,246,181,231,25,17,212,69,1,251,243,44,252,91,83,138,250,137],[74,71,70,38,35,160,74,122,176,116,165,134,128,115,1,58,233,101,225,118,124,212,192,134,243,174,216,161,155,249,14,81],[48,100,78,114,225,49,160,41,184,80,69,182,129,129,88,93,151,129,106,145,104,113,202,141,60,32,140,22,216,124,253,71],[207,155,177,141,30,206,95,214,71,175,186,73,126,126,167,162,104,126,149,110,151,142,53,114,195,223,115,233,39,131,2,185],[245,122,34,183,145,136,140,107,216,175,203,208,24,51,218,128,158,222,125,101,30,202,106,201,135,210,7,130,228,134,99,137],[42,31,103,68,206,23,157,142,51,75,234,78,105,107,210,132,31,106,193,122,225,85,33,185,122,23,202,169,80,173,40,215],[249,187,24,209,236,229,253,100,122,251,164,151,231,234,122,38,135,233,86,233,120,227,87,44,61,247,62,146,120,48,43,144],[6,68,231,46,19,26,2,155,133,4,91,104,24,21,133,217,120,22,169,22,135,28,168,211,194,8,193,109,135,207,212,111],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0],[7,155,177,253,3,237,92,151,14,41,125,66,188,24,151,228,93,136,135,3,202,158,108,195,48,138,79,213,56,163,134,170]],"0x000000000000000000000000000000000000800d":[[0,5,0,0,0,0,0,2,0,0,0,0,0,4,0,31,0,1,0,0,0,5,0,31,0,2,0,0,0,6,0,31],[0,3,0,0,0,7,0,31,0,4,0,0,0,1,3,85,0,0,0,96,1,16,2,112,0,0,0,20,1,16,1,151],[0,0,0,1,4,32,1,144,0,0,0,69,0,0,193,61,0,0,0,2,2,32,1,144,0,0,0,67,0,0,97,61],[0,0,0,5,2,48,0,140,0,0,0,67,0,0,129,61,0,0,0,32,2,16,2,16,0,0,0,0,2,35,0,25],[0,0,0,1,2,32,0,57,0,0,0,0,4,0,4,17,0,0,0,0,0,66,4,31,0,0,0,1,2,48,0,140],[0,0,0,33,0,0,161,61,0,0,0,2,2,48,0,140,0,0,0,41,0,0,97,61,0,0,0,3,2,48,0,140],[0,0,0,46,0,0,97,61,0,0,0,4,2,48,0,140,0,0,0,67,0,0,193,61,0,0,0,1,2,0,0,49],[0,0,0,0,3,0,0,49,0,0,0,0,0,35,4,30,0,0,0,3,2,0,0,49,0,0,0,2,3,0,0,49],[0,0,0,43,0,0,1,61,0,0,0,0,2,3,0,75,0,0,0,54,0,0,97,61,0,0,0,1,2,48,0,140],[0,0,0,67,0,0,193,61,0,0,0,4,2,0,3,103,0,0,0,0,2,2,4,59,0,0,0,0,3,0,0,49],[0,0,0,52,0,0,1,61,0,0,0,1,2,0,0,49,0,0,0,0,3,0,0,49,0,0,0,0,0,35,4,30],[0,0,0,0,3,0,0,25,0,0,0,54,0,0,1,61,0,0,0,1,2,0,0,49,0,0,0,0,3,0,0,49],[0,0,0,0,0,35,4,30,0,0,0,4,2,0,3,103,0,0,0,0,2,2,4,59,0,0,0,2,3,0,0,49],[0,0,0,0,0,35,4,30,0,0,0,32,3,0,0,57,0,0,0,0,2,19,0,75,0,0,0,65,0,0,129,61],[0,0,0,32,2,48,0,57,0,0,0,4,2,32,3,103,0,0,0,4,4,48,3,103,0,0,0,0,4,4,4,59],[0,0,0,0,2,2,4,59,0,0,0,0,0,36,4,30,0,0,0,64,3,48,0,57,0,0,0,0,2,19,0,75],[0,0,0,56,0,0,65,61,0,0,0,0,1,0,0,25,0,0,0,0,0,1,4,45,0,0,0,0,1,0,0,25],[0,0,0,76,0,1,4,48,0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67],[0,0,0,21,1,0,0,65,0,0,0,75,0,1,4,46,0,0,0,74,0,0,4,50,0,0,0,75,0,1,4,46],[0,0,0,76,0,1,4,48,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[180,184,165,48,127,13,205,253,29,139,217,234,142,173,226,137,254,133,108,230,229,7,36,30,205,42,49,201,117,98,142,148]],"0x000000000000000000000000000000000000800a":[[0,5,0,0,0,0,0,2,0,0,0,128,3,0,0,57,0,0,0,64,0,48,4,63,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,0,215,3,48,1,151,0,0,0,1,2,32,1,144,0,0,0,36,0,0,193,61],[0,0,0,4,2,48,0,140,0,0,3,10,0,0,65,61,0,0,0,0,2,1,4,59,0,0,0,224,2,32,2,112],[0,0,0,217,4,32,0,156,0,0,0,44,0,0,161,61,0,0,0,218,4,32,0,156,0,0,0,56,0,0,161,61],[0,0,0,219,4,32,0,156,0,0,0,149,0,0,97,61,0,0,0,220,4,32,0,156,0,0,1,234,0,0,97,61],[0,0,0,221,2,32,0,156,0,0,3,10,0,0,193,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75],[0,0,3,10,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140,0,0,3,10,0,0,65,61],[0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59,0,0,0,229,1,16,1,151,0,0,0,0,0,16,4,53],[0,0,0,32,0,0,4,63,0,0,0,0,1,0,0,25,3,88,3,60,0,0,4,15,0,0,0,54,0,0,1,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,10,0,0,193,61,0,0,0,32,1,0,0,57],[0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,0,216,1,0,0,65,0,0,3,89,0,1,4,46],[0,0,0,224,4,32,0,156,0,0,0,96,0,0,33,61,0,0,0,227,1,32,0,156,0,0,1,166,0,0,97,61],[0,0,0,228,1,32,0,156,0,0,3,10,0,0,193,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,3,10,0,0,193,61,0,0,0,1,1,0,0,57,0,0,0,0,1,1,4,26,0,0,1,231,0,0,1,61],[0,0,0,222,4,32,0,156,0,0,1,175,0,0,97,61,0,0,0,223,2,32,0,156,0,0,3,10,0,0,193,61],[0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,3,10,0,0,193,61,0,0,0,4,2,48,0,138],[0,0,0,96,2,32,0,140,0,0,3,10,0,0,65,61,0,0,0,4,2,16,3,112,0,0,0,0,4,2,4,59],[0,0,0,229,2,64,0,156,0,0,3,10,0,0,33,61,0,0,0,36,2,16,3,112,0,0,0,0,2,2,4,59],[0,0,0,229,5,32,1,151,0,0,0,229,2,32,0,156,0,0,3,10,0,0,33,61,0,0,0,0,2,0,4,17],[0,0,0,68,1,16,3,112,0,0,0,0,3,1,4,59,0,0,128,6,1,32,0,140,0,0,2,9,0,0,97,61],[0,0,0,9,1,0,0,138,0,0,0,0,1,18,1,111,0,0,128,1,1,16,0,140,0,0,2,9,0,0,97,61],[0,0,0,240,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63],[0,0,0,62,1,0,0,57,0,0,0,164,0,16,4,63,0,0,0,241,1,0,0,65,0,0,0,196,0,16,4,63],[0,0,0,242,1,0,0,65,0,0,0,228,0,16,4,63,0,0,0,243,1,0,0,65,0,0,3,90,0,1,4,48],[0,0,0,225,4,32,0,156,0,0,1,227,0,0,97,61,0,0,0,226,2,32,0,156,0,0,3,10,0,0,193,61],[0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,3,10,0,0,193,61,0,0,0,4,2,48,0,138],[0,0,0,64,2,32,0,140,0,0,3,10,0,0,65,61,0,0,0,4,2,16,3,112,0,0,0,0,4,2,4,59],[0,0,0,229,2,64,0,156,0,0,3,10,0,0,33,61,0,0,0,36,1,16,3,112,0,0,0,0,5,1,4,59],[0,0,0,0,1,0,4,17,0,0,128,1,1,16,0,140,0,0,1,255,0,0,193,61,0,0,0,1,1,0,0,57],[0,0,0,0,3,1,4,26,0,0,0,0,2,83,0,25,0,0,0,0,3,50,0,75,0,0,0,0,3,0,0,25],[0,0,0,1,3,0,64,57,0,0,0,1,3,48,1,144,0,0,0,145,0,0,193,61,0,4,0,0,0,5,0,29],[0,0,0,0,0,33,4,27,0,0,0,0,0,64,4,53,0,0,0,32,0,0,4,63,0,0,0,215,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,0,215,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,0,235,1,16,1,199,0,0,128,16,2,0,0,57,0,5,0,0,0,4,0,29,3,88,3,83,0,0,4,15],[0,0,0,5,5,0,0,41,0,0,0,1,2,32,1,144,0,0,3,10,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,2,1,4,26,0,0,0,4,3,0,0,41,0,0,0,0,2,50,0,26,0,0,0,145,0,0,65,61],[0,0,2,194,0,0,1,61,0,0,0,250,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57],[0,0,1,224,0,0,1,61,0,0,0,4,2,48,0,138,0,0,0,64,2,32,0,140,0,0,3,10,0,0,65,61],[0,0,0,4,2,16,3,112,0,0,0,0,8,2,4,59,0,0,0,229,2,128,0,156,0,0,3,10,0,0,33,61],[0,0,0,36,2,16,3,112,0,0,0,0,4,2,4,59,0,0,0,233,2,64,0,156,0,0,3,10,0,0,33,61],[0,0,0,35,2,64,0,57,0,0,0,234,5,0,0,65,0,0,0,0,6,50,0,75,0,0,0,0,6,0,0,25],[0,0,0,0,6,5,128,25,0,0,0,234,2,32,1,151,0,0,0,0,7,2,0,75,0,0,0,0,5,0,128,25],[0,0,0,234,2,32,0,156,0,0,0,0,5,6,192,25,0,0,0,0,2,5,0,75,0,0,3,10,0,0,193,61],[0,0,0,4,5,64,0,57,0,0,0,0,2,81,3,79,0,0,0,0,2,2,4,59,0,0,0,233,6,32,0,156],[0,0,1,221,0,0,33,61,0,0,0,191,6,32,0,57,0,0,0,32,9,0,0,138,0,0,0,0,6,150,1,111],[0,0,0,233,7,96,0,156,0,0,1,221,0,0,33,61,0,0,0,64,0,96,4,63,0,0,0,128,0,32,4,63],[0,0,0,0,4,36,0,25,0,0,0,36,4,64,0,57,0,0,0,0,3,52,0,75,0,0,3,10,0,0,33,61],[0,0,0,32,3,80,0,57,0,0,0,0,1,49,3,79,0,0,0,31,3,32,1,143,0,0,0,5,4,32,2,114],[0,0,0,202,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,7,7,4,59,0,0,0,160,6,96,0,57,0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57],[0,0,0,0,6,69,0,75,0,0,0,194,0,0,65,61,0,4,0,0,0,9,0,29,0,5,0,0,0,8,0,29],[0,0,0,0,5,3,0,75,0,0,0,219,0,0,97,61,0,0,0,5,4,64,2,16,0,0,0,0,1,65,3,79],[0,0,0,3,3,48,2,16,0,0,0,160,4,64,0,57,0,0,0,0,5,4,4,51,0,0,0,0,5,53,1,207],[0,0,0,0,5,53,2,47,0,0,0,0,1,1,4,59,0,0,1,0,3,48,0,137,0,0,0,0,1,49,2,47],[0,0,0,0,1,49,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,20,4,53,0,0,0,160,1,32,0,57],[0,0,0,0,0,1,4,53,0,0,0,0,1,0,4,22,0,3,0,0,0,1,0,29,0,0,0,0,1,0,4,16],[0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,0,215,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,0,215,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,0,235,1,16,1,199],[0,0,128,16,2,0,0,57,3,88,3,83,0,0,4,15,0,0,0,1,2,32,1,144,0,0,0,5,4,0,0,41],[0,0,0,4,7,0,0,41,0,0,3,10,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,2,1,4,26],[0,0,0,3,9,0,0,41,0,0,0,0,2,146,0,73,0,0,0,0,0,33,4,27,0,0,0,1,1,0,0,57],[0,0,0,0,2,1,4,26,0,0,0,0,2,146,0,73,0,0,0,0,0,33,4,27,0,0,0,236,2,0,0,65],[0,0,0,64,1,0,4,61,0,0,0,32,3,16,0,57,0,0,0,0,0,35,4,53,0,0,0,96,2,64,2,16],[0,0,0,36,3,16,0,57,0,0,0,0,0,35,4,53,0,0,0,0,8,0,4,17,0,0,0,96,2,128,2,16],[0,0,0,88,3,16,0,57,0,0,0,0,0,35,4,53,0,0,0,56,2,16,0,57,0,0,0,0,0,146,4,53],[0,0,0,108,3,16,0,57,0,0,0,128,2,0,4,61,0,0,0,0,4,2,0,75,0,0,1,16,0,0,97,61],[0,0,0,0,4,0,0,25,0,0,0,0,5,52,0,25,0,0,0,160,6,64,0,57,0,0,0,0,6,6,4,51],[0,0,0,0,0,101,4,53,0,0,0,32,4,64,0,57,0,0,0,0,5,36,0,75,0,0,1,9,0,0,65,61],[0,0,0,0,3,50,0,25,0,0,0,0,0,3,4,53,0,0,0,76,3,32,0,57,0,0,0,0,0,49,4,53],[0,0,0,139,2,32,0,57,0,0,0,0,2,114,1,111,0,0,0,0,10,18,0,25,0,0,0,0,2,42,0,75],[0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,0,233,3,160,0,156,0,0,1,221,0,0,33,61],[0,0,0,1,2,32,1,144,0,0,1,221,0,0,193,61,0,1,0,0,0,8,0,29,0,0,0,64,0,160,4,63],[0,0,0,237,2,0,0,65,0,0,0,0,0,42,4,53,0,0,0,4,2,160,0,57,0,0,0,32,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,0,0,2,1,4,51,0,0,0,36,3,160,0,57,0,0,0,0,0,35,4,53],[0,0,0,68,3,160,0,57,0,0,0,0,4,2,0,75,0,0,1,51,0,0,97,61,0,0,0,0,4,0,0,25],[0,0,0,0,5,52,0,25,0,0,0,32,4,64,0,57,0,0,0,0,6,20,0,25,0,0,0,0,6,6,4,51],[0,0,0,0,0,101,4,53,0,0,0,0,5,36,0,75,0,0,1,44,0,0,65,61,0,0,0,0,1,50,0,25],[0,0,0,0,0,1,4,53,0,0,0,31,1,32,0,57,0,0,0,0,1,113,1,111,0,0,0,215,2,0,0,65],[0,0,0,215,3,160,0,156,0,0,0,0,3,2,0,25,0,0,0,0,3,10,64,25,0,0,0,64,3,48,2,16],[0,0,0,68,1,16,0,57,0,0,0,215,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,96,1,16,2,16],[0,0,0,0,1,49,1,159,0,0,0,0,3,0,4,20,0,0,0,215,4,48,0,156,0,0,0,0,3,2,128,25],[0,0,0,192,2,48,2,16,0,0,0,0,1,18,1,159,0,0,128,8,2,0,0,57,0,2,0,0,0,10,0,29],[3,88,3,78,0,0,4,15,0,0,0,2,10,0,0,41,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,215,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57],[0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114,0,0,1,92,0,0,97,61,0,0,0,0,7,0,0,25],[0,0,0,5,8,112,2,16,0,0,0,0,9,138,0,25,0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59],[0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,1,84,0,0,65,61],[0,0,0,0,7,5,0,75,0,0,1,107,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,6,106,0,25,0,0,0,3,5,80,2,16,0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207],[0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144],[0,0,3,12,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,2,16,1,143,0,0,0,0,1,162,0,25],[0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,0,233,4,16,0,156],[0,0,0,5,4,0,0,41,0,0,0,3,5,0,0,41,0,0,1,221,0,0,33,61,0,0,0,1,2,32,1,144],[0,0,1,221,0,0,193,61,0,0,0,64,0,16,4,63,0,0,0,32,2,48,0,140,0,0,3,10,0,0,65,61],[0,0,0,32,2,16,0,57,0,0,0,64,3,0,0,57,0,0,0,0,0,50,4,53,0,0,0,0,0,81,4,53],[0,0,0,64,3,16,0,57,0,0,0,128,2,0,4,61,0,0,0,0,0,35,4,53,0,0,0,96,3,16,0,57],[0,0,0,229,6,64,1,151,0,0,0,0,4,2,0,75,0,0,1,143,0,0,97,61,0,0,0,0,4,0,0,25],[0,0,0,0,5,52,0,25,0,0,0,160,7,64,0,57,0,0,0,0,7,7,4,51,0,0,0,0,0,117,4,53],[0,0,0,32,4,64,0,57,0,0,0,0,5,36,0,75,0,0,1,136,0,0,65,61,0,0,0,0,3,50,0,25],[0,0,0,0,0,3,4,53,0,0,0,127,2,32,0,57,0,0,0,4,2,32,1,127,0,0,0,215,3,0,0,65],[0,0,0,215,4,16,0,156,0,0,0,0,1,3,128,25,0,0,0,64,1,16,2,16,0,0,0,215,4,32,0,156],[0,0,0,0,2,3,128,25,0,0,0,96,2,32,2,16,0,0,0,0,1,18,1,159,0,0,0,0,2,0,4,20],[0,0,0,215,4,32,0,156,0,0,0,0,2,3,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,0,238,1,16,1,199,0,0,128,13,2,0,0,57,0,0,0,3,3,0,0,57,0,0,0,239,4,0,0,65],[0,0,0,1,5,0,0,41,0,0,3,5,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,3,10,0,0,193,61,0,0,0,192,1,0,0,57,0,0,0,64,0,16,4,63,0,0,0,5,1,0,0,57],[0,0,0,128,0,16,4,63,0,0,0,255,1,0,0,65,0,0,1,242,0,0,1,61,0,0,0,4,2,48,0,138],[0,0,0,32,2,32,0,140,0,0,3,10,0,0,65,61,0,0,0,4,1,16,3,112,0,0,0,0,4,1,4,59],[0,0,0,229,1,64,0,156,0,0,3,10,0,0,33,61,0,0,0,0,1,0,4,22,0,4,0,0,0,1,0,29],[0,0,0,0,1,0,4,16,0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,0,215,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,0,215,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,0,235,1,16,1,199,0,0,128,16,2,0,0,57,0,5,0,0,0,4,0,29,3,88,3,83,0,0,4,15],[0,0,0,5,4,0,0,41,0,0,0,1,2,32,1,144,0,0,3,10,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,2,1,4,26,0,0,0,4,5,0,0,41,0,0,0,0,2,82,0,73,0,0,0,0,0,33,4,27],[0,0,0,1,1,0,0,57,0,0,0,0,2,1,4,26,0,0,0,0,2,82,0,73,0,0,0,0,0,33,4,27],[0,0,0,236,2,0,0,65,0,0,0,64,1,0,4,61,0,0,0,32,3,16,0,57,0,0,0,0,0,35,4,53],[0,0,0,96,2,64,2,16,0,0,0,36,3,16,0,57,0,0,0,0,0,35,4,53,0,0,0,56,2,16,0,57],[0,0,0,0,0,82,4,53,0,0,0,56,2,0,0,57,0,0,0,0,0,33,4,53,0,0,0,248,2,16,0,156],[0,0,2,47,0,0,65,61,0,0,0,250,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,0,251,1,0,0,65,0,0,3,90,0,1,4,48,0,0,0,0,1,0,4,22],[0,0,0,0,1,1,0,75,0,0,3,10,0,0,193,61,0,0,0,18,1,0,0,57,0,0,0,128,0,16,4,63],[0,0,0,230,1,0,0,65,0,0,3,89,0,1,4,46,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,3,10,0,0,193,61,0,0,0,192,1,0,0,57,0,0,0,64,0,16,4,63,0,0,0,3,1,0,0,57],[0,0,0,128,0,16,4,63,0,0,0,231,1,0,0,65,0,0,0,160,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,192,0,16,4,63,0,0,0,128,1,0,0,57,0,0,0,224,2,0,0,57,3,88,3,41,0,0,4,15],[0,0,0,192,1,16,0,138,0,0,0,215,2,0,0,65,0,0,0,215,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,96,1,16,2,16,0,0,0,232,1,16,1,199,0,0,3,89,0,1,4,46,0,0,0,240,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,31,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,0,252,1,0,0,65,0,0,0,196,0,16,4,63,0,0,0,253,1,0,0,65],[0,0,3,90,0,1,4,48,0,4,0,0,0,3,0,29,0,0,0,0,0,64,4,53,0,0,0,32,0,0,4,63],[0,0,0,215,1,0,0,65,0,0,0,0,2,0,4,20,0,0,0,215,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,0,235,1,16,1,199,0,0,128,16,2,0,0,57,0,5,0,0,0,4,0,29],[0,3,0,0,0,5,0,29,3,88,3,83,0,0,4,15,0,0,0,5,3,0,0,41,0,0,0,1,2,32,1,144],[0,0,3,10,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,2,1,4,26,0,0,0,4,1,32,0,108],[0,0,2,211,0,0,129,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,0,246,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,31,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,0,240,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,0,215,2,0,0,65,0,0,0,215,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,64,1,16,2,16,0,0,0,247,1,16,1,199,0,0,3,90,0,1,4,48,0,0,0,96,7,16,0,57],[0,0,0,64,0,112,4,63,0,0,0,237,2,0,0,65,0,0,0,0,0,39,4,53,0,0,0,100,2,16,0,57],[0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53,0,0,0,132,3,16,0,57,0,0,0,0,2,1,4,51],[0,0,0,0,0,35,4,53,0,0,0,164,3,16,0,57,0,0,0,0,4,2,0,75,0,0,2,68,0,0,97,61],[0,0,0,0,4,0,0,25,0,0,0,0,5,52,0,25,0,0,0,32,4,64,0,57,0,0,0,0,6,20,0,25],[0,0,0,0,6,6,4,51,0,0,0,0,0,101,4,53,0,0,0,0,5,36,0,75,0,0,2,61,0,0,65,61],[0,0,0,0,1,50,0,25,0,0,0,0,0,1,4,53,0,0,0,31,1,32,0,57,0,0,0,32,2,0,0,138],[0,0,0,0,1,33,1,111,0,0,0,215,2,0,0,65,0,0,0,215,3,112,0,156,0,0,0,0,3,2,0,25],[0,0,0,0,3,7,64,25,0,0,0,64,3,48,2,16,0,0,0,68,1,16,0,57,0,0,0,215,4,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,49,1,159,0,0,0,0,3,0,4,20],[0,0,0,215,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16,0,0,0,0,1,18,1,159],[0,0,128,8,2,0,0,57,0,3,0,0,0,7,0,29,3,88,3,78,0,0,4,15,0,0,0,3,10,0,0,41],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,215,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114],[0,0,2,110,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,138,0,25],[0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,103,0,75,0,0,2,102,0,0,65,61,0,0,0,0,7,5,0,75,0,0,2,125,0,0,97,61],[0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,0,6,106,0,25,0,0,0,3,5,80,2,16],[0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159],[0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144,0,0,2,159,0,0,97,61,0,0,0,31,1,64,0,57],[0,0,0,96,2,16,1,143,0,0,0,0,1,162,0,25,0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25],[0,0,0,1,2,0,64,57,0,0,0,233,4,16,0,156,0,0,0,5,5,0,0,41,0,0,0,4,4,0,0,41],[0,0,1,221,0,0,33,61,0,0,0,1,2,32,1,144,0,0,1,221,0,0,193,61,0,0,0,64,0,16,4,63],[0,0,0,32,2,48,0,140,0,0,3,10,0,0,65,61,0,0,0,0,0,65,4,53,0,0,0,215,2,0,0,65],[0,0,0,0,3,0,4,20,0,0,0,215,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,215,4,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,0,192,2,48,2,16,0,0,0,0,1,18,1,159],[0,0,0,244,1,16,1,199,0,0,0,229,6,80,1,151,0,0,128,13,2,0,0,57,0,0,0,3,3,0,0,57],[0,0,0,0,5,0,4,17,0,0,0,249,4,0,0,65,0,0,3,5,0,0,1,61,0,0,0,64,2,0,4,61],[0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,2,172,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,2,164,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,2,187,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,0,215,1,0,0,65],[0,0,0,215,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,0,96,2,48,2,16],[0,0,0,0,1,33,1,159,0,0,3,90,0,1,4,48,0,0,0,0,0,33,4,27,0,0,0,64,1,0,4,61],[0,0,0,0,0,49,4,53,0,0,0,215,2,0,0,65,0,0,0,0,3,0,4,20,0,0,0,215,4,48,0,156],[0,0,0,0,3,2,128,25,0,0,0,215,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16],[0,0,0,192,2,48,2,16,0,0,0,0,1,18,1,159,0,0,0,244,1,16,1,199,0,0,128,13,2,0,0,57],[0,0,0,2,3,0,0,57,0,0,0,254,4,0,0,65,0,0,3,5,0,0,1,61,0,2,0,0,0,2,0,29],[0,0,0,0,0,48,4,53,0,0,0,32,0,0,4,63,0,0,0,215,3,0,0,65,0,0,0,0,1,0,4,20],[0,0,0,215,2,16,0,156,0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,0,235,1,16,1,199],[0,0,128,16,2,0,0,57,3,88,3,83,0,0,4,15,0,0,0,3,3,0,0,41,0,0,0,1,2,32,1,144],[0,0,3,10,0,0,97,61,0,0,0,2,4,0,0,41,0,0,0,4,2,64,0,106,0,0,0,0,1,1,4,59],[0,0,0,0,0,33,4,27,0,0,0,0,0,48,4,53,0,0,0,0,1,0,4,20,0,0,0,215,2,16,0,156],[0,0,0,215,1,0,128,65,0,0,0,192,1,16,2,16,0,0,0,235,1,16,1,199,0,0,128,16,2,0,0,57],[3,88,3,83,0,0,4,15,0,0,0,3,6,0,0,41,0,0,0,5,5,0,0,41,0,0,0,1,2,32,1,144],[0,0,3,10,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,2,1,4,26,0,0,0,4,3,0,0,41],[0,0,0,0,2,50,0,25,0,0,0,0,0,33,4,27,0,0,0,64,1,0,4,61,0,0,0,0,0,49,4,53],[0,0,0,215,2,0,0,65,0,0,0,0,3,0,4,20,0,0,0,215,4,48,0,156,0,0,0,0,3,2,128,25],[0,0,0,215,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,0,192,2,48,2,16],[0,0,0,0,1,18,1,159,0,0,0,244,1,16,1,199,0,0,128,13,2,0,0,57,0,0,0,3,3,0,0,57],[0,0,0,245,4,0,0,65,3,88,3,78,0,0,4,15,0,0,0,1,1,32,1,144,0,0,3,10,0,0,97,61],[0,0,0,0,1,0,0,25,0,0,3,89,0,1,4,46,0,0,0,0,1,0,0,25,0,0,3,90,0,1,4,48],[0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,3,25,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,3,17,0,0,65,61,0,0,0,0,6,4,0,75,0,0,3,40,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,2,187,0,0,1,61,0,0,0,0,3,1,4,51,0,0,0,0,2,50,4,54,0,0,0,0,4,3,0,75],[0,0,3,53,0,0,97,61,0,0,0,0,4,0,0,25,0,0,0,0,5,36,0,25,0,0,0,32,4,64,0,57],[0,0,0,0,6,20,0,25,0,0,0,0,6,6,4,51,0,0,0,0,0,101,4,53,0,0,0,0,5,52,0,75],[0,0,3,46,0,0,65,61,0,0,0,0,1,35,0,25,0,0,0,0,0,1,4,53,0,0,0,31,1,48,0,57],[0,0,0,32,3,0,0,138,0,0,0,0,1,49,1,111,0,0,0,0,1,18,0,25,0,0,0,0,0,1,4,45],[0,0,0,215,2,0,0,65,0,0,0,215,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,0,3,0,4,20],[0,0,0,215,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16,0,0,0,64,1,16,2,16],[0,0,0,0,1,33,1,159,0,0,0,235,1,16,1,199,0,0,128,16,2,0,0,57,3,88,3,83,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,3,76,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,0,1,4,45],[0,0,0,0,1,0,0,25,0,0,3,90,0,1,4,48,0,0,3,81,0,33,4,33,0,0,0,1,2,0,0,57],[0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,3,86,0,33,4,35],[0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45],[0,0,3,88,0,0,4,50,0,0,3,89,0,1,4,46,0,0,3,90,0,1,4,48,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,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,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,0,0,0,0,0,81,207,248,216],[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,132,188,62,175],[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,132,188,62,176],[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,149,216,155,65],[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,156,199,247,8],[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,81,207,248,217],[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,87,153,82,252],[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,49,60,229,102],[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,49,60,229,103],[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,64,193,15,25],[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,6,253,222,3],[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,24,22,13,221],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,128,0,0,0,0,0,0,0,0],[69,84,72,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,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,255,255,255,255,255,255,255,255],[128,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],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0],[108,9,96,249,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],[98,248,75,36,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],[2,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],[196,5,254,137,88,65,11,186,240,199,59,122,12,62,32,133,158,134,202,22,138,76,155,13,239,156,84,210,85,90,48,107],[8,195,121,160,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],[79,110,108,121,32,115,121,115,116,101,109,32,99,111,110,116,114,97,99,116,115,32,119,105,116,104,32,115,112,101,99,105],[97,108,32,97,99,99,101,115,115,32,99,97,110,32,99,97,108,108,32,116,104,105,115,32,109,101,116,104,111,100,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[221,242,82,173,27,226,200,155,105,194,176,104,252,55,141,170,149,43,167,241,99,196,161,22,40,245,90,77,245,35,179,239],[84,114,97,110,115,102,101,114,32,97,109,111,117,110,116,32,101,120,99,101,101,100,115,32,98,97,108,97,110,99,101,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,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,0,0,0,0,255,255,255,255,255,255,255,160],[39,23,234,214,185,32,13,210,53,170,212,104,201,128,158,164,0,254,51,172,105,181,191,170,109,62,144,252,146,43,99,152],[78,72,123,113,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[67,97,108,108,97,98,108,101,32,111,110,108,121,32,98,121,32,116,104,101,32,98,111,111,116,108,111,97,100,101,114,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,128,0,0,0,0,0,0,0,0],[15,103,152,165,96,121,58,84,195,188,254,134,169,60,222,30,115,8,125,148,76,14,162,5,68,19,125,65,33,57,104,133],[69,116,104,101,114,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],[138,45,232,35,156,84,136,62,74,211,18,128,185,183,6,203,181,237,138,115,51,209,123,80,172,154,86,215,37,44,38,96]],"0x0000000000000000000000000000000000008004":[[0,1,0,0,0,0,0,2,0,8,0,0,0,0,0,2,0,0,0,0,0,1,3,85,0,0,0,128,3,0,0,57],[0,0,0,64,0,48,4,63,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,95,3,48,1,151],[0,0,0,1,2,32,1,144,0,0,0,32,0,0,193,61,0,0,0,4,2,48,0,140,0,0,1,24,0,0,65,61],[0,0,0,0,2,1,4,59,0,0,0,224,2,32,2,112,0,0,0,97,4,32,0,156,0,0,0,40,0,0,97,61],[0,0,0,98,4,32,0,156,0,0,0,127,0,0,97,61,0,0,0,99,2,32,0,156,0,0,1,24,0,0,193,61],[0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,1,24,0,0,193,61,0,0,0,4,2,48,0,138],[0,0,0,32,2,32,0,140,0,0,1,24,0,0,65,61,0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59],[0,0,0,0,1,1,4,26,0,0,0,128,0,16,4,63,0,0,0,123,1,0,0,65,0,0,1,121,0,1,4,46],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,1,24,0,0,193,61,0,0,0,32,1,0,0,57],[0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,0,96,1,0,0,65,0,0,1,121,0,1,4,46],[0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,1,24,0,0,193,61,0,0,0,4,2,48,0,138],[0,0,0,64,2,32,0,140,0,0,1,24,0,0,65,61,0,0,0,4,2,16,3,112,0,0,0,0,4,2,4,59],[0,0,0,0,2,4,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,192,57,0,2,0,0,0,4,0,29],[0,0,0,0,2,36,0,75,0,0,1,24,0,0,193,61,0,0,0,36,2,16,3,112,0,0,0,0,2,2,4,59],[0,0,0,100,4,32,0,156,0,0,1,24,0,0,33,61,0,0,0,35,4,32,0,57,0,0,0,101,5,0,0,65],[0,0,0,0,6,52,0,75,0,0,0,0,6,0,0,25,0,0,0,0,6,5,128,25,0,0,0,101,4,64,1,151],[0,0,0,0,7,4,0,75,0,0,0,0,5,0,128,25,0,0,0,101,4,64,0,156,0,0,0,0,5,6,192,25],[0,0,0,0,4,5,0,75,0,0,1,24,0,0,193,61,0,0,0,4,4,32,0,57,0,0,0,0,4,65,3,79],[0,0,0,0,4,4,4,59,0,8,0,0,0,4,0,29,0,0,0,100,4,64,0,156,0,0,1,24,0,0,33,61],[0,7,0,36,0,32,0,61,0,0,0,8,2,0,0,41,0,0,0,5,2,32,2,16,0,0,0,7,2,32,0,41],[0,0,0,0,2,50,0,75,0,0,1,24,0,0,33,61,0,0,0,0,2,0,4,17,0,0,128,1,2,32,0,140],[0,0,0,192,0,0,193,61,0,0,0,8,2,0,0,107,0,0,0,190,0,0,97,61,0,0,0,2,2,0,0,107],[0,0,0,200,0,0,193,61,0,5,0,1,0,0,0,61,0,4,128,13,0,0,0,61,0,3,0,3,0,0,0,61],[0,0,0,0,4,0,0,25,0,0,0,97,0,0,1,61,0,0,0,1,4,64,0,57,0,0,0,8,2,64,0,108],[0,0,0,190,0,0,129,61,0,0,0,5,2,64,2,16,0,0,0,7,2,32,0,41,0,0,0,0,2,33,3,79],[0,0,0,0,5,2,4,59,0,0,0,0,2,5,4,26,0,0,0,0,2,2,0,75,0,0,0,94,0,0,193,61],[0,0,0,105,1,80,1,151,0,0,0,106,1,16,0,156,0,0,1,26,0,0,193,61,0,6,0,0,0,4,0,29],[0,0,0,107,1,80,1,152,0,0,1,47,0,0,97,61,0,0,0,5,1,0,0,41,0,0,0,0,0,21,4,27],[0,0,0,0,1,0,4,20,0,0,0,95,2,16,0,156,0,0,0,95,1,0,128,65,0,0,0,192,1,16,2,16],[0,0,0,113,1,16,1,199,0,0,0,4,2,0,0,41,0,0,0,3,3,0,0,41,0,0,0,114,4,0,0,65],[0,0,0,0,6,0,0,25,1,120,1,110,0,0,4,15,0,0,0,0,1,0,3,103,0,0,0,1,2,32,1,144],[0,0,0,6,4,0,0,41,0,0,0,94,0,0,193,61,0,0,1,24,0,0,1,61,0,0,0,0,2,0,4,22],[0,0,0,0,2,2,0,75,0,0,1,24,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140],[0,0,1,24,0,0,65,61,0,0,0,4,1,16,3,112,0,0,0,0,5,1,4,59,0,0,0,0,1,0,4,17],[0,0,128,14,1,16,0,140,0,0,0,153,0,0,193,61,0,0,0,0,1,5,4,26,0,0,0,0,1,1,0,75],[0,0,0,190,0,0,193,61,0,0,0,105,1,80,1,151,0,0,0,106,1,16,0,156,0,0,0,163,0,0,193,61],[0,0,0,107,1,80,1,152,0,0,0,175,0,0,193,61,0,0,0,102,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,164,0,16,4,63,0,0,0,119,1,0,0,65],[0,0,0,160,0,0,1,61,0,0,0,102,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,132,0,16,4,63,0,0,0,31,1,0,0,57,0,0,0,164,0,16,4,63,0,0,0,121,1,0,0,65],[0,0,0,196,0,16,4,63,0,0,0,104,1,0,0,65,0,0,1,122,0,1,4,48,0,0,0,102,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,34,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,0,117,1,0,0,65,0,0,0,196,0,16,4,63,0,0,0,116,1,0,0,65],[0,0,0,228,0,16,4,63,0,0,0,122,1,0,0,65,0,0,1,122,0,1,4,48,0,0,0,1,1,0,0,57],[0,0,0,0,0,21,4,27,0,0,0,95,1,0,0,65,0,0,0,0,2,0,4,20,0,0,0,95,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,0,113,1,16,1,199,0,0,128,13,2,0,0,57],[0,0,0,3,3,0,0,57,0,0,0,114,4,0,0,65,0,0,0,0,6,0,0,25,1,120,1,110,0,0,4,15],[0,0,0,1,1,32,1,144,0,0,1,24,0,0,97,61,0,0,0,0,1,0,0,25,0,0,1,121,0,1,4,46],[0,0,0,102,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63],[0,0,0,31,1,0,0,57,0,0,0,164,0,16,4,63,0,0,0,103,1,0,0,65,0,0,0,160,0,0,1,61],[0,5,128,8,0,0,0,61,0,1,128,2,0,0,0,61,0,0,0,0,4,0,0,25,0,0,0,207,0,0,1,61],[0,0,0,1,4,64,0,57,0,0,0,8,2,64,0,108,0,0,0,190,0,0,129,61,0,0,0,5,2,64,2,16],[0,0,0,7,2,32,0,41,0,0,0,0,2,33,3,79,0,0,0,0,3,2,4,59,0,0,0,0,2,3,4,26],[0,0,0,0,2,2,0,75,0,0,0,204,0,0,193,61,0,0,0,105,1,48,1,151,0,0,0,106,1,16,0,156],[0,0,1,26,0,0,193,61,0,4,0,0,0,4,0,29,0,6,0,0,0,3,0,29,0,0,0,107,1,48,1,152],[0,0,1,47,0,0,97,61,0,0,0,108,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,5,1,0,0,41],[0,0,0,4,0,16,4,67,0,0,0,0,1,0,4,20,0,0,0,95,2,16,0,156,0,0,0,95,1,0,128,65],[0,0,0,192,1,16,2,16,0,0,0,109,1,16,1,199,0,0,0,1,2,0,0,41,1,120,1,115,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,1,64,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75],[0,0,0,6,2,0,0,41,0,0,1,24,0,0,97,61,0,0,0,64,4,0,4,61,0,0,0,110,1,0,0,65],[0,0,0,0,0,20,4,53,0,0,0,4,1,64,0,57,0,0,0,0,0,33,4,53,0,0,0,0,1,0,4,20],[0,0,0,95,2,16,0,156,0,0,0,95,3,0,0,65,0,0,0,0,1,3,128,25,0,0,0,95,2,64,0,156],[0,3,0,0,0,4,0,29,0,0,0,0,2,3,0,25,0,0,0,0,2,4,64,25,0,0,0,64,2,32,2,16],[0,0,0,192,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,111,1,16,1,199,0,0,0,5,2,0,0,41],[1,120,1,110,0,0,4,15,0,0,0,1,2,32,1,144,0,0,1,65,0,0,97,61,0,0,0,3,2,0,0,41],[0,0,0,112,1,32,0,156,0,0,1,103,0,0,129,61,0,0,0,64,0,32,4,63,0,0,0,1,1,0,0,57],[0,0,0,6,5,0,0,41,0,0,0,0,0,21,4,27,0,0,0,0,1,0,4,20,0,0,0,95,2,16,0,156],[0,0,0,95,1,0,128,65,0,0,0,192,1,16,2,16,0,0,0,113,1,16,1,199,0,0,128,13,2,0,0,57],[0,0,0,3,3,0,0,57,0,0,0,114,4,0,0,65,0,0,0,2,6,0,0,41,1,120,1,110,0,0,4,15],[0,0,0,0,1,0,3,103,0,0,0,1,2,32,1,144,0,0,0,4,4,0,0,41,0,0,0,204,0,0,193,61],[0,0,0,0,1,0,0,25,0,0,1,122,0,1,4,48,0,0,0,64,1,0,4,61,0,0,0,100,2,16,0,57],[0,0,0,116,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,68,2,16,0,57,0,0,0,117,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,34,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,0,102,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,0,95,2,0,0,65,0,0,0,95,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,64,1,16,2,16,0,0,0,118,1,16,1,199,0,0,1,122,0,1,4,48,0,0,0,64,1,0,4,61],[0,0,0,68,2,16,0,57,0,0,0,119,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,102,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,36,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,0,4,2,16,0,57,0,0,0,0,0,50,4,53,0,0,0,95,2,0,0,65,0,0,0,95,3,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,0,120,1,16,1,199,0,0,1,122,0,1,4,48],[0,0,0,0,0,1,4,47,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,31,4,48,1,143,0,0,0,95,3,48,1,151,0,0,0,5,5,48,2,114,0,0,1,81,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,1,73,0,0,65,61,0,0,0,0,6,4,0,75,0,0,1,96,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,0,95,1,0,0,65,0,0,0,95,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16],[0,0,0,96,2,48,2,16,0,0,0,0,1,33,1,159,0,0,1,122,0,1,4,48,0,0,0,115,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57,0,0,0,4,0,16,4,63,0,0,0,111,1,0,0,65],[0,0,1,122,0,1,4,48,0,0,0,0,0,1,4,47,0,0,1,113,0,33,4,33,0,0,0,1,2,0,0,57],[0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,1,118,0,33,4,35],[0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45],[0,0,1,120,0,0,4,50,0,0,1,121,0,1,4,46,0,0,1,122,0,1,4,48,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,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,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,0,0,0,0,0,229,22,118,30],[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,121,196,249,41],[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,76,99,20,240],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255],[128,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],[8,195,121,160,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],[67,97,108,108,97,98,108,101,32,111,110,108,121,32,98,121,32,116,104,101,32,98,111,111,116,108,111,97,100,101,114,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,128,0,0,0,0,0,0,0,0],[255,255,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],[1,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,0,0,1,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],[24,6,170,24,150,187,242,101,104,232,132,167,55,75,65,224,2,80,9,98,202,186,106,21,2,58,141,144,232,80,139,131],[2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[57,179,76,110,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,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,0,0,0,1,0,0,0,0,0,0,0,0],[2,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],[201,71,34,255,19,234,207,83,84,124,71,65,218,181,34,131,83,160,89,56,255,205,213,212,162,213,51,174,14,97,130,135],[78,72,123,113,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],[115,104,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],[73,110,99,111,114,114,101,99,116,108,121,32,102,111,114,109,97,116,116,101,100,32,98,121,116,101,99,111,100,101,72,97],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,0,0],[67,111,100,101,32,108,101,110,103,116,104,32,105,110,32,119,111,114,100,115,32,109,117,115,116,32,98,101,32,111,100,100],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0],[67,97,108,108,97,98,108,101,32,111,110,108,121,32,98,121,32,116,104,101,32,99,111,109,112,114,101,115,115,111,114,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,128,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,32,0,0,0,128,0,0,0,0,0,0,0,0],[19,244,124,140,251,27,40,215,67,122,206,132,217,200,125,100,205,240,125,135,58,151,188,173,230,233,239,192,213,110,224,239]],"0x0000000000000000000000000000000000008006":[[0,2,0,0,0,0,0,2,0,11,0,0,0,0,0,2,0,0,0,0,3,2,0,25,0,1,0,0,0,1,3,85],[0,0,0,0,2,1,0,25,0,0,0,96,2,32,2,112,0,0,4,244,0,32,1,157,0,0,0,128,4,0,0,57],[0,0,0,64,0,64,4,63,0,0,4,244,2,32,1,151,0,0,0,1,4,48,1,144,0,0,0,134,0,0,193,61],[0,0,0,4,4,32,0,140,0,0,7,102,0,0,65,61,0,0,0,0,4,1,4,59,0,0,0,224,4,64,2,112],[0,0,4,246,5,64,0,156,0,0,0,142,0,0,161,61,0,0,4,247,5,64,0,156,0,0,0,207,0,0,161,61],[0,0,4,248,5,64,0,156,0,0,0,0,5,0,4,16,0,11,0,0,0,5,0,29,0,0,1,71,0,0,33,61],[0,0,4,251,5,64,0,156,0,0,1,180,0,0,97,61,0,0,4,252,4,64,0,156,0,0,7,102,0,0,193,61],[0,0,0,0,4,0,4,22,0,0,0,0,4,4,0,75,0,0,7,102,0,0,193,61,0,0,0,4,2,32,0,138],[0,0,0,32,2,32,0,140,0,0,7,102,0,0,65,61,0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59],[0,11,0,0,0,1,0,29,0,0,0,1,1,16,0,140,0,0,7,102,0,0,33,61,0,0,0,0,2,0,4,17],[0,0,0,2,1,48,1,144,0,0,0,44,0,0,193,61,0,0,255,255,1,32,0,140,0,0,3,170,0,0,33,61],[0,10,0,0,0,2,0,29,0,0,0,0,0,32,4,53,0,0,0,32,0,0,4,63,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,5,15,1,16,1,199,0,0,128,16,2,0,0,57,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,7,102,0,0,97,61,0,0,0,64,4,0,4,61,0,0,5,32,2,64,0,156,0,0,3,211,0,0,33,61],[0,0,0,0,1,1,4,59,0,0,0,64,2,64,0,57,0,0,0,64,0,32,4,63,0,0,0,0,1,1,4,26],[0,0,0,255,2,16,1,143,0,0,0,1,3,32,0,140,0,0,4,25,0,0,33,61,0,0,0,0,3,36,4,54],[0,0,0,8,1,16,2,112,0,0,0,255,1,16,1,143,0,0,0,1,2,16,0,140,0,0,4,25,0,0,33,61],[0,9,0,0,0,4,0,29,0,0,0,0,0,19,4,53,0,0,0,11,2,0,0,41,0,0,0,1,2,32,0,140],[0,0,6,94,0,0,193,61,0,0,0,0,1,1,0,75,0,0,6,94,0,0,193,61,0,0,0,1,1,0,0,57],[0,11,0,0,0,3,0,29,0,8,0,0,0,1,0,29,0,0,0,0,0,19,4,53,0,0,0,10,1,0,0,41],[0,0,5,9,1,16,1,151,0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,5,15,1,16,1,199,0,0,128,16,2,0,0,57,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,7,102,0,0,97,61,0,0,0,9,2,0,0,41,0,0,0,0,2,2,4,51,0,0,0,1,3,32,0,140],[0,0,0,11,5,0,0,41,0,0,4,25,0,0,33,61,0,0,0,0,1,1,4,59,0,0,0,0,3,1,4,26],[0,0,1,0,4,0,0,138,0,0,0,0,3,67,1,111,0,0,0,0,2,35,1,159,0,0,0,0,0,33,4,27],[0,0,0,0,3,5,4,51,0,0,0,1,4,48,0,140,0,0,4,25,0,0,33,61,0,0,5,16,4,0,0,65],[0,0,0,0,2,66,1,111,0,0,0,8,3,48,2,16,0,0,255,0,3,48,1,143,0,0,0,0,2,35,1,159],[0,0,0,0,0,33,4,27,0,0,0,64,1,0,4,61,0,0,0,8,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,4,244,2,0,0,65,0,0,0,0,3,0,4,20,0,0,4,244,4,48,0,156,0,0,0,0,3,2,128,25],[0,0,4,244,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,0,192,2,48,2,16],[0,0,0,0,1,18,1,159,0,0,5,49,1,16,1,199,0,0,128,13,2,0,0,57,0,0,0,2,3,0,0,57],[0,0,5,50,4,0,0,65,0,0,0,201,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,7,102,0,0,193,61,0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67],[0,0,4,245,1,0,0,65,0,0,19,202,0,1,4,46,0,0,5,0,5,64,0,156,0,0,1,35,0,0,33,61],[0,0,5,4,5,64,0,156,0,0,2,240,0,0,97,61,0,0,5,5,5,64,0,156,0,0,3,125,0,0,97,61],[0,0,5,6,4,64,0,156,0,0,7,102,0,0,193,61,0,0,0,0,4,0,4,22,0,0,0,0,4,4,0,75],[0,0,7,102,0,0,193,61,0,0,0,4,2,32,0,138,0,0,0,32,2,32,0,140,0,0,7,102,0,0,65,61],[0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59,0,11,0,0,0,1,0,29,0,0,0,1,1,16,0,140],[0,0,7,102,0,0,33,61,0,0,0,0,2,0,4,17,0,0,0,2,1,48,1,144,0,0,0,166,0,0,193,61],[0,0,255,255,1,32,0,140,0,0,3,170,0,0,33,61,0,10,0,0,0,2,0,29,0,0,0,0,0,32,4,53],[0,0,0,32,0,0,4,63,0,0,4,244,3,0,0,65,0,0,0,0,1,0,4,20,0,0,4,244,2,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,5,15,1,16,1,199,0,0,128,16,2,0,0,57],[19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,7,102,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,2,1,4,26,0,0,1,0,3,0,0,138,0,0,0,0,2,50,1,111,0,0,0,11,3,0,0,41],[0,0,0,0,2,50,1,159,0,0,0,0,0,33,4,27,0,0,0,64,1,0,4,61,0,0,0,0,0,49,4,53],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,4,244,4,0,0,65,0,0,0,0,2,4,128,25],[0,0,4,244,3,16,0,156,0,0,0,0,1,4,128,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,5,49,1,16,1,199,0,0,128,13,2,0,0,57,0,0,0,2,3,0,0,57],[0,0,5,67,4,0,0,65,0,0,0,10,5,0,0,41,19,201,19,180,0,0,4,15,0,0,0,1,1,32,1,144],[0,0,7,102,0,0,97,61,0,0,0,0,1,0,0,25,0,0,19,202,0,1,4,46,0,0,4,253,5,64,0,156],[0,0,2,81,0,0,97,61,0,0,4,254,3,64,0,156,0,0,2,188,0,0,97,61,0,0,4,255,3,64,0,156],[0,0,7,102,0,0,193,61,0,0,0,4,2,32,0,138,0,0,0,32,2,32,0,140,0,0,7,102,0,0,65,61],[0,0,0,4,1,16,3,112,0,0,0,0,2,1,4,59,0,0,0,0,1,0,4,17,0,0,128,7,1,16,0,140],[0,0,3,215,0,0,193,61,0,0,5,13,1,0,0,65,0,0,0,128,0,16,4,63,0,11,0,0,0,2,0,29],[0,0,0,132,0,32,4,63,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,14,1,16,1,199,0,0,128,4,2,0,0,57],[19,201,19,185,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151],[0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143],[0,0,0,5,6,64,2,114,0,0,0,251,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16],[0,0,0,0,9,129,3,79,0,0,0,0,9,9,4,59,0,0,0,128,8,128,0,57,0,0,0,0,0,152,4,53],[0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,0,243,0,0,65,61,0,0,0,0,7,5,0,75],[0,0,1,10,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,3,5,80,2,16],[0,0,0,128,6,96,0,57,0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47],[0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207],[0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144,0,0,3,225,0,0,97,61],[0,0,0,31,1,64,0,57,0,0,0,96,2,16,1,143,0,0,0,128,1,32,1,191,0,0,0,64,0,16,4,63],[0,0,0,32,3,48,0,140,0,0,7,102,0,0,65,61,0,0,0,128,3,0,4,61,0,0,0,0,3,3,0,75],[0,0,4,119,0,0,193,61,0,0,5,10,3,0,0,65,0,0,0,0,0,49,4,53,0,0,0,132,3,32,1,191],[0,0,0,32,4,0,0,57,0,0,0,0,0,67,4,53,0,0,0,196,3,32,0,57,0,0,5,41,4,0,0,65],[0,0,0,0,0,67,4,53,0,0,0,164,2,32,0,57,0,0,0,26,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,0,64,1,16,2,16,0,0,5,20,1,16,1,199,0,0,19,203,0,1,4,48,0,0,5,1,5,64,0,156],[0,0,3,7,0,0,97,61,0,0,5,2,3,64,0,156,0,0,3,182,0,0,97,61,0,0,5,3,3,64,0,156],[0,0,7,102,0,0,193,61,0,0,0,0,3,0,4,22,0,0,0,0,3,3,0,75,0,0,7,102,0,0,193,61],[0,0,0,4,3,32,0,138,0,0,0,128,3,48,0,140,0,0,7,102,0,0,65,61,0,0,0,4,3,16,3,112],[0,0,0,0,3,3,4,59,0,11,0,0,0,3,0,29,0,0,5,9,3,48,0,156,0,0,7,102,0,0,33,61],[0,0,0,100,1,16,3,112,0,0,0,0,1,1,4,59,0,0,5,7,3,16,0,156,0,0,7,102,0,0,33,61],[0,0,0,4,1,16,0,57,19,201,10,44,0,0,4,15,0,0,0,1,4,0,3,103,0,0,0,68,3,64,3,112],[0,0,0,0,3,3,4,59,0,0,0,36,4,64,3,112,0,0,0,0,4,4,4,59,0,0,0,0,5,1,0,25],[0,0,0,0,6,2,0,25,0,0,0,11,1,0,0,41,0,0,0,0,2,4,0,25,0,0,0,0,4,5,0,25],[0,0,0,0,5,6,0,25,19,201,10,70,0,0,4,15,0,0,2,254,0,0,1,61,0,0,4,249,5,64,0,156],[0,0,1,224,0,0,97,61,0,0,4,250,3,64,0,156,0,0,7,102,0,0,193,61,0,0,0,4,3,32,0,138],[0,0,0,64,3,48,0,140,0,0,7,102,0,0,65,61,0,0,0,4,3,16,3,112,0,0,0,0,3,3,4,59],[0,10,0,0,0,3,0,29,0,0,5,7,3,48,0,156,0,0,7,102,0,0,33,61,0,0,0,10,4,32,0,106],[0,0,5,8,2,0,0,65,0,0,0,164,3,64,0,140,0,0,0,0,3,0,0,25,0,0,0,0,3,2,64,25],[0,9,0,0,0,4,0,29,0,0,5,8,4,64,1,151,0,0,0,0,5,4,0,75,0,0,0,0,2,0,160,25],[0,0,5,8,4,64,0,156,0,0,0,0,2,3,192,25,0,0,0,0,2,2,0,75,0,0,7,102,0,0,193,61],[0,0,0,36,2,16,3,112,0,0,0,0,2,2,4,59,0,8,0,0,0,2,0,29,0,0,5,9,2,32,0,156],[0,0,7,102,0,0,33,61,0,0,0,0,2,0,4,17,0,0,0,11,2,32,0,108,0,0,4,43,0,0,193,61],[0,0,0,10,2,0,0,41,0,7,0,4,0,32,0,61,0,0,0,7,1,16,3,96,0,0,0,0,2,1,4,59],[0,0,5,13,1,0,0,65,0,0,0,128,0,16,4,63,0,6,0,0,0,2,0,29,0,0,0,132,0,32,4,63],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,5,14,1,16,1,199,0,0,128,4,2,0,0,57,19,201,19,185,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114],[0,0,1,138,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,129,3,79],[0,0,0,0,9,9,4,59,0,0,0,128,8,128,0,57,0,0,0,0,0,152,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,103,0,75,0,0,1,130,0,0,65,61,0,0,0,0,7,5,0,75,0,0,1,153,0,0,97,61],[0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,3,5,80,2,16,0,0,0,128,6,96,0,57],[0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159],[0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144,0,0,5,174,0,0,97,61,0,0,0,31,1,64,0,57],[0,0,0,96,1,16,1,143,0,0,0,128,2,16,1,191,0,5,0,0,0,2,0,29,0,0,0,64,0,32,4,63],[0,0,0,32,2,48,0,140,0,0,7,102,0,0,65,61,0,0,0,128,2,0,4,61,0,0,0,0,2,2,0,75],[0,0,6,118,0,0,193,61,0,0,5,10,2,0,0,65,0,0,0,5,4,0,0,41,0,0,0,0,0,36,4,53],[0,0,0,132,2,16,1,191,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53,0,0,0,196,2,16,0,57],[0,0,5,41,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,164,1,16,0,57,0,0,0,26,2,0,0,57],[0,0,0,0,0,33,4,53,0,0,0,64,1,64,2,16,0,0,5,20,1,16,1,199,0,0,19,203,0,1,4,48],[0,0,0,4,3,32,0,138,0,0,0,32,3,48,0,140,0,0,7,102,0,0,65,61,0,0,0,4,3,16,3,112],[0,0,0,0,3,3,4,59,0,5,0,0,0,3,0,29,0,0,5,7,3,48,0,156,0,0,7,102,0,0,33,61],[0,0,0,5,3,0,0,41,0,0,0,35,3,48,0,57,0,0,5,8,4,0,0,65,0,0,0,0,5,35,0,75],[0,0,0,0,5,0,0,25,0,0,0,0,5,4,128,25,0,0,5,8,3,48,1,151,0,0,0,0,6,3,0,75],[0,0,0,0,4,0,128,25,0,0,5,8,3,48,0,156,0,0,0,0,4,5,192,25,0,0,0,0,3,4,0,75],[0,0,7,102,0,0,193,61,0,0,0,5,3,0,0,41,0,0,0,4,3,48,0,57,0,0,0,0,3,49,3,79],[0,0,0,0,13,3,4,59,0,0,5,7,3,208,0,156,0,0,7,102,0,0,33,61,0,0,0,5,3,0,0,41],[0,0,0,36,14,48,0,57,0,0,0,5,3,208,2,16,0,0,0,0,3,227,0,25,0,0,0,0,3,35,0,75],[0,0,7,102,0,0,33,61,0,0,0,9,4,0,0,138,0,0,0,0,3,0,4,17,0,0,0,0,4,67,1,111],[0,0,128,7,4,64,0,140,0,0,4,31,0,0,193,61,0,0,0,0,4,13,0,75,0,0,4,180,0,0,193,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,0,205,0,0,97,61,0,0,6,22,0,0,1,61],[0,0,0,4,4,32,0,138,0,0,0,128,4,64,0,140,0,0,7,102,0,0,65,61,0,0,0,36,4,16,3,112],[0,0,0,0,4,4,4,59,0,11,0,0,0,4,0,29,0,0,0,68,4,16,3,112,0,0,0,0,4,4,4,59],[0,0,5,7,5,64,0,156,0,0,7,102,0,0,33,61,0,0,0,35,5,64,0,57,0,0,5,8,6,0,0,65],[0,0,0,0,7,37,0,75,0,0,0,0,7,0,0,25,0,0,0,0,7,6,128,25,0,0,5,8,5,80,1,151],[0,0,0,0,8,5,0,75,0,0,0,0,6,0,128,25,0,0,5,8,5,80,0,156,0,0,0,0,6,7,192,25],[0,0,0,0,5,6,0,75,0,0,7,102,0,0,193,61,0,0,0,4,5,64,0,57,0,0,0,0,5,81,3,79],[0,0,0,0,5,5,4,59,0,10,0,0,0,5,0,29,0,0,5,7,5,80,0,156,0,0,7,102,0,0,33,61],[0,0,0,36,5,64,0,57,0,9,0,0,0,5,0,29,0,0,0,10,4,80,0,41,0,0,0,0,2,36,0,75],[0,0,7,102,0,0,33,61,0,0,0,100,1,16,3,112,0,0,0,0,1,1,4,59,0,8,0,0,0,1,0,29],[0,0,0,1,1,16,0,140,0,0,7,102,0,0,33,61,0,0,0,2,1,48,1,144,0,0,0,1,1,16,2,112],[0,0,2,13,0,0,193,61,0,0,0,0,1,0,4,17,0,0,5,42,1,16,0,156,0,0,0,0,1,0,0,25],[0,0,0,1,1,0,64,57,0,0,0,0,1,1,0,75,0,0,3,170,0,0,97,61,0,0,5,43,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,0,1,0,4,17,0,7,0,0,0,1,0,29,0,0,0,132,0,16,4,63],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,5,14,1,16,1,199,0,0,128,3,2,0,0,57,19,201,19,180,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114],[0,0,2,46,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,129,3,79],[0,0,0,0,9,9,4,59,0,0,0,128,8,128,0,57,0,0,0,0,0,152,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,103,0,75,0,0,2,38,0,0,65,61,0,0,0,0,7,5,0,75,0,0,2,61,0,0,97,61],[0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,3,5,80,2,16,0,0,0,128,6,96,0,57],[0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159],[0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144,0,0,6,36,0,0,97,61,0,0,0,31,1,64,0,57],[0,0,0,96,1,16,1,143,0,0,0,128,1,16,1,191,0,0,0,64,0,16,4,63,0,0,0,32,1,48,0,140],[0,0,7,102,0,0,65,61,0,0,0,128,2,0,4,61,0,0,0,7,1,0,0,41,19,201,11,13,0,0,4,15],[0,0,0,0,2,1,0,25,0,7,0,0,0,2,0,29,0,0,0,11,1,0,0,41,0,0,0,8,3,0,0,41],[0,0,0,9,4,0,0,41,0,0,0,10,5,0,0,41,19,201,15,118,0,0,4,15,0,0,0,7,1,0,0,41],[0,0,2,254,0,0,1,61,0,0,0,4,4,32,0,138,0,0,0,96,4,64,0,140,0,0,7,102,0,0,65,61],[0,0,0,36,4,16,3,112,0,0,0,0,4,4,4,59,0,11,0,0,0,4,0,29,0,0,0,68,4,16,3,112],[0,0,0,0,4,4,4,59,0,0,5,7,5,64,0,156,0,0,7,102,0,0,33,61,0,0,0,35,5,64,0,57],[0,0,5,8,6,0,0,65,0,0,0,0,7,37,0,75,0,0,0,0,7,0,0,25,0,0,0,0,7,6,128,25],[0,0,5,8,5,80,1,151,0,0,0,0,8,5,0,75,0,0,0,0,6,0,128,25,0,0,5,8,5,80,0,156],[0,0,0,0,6,7,192,25,0,0,0,0,5,6,0,75,0,0,7,102,0,0,193,61,0,0,0,4,5,64,0,57],[0,0,0,0,1,81,3,79,0,0,0,0,1,1,4,59,0,10,0,0,0,1,0,29,0,0,5,7,1,16,0,156],[0,0,7,102,0,0,33,61,0,0,0,36,4,64,0,57,0,9,0,0,0,4,0,29,0,0,0,10,1,64,0,41],[0,0,0,0,1,33,0,75,0,0,7,102,0,0,33,61,0,0,0,2,1,48,1,144,0,0,0,1,1,16,2,112],[0,0,2,121,0,0,193,61,0,0,0,0,1,0,4,17,0,0,5,42,1,16,0,156,0,0,0,0,1,0,0,25],[0,0,0,1,1,0,64,57,0,0,0,0,1,1,0,75,0,0,3,170,0,0,97,61,0,0,5,43,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,0,1,0,4,17,0,8,0,0,0,1,0,29,0,0,0,132,0,16,4,63],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,5,14,1,16,1,199,0,0,128,3,2,0,0,57,19,201,19,180,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114],[0,0,2,154,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,129,3,79],[0,0,0,0,9,9,4,59,0,0,0,128,8,128,0,57,0,0,0,0,0,152,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,103,0,75,0,0,2,146,0,0,65,61,0,0,0,0,7,5,0,75,0,0,2,169,0,0,97,61],[0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,3,5,80,2,16,0,0,0,128,6,96,0,57],[0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159],[0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144,0,0,5,203,0,0,97,61,0,0,0,31,1,64,0,57],[0,0,0,96,1,16,1,143,0,0,0,128,1,16,1,191,0,0,0,64,0,16,4,63,0,0,0,32,1,48,0,140],[0,0,7,102,0,0,65,61,0,0,0,128,2,0,4,61,0,0,0,8,1,0,0,41,19,201,11,13,0,0,4,15],[0,0,0,0,2,1,0,25,0,8,0,0,0,2,0,29,0,0,0,11,1,0,0,41,0,0,0,9,3,0,0,41],[0,0,0,10,4,0,0,41,19,201,11,57,0,0,4,15,0,0,0,8,1,0,0,41,0,0,2,254,0,0,1,61],[0,0,0,0,3,0,4,22,0,0,0,0,3,3,0,75,0,0,7,102,0,0,193,61,0,0,0,4,2,32,0,138],[0,0,0,32,2,32,0,140,0,0,7,102,0,0,65,61,0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59],[0,11,0,0,0,1,0,29,0,0,5,9,1,16,0,156,0,0,7,102,0,0,33,61,0,0,0,11,1,0,0,41],[0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,15,1,16,1,199],[0,0,128,16,2,0,0,57,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,7,102,0,0,97,61],[0,0,0,64,2,0,4,61,0,0,5,32,3,32,0,156,0,0,3,211,0,0,33,61,0,0,0,0,1,1,4,59],[0,0,0,64,3,32,0,57,0,0,0,64,0,48,4,63,0,0,0,0,1,1,4,26,0,0,0,255,3,16,1,143],[0,0,0,1,4,48,0,140,0,0,4,25,0,0,33,61,0,0,0,0,3,50,4,54,0,0,0,8,1,16,2,112],[0,0,0,255,1,16,1,143,0,0,0,1,4,16,0,140,0,0,4,25,0,0,33,61,0,0,0,0,0,19,4,53],[0,0,0,0,2,2,4,51,0,0,0,1,1,32,0,140,0,0,4,25,0,0,33,61,0,0,0,1,1,0,0,57],[0,0,0,0,2,2,0,75,0,0,2,255,0,0,193,61,0,0,0,11,1,0,0,41,0,0,5,63,1,16,1,152],[0,0,0,0,1,0,0,25,0,0,7,33,0,0,193,61,0,0,0,1,1,16,1,143,0,0,2,255,0,0,1,61],[0,0,0,0,3,0,4,22,0,0,0,0,3,3,0,75,0,0,7,102,0,0,193,61,0,0,0,4,2,32,0,138],[0,0,0,64,2,32,0,140,0,0,7,102,0,0,65,61,0,0,0,4,2,16,3,112,0,0,0,0,3,2,4,59],[0,0,5,9,2,48,0,156,0,0,7,102,0,0,33,61,0,0,0,36,1,16,3,112,0,0,0,0,2,1,4,59],[0,0,0,0,1,3,0,25,19,201,11,13,0,0,4,15,0,0,5,9,1,16,1,151,0,0,0,64,2,0,4,61],[0,0,0,0,0,18,4,53,0,0,4,244,1,0,0,65,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,64,1,32,2,16,0,0,5,44,1,16,1,199,0,0,19,202,0,1,4,46,0,0,0,4,4,32,0,138],[0,0,0,128,4,64,0,140,0,0,7,102,0,0,65,61,0,0,0,36,4,16,3,112,0,0,0,0,4,4,4,59],[0,11,0,0,0,4,0,29,0,0,0,4,4,16,3,112,0,0,0,0,4,4,4,59,0,10,0,0,0,4,0,29],[0,0,0,68,4,16,3,112,0,0,0,0,4,4,4,59,0,0,5,7,5,64,0,156,0,0,7,102,0,0,33,61],[0,0,0,35,5,64,0,57,0,0,5,8,6,0,0,65,0,0,0,0,7,37,0,75,0,0,0,0,7,0,0,25],[0,0,0,0,7,6,128,25,0,0,5,8,5,80,1,151,0,0,0,0,8,5,0,75,0,0,0,0,6,0,128,25],[0,0,5,8,5,80,0,156,0,0,0,0,6,7,192,25,0,0,0,0,5,6,0,75,0,0,7,102,0,0,193,61],[0,0,0,4,5,64,0,57,0,0,0,0,5,81,3,79,0,0,0,0,5,5,4,59,0,9,0,0,0,5,0,29],[0,0,5,7,5,80,0,156,0,0,7,102,0,0,33,61,0,0,0,36,5,64,0,57,0,8,0,0,0,5,0,29],[0,0,0,9,4,80,0,41,0,0,0,0,2,36,0,75,0,0,7,102,0,0,33,61,0,0,0,100,1,16,3,112],[0,0,0,0,1,1,4,59,0,7,0,0,0,1,0,29,0,0,0,1,1,16,0,140,0,0,7,102,0,0,33,61],[0,0,0,2,1,48,1,144,0,0,0,1,1,16,2,112,0,0,3,55,0,0,193,61,0,0,0,0,1,0,4,17],[0,0,5,42,1,16,0,156,0,0,0,0,1,0,0,25,0,0,0,1,1,0,64,57,0,0,0,0,1,1,0,75],[0,0,3,170,0,0,97,61,0,0,5,43,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,0,1,0,4,17],[0,6,0,0,0,1,0,29,0,0,0,132,0,16,4,63,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,14,1,16,1,199],[0,0,128,3,2,0,0,57,19,201,19,180,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,4,244,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57],[0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114,0,0,3,88,0,0,97,61,0,0,0,0,7,0,0,25],[0,0,0,5,8,112,2,16,0,0,0,0,9,129,3,79,0,0,0,0,9,9,4,59,0,0,0,128,8,128,0,57],[0,0,0,0,0,152,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,3,80,0,0,65,61],[0,0,0,0,7,5,0,75,0,0,3,103,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79],[0,0,0,3,5,80,2,16,0,0,0,128,6,96,0,57,0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207],[0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144],[0,0,6,65,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,1,16,1,143,0,0,0,128,1,16,1,191],[0,0,0,64,0,16,4,63,0,0,0,32,1,48,0,140,0,0,7,102,0,0,65,61,0,0,0,6,1,0,0,41],[0,0,0,11,2,0,0,41,0,0,0,10,3,0,0,41,0,0,0,8,4,0,0,41,0,0,0,9,5,0,0,41],[19,201,10,70,0,0,4,15,0,0,0,0,2,1,0,25,0,10,0,0,0,2,0,29,0,0,0,11,1,0,0,41],[0,0,0,7,3,0,0,41,0,0,0,8,4,0,0,41,0,0,0,9,5,0,0,41,19,201,15,118,0,0,4,15],[0,0,4,117,0,0,1,61,0,0,0,4,4,32,0,138,0,0,0,96,4,64,0,140,0,0,7,102,0,0,65,61],[0,0,0,36,4,16,3,112,0,0,0,0,4,4,4,59,0,11,0,0,0,4,0,29,0,0,0,4,4,16,3,112],[0,0,0,0,4,4,4,59,0,10,0,0,0,4,0,29,0,0,0,68,4,16,3,112,0,0,0,0,4,4,4,59],[0,0,5,7,5,64,0,156,0,0,7,102,0,0,33,61,0,0,0,35,5,64,0,57,0,0,5,8,6,0,0,65],[0,0,0,0,7,37,0,75,0,0,0,0,7,0,0,25,0,0,0,0,7,6,128,25,0,0,5,8,5,80,1,151],[0,0,0,0,8,5,0,75,0,0,0,0,6,0,128,25,0,0,5,8,5,80,0,156,0,0,0,0,6,7,192,25],[0,0,0,0,5,6,0,75,0,0,7,102,0,0,193,61,0,0,0,4,5,64,0,57,0,0,0,0,1,81,3,79],[0,0,0,0,1,1,4,59,0,9,0,0,0,1,0,29,0,0,5,7,1,16,0,156,0,0,7,102,0,0,33,61],[0,0,0,36,4,64,0,57,0,8,0,0,0,4,0,29,0,0,0,9,1,64,0,41,0,0,0,0,1,33,0,75],[0,0,7,102,0,0,33,61,0,0,0,2,1,48,1,144,0,0,0,1,1,16,2,112,0,0,3,168,0,0,193,61],[0,0,0,0,1,0,4,17,0,0,5,42,1,16,0,156,0,0,0,0,1,0,0,25,0,0,0,1,1,0,64,57],[0,0,0,0,1,1,0,75,0,0,4,51,0,0,193,61,0,0,5,10,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,36,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,5,68,1,0,0,65,0,0,0,196,0,16,4,63,0,0,5,69,1,0,0,65,0,0,0,228,0,16,4,63],[0,0,5,70,1,0,0,65,0,0,19,203,0,1,4,48,0,0,0,0,3,0,4,22,0,0,0,0,3,3,0,75],[0,0,7,102,0,0,193,61,0,0,0,4,2,32,0,138,0,0,0,32,2,32,0,140,0,0,7,102,0,0,65,61],[0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59,0,0,5,9,2,16,0,156,0,0,7,102,0,0,33,61],[0,0,0,192,2,0,0,57,0,0,0,64,0,32,4,63,0,0,0,128,0,0,4,63,0,0,0,160,0,0,4,63],[0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,15,1,16,1,199],[0,0,128,16,2,0,0,57,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,7,102,0,0,97,61],[0,0,0,64,2,0,4,61,0,0,5,65,3,32,0,156,0,0,4,4,0,0,65,61,0,0,5,58,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57,0,0,4,28,0,0,1,61,0,0,5,10,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,20,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,5,62,1,0,0,65,0,0,0,196,0,16,4,63,0,0,5,12,1,0,0,65],[0,0,19,203,0,1,4,48,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114],[0,0,3,238,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,3,230,0,0,65,61,0,0,0,0,6,4,0,75,0,0,3,253,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,4,244,1,0,0,65,0,0,4,244,4,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,64,1,32,2,16,0,0,0,96,2,48,2,16,0,0,0,0,1,33,1,159,0,0,19,203,0,1,4,48],[0,0,0,0,1,1,4,59,0,0,0,64,3,32,0,57,0,0,0,64,0,48,4,63,0,0,0,0,3,1,4,26],[0,0,0,255,1,48,1,143,0,0,0,2,4,16,0,140,0,0,4,25,0,0,129,61,0,0,0,0,1,18,4,54],[0,0,0,8,3,48,2,112,0,0,0,255,3,48,1,143,0,0,0,1,4,48,0,140,0,0,4,25,0,0,33,61],[0,0,0,0,0,49,4,53,0,0,0,0,3,2,4,51,0,0,0,1,2,48,0,140,0,0,4,25,0,0,33,61],[0,0,0,64,2,0,4,61,0,0,0,0,3,50,4,54,0,0,0,0,1,1,4,51,0,0,0,1,4,16,0,140],[0,0,7,26,0,0,161,61,0,0,5,58,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,33,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,5,31,1,0,0,65,0,0,19,203,0,1,4,48,0,0,5,10,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,65,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,5,51,1,0,0,65,0,0,0,196,0,16,4,63,0,0,5,52,1,0,0,65],[0,0,0,228,0,16,4,63,0,0,5,53,1,0,0,65,0,0,6,33,0,0,1,61,0,0,5,10,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,21,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,5,11,1,0,0,65,0,0,3,222,0,0,1,61,0,0,5,43,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,0,1,0,4,17,0,7,0,0,0,1,0,29,0,0,0,132,0,16,4,63],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,5,14,1,16,1,199,0,0,128,3,2,0,0,57,19,201,19,180,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114],[0,0,4,82,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,129,3,79],[0,0,0,0,9,9,4,59,0,0,0,128,8,128,0,57,0,0,0,0,0,152,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,103,0,75,0,0,4,74,0,0,65,61,0,0,0,0,7,5,0,75,0,0,4,97,0,0,97,61],[0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,3,5,80,2,16,0,0,0,128,6,96,0,57],[0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159],[0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144,0,0,5,232,0,0,97,61,0,0,0,31,1,64,0,57],[0,0,0,96,1,16,1,143,0,0,0,128,1,16,1,191,0,0,0,64,0,16,4,63,0,0,0,32,1,48,0,140],[0,0,7,102,0,0,65,61,0,0,0,7,1,0,0,41,0,0,0,11,2,0,0,41,0,0,0,10,3,0,0,41],[0,0,0,8,4,0,0,41,0,0,0,9,5,0,0,41,19,201,10,70,0,0,4,15,0,0,0,0,2,1,0,25],[0,10,0,0,0,2,0,29,0,0,0,11,1,0,0,41,0,0,0,8,3,0,0,41,0,0,0,9,4,0,0,41],[19,201,11,57,0,0,4,15,0,0,0,10,1,0,0,41,0,0,2,254,0,0,1,61,0,0,0,0,3,0,4,22],[0,0,0,0,3,3,0,75,0,0,6,5,0,0,193,61,0,0,5,17,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,128,2,2,0,0,57,0,0,0,4,0,32,4,67,0,0,4,244,1,0,0,65,0,0,0,0,3,0,4,20],[0,0,4,244,4,48,0,156,0,0,0,0,3,1,128,25,0,0,0,192,1,48,2,16,0,0,5,18,1,16,1,199],[19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,9,208,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,1,1,0,75,0,0,7,102,0,0,97,61,0,0,0,64,4,0,4,61,0,0,0,36,1,64,0,57],[0,0,0,11,2,0,0,41,0,0,0,0,0,33,4,53,0,0,5,38,1,0,0,65,0,0,0,0,0,20,4,53],[0,0,0,4,1,64,0,57,0,0,128,16,2,0,0,57,0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156],[0,10,0,0,0,4,0,29,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,5,24,1,16,1,199,0,0,128,2,2,0,0,57,19,201,19,180,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,7,104,0,0,97,61,0,0,0,10,1,0,0,41,0,0,5,7,1,16,0,156],[0,0,3,211,0,0,33,61,0,0,0,10,1,0,0,41,0,0,0,64,0,16,4,63,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,5,39,1,16,1,199,0,0,128,13,2,0,0,57,0,0,0,4,3,0,0,57,0,0,128,7,5,0,0,57],[0,0,128,16,7,0,0,57,0,0,5,40,4,0,0,65,0,0,0,11,6,0,0,41,0,0,0,202,0,0,1,61],[0,0,0,5,5,0,0,41,0,0,0,0,4,82,0,73,0,0,0,132,2,80,0,57,0,0,0,195,4,64,0,138],[0,0,5,8,6,0,0,65,0,0,0,0,7,0,0,25,0,0,0,0,5,0,0,25,0,0,0,5,8,112,2,16],[0,0,0,0,8,232,0,25,0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,9,72,0,75],[0,0,0,0,9,0,0,25,0,0,0,0,9,6,128,25,0,0,5,8,10,64,1,151,0,0,5,8,11,128,1,151],[0,0,0,0,12,171,0,75,0,0,0,0,12,0,0,25,0,0,0,0,12,6,64,25,0,0,0,0,10,171,1,63],[0,0,5,8,10,160,0,156,0,0,0,0,12,9,192,25,0,0,0,0,9,12,0,75,0,0,7,102,0,0,193,61],[0,0,0,0,8,130,0,25,0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,5,88,0,25],[0,0,0,0,8,133,0,75,0,0,0,0,8,0,0,25,0,0,0,1,8,0,64,57,0,0,0,1,8,128,1,144],[0,0,8,11,0,0,193,61,0,0,0,1,7,112,0,57,0,0,0,0,8,215,0,75,0,0,4,187,0,0,65,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,81,0,75,0,0,6,22,0,0,193,61,0,4,5,9,0,48,1,155],[0,0,5,8,8,0,0,65,0,0,0,0,9,0,0,25,0,8,0,0,0,13,0,29,0,7,0,0,0,14,0,29],[0,0,0,5,1,144,2,16,0,0,0,0,2,225,0,25,0,0,0,1,1,0,3,103,0,0,0,0,2,33,3,79],[0,0,0,0,2,2,4,59,0,0,0,5,3,0,0,41,0,0,0,0,3,48,0,121,0,0,0,195,3,48,0,138],[0,0,0,0,4,50,0,75,0,0,0,0,4,0,0,25,0,0,0,0,4,8,128,25,0,0,5,8,3,48,1,151],[0,0,5,8,5,32,1,151,0,0,0,0,6,53,0,75,0,0,0,0,6,0,0,25,0,0,0,0,6,8,64,25],[0,0,0,0,3,53,1,63,0,0,5,8,3,48,0,156,0,0,0,0,6,4,192,25,0,0,0,0,3,6,0,75],[0,0,7,102,0,0,193,61,0,10,0,0,0,9,0,29,0,0,0,0,2,226,0,25,0,9,0,0,0,2,0,29],[0,0,0,96,2,32,0,57,0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,6,0,0,0,1,0,29],[0,0,5,17,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,11,1,0,0,41,0,0,0,4,0,16,4,67],[0,0,0,0,1,0,4,20,0,0,4,244,2,16,0,156,0,0,4,244,1,0,128,65,0,0,0,192,1,16,2,16],[0,0,5,18,1,16,1,199,0,0,128,2,2,0,0,57,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,9,208,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,0,8,13,0,0,41],[0,0,0,7,14,0,0,41,0,0,5,8,8,0,0,65,0,0,0,10,9,0,0,41,0,0,0,9,11,0,0,41],[0,0,7,102,0,0,97,61,0,0,0,64,10,0,4,61,0,0,5,55,1,0,0,65,0,0,0,0,0,26,4,53],[0,0,0,4,1,160,0,57,0,0,0,64,2,0,0,57,0,0,0,0,0,33,4,53,0,0,0,1,1,0,3,103],[0,0,0,0,2,177,3,79,0,0,0,0,2,2,4,59,0,0,0,68,3,160,0,57,0,0,0,0,0,35,4,53],[0,0,0,32,2,176,0,57,0,0,0,0,3,33,3,79,0,0,0,0,3,3,4,59,0,0,5,9,4,48,0,156],[0,0,7,102,0,0,33,61,0,0,0,100,4,160,0,57,0,0,0,0,0,52,4,53,0,0,0,32,2,32,0,57],[0,0,0,0,3,33,3,79,0,0,0,0,3,3,4,59,0,0,0,0,4,3,0,75,0,0,0,0,4,0,0,25],[0,0,0,1,4,0,192,57,0,0,0,0,4,67,0,75,0,0,7,102,0,0,193,61,0,0,0,132,4,160,0,57],[0,0,0,0,0,52,4,53,0,0,0,32,3,32,0,57,0,0,0,0,3,49,3,79,0,0,0,0,3,3,4,59],[0,0,0,164,4,160,0,57,0,0,0,0,0,52,4,53,0,0,0,64,2,32,0,57,0,0,0,0,2,33,3,79],[0,0,0,0,2,2,4,59,0,0,0,0,3,0,0,49,0,0,0,0,4,179,0,73,0,0,0,31,4,64,0,138],[0,0,0,0,5,66,0,75,0,0,0,0,5,0,0,25,0,0,0,0,5,8,128,25,0,0,5,8,4,64,1,151],[0,0,5,8,6,32,1,151,0,0,0,0,7,70,0,75,0,0,0,0,7,0,0,25,0,0,0,0,7,8,64,25],[0,0,0,0,4,70,1,63,0,0,5,8,4,64,0,156,0,0,0,0,7,5,192,25,0,0,0,0,4,7,0,75],[0,0,7,102,0,0,193,61,0,0,0,0,4,178,0,25,0,0,0,0,2,65,3,79,0,0,0,0,2,2,4,59],[0,0,5,7,5,32,0,156,0,0,7,102,0,0,33,61,0,0,0,32,4,64,0,57,0,0,0,0,3,35,0,73],[0,0,0,0,5,52,0,75,0,0,0,0,5,0,0,25,0,0,0,0,5,8,32,25,0,0,5,8,3,48,1,151],[0,0,5,8,6,64,1,151,0,0,0,0,7,54,0,75,0,0,0,0,7,0,0,25,0,0,0,0,7,8,64,25],[0,0,0,0,3,54,1,63,0,0,5,8,3,48,0,156,0,0,0,0,7,5,192,25,0,0,0,0,3,7,0,75],[0,0,7,102,0,0,193,61,0,0,0,196,3,160,0,57,0,0,0,160,5,0,0,57,0,0,0,0,0,83,4,53],[0,0,0,228,3,160,0,57,0,0,0,0,0,35,4,53,0,0,0,0,3,65,3,79,0,0,1,4,1,160,0,57],[0,0,0,5,4,32,2,114,0,0,5,107,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16],[0,0,0,0,7,97,0,25,0,0,0,0,6,99,3,79,0,0,0,0,6,6,4,59,0,0,0,0,0,103,4,53],[0,0,0,1,5,80,0,57,0,0,0,0,6,69,0,75,0,0,5,99,0,0,65,61,0,0,0,31,5,32,1,144],[0,0,5,122,0,0,97,61,0,0,0,5,4,64,2,16,0,0,0,0,3,67,3,79,0,0,0,0,4,65,0,25],[0,0,0,3,5,80,2,16,0,0,0,0,6,4,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47],[0,0,0,0,3,3,4,59,0,0,1,0,5,80,0,137,0,0,0,0,3,83,2,47,0,0,0,0,3,83,1,207],[0,0,0,0,3,99,1,159,0,0,0,0,0,52,4,53,0,0,0,0,1,18,0,25,0,0,0,0,0,1,4,53],[0,0,0,36,1,160,0,57,0,0,0,4,3,0,0,41,0,0,0,0,0,49,4,53,0,0,0,0,1,0,4,20],[0,0,0,11,3,0,0,41,0,0,0,4,3,48,0,140,0,0,5,167,0,0,97,61,0,0,0,31,2,32,0,57],[0,0,0,32,3,0,0,138,0,0,0,0,2,50,1,111,0,0,5,56,3,32,0,156,0,0,5,56,2,0,128,65],[0,0,4,244,3,160,0,156,0,0,4,244,4,0,0,65,0,9,0,0,0,10,0,29,0,0,0,0,3,4,0,25],[0,0,0,0,3,10,64,25,0,0,0,64,3,48,2,16,0,0,0,96,2,32,2,16,0,0,0,0,2,50,1,159],[0,0,4,244,3,16,0,156,0,0,0,0,1,4,128,25,0,0,0,192,1,16,2,16,0,0,0,0,1,18,1,159],[0,0,5,57,1,16,0,65,0,0,0,6,3,0,0,41,0,0,0,0,2,3,0,75,0,0,5,158,0,0,97,61],[0,0,5,39,1,16,1,199,0,0,128,9,2,0,0,57,0,0,0,11,4,0,0,41,0,0,0,0,5,0,0,25],[19,201,19,180,0,0,4,15,0,0,5,160,0,0,1,61,0,0,0,11,2,0,0,41,19,201,19,180,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,0,8,13,0,0,41,0,0,0,7,14,0,0,41,0,0,5,8,8,0,0,65],[0,0,0,10,9,0,0,41,0,0,0,9,10,0,0,41,0,0,7,170,0,0,97,61,0,0,5,7,1,160,0,156],[0,0,3,211,0,0,33,61,0,0,0,64,0,160,4,63,0,0,0,1,9,144,0,57,0,0,0,0,1,217,0,75],[0,0,4,224,0,0,65,61,0,0,0,205,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143],[0,0,0,5,5,48,2,114,0,0,5,187,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,5,179,0,0,65,61,0,0,0,0,6,4,0,75],[0,0,5,202,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25],[0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,3,253,0,0,1,61,0,0,0,64,2,0,4,61],[0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,5,216,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,5,208,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,5,231,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,3,253,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,5,245,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,5,237,0,0,65,61,0,0,0,0,6,4,0,75,0,0,3,253,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,3,253,0,0,1,61,0,0,5,10,3,0,0,65,0,0,0,0,0,49,4,53,0,0,0,132,3,32,1,191],[0,0,0,32,4,0,0,57,0,0,0,0,0,67,4,53,0,0,0,228,3,32,0,57,0,0,5,35,4,0,0,65],[0,0,0,0,0,67,4,53,0,0,0,196,3,32,0,57,0,0,5,36,4,0,0,65,0,0,0,0,0,67,4,53],[0,0,0,164,2,32,0,57,0,0,0,56,3,0,0,57,0,0,0,0,0,50,4,53,0,0,0,64,1,16,2,16],[0,0,5,37,1,16,1,199,0,0,19,203,0,1,4,48,0,0,5,10,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,69,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,5,59,1,0,0,65,0,0,0,196,0,16,4,63,0,0,5,60,1,0,0,65,0,0,0,228,0,16,4,63],[0,0,5,61,1,0,0,65,0,0,1,4,0,16,4,63,0,0,5,54,1,0,0,65,0,0,19,203,0,1,4,48],[0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,6,49,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,6,41,0,0,65,61,0,0,0,0,6,4,0,75,0,0,6,64,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,3,253,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114],[0,0,6,78,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,6,70,0,0,65,61,0,0,0,0,6,4,0,75,0,0,6,93,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,3,253,0,0,1,61,0,0,0,64,1,0,4,61,0,0,0,132,2,16,0,57],[0,0,5,45,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,100,2,16,0,57,0,0,5,46,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,68,2,16,0,57,0,0,5,47,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,67,3,0,0,57,0,0,0,0,0,50,4,53,0,0,5,10,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,4,244,2,0,0,65,0,0,4,244,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16],[0,0,5,48,1,16,1,199,0,0,19,203,0,1,4,48,0,0,0,192,2,16,0,57,0,0,0,64,0,32,4,63],[0,0,0,5,2,0,0,41,0,0,0,0,0,2,4,53,0,0,0,160,1,16,0,57,0,4,0,0,0,1,0,29],[0,0,0,0,0,1,4,53,0,0,0,7,1,0,0,41,0,0,0,32,1,16,0,57,0,3,0,0,0,1,0,29],[0,0,0,1,1,16,3,103,0,0,0,0,1,1,4,59,0,7,0,0,0,1,0,29,0,0,5,9,1,16,0,156],[0,0,7,102,0,0,33,61,0,0,0,7,1,0,0,41,0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,5,15,1,16,1,199,0,0,128,16,2,0,0,57,19,201,19,185,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,7,102,0,0,97,61,0,0,0,5,2,0,0,41,0,0,0,0,2,2,4,51],[0,0,0,1,3,32,0,140,0,0,4,25,0,0,33,61,0,0,0,0,1,1,4,59,0,0,0,0,3,1,4,26],[0,0,1,0,4,0,0,138,0,0,0,0,3,67,1,111,0,0,0,0,2,35,1,159,0,0,0,0,0,33,4,27],[0,0,0,4,3,0,0,41,0,0,0,0,3,3,4,51,0,0,0,1,4,48,0,140,0,0,4,25,0,0,33,61],[0,0,5,16,4,0,0,65,0,0,0,0,2,66,1,111,0,0,0,8,3,48,2,16,0,0,255,0,3,48,1,143],[0,0,0,0,2,35,1,159,0,0,0,0,0,33,4,27,0,0,0,3,1,0,0,41,0,0,0,96,2,16,0,57],[0,0,0,1,1,0,3,103,0,0,0,0,3,33,3,79,0,0,0,0,3,3,4,59,0,0,0,9,4,0,0,41],[0,0,0,35,4,64,0,138,0,0,5,8,5,0,0,65,0,0,0,0,6,67,0,75,0,0,0,0,6,0,0,25],[0,0,0,0,6,5,128,25,0,0,5,8,4,64,1,151,0,0,5,8,7,48,1,151,0,0,0,0,8,71,0,75],[0,0,0,0,5,0,128,25,0,0,0,0,4,71,1,63,0,0,5,8,4,64,0,156,0,0,0,0,5,6,192,25],[0,0,0,0,4,5,0,75,0,0,7,102,0,0,193,61,0,0,0,10,3,48,0,41,0,0,0,4,4,48,0,57],[0,0,0,0,4,65,3,79,0,0,0,0,4,4,4,59,0,10,0,0,0,4,0,29,0,0,5,7,4,64,0,156],[0,0,7,102,0,0,33,61,0,0,0,10,4,0,0,41,0,0,0,0,4,64,0,121,0,0,0,36,6,48,0,57],[0,0,5,8,3,0,0,65,0,0,0,0,5,70,0,75,0,0,0,0,5,0,0,25,0,0,0,0,5,3,32,25],[0,0,5,8,4,64,1,151,0,9,0,0,0,6,0,29,0,0,5,8,6,96,1,151,0,0,0,0,7,70,0,75],[0,0,0,0,3,0,128,25,0,0,0,0,4,70,1,63,0,0,5,8,4,64,0,156,0,0,0,0,3,5,192,25],[0,0,0,0,3,3,0,75,0,0,7,102,0,0,193,61,0,0,0,64,2,32,0,138,0,0,0,0,1,33,3,79],[0,0,0,0,1,1,4,59,0,0,0,0,2,1,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,192,57],[0,0,0,0,2,33,0,75,0,0,7,102,0,0,193,61,0,0,0,0,2,0,4,22,0,5,0,0,0,2,0,29],[0,0,0,0,1,1,0,75,0,0,7,202,0,0,193,61,0,0,0,5,1,0,0,107,0,0,8,15,0,0,193,61],[0,0,5,17,1,0,0,65,0,0,0,0,0,16,4,57,0,0,128,2,2,0,0,57,0,0,0,4,0,32,4,67],[0,0,4,244,1,0,0,65,0,0,0,0,3,0,4,20,0,0,4,244,4,48,0,156,0,0,0,0,3,1,128,25],[0,0,0,192,1,48,2,16,0,0,5,18,1,16,1,199,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,9,208,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,7,102,0,0,97,61],[0,0,0,64,4,0,4,61,0,0,0,36,1,64,0,57,0,0,0,6,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,5,38,1,0,0,65,0,0,0,0,0,20,4,53,0,0,0,4,1,64,0,57,0,0,0,7,2,0,0,41],[0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156,0,11,0,0,0,4,0,29,0,0,0,0,1,4,64,25],[0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,24,1,16,1,199],[0,0,128,2,2,0,0,57,19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144,0,0,8,117,0,0,97,61],[0,0,0,11,1,0,0,41,0,0,5,7,1,16,0,156,0,0,3,211,0,0,33,61,0,0,0,11,1,0,0,41],[0,0,0,64,0,16,4,63,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,39,1,16,1,199,0,0,128,13,2,0,0,57],[0,0,0,4,3,0,0,57,0,0,5,40,4,0,0,65,0,0,0,8,5,0,0,41,0,0,0,6,6,0,0,41],[0,0,0,7,7,0,0,41,0,0,0,202,0,0,1,61,0,0,0,0,0,19,4,53,0,0,4,244,1,0,0,65],[0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,5,66,1,16,1,199],[0,0,19,202,0,1,4,46,0,0,0,64,4,0,4,61,0,10,0,0,0,4,0,29,0,0,5,64,1,0,0,65],[0,0,0,0,0,20,4,53,0,0,0,4,1,64,0,57,0,0,0,11,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,4,244,3,64,0,156,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,5,31,1,16,1,199,0,0,128,2,2,0,0,57,19,201,19,185,0,0,4,15],[0,0,0,10,10,0,0,41,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151],[0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143],[0,0,0,5,6,64,2,114,0,0,7,71,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16],[0,0,0,0,9,138,0,25,0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53],[0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,7,63,0,0,65,61,0,0,0,0,9,10,0,25],[0,0,0,0,7,5,0,75,0,0,7,87,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,6,105,0,25,0,0,0,3,5,80,2,16,0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207],[0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144],[0,0,7,136,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,2,16,1,143,0,0,0,0,1,146,0,25],[0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,5,7,4,16,0,156],[0,0,3,211,0,0,33,61,0,0,0,1,2,32,1,144,0,0,3,211,0,0,193,61,0,0,0,64,0,16,4,63],[0,0,0,32,1,48,0,140,0,0,7,165,0,0,129,61,0,0,0,0,1,0,0,25,0,0,19,203,0,1,4,48],[0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,31,4,48,1,143],[0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,7,120,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,7,112,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,7,135,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,3,253,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,7,149,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,7,141,0,0,65,61,0,0,0,0,6,4,0,75,0,0,7,164,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,3,253,0,0,1,61,0,0,0,0,1,9,4,51,0,0,0,0,1,1,0,75,0,0,0,0,1,0,0,25],[0,0,0,1,1,0,96,57,0,0,2,238,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,0,31,4,48,1,143,0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114],[0,0,7,186,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,7,178,0,0,65,61,0,0,0,0,6,4,0,75,0,0,7,201,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,3,253,0,0,1,61,0,0,0,5,1,0,0,107,0,0,8,34,0,0,193,61],[0,0,5,17,1,0,0,65,0,0,0,0,0,16,4,57,0,0,128,2,2,0,0,57,0,0,0,4,0,32,4,67],[0,0,4,244,1,0,0,65,0,0,0,0,3,0,4,20,0,0,4,244,4,48,0,156,0,0,0,0,3,1,128,25],[0,0,0,192,1,48,2,16,0,0,5,18,1,16,1,199,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,9,208,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,7,102,0,0,97,61],[0,0,0,64,4,0,4,61,0,0,5,21,1,0,0,65,0,0,0,0,0,20,4,53,0,0,0,4,2,64,0,57],[0,0,0,7,1,0,0,41,0,4,0,0,0,2,0,29,0,0,0,0,0,18,4,53,0,0,0,6,1,0,0,41],[0,0,5,22,1,16,1,151,0,0,5,23,1,16,1,199,0,0,0,36,2,64,0,57,0,3,0,0,0,2,0,29],[0,0,0,0,0,18,4,53,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156,0,11,0,0,0,4,0,29,0,0,0,0,1,4,64,25],[0,2,0,64,0,16,2,24,0,0,0,192,1,32,2,16,0,0,0,2,1,16,1,175,0,0,5,24,1,16,1,199],[0,0,128,2,2,0,0,57,0,1,0,0,0,2,0,29,19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,8,85,0,0,97,61,0,0,0,11,1,0,0,41,0,0,5,7,1,16,0,156,0,0,3,211,0,0,33,61],[0,0,0,11,1,0,0,41,0,0,0,64,0,16,4,63,0,0,0,5,1,0,0,107,0,0,8,3,0,0,97,61],[0,0,0,0,1,0,4,22,0,0,5,25,1,16,1,151,0,0,0,0,0,1,4,23,0,0,0,0,1,0,4,20],[0,0,0,9,3,0,0,41,0,0,0,10,2,48,0,42,0,0,4,244,4,48,1,151,0,0,8,11,0,0,65,61],[0,0,0,0,3,0,0,49,0,0,0,0,5,35,0,75,0,0,8,181,0,0,129,61,0,0,5,58,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57,0,0,4,28,0,0,1,61,0,0,0,64,1,0,4,61],[0,0,0,100,2,16,0,57,0,0,5,35,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,68,2,16,0,57],[0,0,5,36,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,56,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,5,10,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57],[0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53,0,0,4,244,2,0,0,65,0,0,4,244,3,16,0,156],[0,0,0,0,1,2,128,25,0,0,6,19,0,0,1,61,0,0,5,17,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,128,10,1,0,0,57,0,0,0,4,0,16,4,67,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,18,1,16,1,199],[0,0,128,2,2,0,0,57,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,9,208,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,7,102,0,0,97,61,0,0,0,64,4,0,4,61],[0,0,5,19,1,0,0,65,0,0,0,0,0,20,4,53,0,0,0,68,1,64,0,57,0,0,0,0,2,0,4,22],[0,0,0,0,0,33,4,53,0,0,0,36,1,64,0,57,0,0,0,7,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,0,11,1,0,0,41,0,0,5,9,1,16,1,151,0,0,0,4,2,64,0,57,0,0,0,0,0,18,4,53],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,4,244,3,64,0,156,0,11,0,0,0,4,0,29,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,20,1,16,1,199,0,0,128,10,2,0,0,57],[19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144,0,0,8,149,0,0,97,61,0,0,0,11,1,0,0,41],[0,0,5,7,1,16,0,156,0,0,3,211,0,0,33,61,0,0,0,11,1,0,0,41,0,0,0,64,0,16,4,63],[0,0,7,204,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,31,4,48,1,143,0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,8,101,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,8,93,0,0,65,61,0,0,0,0,6,4,0,75,0,0,8,116,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,3,253,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,31,4,48,1,143,0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,8,133,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,8,125,0,0,65,61,0,0,0,0,6,4,0,75,0,0,8,148,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,3,253,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,31,4,48,1,143,0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,8,165,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,8,157,0,0,65,61,0,0,0,0,6,4,0,75,0,0,8,180,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,3,253,0,0,1,61,0,0,0,1,4,64,3,103,0,0,5,26,5,16,0,156,0,0,8,199,0,0,65,61],[0,0,5,10,1,0,0,65,0,0,0,11,2,0,0,41,0,0,0,0,0,18,4,53,0,0,0,32,1,0,0,57],[0,0,0,4,3,0,0,41,0,0,0,0,0,19,4,53,0,0,0,8,1,0,0,57,0,0,0,3,3,0,0,41],[0,0,0,0,0,19,4,53,0,0,0,68,1,32,0,57,0,0,5,34,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,2,1,0,0,41,0,0,5,20,1,16,1,199,0,0,19,203,0,1,4,48,0,0,0,0,2,35,0,73],[0,0,4,244,2,32,1,151,0,0,0,0,2,36,3,223,0,0,0,192,1,16,2,16,0,0,5,27,1,16,1,151],[0,0,5,28,1,16,1,199,0,0,0,0,1,18,3,175,0,0,0,7,2,0,0,41,0,0,0,8,13,0,0,41],[19,201,19,195,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151],[0,0,0,1,2,32,1,144,0,0,9,209,0,0,97,61,0,0,0,63,2,48,0,57,0,0,5,29,2,32,1,151],[0,0,0,64,4,0,4,61,0,0,0,0,2,36,0,25,0,11,0,0,0,4,0,29,0,0,0,0,4,66,0,75],[0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57,0,0,5,7,5,32,0,156,0,0,3,211,0,0,33,61],[0,0,0,1,4,64,1,144,0,0,3,211,0,0,193,61,0,0,0,64,0,32,4,63,0,0,0,11,2,0,0,41],[0,0,0,0,8,50,4,54,0,0,0,31,2,48,0,57,0,0,0,5,2,32,2,114,0,0,8,243,0,0,97,61],[0,0,0,0,4,0,0,49,0,0,0,1,4,64,3,103,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16],[0,0,0,0,7,104,0,25,0,0,0,0,6,100,3,79,0,0,0,0,6,6,4,59,0,0,0,0,0,103,4,53],[0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75,0,0,8,235,0,0,65,61,0,9,0,0,0,8,0,29],[0,0,0,0,2,0,0,75,0,0,8,246,0,0,97,61,0,0,0,31,2,48,1,143,0,0,0,5,3,48,2,114],[0,0,0,9,7,0,0,41,0,0,9,3,0,0,97,61,0,0,0,0,4,0,0,25,0,0,0,5,5,64,2,16],[0,0,0,0,6,87,0,25,0,0,0,0,5,81,3,79,0,0,0,0,5,5,4,59,0,0,0,0,0,86,4,53],[0,0,0,1,4,64,0,57,0,0,0,0,5,52,0,75,0,0,8,251,0,0,65,61,0,0,0,0,4,2,0,75],[0,0,9,18,0,0,97,61,0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79,0,0,0,9,3,48,0,41],[0,0,0,3,2,32,2,16,0,0,0,0,4,3,4,51,0,0,0,0,4,36,1,207,0,0,0,0,4,36,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,2,32,0,137,0,0,0,0,1,33,2,47,0,0,0,0,1,33,1,207],[0,0,0,0,1,65,1,159,0,0,0,0,0,19,4,53,0,0,5,17,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,0,1,2,0,0,41,0,0,0,4,0,32,4,67,0,0,4,244,1,0,0,65,0,0,0,0,4,0,4,20],[0,0,4,244,3,64,0,156,0,0,0,0,4,1,128,25,0,0,0,192,1,64,2,16,0,0,5,18,1,16,1,199],[19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,9,208,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,1,1,0,75,0,0,7,102,0,0,97,61,0,0,0,64,4,0,4,61,0,0,5,30,1,0,0,65],[0,0,0,0,0,20,4,53,0,0,0,4,1,64,0,57,0,0,0,7,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,4,244,3,64,0,156,0,10,0,0,0,4,0,29,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,31,1,16,1,199,0,0,128,2,2,0,0,57],[19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144,0,0,9,236,0,0,97,61,0,0,0,10,1,0,0,41],[0,0,5,7,1,16,0,156,0,0,3,211,0,0,33,61,0,0,0,10,1,0,0,41,0,0,0,64,0,16,4,63],[0,0,0,11,1,0,0,41,0,0,0,0,1,1,4,51,0,0,5,8,2,0,0,65,0,0,0,32,3,16,0,140],[0,0,0,0,3,0,0,25,0,0,0,0,3,2,64,25,0,0,5,8,4,16,1,151,0,0,0,0,5,4,0,75],[0,0,0,0,2,0,160,25,0,0,5,8,4,64,0,156,0,0,0,0,2,3,192,25,0,0,0,0,2,2,0,75],[0,0,7,102,0,0,193,61,0,0,0,9,2,0,0,41,0,0,0,0,2,2,4,51,0,0,5,7,3,32,0,156],[0,0,7,102,0,0,33,61,0,0,0,9,1,16,0,41,0,0,0,9,2,32,0,41,0,0,0,31,3,32,0,57],[0,0,5,8,4,0,0,65,0,0,0,0,5,19,0,75,0,0,0,0,5,0,0,25,0,0,0,0,5,4,128,25],[0,0,5,8,3,48,1,151,0,0,5,8,6,16,1,151,0,0,0,0,7,99,0,75,0,0,0,0,4,0,128,25],[0,0,0,0,3,99,1,63,0,0,5,8,3,48,0,156,0,0,0,0,4,5,192,25,0,0,0,0,3,4,0,75],[0,0,7,102,0,0,193,61,0,0,0,0,35,2,4,52,0,0,5,7,4,48,0,156,0,0,3,211,0,0,33,61],[0,0,0,5,4,48,2,16,0,0,0,63,4,64,0,57,0,0,0,32,5,0,0,138,0,0,0,0,4,84,1,111],[0,0,0,10,4,64,0,41,0,0,5,7,5,64,0,156,0,0,3,211,0,0,33,61,0,0,0,64,0,64,4,63],[0,0,0,10,4,0,0,41,0,0,0,0,0,52,4,53,0,0,0,6,3,48,2,16,0,0,0,0,3,35,0,25],[0,0,0,0,4,19,0,75,0,0,7,102,0,0,33,61,0,0,0,0,4,50,0,75,0,0,9,140,0,0,129,61],[0,0,5,8,4,0,0,65,0,0,0,10,5,0,0,41,0,0,0,0,6,33,0,73,0,0,0,64,7,96,0,140],[0,0,0,0,7,0,0,25,0,0,0,0,7,4,64,25,0,0,5,8,6,96,1,151,0,0,0,0,8,6,0,75],[0,0,0,0,8,0,0,25,0,0,0,0,8,4,32,25,0,0,5,8,6,96,0,156,0,0,0,0,8,7,192,25],[0,0,0,0,6,8,0,75,0,0,7,102,0,0,193,61,0,0,0,64,6,0,4,61,0,0,5,32,7,96,0,156],[0,0,3,211,0,0,33,61,0,0,0,32,5,80,0,57,0,0,0,64,7,96,0,57,0,0,0,64,0,112,4,63],[0,0,0,0,135,2,4,52,0,0,0,0,7,118,4,54,0,0,0,0,8,8,4,51,0,0,0,0,0,135,4,53],[0,0,0,0,0,101,4,53,0,0,0,64,2,32,0,57,0,0,0,0,6,50,0,75,0,0,9,114,0,0,65,61],[0,0,5,17,1,0,0,65,0,0,0,0,0,16,4,57,0,0,128,5,1,0,0,57,0,0,0,4,0,16,4,67],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,5,18,1,16,1,199,0,0,128,2,2,0,0,57,19,201,19,185,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,9,208,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75],[0,0,7,102,0,0,97,61,0,0,0,64,3,0,4,61,0,0,0,36,1,48,0,57,0,0,0,64,2,0,0,57],[0,0,0,0,0,33,4,53,0,0,5,33,1,0,0,65,0,0,0,0,0,19,4,53,0,0,0,4,1,48,0,57],[0,0,0,7,2,0,0,41,0,0,0,0,0,33,4,53,0,0,0,10,1,0,0,41,0,0,0,0,1,1,4,51],[0,0,0,68,2,48,0,57,0,0,0,0,0,18,4,53,0,11,0,0,0,3,0,29,0,0,0,100,2,48,0,57],[0,0,0,0,3,1,0,75,0,0,9,187,0,0,97,61,0,0,0,0,3,0,0,25,0,0,0,10,4,0,0,41],[0,0,0,32,4,64,0,57,0,10,0,0,0,4,0,29,0,0,0,0,4,4,4,51,0,0,0,0,84,4,4,52],[0,0,0,0,4,66,4,54,0,0,0,0,5,5,4,51,0,0,0,0,0,84,4,53,0,0,0,64,2,32,0,57],[0,0,0,1,3,48,0,57,0,0,0,0,4,19,0,75,0,0,9,175,0,0,65,61,0,0,0,11,4,0,0,41],[0,0,0,0,1,66,0,73,0,0,4,244,2,0,0,65,0,0,4,244,3,64,0,156,0,0,0,0,3,2,0,25],[0,0,0,0,3,4,64,25,0,0,0,64,3,48,2,16,0,0,4,244,4,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,96,1,16,2,16,0,0,0,0,1,49,1,159,0,0,0,0,3,0,4,20,0,0,4,244,4,48,0,156],[0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16,0,0,0,0,1,33,1,159,0,0,128,5,2,0,0,57],[19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144,0,0,10,12,0,0,97,61,0,0,7,8,0,0,1,61],[0,0,0,0,0,1,4,47,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114,0,0,9,220,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75,0,0,9,213,0,0,65,61],[0,0,0,0,5,4,0,75,0,0,9,234,0,0,97,61,0,0,0,3,4,64,2,16,0,0,0,5,2,32,2,16],[0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47,0,0,0,0,1,33,3,79],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16,0,0,19,203,0,1,4,48],[0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,31,4,48,1,143],[0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,9,252,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,9,244,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,10,11,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,3,253,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,31,4,48,1,143],[0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,10,28,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,10,20,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,10,43,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,3,253,0,0,1,61],[0,0,0,31,3,16,0,57,0,0,5,8,4,0,0,65,0,0,0,0,5,35,0,75,0,0,0,0,5,0,0,25],[0,0,0,0,5,4,64,25,0,0,5,8,6,32,1,151,0,0,5,8,3,48,1,151,0,0,0,0,7,99,0,75],[0,0,0,0,4,0,160,25,0,0,0,0,3,99,1,63,0,0,5,8,3,48,0,156,0,0,0,0,4,5,192,25],[0,0,0,0,3,4,0,75,0,0,10,68,0,0,97,61,0,0,0,1,3,16,3,103,0,0,0,0,3,3,4,59],[0,0,5,7,4,48,0,156,0,0,10,68,0,0,33,61,0,0,0,32,1,16,0,57,0,0,0,0,4,49,0,25],[0,0,0,0,2,36,0,75,0,0,10,68,0,0,33,61,0,0,0,0,2,3,0,25,0,0,0,0,0,1,4,45],[0,0,0,0,1,0,0,25,0,0,19,203,0,1,4,48,0,3,0,0,0,0,0,2,0,0,0,0,7,0,4,20],[0,0,0,0,8,69,0,25,0,0,0,0,5,88,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57],[0,0,4,244,4,64,1,151,0,0,0,1,5,80,1,144,0,0,10,206,0,0,193,61,0,0,0,0,6,0,0,49],[0,0,0,0,5,134,0,75,0,0,10,206,0,0,65,61,0,2,0,0,0,2,0,29,0,3,0,0,0,1,0,29],[0,1,0,0,0,3,0,29,0,0,0,1,4,64,3,103,0,0,5,26,5,112,0,156,0,0,10,216,0,0,129,61],[0,0,0,0,2,134,0,73,0,0,4,244,2,32,1,151,0,0,0,0,2,36,3,223,0,0,0,192,1,112,2,16],[0,0,5,27,1,16,1,151,0,0,5,71,1,16,1,199,0,0,0,0,1,18,3,175,0,0,128,16,2,0,0,57],[19,201,19,190,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151],[0,0,0,1,2,32,1,144,0,0,10,223,0,0,97,61,0,0,0,63,2,48,0,57,0,0,5,29,4,32,1,151],[0,0,0,64,2,0,4,61,0,0,0,0,4,66,0,25,0,0,0,0,5,36,0,75,0,0,0,0,5,0,0,25],[0,0,0,1,5,0,64,57,0,0,5,7,6,64,0,156,0,0,10,210,0,0,33,61,0,0,0,1,5,80,1,144],[0,0,10,210,0,0,193,61,0,0,0,64,0,64,4,63,0,0,0,0,4,50,4,54,0,0,0,31,5,48,0,57],[0,0,0,5,5,80,2,114,0,0,10,129,0,0,97,61,0,0,0,0,6,0,0,49,0,0,0,1,6,96,3,103],[0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,132,0,25,0,0,0,0,8,134,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,87,0,75],[0,0,10,121,0,0,65,61,0,0,0,0,5,0,0,75,0,0,10,131,0,0,97,61,0,0,0,31,5,48,1,143],[0,0,0,5,3,48,2,114,0,0,10,143,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,116,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,54,0,75,0,0,10,135,0,0,65,61,0,0,0,0,6,5,0,75],[0,0,10,158,0,0,97,61,0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79,0,0,0,0,3,52,0,25],[0,0,0,3,5,80,2,16,0,0,0,0,6,3,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,5,80,0,137,0,0,0,0,1,81,2,47,0,0,0,0,1,81,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,19,4,53,0,0,0,64,1,0,4,61,0,0,0,0,2,2,4,51],[0,0,0,32,2,32,0,140,0,0,0,3,5,0,0,41,0,0,0,2,6,0,0,41,0,0,10,250,0,0,193,61],[0,0,0,0,2,4,4,51,0,0,0,160,3,16,0,57,0,0,0,0,0,35,4,53,0,0,0,128,2,16,0,57],[0,0,0,0,0,98,4,53,0,0,0,96,2,16,0,57,0,0,0,1,3,0,0,41,0,0,0,0,0,50,4,53],[0,0,5,9,2,80,1,151,0,0,0,64,3,16,0,57,0,0,0,0,0,35,4,53,0,0,0,32,2,16,0,57],[0,0,5,73,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,160,3,0,0,57,0,0,0,0,0,49,4,53],[0,0,5,74,3,16,0,156,0,0,10,210,0,0,33,61,0,0,0,192,3,16,0,57,0,0,0,64,0,48,4,63],[0,0,4,244,3,0,0,65,0,0,4,244,4,32,0,156,0,0,0,0,2,3,128,25,0,0,0,64,2,32,2,16],[0,0,0,0,1,1,4,51,0,0,4,244,4,16,0,156,0,0,0,0,1,3,128,25,0,0,0,96,1,16,2,16],[0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20,0,0,4,244,4,32,0,156,0,0,0,0,2,3,128,25],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,39,1,16,1,199,0,0,128,16,2,0,0,57],[19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,11,11,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,5,9,1,16,1,151,0,0,0,0,0,1,4,45,0,0,5,58,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,17,1,0,0,57,0,0,10,213,0,0,1,61,0,0,5,58,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,65,1,0,0,57,0,0,0,4,0,16,4,63,0,0,5,31,1,0,0,65,0,0,19,203,0,1,4,48],[0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,5,34,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,8,3,0,0,57,0,0,10,255,0,0,1,61,0,0,0,31,4,48,1,143],[0,0,0,5,2,48,2,114,0,0,10,234,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16],[0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57],[0,0,0,0,6,37,0,75,0,0,10,227,0,0,65,61,0,0,0,0,5,4,0,75,0,0,10,248,0,0,97,61],[0,0,0,3,4,64,2,16,0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207],[0,0,0,0,5,69,2,47,0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53],[0,0,0,96,1,48,2,16,0,0,19,203,0,1,4,48,0,0,0,68,2,16,0,57,0,0,5,72,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,31,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,5,10,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,4,244,2,0,0,65,0,0,4,244,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,64,1,16,2,16,0,0,5,20,1,16,1,199,0,0,19,203,0,1,4,48,0,0,0,0,1,0,0,25],[0,0,19,203,0,1,4,48,0,0,0,64,3,0,4,61,0,0,0,96,4,48,0,57,0,0,0,0,0,36,4,53],[0,0,5,9,1,16,1,151,0,0,0,64,2,48,0,57,0,0,0,0,0,18,4,53,0,0,0,96,1,0,0,57],[0,0,0,0,1,19,4,54,0,0,5,75,2,0,0,65,0,0,0,0,0,33,4,53,0,0,5,76,2,48,0,156],[0,0,11,49,0,0,129,61,0,0,0,128,2,48,0,57,0,0,0,64,0,32,4,63,0,0,4,244,2,0,0,65],[0,0,4,244,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,0,0,3,3,4,51],[0,0,4,244,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,96,3,48,2,16,0,0,0,0,1,19,1,159],[0,0,0,0,3,0,4,20,0,0,4,244,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16],[0,0,0,0,1,18,1,159,0,0,5,39,1,16,1,199,0,0,128,16,2,0,0,57,19,201,19,185,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,11,55,0,0,97,61,0,0,0,0,1,1,4,59,0,0,5,9,1,16,1,151],[0,0,0,0,0,1,4,45,0,0,5,58,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,5,31,1,0,0,65,0,0,19,203,0,1,4,48,0,0,0,0,1,0,0,25],[0,0,19,203,0,1,4,48,0,9,0,0,0,0,0,2,0,5,0,0,0,3,0,29,0,0,0,64,5,0,4,61],[0,0,0,4,3,80,0,57,0,8,0,0,0,1,0,29,0,0,0,0,1,1,0,75,0,0,14,5,0,0,97,61],[0,4,0,0,0,4,0,29,0,3,0,0,0,2,0,29,0,0,5,9,1,32,1,151,0,0,255,255,2,16,0,140],[0,0,14,21,0,0,161,61,0,0,5,77,2,0,0,65,0,0,0,0,0,37,4,53,0,9,0,0,0,1,0,29],[0,0,0,0,0,19,4,53,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,4,244,3,80,0,156,0,0,0,0,1,5,64,25,0,0,0,64,1,16,2,16],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,31,1,16,1,199,0,0,128,2,2,0,0,57],[0,6,0,0,0,2,0,29,0,7,0,0,0,5,0,29,19,201,19,185,0,0,4,15,0,0,0,7,10,0,0,41],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114],[0,0,11,106,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,138,0,25],[0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,103,0,75,0,0,11,98,0,0,65,61,0,0,0,0,7,5,0,75,0,0,11,121,0,0,97,61],[0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,0,6,106,0,25,0,0,0,3,5,80,2,16],[0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159],[0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144,0,0,14,40,0,0,97,61,0,0,0,31,1,64,0,57],[0,0,0,96,1,16,1,143,0,0,0,0,4,161,0,25,0,0,0,0,1,20,0,75,0,0,0,0,1,0,0,25],[0,0,0,1,1,0,64,57,0,0,5,7,2,64,0,156,0,0,13,246,0,0,33,61,0,0,0,1,1,16,1,144],[0,0,13,246,0,0,193,61,0,0,0,64,0,64,4,63,0,0,0,31,1,48,0,140,0,0,13,244,0,0,161,61],[0,0,0,4,1,64,0,57,0,0,0,0,2,10,4,51,0,0,0,0,2,2,0,75,0,0,14,69,0,0,193,61],[0,0,5,79,2,0,0,65,0,0,0,0,0,36,4,53,0,0,0,9,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,4,244,3,64,0,156,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,5,31,1,16,1,199,0,0,128,3,2,0,0,57,0,7,0,0,0,4,0,29],[19,201,19,185,0,0,4,15,0,0,0,7,10,0,0,41,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,4,244,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57],[0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114,0,0,11,176,0,0,97,61,0,0,0,0,7,0,0,25],[0,0,0,5,8,112,2,16,0,0,0,0,9,138,0,25,0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59],[0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,11,168,0,0,65,61],[0,0,0,0,7,5,0,75,0,0,11,191,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,6,106,0,25,0,0,0,3,5,80,2,16,0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207],[0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144],[0,0,14,79,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,1,16,1,143,0,0,0,0,4,161,0,25],[0,0,5,7,1,64,0,156,0,0,13,246,0,0,33,61,0,0,0,64,0,64,4,63,0,0,0,32,1,48,0,140],[0,0,13,244,0,0,65,61,0,0,0,4,1,64,0,57,0,0,0,0,2,10,4,51,0,0,0,0,2,2,0,75],[0,0,14,108,0,0,193,61,0,0,5,13,2,0,0,65,0,0,0,0,0,36,4,53,0,0,0,8,2,0,0,41],[0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,31,1,16,1,199,0,0,128,4,2,0,0,57],[0,7,0,0,0,4,0,29,19,201,19,185,0,0,4,15,0,0,0,7,10,0,0,41,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25],[0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114,0,0,11,241,0,0,97,61],[0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,138,0,25,0,0,0,0,8,129,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75],[0,0,11,233,0,0,65,61,0,0,0,0,7,5,0,75,0,0,12,0,0,0,97,61,0,0,0,5,6,96,2,16],[0,0,0,0,7,97,3,79,0,0,0,0,6,106,0,25,0,0,0,3,5,80,2,16,0,0,0,0,8,6,4,51],[0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137],[0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53],[0,0,0,1,2,32,1,144,0,0,14,118,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,1,16,1,143],[0,0,0,0,4,161,0,25,0,0,5,7,1,64,0,156,0,0,13,246,0,0,33,61,0,0,0,64,0,64,4,63],[0,0,0,32,1,48,0,140,0,0,13,244,0,0,65,61,0,0,0,0,1,10,4,51,0,0,0,0,1,1,0,75],[0,0,14,147,0,0,97,61,0,0,5,32,1,64,0,156,0,0,13,246,0,0,33,61,0,0,0,64,1,64,0,57],[0,0,0,64,0,16,4,63,0,0,0,0,1,4,4,54,0,2,0,0,0,1,0,29,0,0,0,0,0,1,4,53],[0,0,0,9,1,0,0,41,0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,5,15,1,16,1,199,0,0,128,16,2,0,0,57,0,7,0,0,0,4,0,29,19,201,19,185,0,0,4,15],[0,0,0,7,3,0,0,41,0,0,0,1,2,32,1,144,0,0,13,244,0,0,97,61,0,0,0,0,2,3,4,51],[0,0,0,2,3,32,0,140,0,0,13,253,0,0,129,61,0,0,0,0,1,1,4,59,0,0,0,0,3,1,4,26],[0,0,1,0,4,0,0,138,0,0,0,0,3,67,1,111,0,0,0,0,2,35,1,159,0,0,0,0,0,33,4,27],[0,0,0,2,3,0,0,41,0,0,0,0,3,3,4,51,0,0,0,1,4,48,0,140,0,0,13,253,0,0,33,61],[0,0,5,16,4,0,0,65,0,0,0,0,2,66,1,111,0,0,0,8,3,48,2,16,0,0,255,0,3,48,1,143],[0,0,0,0,2,35,1,159,0,0,0,0,0,33,4,27,0,0,0,0,1,0,4,22,0,0,5,17,2,0,0,65],[0,0,0,0,0,32,4,57,0,0,0,0,1,1,0,75,0,0,12,159,0,0,97,61,0,0,128,10,1,0,0,57],[0,0,0,4,0,16,4,67,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,18,1,16,1,199,0,0,128,2,2,0,0,57],[0,7,0,0,0,2,0,29,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,13,252,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,13,244,0,0,97,61,0,0,0,64,4,0,4,61],[0,0,5,19,1,0,0,65,0,0,0,0,0,20,4,53,0,0,0,68,1,64,0,57,0,0,0,0,2,0,4,22],[0,0,0,0,0,33,4,53,0,0,0,36,1,64,0,57,0,0,0,9,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,0,0,1,0,4,16,0,0,5,9,1,16,1,151,0,0,0,4,2,64,0,57,0,0,0,0,0,18,4,53],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,4,244,3,64,0,156,0,2,0,0,0,4,0,29,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,20,1,16,1,199,0,0,128,10,2,0,0,57],[19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144,0,0,15,16,0,0,97,61,0,0,0,2,2,0,0,41],[0,0,5,7,1,32,0,156,0,0,13,246,0,0,33,61,0,0,0,64,0,32,4,63,0,0,5,17,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,0,7,2,0,0,41,0,0,0,4,0,32,4,67,0,0,4,244,1,0,0,65],[0,0,0,0,4,0,4,20,0,0,4,244,3,64,0,156,0,0,0,0,4,1,128,25,0,0,0,192,1,64,2,16],[0,0,5,18,1,16,1,199,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,13,252,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,13,244,0,0,97,61,0,0,0,64,4,0,4,61],[0,0,5,21,1,0,0,65,0,0,0,0,0,20,4,53,0,0,0,4,2,64,0,57,0,0,0,9,1,0,0,41],[0,2,0,0,0,2,0,29,0,0,0,0,0,18,4,53,0,0,0,8,1,0,0,41,0,0,5,22,1,16,1,151],[0,0,5,23,1,16,1,199,0,0,0,36,2,64,0,57,0,1,0,0,0,2,0,29,0,0,0,0,0,18,4,53],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,4,244,3,64,0,156,0,7,0,0,0,4,0,29,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,24,1,16,1,199,0,0,128,2,2,0,0,57],[19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144,0,0,15,48,0,0,97,61,0,0,0,7,6,0,0,41],[0,0,5,7,1,96,0,156,0,0,13,246,0,0,33,61,0,0,0,64,0,96,4,63,0,0,0,0,1,0,4,22],[0,0,5,25,1,16,1,151,0,0,0,0,0,1,4,23,0,0,12,205,0,0,1,61,0,0,0,6,2,0,0,41],[0,0,0,4,0,32,4,67,0,0,4,244,1,0,0,65,0,0,0,0,4,0,4,20,0,0,4,244,3,64,0,156],[0,0,0,0,4,1,128,25,0,0,0,192,1,64,2,16,0,0,5,18,1,16,1,199,19,201,19,185,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,13,252,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75],[0,0,13,244,0,0,97,61,0,0,0,64,4,0,4,61,0,0,5,21,1,0,0,65,0,0,0,0,0,20,4,53],[0,0,0,4,2,64,0,57,0,0,0,9,1,0,0,41,0,2,0,0,0,2,0,29,0,0,0,0,0,18,4,53],[0,0,0,8,1,0,0,41,0,0,5,22,1,16,1,151,0,0,5,23,1,16,1,199,0,0,0,36,2,64,0,57],[0,1,0,0,0,2,0,29,0,0,0,0,0,18,4,53,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156,0,7,0,0,0,4,0,29],[0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,5,24,1,16,1,199,0,0,128,2,2,0,0,57,19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,15,80,0,0,97,61,0,0,0,7,6,0,0,41,0,0,5,7,1,96,0,156,0,0,13,246,0,0,33,61],[0,0,0,64,0,96,4,63,0,0,0,0,1,0,4,20,0,0,0,5,4,0,0,41,0,0,0,4,2,64,0,41],[0,0,0,4,3,32,0,108,0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57,0,0,4,244,4,64,1,151],[0,0,0,1,3,48,1,144,0,0,14,1,0,0,193,61,0,0,0,0,3,0,0,49,0,0,0,0,5,35,0,75],[0,0,14,1,0,0,65,61,0,0,0,1,4,64,3,103,0,0,5,26,5,16,0,156,0,0,14,164,0,0,129,61],[0,0,0,0,5,0,4,17,0,0,0,0,2,35,0,73,0,0,4,244,2,32,1,151,0,0,0,0,2,36,3,223],[0,0,0,192,1,16,2,16,0,0,5,27,1,16,1,151,0,0,5,28,1,16,1,199,0,0,0,0,1,18,3,175],[0,4,0,0,0,5,0,29,0,0,5,9,13,80,1,151,0,0,0,3,2,0,0,41,19,201,19,195,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151,0,0,0,1,2,32,1,144],[0,0,14,181,0,0,97,61,0,0,0,63,2,48,0,57,0,0,5,29,2,32,1,151,0,0,0,64,6,0,4,61],[0,0,0,0,2,38,0,25,0,0,0,0,4,98,0,75,0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57],[0,0,5,7,5,32,0,156,0,0,13,246,0,0,33,61,0,0,0,1,4,64,1,144,0,0,13,246,0,0,193,61],[0,0,0,64,0,32,4,63,0,5,0,0,0,6,0,29,0,0,0,0,8,54,4,54,0,0,0,31,2,48,0,57],[0,0,0,5,2,32,2,114,0,0,13,9,0,0,97,61,0,0,0,0,4,0,0,49,0,0,0,1,4,64,3,103],[0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,104,0,25,0,0,0,0,6,100,3,79],[0,0,0,0,6,6,4,59,0,0,0,0,0,103,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75],[0,0,13,1,0,0,65,61,0,0,0,0,2,0,0,75,0,0,13,11,0,0,97,61,0,0,0,31,2,48,1,143],[0,0,0,5,3,48,2,114,0,0,13,23,0,0,97,61,0,0,0,0,4,0,0,25,0,0,0,5,5,64,2,16],[0,0,0,0,6,88,0,25,0,0,0,0,5,81,3,79,0,0,0,0,5,5,4,59,0,0,0,0,0,86,4,53],[0,0,0,1,4,64,0,57,0,0,0,0,5,52,0,75,0,0,13,15,0,0,65,61,0,0,0,0,4,2,0,75],[0,0,13,38,0,0,97,61,0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79,0,0,0,0,3,56,0,25],[0,0,0,3,2,32,2,16,0,0,0,0,4,3,4,51,0,0,0,0,4,36,1,207,0,0,0,0,4,36,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,2,32,0,137,0,0,0,0,1,33,2,47,0,0,0,0,1,33,1,207],[0,0,0,0,1,65,1,159,0,0,0,0,0,19,4,53,0,7,0,0,0,8,0,29,0,0,5,17,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,0,6,2,0,0,41,0,0,0,4,0,32,4,67,0,0,4,244,1,0,0,65],[0,0,0,0,4,0,4,20,0,0,4,244,3,64,0,156,0,0,0,0,4,1,128,25,0,0,0,192,1,64,2,16],[0,0,5,18,1,16,1,199,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,13,252,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,13,244,0,0,97,61,0,0,0,64,4,0,4,61],[0,0,5,30,1,0,0,65,0,0,0,0,0,20,4,53,0,0,0,4,1,64,0,57,0,0,0,9,2,0,0,41],[0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156,0,6,0,0,0,4,0,29,0,0,0,0,1,4,64,25],[0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,31,1,16,1,199],[0,0,128,2,2,0,0,57,19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144,0,0,14,208,0,0,97,61],[0,0,0,6,9,0,0,41,0,0,5,7,1,144,0,156,0,0,0,5,1,0,0,41,0,0,13,246,0,0,33,61],[0,0,0,64,0,144,4,63,0,0,0,0,1,1,4,51,0,0,5,8,2,0,0,65,0,0,0,32,3,16,0,140],[0,0,0,0,3,0,0,25,0,0,0,0,3,2,64,25,0,0,5,8,4,16,1,151,0,0,0,0,5,4,0,75],[0,0,0,0,2,0,160,25,0,0,5,8,4,64,0,156,0,0,0,0,2,3,192,25,0,0,0,0,2,2,0,75],[0,0,13,244,0,0,193,61,0,0,0,7,2,0,0,41,0,0,0,0,2,2,4,51,0,0,5,7,3,32,0,156],[0,0,13,244,0,0,33,61,0,0,0,7,1,16,0,41,0,0,0,7,2,32,0,41,0,0,0,31,3,32,0,57],[0,0,5,8,4,0,0,65,0,0,0,0,5,19,0,75,0,0,0,0,5,0,0,25,0,0,0,0,5,4,128,25],[0,0,5,8,3,48,1,151,0,0,5,8,6,16,1,151,0,0,0,0,7,99,0,75,0,0,0,0,4,0,128,25],[0,0,0,0,3,99,1,63,0,0,5,8,3,48,0,156,0,0,0,0,4,5,192,25,0,0,0,0,3,4,0,75],[0,0,13,244,0,0,193,61,0,0,0,0,35,2,4,52,0,0,5,7,4,48,0,156,0,0,13,246,0,0,33,61],[0,0,0,5,4,48,2,16,0,0,0,63,4,64,0,57,0,0,0,32,5,0,0,138,0,0,0,0,4,84,1,111],[0,0,0,0,4,148,0,25,0,0,5,7,5,64,0,156,0,0,13,246,0,0,33,61,0,0,0,64,0,64,4,63],[0,0,0,0,0,57,4,53,0,0,0,6,3,48,2,16,0,0,0,0,3,35,0,25,0,0,0,0,4,19,0,75],[0,0,13,244,0,0,33,61,0,0,0,0,4,50,0,75,0,0,13,159,0,0,129,61,0,0,5,8,4,0,0,65],[0,0,0,0,5,9,0,25,0,0,0,0,6,33,0,73,0,0,0,64,7,96,0,140,0,0,0,0,7,0,0,25],[0,0,0,0,7,4,64,25,0,0,5,8,6,96,1,151,0,0,0,0,8,6,0,75,0,0,0,0,8,0,0,25],[0,0,0,0,8,4,32,25,0,0,5,8,6,96,0,156,0,0,0,0,8,7,192,25,0,0,0,0,6,8,0,75],[0,0,13,244,0,0,193,61,0,0,0,64,6,0,4,61,0,0,5,32,7,96,0,156,0,0,13,246,0,0,33,61],[0,0,0,32,5,80,0,57,0,0,0,64,7,96,0,57,0,0,0,64,0,112,4,63,0,0,0,0,135,2,4,52],[0,0,0,0,7,118,4,54,0,0,0,0,8,8,4,51,0,0,0,0,0,135,4,53,0,0,0,0,0,101,4,53],[0,0,0,64,2,32,0,57,0,0,0,0,6,50,0,75,0,0,13,133,0,0,65,61,0,0,5,17,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,128,5,1,0,0,57,0,0,0,4,0,16,4,67,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,5,18,1,16,1,199,0,0,128,2,2,0,0,57,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,13,252,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,0,6,6,0,0,41],[0,0,13,244,0,0,97,61,0,0,0,64,7,0,4,61,0,0,0,36,1,112,0,57,0,0,0,64,2,0,0,57],[0,0,0,0,0,33,4,53,0,0,5,33,1,0,0,65,0,0,0,0,0,23,4,53,0,0,0,4,1,112,0,57],[0,0,0,9,2,0,0,41,0,0,0,0,0,33,4,53,0,0,0,0,1,6,4,51,0,0,0,68,2,112,0,57],[0,0,0,0,0,18,4,53,0,0,0,100,2,112,0,57,0,0,0,0,3,1,0,75,0,0,13,203,0,0,97,61],[0,0,0,0,3,0,0,25,0,0,0,32,6,96,0,57,0,0,0,0,4,6,4,51,0,0,0,0,84,4,4,52],[0,0,0,0,4,66,4,54,0,0,0,0,5,5,4,51,0,0,0,0,0,84,4,53,0,0,0,64,2,32,0,57],[0,0,0,1,3,48,0,57,0,0,0,0,4,19,0,75,0,0,13,193,0,0,65,61,0,0,0,0,1,114,0,73],[0,0,4,244,2,0,0,65,0,0,4,244,3,112,0,156,0,0,0,0,3,2,0,25,0,0,0,0,3,7,64,25],[0,0,0,64,3,48,2,16,0,0,4,244,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,96,1,16,2,16],[0,0,0,0,1,49,1,159,0,0,0,0,3,0,4,20,0,0,4,244,4,48,0,156,0,0,0,0,3,2,128,25],[0,0,0,192,2,48,2,16,0,0,0,0,1,33,1,159,0,0,128,5,2,0,0,57,0,7,0,0,0,7,0,29],[19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144,0,0,14,240,0,0,97,61,0,0,0,7,2,0,0,41],[0,0,5,7,1,32,0,156,0,0,0,0,1,2,0,25,0,0,13,246,0,0,33,61,0,0,0,64,0,16,4,63],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,5,39,1,16,1,199,0,0,128,13,2,0,0,57,0,0,0,4,3,0,0,57],[0,0,5,40,4,0,0,65,0,0,0,4,5,0,0,41,0,0,0,8,6,0,0,41,0,0,0,9,7,0,0,41],[19,201,19,180,0,0,4,15,0,0,0,1,1,32,1,144,0,0,13,244,0,0,97,61,0,0,0,0,0,1,4,45],[0,0,0,0,1,0,0,25,0,0,19,203,0,1,4,48,0,0,5,58,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,65,1,0,0,57,0,0,0,4,0,16,4,63,0,0,5,31,1,0,0,65,0,0,19,203,0,1,4,48],[0,0,0,0,0,1,4,47,0,0,5,58,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,33,1,0,0,57],[0,0,13,249,0,0,1,61,0,0,5,58,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57],[0,0,13,249,0,0,1,61,0,0,5,10,2,0,0,65,0,0,0,0,0,37,4,53,0,0,0,32,2,0,0,57],[0,0,0,0,0,35,4,53,0,0,0,68,1,80,0,57,0,0,5,83,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,36,1,80,0,57,0,0,0,27,2,0,0,57,0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65],[0,0,4,244,2,80,0,156,0,0,0,0,5,1,128,25,0,0,0,64,1,80,2,16,0,0,5,20,1,16,1,199],[0,0,19,203,0,1,4,48,0,0,5,10,2,0,0,65,0,0,0,0,0,37,4,53,0,0,0,32,2,0,0,57],[0,0,0,0,0,35,4,53,0,0,0,100,1,80,0,57,0,0,5,81,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,68,1,80,0,57,0,0,5,82,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,36,1,80,0,57],[0,0,0,40,2,0,0,57,0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65,0,0,4,244,2,80,0,156],[0,0,0,0,5,1,128,25,0,0,0,64,1,80,2,16,0,0,5,37,1,16,1,199,0,0,19,203,0,1,4,48],[0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,14,53,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,14,45,0,0,65,61,0,0,0,0,6,4,0,75,0,0,15,111,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,15,111,0,0,1,61,0,0,5,10,2,0,0,65,0,0,0,0,0,36,4,53,0,0,0,32,2,0,0,57],[0,0,0,0,0,33,4,53,0,0,0,68,1,64,0,57,0,0,5,78,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,36,1,64,0,57,0,0,0,21,2,0,0,57,0,0,14,157,0,0,1,61,0,0,0,64,2,0,4,61],[0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,14,92,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,14,84,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,14,107,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,15,111,0,0,1,61],[0,0,5,10,2,0,0,65,0,0,0,0,0,36,4,53,0,0,0,32,2,0,0,57,0,0,0,0,0,33,4,53],[0,0,0,68,1,64,0,57,0,0,5,80,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,36,1,64,0,57],[0,0,0,19,2,0,0,57,0,0,14,157,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143],[0,0,0,5,5,48,2,114,0,0,14,131,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,14,123,0,0,65,61,0,0,0,0,6,4,0,75],[0,0,14,146,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25],[0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,15,111,0,0,1,61,0,0,0,68,1,64,0,57],[0,0,5,41,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,36,1,64,0,57,0,0,0,26,2,0,0,57],[0,0,0,0,0,33,4,53,0,0,5,10,1,0,0,65,0,0,0,0,0,20,4,53,0,0,0,4,1,64,0,57],[0,0,0,32,2,0,0,57,0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65,0,0,4,244,2,64,0,156],[0,0,0,0,4,1,128,25,0,0,0,64,1,64,2,16,0,0,5,20,1,16,1,199,0,0,19,203,0,1,4,48],[0,0,5,10,1,0,0,65,0,0,0,0,0,22,4,53,0,0,0,32,1,0,0,57,0,0,0,2,2,0,0,41],[0,0,0,0,0,18,4,53,0,0,0,8,1,0,0,57,0,0,0,1,2,0,0,41,0,0,0,0,0,18,4,53],[0,0,0,68,1,96,0,57,0,0,5,34,2,0,0,65,0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65],[0,0,4,244,2,96,0,156,0,0,0,0,6,1,128,25,0,0,0,64,1,96,2,16,0,0,5,20,1,16,1,199],[0,0,19,203,0,1,4,48,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114,0,0,14,192,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75,0,0,14,185,0,0,65,61],[0,0,0,0,5,4,0,75,0,0,14,206,0,0,97,61,0,0,0,3,4,64,2,16,0,0,0,5,2,32,2,16],[0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47,0,0,0,0,1,33,3,79],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16,0,0,19,203,0,1,4,48],[0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,31,4,48,1,143],[0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,14,224,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,14,216,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,14,239,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,15,111,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,31,4,48,1,143],[0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,15,0,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,14,248,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,15,15,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,15,111,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,31,4,48,1,143],[0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,15,32,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,15,24,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,15,47,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,15,111,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,31,4,48,1,143],[0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,15,64,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,15,56,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,15,79,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,15,111,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,31,4,48,1,143],[0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,15,96,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,15,88,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,15,111,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,4,244,1,0,0,65],[0,0,4,244,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,0,96,2,48,2,16],[0,0,0,0,1,33,1,159,0,0,19,203,0,1,4,48,0,9,0,0,0,0,0,2,0,3,0,0,0,5,0,29],[0,4,0,0,0,4,0,29,0,5,0,0,0,3,0,29,0,0,0,64,4,0,4,61,0,0,0,4,3,64,0,57],[0,8,0,0,0,1,0,29,0,0,0,0,1,1,0,75,0,0,18,72,0,0,97,61,0,2,0,0,0,2,0,29],[0,0,5,9,1,32,1,151,0,0,255,255,2,16,0,140,0,0,18,82,0,0,161,61,0,0,5,77,2,0,0,65],[0,0,0,0,0,36,4,53,0,9,0,0,0,1,0,29,0,0,0,0,0,19,4,53,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156],[0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,5,31,1,16,1,199,0,0,128,2,2,0,0,57,0,6,0,0,0,2,0,29,0,7,0,0,0,4,0,29],[19,201,19,185,0,0,4,15,0,0,0,7,10,0,0,41,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,4,244,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57],[0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114,0,0,15,168,0,0,97,61,0,0,0,0,7,0,0,25],[0,0,0,5,8,112,2,16,0,0,0,0,9,138,0,25,0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59],[0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,15,160,0,0,65,61],[0,0,0,0,7,5,0,75,0,0,15,183,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,6,106,0,25,0,0,0,3,5,80,2,16,0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207],[0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144],[0,0,18,101,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,1,16,1,143,0,0,0,0,4,161,0,25],[0,0,0,0,1,20,0,75,0,0,0,0,1,0,0,25,0,0,0,1,1,0,64,57,0,0,5,7,2,64,0,156],[0,0,18,57,0,0,33,61,0,0,0,1,1,16,1,144,0,0,18,57,0,0,193,61,0,0,0,64,0,64,4,63],[0,0,0,31,1,48,0,140,0,0,18,55,0,0,161,61,0,0,0,4,1,64,0,57,0,0,0,0,2,10,4,51],[0,0,0,0,2,2,0,75,0,0,18,130,0,0,193,61,0,0,5,79,2,0,0,65,0,0,0,0,0,36,4,53],[0,0,0,9,2,0,0,41,0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156,0,0,0,0,1,4,64,25],[0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,31,1,16,1,199],[0,0,128,3,2,0,0,57,0,7,0,0,0,4,0,29,19,201,19,185,0,0,4,15,0,0,0,7,10,0,0,41],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114],[0,0,15,238,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,138,0,25],[0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,103,0,75,0,0,15,230,0,0,65,61,0,0,0,0,7,5,0,75,0,0,15,253,0,0,97,61],[0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,0,6,106,0,25,0,0,0,3,5,80,2,16],[0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159],[0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144,0,0,18,140,0,0,97,61,0,0,0,31,1,64,0,57],[0,0,0,96,1,16,1,143,0,0,0,0,4,161,0,25,0,0,5,7,1,64,0,156,0,0,18,57,0,0,33,61],[0,0,0,64,0,64,4,63,0,0,0,32,1,48,0,140,0,0,18,55,0,0,65,61,0,0,0,4,1,64,0,57],[0,0,0,0,2,10,4,51,0,0,0,0,2,2,0,75,0,0,18,169,0,0,193,61,0,0,5,13,2,0,0,65],[0,0,0,0,0,36,4,53,0,0,0,8,2,0,0,41,0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156],[0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,5,31,1,16,1,199,0,0,128,4,2,0,0,57,0,7,0,0,0,4,0,29,19,201,19,185,0,0,4,15],[0,0,0,7,10,0,0,41,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151],[0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143],[0,0,0,5,6,64,2,114,0,0,16,47,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16],[0,0,0,0,9,138,0,25,0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53],[0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,16,39,0,0,65,61,0,0,0,0,7,5,0,75],[0,0,16,62,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,0,6,106,0,25],[0,0,0,3,5,80,2,16,0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47],[0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207],[0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144,0,0,18,179,0,0,97,61],[0,0,0,31,1,64,0,57,0,0,0,96,1,16,1,143,0,0,0,0,4,161,0,25,0,0,5,7,1,64,0,156],[0,0,18,57,0,0,33,61,0,0,0,64,0,64,4,63,0,0,0,32,1,48,0,140,0,0,18,55,0,0,65,61],[0,0,0,0,1,10,4,51,0,0,0,0,1,1,0,75,0,0,18,208,0,0,97,61,0,0,5,32,1,64,0,156],[0,0,18,57,0,0,33,61,0,0,0,64,1,64,0,57,0,0,0,64,0,16,4,63,0,0,0,0,3,4,4,54],[0,0,0,0,0,3,4,53,0,0,0,5,2,0,0,41,0,0,0,2,1,32,0,140,0,0,18,64,0,0,129,61],[0,0,0,0,0,36,4,53,0,5,0,0,0,3,0,29,0,0,0,0,0,3,4,53,0,0,0,9,1,0,0,41],[0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,15,1,16,1,199],[0,0,128,16,2,0,0,57,0,7,0,0,0,4,0,29,19,201,19,185,0,0,4,15,0,0,0,7,3,0,0,41],[0,0,0,1,2,32,1,144,0,0,18,55,0,0,97,61,0,0,0,0,2,3,4,51,0,0,0,1,3,32,0,140],[0,0,0,5,5,0,0,41,0,0,18,64,0,0,33,61,0,0,0,0,1,1,4,59,0,0,0,0,3,1,4,26],[0,0,1,0,4,0,0,138,0,0,0,0,3,67,1,111,0,0,0,0,2,35,1,159,0,0,0,0,0,33,4,27],[0,0,0,0,3,5,4,51,0,0,0,1,4,48,0,140,0,0,18,64,0,0,33,61,0,0,5,16,4,0,0,65],[0,0,0,0,2,66,1,111,0,0,0,8,3,48,2,16,0,0,255,0,3,48,1,143,0,0,0,0,2,35,1,159],[0,0,0,0,0,33,4,27,0,0,0,0,1,0,4,22,0,0,5,17,2,0,0,65,0,0,0,0,0,32,4,57],[0,0,0,0,1,1,0,75,0,0,16,226,0,0,97,61,0,0,128,10,1,0,0,57,0,0,0,4,0,16,4,67],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,5,18,1,16,1,199,0,0,128,2,2,0,0,57,0,7,0,0,0,2,0,29],[19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,18,63,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,1,1,0,75,0,0,18,55,0,0,97,61,0,0,0,64,4,0,4,61,0,0,5,19,1,0,0,65],[0,0,0,0,0,20,4,53,0,0,0,68,1,64,0,57,0,0,0,0,2,0,4,22,0,0,0,0,0,33,4,53],[0,0,0,36,1,64,0,57,0,0,0,9,2,0,0,41,0,0,0,0,0,33,4,53,0,0,0,0,1,0,4,16],[0,0,5,9,1,16,1,151,0,0,0,4,2,64,0,57,0,0,0,0,0,18,4,53,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156],[0,5,0,0,0,4,0,29,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,5,20,1,16,1,199,0,0,128,10,2,0,0,57,19,201,19,180,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,19,77,0,0,97,61,0,0,0,5,2,0,0,41,0,0,5,7,1,32,0,156],[0,0,18,57,0,0,33,61,0,0,0,64,0,32,4,63,0,0,5,17,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,0,7,2,0,0,41,0,0,0,4,0,32,4,67,0,0,4,244,1,0,0,65,0,0,0,0,4,0,4,20],[0,0,4,244,3,64,0,156,0,0,0,0,4,1,128,25,0,0,0,192,1,64,2,16,0,0,5,18,1,16,1,199],[19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,18,63,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,1,1,0,75,0,0,18,55,0,0,97,61,0,0,0,64,4,0,4,61,0,0,5,21,1,0,0,65],[0,0,0,0,0,20,4,53,0,0,0,4,2,64,0,57,0,0,0,9,1,0,0,41,0,5,0,0,0,2,0,29],[0,0,0,0,0,18,4,53,0,0,0,8,1,0,0,41,0,0,5,22,1,16,1,151,0,0,5,23,1,16,1,199],[0,0,0,36,2,64,0,57,0,1,0,0,0,2,0,29,0,0,0,0,0,18,4,53,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156],[0,7,0,0,0,4,0,29,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,5,24,1,16,1,199,0,0,128,2,2,0,0,57,19,201,19,180,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,19,109,0,0,97,61,0,0,0,7,6,0,0,41,0,0,5,7,1,96,0,156],[0,0,18,57,0,0,33,61,0,0,0,64,0,96,4,63,0,0,0,0,1,0,4,22,0,0,5,25,1,16,1,151],[0,0,0,0,0,1,4,23,0,0,17,16,0,0,1,61,0,0,0,6,2,0,0,41,0,0,0,4,0,32,4,67],[0,0,4,244,1,0,0,65,0,0,0,0,4,0,4,20,0,0,4,244,3,64,0,156,0,0,0,0,4,1,128,25],[0,0,0,192,1,64,2,16,0,0,5,18,1,16,1,199,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,18,63,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,18,55,0,0,97,61],[0,0,0,64,4,0,4,61,0,0,5,21,1,0,0,65,0,0,0,0,0,20,4,53,0,0,0,4,2,64,0,57],[0,0,0,9,1,0,0,41,0,5,0,0,0,2,0,29,0,0,0,0,0,18,4,53,0,0,0,8,1,0,0,41],[0,0,5,22,1,16,1,151,0,0,5,23,1,16,1,199,0,0,0,36,2,64,0,57,0,1,0,0,0,2,0,29],[0,0,0,0,0,18,4,53,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156,0,7,0,0,0,4,0,29,0,0,0,0,1,4,64,25],[0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,24,1,16,1,199],[0,0,128,2,2,0,0,57,19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144,0,0,19,141,0,0,97,61],[0,0,0,7,6,0,0,41,0,0,5,7,1,96,0,156,0,0,18,57,0,0,33,61,0,0,0,64,0,96,4,63],[0,0,0,0,1,0,4,20,0,0,0,4,4,0,0,41,0,0,0,3,2,64,0,41,0,0,0,3,3,32,0,108],[0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57,0,0,4,244,4,64,1,151,0,0,0,1,3,48,1,144],[0,0,18,68,0,0,193,61,0,0,0,0,3,0,0,49,0,0,0,0,5,35,0,75,0,0,18,68,0,0,65,61],[0,0,0,1,4,64,3,103,0,0,5,26,5,16,0,156,0,0,18,225,0,0,129,61,0,0,0,0,5,0,4,17],[0,0,0,0,2,35,0,73,0,0,4,244,2,32,1,151,0,0,0,0,2,36,3,223,0,0,0,192,1,16,2,16],[0,0,5,27,1,16,1,151,0,0,5,28,1,16,1,199,0,0,0,0,1,18,3,175,0,4,0,0,0,5,0,29],[0,0,5,9,13,80,1,151,0,0,0,2,2,0,0,41,19,201,19,195,0,0,4,15,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151,0,0,0,1,2,32,1,144,0,0,18,242,0,0,97,61],[0,0,0,63,2,48,0,57,0,0,5,29,2,32,1,151,0,0,0,64,6,0,4,61,0,0,0,0,2,38,0,25],[0,0,0,0,4,98,0,75,0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57,0,0,5,7,5,32,0,156],[0,0,18,57,0,0,33,61,0,0,0,1,4,64,1,144,0,0,18,57,0,0,193,61,0,0,0,64,0,32,4,63],[0,5,0,0,0,6,0,29,0,0,0,0,8,54,4,54,0,0,0,31,2,48,0,57,0,0,0,5,2,32,2,114],[0,0,17,76,0,0,97,61,0,0,0,0,4,0,0,49,0,0,0,1,4,64,3,103,0,0,0,0,5,0,0,25],[0,0,0,5,6,80,2,16,0,0,0,0,7,104,0,25,0,0,0,0,6,100,3,79,0,0,0,0,6,6,4,59],[0,0,0,0,0,103,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75,0,0,17,68,0,0,65,61],[0,0,0,0,2,0,0,75,0,0,17,78,0,0,97,61,0,0,0,31,2,48,1,143,0,0,0,5,3,48,2,114],[0,0,17,90,0,0,97,61,0,0,0,0,4,0,0,25,0,0,0,5,5,64,2,16,0,0,0,0,6,88,0,25],[0,0,0,0,5,81,3,79,0,0,0,0,5,5,4,59,0,0,0,0,0,86,4,53,0,0,0,1,4,64,0,57],[0,0,0,0,5,52,0,75,0,0,17,82,0,0,65,61,0,0,0,0,4,2,0,75,0,0,17,105,0,0,97,61],[0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79,0,0,0,0,3,56,0,25,0,0,0,3,2,32,2,16],[0,0,0,0,4,3,4,51,0,0,0,0,4,36,1,207,0,0,0,0,4,36,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,2,32,0,137,0,0,0,0,1,33,2,47,0,0,0,0,1,33,1,207,0,0,0,0,1,65,1,159],[0,0,0,0,0,19,4,53,0,7,0,0,0,8,0,29,0,0,5,17,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,0,6,2,0,0,41,0,0,0,4,0,32,4,67,0,0,4,244,1,0,0,65,0,0,0,0,4,0,4,20],[0,0,4,244,3,64,0,156,0,0,0,0,4,1,128,25,0,0,0,192,1,64,2,16,0,0,5,18,1,16,1,199],[19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,18,63,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,1,1,0,75,0,0,18,55,0,0,97,61,0,0,0,64,4,0,4,61,0,0,5,30,1,0,0,65],[0,0,0,0,0,20,4,53,0,0,0,4,1,64,0,57,0,0,0,9,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,4,244,3,64,0,156,0,6,0,0,0,4,0,29,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,31,1,16,1,199,0,0,128,2,2,0,0,57],[19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144,0,0,19,13,0,0,97,61,0,0,0,6,9,0,0,41],[0,0,5,7,1,144,0,156,0,0,0,5,1,0,0,41,0,0,18,57,0,0,33,61,0,0,0,64,0,144,4,63],[0,0,0,0,1,1,4,51,0,0,5,8,2,0,0,65,0,0,0,32,3,16,0,140,0,0,0,0,3,0,0,25],[0,0,0,0,3,2,64,25,0,0,5,8,4,16,1,151,0,0,0,0,5,4,0,75,0,0,0,0,2,0,160,25],[0,0,5,8,4,64,0,156,0,0,0,0,2,3,192,25,0,0,0,0,2,2,0,75,0,0,18,55,0,0,193,61],[0,0,0,7,2,0,0,41,0,0,0,0,2,2,4,51,0,0,5,7,3,32,0,156,0,0,18,55,0,0,33,61],[0,0,0,7,1,16,0,41,0,0,0,7,2,32,0,41,0,0,0,31,3,32,0,57,0,0,5,8,4,0,0,65],[0,0,0,0,5,19,0,75,0,0,0,0,5,0,0,25,0,0,0,0,5,4,128,25,0,0,5,8,3,48,1,151],[0,0,5,8,6,16,1,151,0,0,0,0,7,99,0,75,0,0,0,0,4,0,128,25,0,0,0,0,3,99,1,63],[0,0,5,8,3,48,0,156,0,0,0,0,4,5,192,25,0,0,0,0,3,4,0,75,0,0,18,55,0,0,193,61],[0,0,0,0,35,2,4,52,0,0,5,7,4,48,0,156,0,0,18,57,0,0,33,61,0,0,0,5,4,48,2,16],[0,0,0,63,4,64,0,57,0,0,0,32,5,0,0,138,0,0,0,0,4,84,1,111,0,0,0,0,4,148,0,25],[0,0,5,7,5,64,0,156,0,0,18,57,0,0,33,61,0,0,0,64,0,64,4,63,0,0,0,0,0,57,4,53],[0,0,0,6,3,48,2,16,0,0,0,0,3,35,0,25,0,0,0,0,4,19,0,75,0,0,18,55,0,0,33,61],[0,0,0,0,4,50,0,75,0,0,17,226,0,0,129,61,0,0,5,8,4,0,0,65,0,0,0,0,5,9,0,25],[0,0,0,0,6,33,0,73,0,0,0,64,7,96,0,140,0,0,0,0,7,0,0,25,0,0,0,0,7,4,64,25],[0,0,5,8,6,96,1,151,0,0,0,0,8,6,0,75,0,0,0,0,8,0,0,25,0,0,0,0,8,4,32,25],[0,0,5,8,6,96,0,156,0,0,0,0,8,7,192,25,0,0,0,0,6,8,0,75,0,0,18,55,0,0,193,61],[0,0,0,64,6,0,4,61,0,0,5,32,7,96,0,156,0,0,18,57,0,0,33,61,0,0,0,32,5,80,0,57],[0,0,0,64,7,96,0,57,0,0,0,64,0,112,4,63,0,0,0,0,135,2,4,52,0,0,0,0,7,118,4,54],[0,0,0,0,8,8,4,51,0,0,0,0,0,135,4,53,0,0,0,0,0,101,4,53,0,0,0,64,2,32,0,57],[0,0,0,0,6,50,0,75,0,0,17,200,0,0,65,61,0,0,5,17,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,128,5,1,0,0,57,0,0,0,4,0,16,4,67,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,18,1,16,1,199],[0,0,128,2,2,0,0,57,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,18,63,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,0,6,6,0,0,41,0,0,18,55,0,0,97,61],[0,0,0,64,7,0,4,61,0,0,0,36,1,112,0,57,0,0,0,64,2,0,0,57,0,0,0,0,0,33,4,53],[0,0,5,33,1,0,0,65,0,0,0,0,0,23,4,53,0,0,0,4,1,112,0,57,0,0,0,9,2,0,0,41],[0,0,0,0,0,33,4,53,0,0,0,0,1,6,4,51,0,0,0,68,2,112,0,57,0,0,0,0,0,18,4,53],[0,0,0,100,2,112,0,57,0,0,0,0,3,1,0,75,0,0,18,14,0,0,97,61,0,0,0,0,3,0,0,25],[0,0,0,32,6,96,0,57,0,0,0,0,4,6,4,51,0,0,0,0,84,4,4,52,0,0,0,0,4,66,4,54],[0,0,0,0,5,5,4,51,0,0,0,0,0,84,4,53,0,0,0,64,2,32,0,57,0,0,0,1,3,48,0,57],[0,0,0,0,4,19,0,75,0,0,18,4,0,0,65,61,0,0,0,0,1,114,0,73,0,0,4,244,2,0,0,65],[0,0,4,244,3,112,0,156,0,0,0,0,3,2,0,25,0,0,0,0,3,7,64,25,0,0,0,64,3,48,2,16],[0,0,4,244,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,49,1,159],[0,0,0,0,3,0,4,20,0,0,4,244,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16],[0,0,0,0,1,33,1,159,0,0,128,5,2,0,0,57,0,7,0,0,0,7,0,29,19,201,19,180,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,19,45,0,0,97,61,0,0,0,7,2,0,0,41,0,0,5,7,1,32,0,156],[0,0,0,0,1,2,0,25,0,0,18,57,0,0,33,61,0,0,0,64,0,16,4,63,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,5,39,1,16,1,199,0,0,128,13,2,0,0,57,0,0,0,4,3,0,0,57,0,0,5,40,4,0,0,65],[0,0,0,4,5,0,0,41,0,0,0,8,6,0,0,41,0,0,0,9,7,0,0,41,19,201,19,180,0,0,4,15],[0,0,0,1,1,32,1,144,0,0,18,55,0,0,97,61,0,0,0,0,0,1,4,45,0,0,0,0,1,0,0,25],[0,0,19,203,0,1,4,48,0,0,5,58,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,5,31,1,0,0,65,0,0,19,203,0,1,4,48,0,0,0,0,0,1,4,47],[0,0,5,58,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,33,1,0,0,57,0,0,18,60,0,0,1,61],[0,0,5,58,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57,0,0,18,60,0,0,1,61],[0,0,5,10,2,0,0,65,0,0,0,0,0,36,4,53,0,0,0,32,2,0,0,57,0,0,0,0,0,35,4,53],[0,0,0,68,1,64,0,57,0,0,5,83,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,36,1,64,0,57],[0,0,0,27,2,0,0,57,0,0,18,218,0,0,1,61,0,0,5,10,2,0,0,65,0,0,0,0,0,36,4,53],[0,0,0,32,2,0,0,57,0,0,0,0,0,35,4,53,0,0,0,100,1,64,0,57,0,0,5,81,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,68,1,64,0,57,0,0,5,82,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,36,1,64,0,57,0,0,0,40,2,0,0,57,0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65],[0,0,4,244,2,64,0,156,0,0,0,0,4,1,128,25,0,0,0,64,1,64,2,16,0,0,5,37,1,16,1,199],[0,0,19,203,0,1,4,48,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114],[0,0,18,114,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,18,106,0,0,65,61,0,0,0,0,6,4,0,75,0,0,19,172,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,19,172,0,0,1,61,0,0,5,10,2,0,0,65,0,0,0,0,0,36,4,53],[0,0,0,32,2,0,0,57,0,0,0,0,0,33,4,53,0,0,0,68,1,64,0,57,0,0,5,78,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,36,1,64,0,57,0,0,0,21,2,0,0,57,0,0,18,218,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,18,153,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,18,145,0,0,65,61,0,0,0,0,6,4,0,75,0,0,18,168,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,19,172,0,0,1,61,0,0,5,10,2,0,0,65,0,0,0,0,0,36,4,53,0,0,0,32,2,0,0,57],[0,0,0,0,0,33,4,53,0,0,0,68,1,64,0,57,0,0,5,80,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,36,1,64,0,57,0,0,0,19,2,0,0,57,0,0,18,218,0,0,1,61,0,0,0,64,2,0,4,61],[0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,18,192,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,18,184,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,18,207,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,19,172,0,0,1,61],[0,0,0,68,1,64,0,57,0,0,5,41,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,36,1,64,0,57],[0,0,0,26,2,0,0,57,0,0,0,0,0,33,4,53,0,0,5,10,1,0,0,65,0,0,0,0,0,20,4,53],[0,0,0,4,1,64,0,57,0,0,0,32,2,0,0,57,0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65],[0,0,4,244,2,64,0,156,0,0,0,0,4,1,128,25,0,0,0,64,1,64,2,16,0,0,5,20,1,16,1,199],[0,0,19,203,0,1,4,48,0,0,5,10,1,0,0,65,0,0,0,0,0,22,4,53,0,0,0,32,1,0,0,57],[0,0,0,5,2,0,0,41,0,0,0,0,0,18,4,53,0,0,0,8,1,0,0,57,0,0,0,1,2,0,0,41],[0,0,0,0,0,18,4,53,0,0,0,68,1,96,0,57,0,0,5,34,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,4,244,1,0,0,65,0,0,4,244,2,96,0,156,0,0,0,0,6,1,128,25,0,0,0,64,1,96,2,16],[0,0,5,20,1,16,1,199,0,0,19,203,0,1,4,48,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114],[0,0,18,253,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75],[0,0,18,246,0,0,65,61,0,0,0,0,5,4,0,75,0,0,19,11,0,0,97,61,0,0,0,3,4,64,2,16],[0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47],[0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16],[0,0,19,203,0,1,4,48,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,31,4,48,1,143,0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,19,29,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,19,21,0,0,65,61,0,0,0,0,6,4,0,75,0,0,19,44,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,19,172,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,31,4,48,1,143,0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,19,61,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,19,53,0,0,65,61,0,0,0,0,6,4,0,75,0,0,19,76,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,19,172,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,31,4,48,1,143,0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,19,93,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,19,85,0,0,65,61,0,0,0,0,6,4,0,75,0,0,19,108,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,19,172,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,31,4,48,1,143,0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,19,125,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,19,117,0,0,65,61,0,0,0,0,6,4,0,75,0,0,19,140,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,19,172,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,31,4,48,1,143,0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,19,157,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,19,149,0,0,65,61,0,0,0,0,6,4,0,75,0,0,19,172,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,4,244,1,0,0,65,0,0,4,244,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16],[0,0,0,96,2,48,2,16,0,0,0,0,1,33,1,159,0,0,19,203,0,1,4,48,0,0,0,0,0,1,4,47],[0,0,19,183,0,33,4,33,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25],[0,0,0,0,0,1,4,45,0,0,19,188,0,33,4,35,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45],[0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,19,193,0,33,4,35,0,0,0,1,2,0,0,57],[0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,0,0,15,13,0,25],[0,0,19,199,0,33,4,41,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25],[0,0,0,0,0,1,4,45,0,0,19,201,0,0,4,50,0,0,19,202,0,1,4,46,0,0,19,203,0,1,4,48],[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],[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,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,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,0,0,0,0,0,156,77,83,90],[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,233,241,140,22],[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,236,249,91,137],[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,236,249,91,138],[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,243,56,95,182],[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,233,241,140,23],[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,236,128,103,199],[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,156,77,83,91],[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,187,15,214,16],[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,218,55,240,127],[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,93,56,38,255],[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,93,56,39,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,123,81,15,232],[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,132,218,31,180],[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,24,117,152,165],[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,60,218,51,81],[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,87,24,9,129],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255],[128,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,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[8,195,121,160,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],[67,97,108,108,97,98,108,101,32,111,110,108,121,32,98,121,32,115,101,108,102,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,100,0,0,0,128,0,0,0,0,0,0,0,0],[76,99,20,240,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,128,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0],[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,255],[24,6,170,24,150,187,242,101,104,232,132,167,55,75,65,224,2,80,9,98,202,186,106,21,2,58,141,144,232,80,139,131],[2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[87,153,82,252,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0],[79,30,27,224,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],[255,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,1,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,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,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[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,1,0,0,0,0],[0,0,0,0,255,255,255,255,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,1,0,1,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,255,255,255,224],[194,228,255,151,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,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,0,0,0,0,255,255,255,255,255,255,255,191],[173,126,35,46,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],[79,118,101,114,102,108,111,119,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[110,111,116,32,99,97,108,108,32,116,104,101,32,99,111,110,115,116,114,117,99,116,111,114,0,0,0,0,0,0,0,0],[84,104,101,32,118,97,108,117,101,32,109,117,115,116,32,98,101,32,122,101,114,111,32,105,102,32,119,101,32,100,111,32],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,0,0],[13,70,81,170,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],[2,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],[41,10,253,174,35,26,63,192,187,174,139,26,246,54,152,176,161,215,155,33,173,23,223,3,66,223,185,82,254,116,248,229],[84,104,101,32,99,111,100,101,32,104,97,115,104,32,105,115,32,110,111,116,32,107,110,111,119,110,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,0,0,0,1,0,0],[48,99,149,198,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[105,110,103,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],[111,109,32,115,101,113,117,101,110,116,105,97,108,32,116,111,32,97,114,98,105,116,114,97,114,121,32,111,114,100,101,114],[73,116,32,105,115,32,111,110,108,121,32,112,111,115,115,105,98,108,101,32,116,111,32,99,104,97,110,103,101,32,102,114],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,164,0,0,0,0,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[199,84,65,148,218,179,139,22,82,243,84,57,185,180,128,109,139,113,225,19,242,207,92,19,81,203,46,207,124,131,149,154],[67,97,110,32,111,110,108,121,32,98,101,32,99,97,108,108,101,100,32,98,121,32,70,79,82,67,69,95,68,69,80,76],[79,89,69,82,32,111,114,32,67,79,77,80,76,69,88,95,85,80,71,82,65,68,69,82,95,67,79,78,84,82,65,67],[84,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,164,0,0,0,128,0,0,0,0,0,0,0,0],[243,56,95,182,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,254,251],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,0,0,0,0,0,0,0,0,0,0,0,0],[78,72,123,113,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],[96,118,97,108,117,101,96,32,112,114,111,118,105,100,101,100,32,105,115,32,110,111,116,32,101,113,117,97,108,32,116,111],[32,116,104,101,32,99,111,109,98,105,110,101,100,32,96,118,97,108,117,101,96,115,32,111,102,32,100,101,112,108,111,121],[109,101,110,116,115,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],[73,110,97,112,112,114,111,112,114,105,97,116,101,32,99,97,108,108,101,114,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0],[77,226,228,104,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,192],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0],[63,182,244,241,93,221,74,117,88,140,169,52,137,74,210,205,202,178,90,80,18,226,81,94,23,131,67,61,1,40,97,26],[84,104,105,115,32,109,101,116,104,111,100,32,114,101,113,117,105,114,101,32,115,121,115,116,101,109,32,99,97,108,108,32],[102,108,97,103,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[0,0,0,1,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],[107,101,99,99,97,107,50,53,54,32,114,101,116,117,114,110,101,100,32,105,110,118,97,108,105,100,32,100,97,116,97,0],[32,32,219,169,27,48,204,0,6,24,138,247,148,194,251,48,221,133,32,219,126,44,8,139,127,199,193,3,192,12,164,148],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,63],[99,186,227,169,149,29,56,232,163,251,183,183,9,9,175,193,32,6,16,252,91,197,90,222,36,47,129,89,116,103,79,35],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,128],[224,63,225,119,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],[67,111,100,101,32,104,97,115,104,32,105,115,32,110,111,110,45,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0],[90,169,182,181,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],[65,99,99,111,117,110,116,32,105,115,32,111,99,99,117,112,105,101,100,0,0,0,0,0,0,0,0,0,0,0,0,0],[101,108,32,115,112,97,99,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[67,97,110,32,110,111,116,32,100,101,112,108,111,121,32,99,111,110,116,114,97,99,116,115,32,105,110,32,107,101,114,110],[66,121,116,101,99,111,100,101,72,97,115,104,32,99,97,110,110,111,116,32,98,101,32,122,101,114,111,0,0,0,0,0],[240,216,92,27,130,178,83,239,156,199,86,153,75,62,76,240,236,53,132,231,151,139,5,161,93,133,7,213,47,126,122,185]],"0x0000000000000000000000000000000000000007":[[0,1,0,0,0,0,0,2,0,2,0,0,0,0,0,2,0,0,0,0,0,1,3,85,0,0,0,1,2,32,1,144],[0,0,0,74,0,0,193,61,0,0,0,32,2,16,3,112,0,0,0,0,3,2,4,59,0,0,0,0,4,1,4,59],[0,0,0,201,2,64,0,156,0,0,0,12,0,0,33,61,0,0,0,202,2,48,0,156,0,0,0,15,0,0,65,61],[0,0,0,0,1,0,4,20,0,0,0,0,1,16,4,32,0,0,0,0,1,0,3,103,0,0,0,0,2,67,1,160],[0,0,0,64,1,16,3,112,0,0,0,0,6,1,4,59,0,0,0,72,0,0,97,61,0,0,0,0,1,4,0,75],[0,0,0,203,33,64,0,209,0,0,0,1,2,32,192,57,0,0,0,204,81,64,0,209,0,0,0,202,81,16,0,209],[0,0,0,0,2,82,0,25,0,0,0,205,1,32,0,65,0,0,0,201,5,32,0,156,0,0,0,0,1,2,160,25],[0,0,0,0,82,17,0,170,0,0,0,1,5,80,192,57,0,0,0,206,114,32,0,209,0,0,0,202,114,32,0,209],[0,0,0,0,2,117,0,25,0,0,0,205,5,32,0,65,0,0,0,201,7,32,0,156,0,0,0,0,5,2,160,25],[0,0,0,0,117,21,0,170,0,0,0,1,7,112,192,57,0,0,0,0,2,3,0,75,0,0,0,203,130,48,0,209],[0,0,0,1,8,128,192,57,0,0,0,204,146,48,0,209,0,0,0,202,146,32,0,209,0,0,0,0,8,152,0,25],[0,0,0,205,2,128,0,65,0,0,0,201,9,128,0,156,0,0,0,0,2,8,160,25,0,0,0,0,152,34,0,170],[0,0,0,1,9,144,192,57,0,0,0,206,165,80,0,209,0,0,0,206,168,128,0,209,0,0,0,202,165,80,0,209],[0,0,0,0,5,167,0,25,0,0,0,202,135,128,0,209,0,0,0,0,7,137,0,25,0,0,0,205,8,80,0,65],[0,0,0,201,9,80,0,156,0,0,0,0,8,5,160,25,0,0,0,205,5,112,0,65,0,0,0,201,9,112,0,156],[0,0,0,0,5,7,160,25,0,0,0,207,7,0,0,65,0,0,0,208,9,0,0,65,0,0,0,209,10,128,0,156],[0,0,0,0,9,7,160,25,0,0,0,0,7,137,0,25,0,0,0,0,5,117,0,75,0,0,0,70,0,0,97,61],[0,0,0,0,5,0,4,20,0,0,0,0,5,80,4,32,0,0,0,0,5,6,0,75,0,0,0,79,0,0,193,61],[0,0,0,214,1,0,0,65,0,0,3,27,0,1,4,46,0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67],[0,0,1,32,0,0,4,67,0,0,0,200,1,0,0,65,0,0,3,27,0,1,4,46,0,0,0,1,5,96,0,140],[0,0,0,85,0,0,193,61,0,0,0,0,0,64,4,53,0,0,0,32,0,48,4,63,0,0,0,214,1,0,0,65],[0,0,3,27,0,1,4,46,0,0,0,2,3,96,0,140,0,0,0,90,0,0,193,61,0,0,0,210,3,0,0,65],[3,26,2,172,0,0,4,15,0,0,2,89,0,0,1,61,0,0,0,210,8,0,0,65,0,0,0,0,3,0,0,25],[0,0,0,210,4,0,0,65,0,0,0,0,15,0,0,25,0,0,0,211,0,0,1,61,0,0,0,0,10,0,0,25],[0,0,0,0,152,34,0,170,0,0,0,206,184,128,0,209,0,0,0,202,184,128,0,209,0,0,0,1,11,176,192,57],[0,0,0,0,9,155,0,25,0,0,0,205,8,144,0,65,0,0,0,201,11,144,0,156,0,0,0,0,8,9,160,25],[0,0,0,1,9,128,2,16,0,0,0,2,11,128,2,16,0,0,0,211,12,176,0,65,0,0,0,201,9,144,0,156],[0,0,0,0,12,11,160,25,0,0,0,0,185,119,0,170,0,0,0,206,217,144,0,209,0,0,0,202,217,144,0,209],[0,0,0,1,13,208,192,57,0,0,0,0,11,189,0,25,0,0,0,0,151,39,0,170,0,0,0,206,215,112,0,209],[0,0,0,202,215,112,0,209,0,0,0,1,13,208,192,57,0,0,0,0,7,157,0,25,0,0,0,1,13,192,2,16],[0,0,0,211,9,208,0,65,0,0,0,201,12,192,0,156,0,0,0,0,9,13,160,25,0,0,0,205,12,176,0,65],[0,0,0,201,13,176,0,156,0,0,0,0,12,11,160,25,0,0,0,0,186,162,0,169,0,0,0,0,219,18,0,169],[0,0,0,0,10,173,0,25,0,0,0,0,33,33,0,170,0,0,0,206,33,16,0,209,0,0,0,202,33,16,0,209],[0,0,0,1,2,32,192,57,0,0,0,0,2,162,0,25,0,0,0,0,1,12,0,75,0,0,0,212,161,192,0,209],[0,0,0,1,10,160,192,57,0,0,0,47,177,192,0,201,0,0,0,202,177,16,0,209,0,0,0,0,10,186,0,25],[0,0,0,205,1,160,0,65,0,0,0,201,11,160,0,156,0,0,0,0,1,10,160,25,0,0,0,205,10,32,0,65],[0,0,0,201,11,32,0,156,0,0,0,0,10,2,160,25,0,0,0,1,2,16,2,16,0,0,0,205,11,32,0,65],[0,0,0,213,12,16,0,156,0,0,0,0,11,2,160,25,0,0,0,0,2,27,0,25,0,0,0,205,11,32,0,65],[0,0,0,201,12,32,0,156,0,0,0,0,11,2,160,25,0,0,0,0,2,184,0,73,0,0,0,202,11,32,0,65],[0,0,0,205,12,32,0,156,0,0,0,0,2,11,128,25,0,0,0,0,186,162,0,170,0,0,0,1,11,176,192,57],[0,0,0,0,8,129,0,25,0,0,0,205,12,128,0,65,0,0,0,201,13,128,0,156,0,0,0,0,12,8,160,25],[0,0,0,0,130,194,0,170,0,0,0,1,8,128,192,57,0,0,0,205,12,144,0,65,0,0,0,201,13,144,0,156],[0,0,0,0,12,9,160,25,0,0,0,0,145,28,0,170,0,0,0,1,9,144,192,57,0,0,0,205,13,112,0,65],[0,0,0,201,14,112,0,156,0,0,0,0,13,7,160,25,0,0,0,0,199,220,0,170,0,0,0,1,12,192,192,57],[0,0,0,206,218,160,0,209,0,0,0,202,218,160,0,209,0,0,0,0,10,219,0,25,0,0,0,1,11,160,2,16],[0,0,0,211,13,176,0,65,0,0,0,201,10,160,0,156,0,0,0,0,13,11,160,25,0,0,0,206,162,32,0,209],[0,0,0,206,161,16,0,209,0,0,0,206,167,112,0,209,0,0,0,202,162,32,0,209,0,0,0,0,2,168,0,25],[0,0,0,202,135,112,0,209,0,0,0,0,7,140,0,25,0,0,0,205,8,112,0,65,0,0,0,201,10,112,0,156],[0,0,0,0,8,7,160,25,0,0,0,202,113,16,0,209,0,0,0,0,7,121,0,25,0,0,0,205,1,208,0,65],[0,0,0,201,9,208,0,156,0,0,0,0,1,13,160,25,0,0,0,205,9,32,0,65,0,0,0,201,10,32,0,156],[0,0,0,0,9,2,160,25,0,0,0,205,2,112,0,65,0,0,0,201,10,112,0,156,0,0,0,0,2,7,160,25],[0,0,0,0,7,41,0,25,0,0,0,205,2,112,0,65,0,0,0,201,9,112,0,156,0,0,0,0,2,7,160,25],[0,0,0,1,7,96,0,140,0,0,0,1,6,96,2,112,0,0,2,87,0,0,161,61,0,0,0,0,7,8,0,25],[0,0,0,1,8,96,1,144,0,0,0,95,0,0,97,61,0,0,0,0,8,3,0,75,0,0,1,114,0,0,97,61],[0,2,0,0,0,1,0,29,0,0,0,0,168,49,0,170,0,0,0,1,10,160,192,57,0,0,0,0,203,127,0,170],[0,0,0,1,12,192,192,57,0,0,0,0,237,116,0,170,0,0,0,1,14,224,192,57,0,0,0,0,1,15,0,25],[0,0,0,0,159,50,0,170,0,0,0,1,9,144,192,57,0,0,0,206,91,176,0,209,0,0,0,202,181,176,0,209],[0,0,0,0,5,188,0,25,0,0,0,206,184,128,0,209,0,0,0,205,12,80,0,65,0,0,0,201,11,80,0,156],[0,0,0,0,12,5,160,25,0,0,0,202,133,128,0,209,0,0,0,0,5,138,0,25,0,0,0,205,11,80,0,65],[0,0,0,201,8,80,0,156,0,0,0,0,11,5,160,25,0,0,0,206,133,208,0,209,0,0,0,202,133,80,0,209],[0,0,0,0,5,142,0,25,0,0,0,0,8,203,0,73,0,0,0,202,10,128,0,65,0,0,0,205,13,128,0,156],[0,0,0,0,8,10,128,25,0,0,0,205,10,80,0,65,0,0,0,201,13,80,0,156,0,0,0,0,10,5,160,25],[0,0,0,206,213,240,0,209,0,0,0,202,213,80,0,209,0,0,0,0,5,217,0,25,0,0,0,205,9,80,0,65],[0,0,0,201,13,80,0,156,0,0,0,0,9,5,160,25,0,0,0,0,10,169,0,73,0,0,0,202,5,160,0,65],[0,0,0,205,13,160,0,156,0,0,0,0,10,5,128,25,0,0,0,0,5,168,1,160,0,0,1,229,0,0,97,61],[0,0,0,0,67,55,0,170,0,0,0,1,4,64,192,57,0,0,0,0,213,170,0,170,0,0,0,1,13,208,192,57],[0,0,0,0,1,7,0,25,0,0,0,0,127,136,0,170,0,0,0,1,7,112,192,57,0,0,0,206,227,48,0,209],[0,0,0,202,227,48,0,209,0,0,0,0,4,228,0,25,0,0,0,205,3,64,0,65,0,0,0,201,14,64,0,156],[0,0,0,0,3,4,160,25,0,0,0,206,84,80,0,209,0,0,0,202,84,64,0,209,0,0,0,0,4,93,0,25],[0,0,0,205,5,64,0,65,0,0,0,201,13,64,0,156,0,0,0,0,5,4,160,25,0,0,0,0,222,53,0,170],[0,0,0,1,13,208,192,57,0,0,0,0,4,188,0,25,0,0,0,205,5,64,0,65,0,0,0,201,12,64,0,156],[0,0,0,0,5,4,160,25,0,0,0,206,196,240,0,209,0,0,0,202,196,64,0,209,0,0,0,0,4,199,0,25],[0,0,0,205,7,64,0,65,0,0,0,201,12,64,0,156,0,0,0,0,7,4,160,25,0,0,0,0,252,87,0,170],[0,0,0,1,15,240,192,57,0,0,0,0,91,183,0,170,0,0,0,1,5,80,192,57,0,1,0,0,64,135,0,174],[0,0,0,1,4,64,192,57,0,0,0,206,124,192,0,209,0,0,0,202,199,192,0,209,0,0,0,0,7,207,0,25],[0,0,0,205,12,112,0,65,0,0,0,201,15,112,0,156,0,0,0,0,12,7,160,25,0,0,0,206,231,224,0,209],[0,0,0,202,231,112,0,209,0,0,0,0,7,237,0,25,0,0,0,205,13,112,0,65,0,0,0,201,14,112,0,156],[0,0,0,0,13,7,160,25,0,0,0,0,7,205,0,73,0,0,0,206,203,176,0,209,0,0,0,202,12,112,0,65],[0,0,0,205,13,112,0,156,0,0,0,0,7,12,128,25,0,0,0,202,203,176,0,209,0,0,0,0,5,197,0,25],[0,0,0,205,11,80,0,65,0,0,0,201,12,80,0,156,0,0,0,0,11,5,160,25,0,0,0,0,5,123,0,73],[0,0,0,202,11,80,0,65,0,0,0,205,12,80,0,156,0,0,0,0,5,11,128,25,0,0,0,0,165,165,0,170],[0,0,0,1,10,160,192,57,0,0,0,0,135,135,0,170,0,0,0,1,8,128,192,57,0,0,0,1,11,0,0,41],[0,0,0,206,203,176,0,209,0,0,0,202,203,176,0,209,0,0,0,0,4,196,0,25,0,0,0,205,11,64,0,65],[0,0,0,201,12,64,0,156,0,0,0,0,11,4,160,25,0,0,0,0,148,155,0,170,0,0,0,1,9,144,192,57],[0,0,0,0,179,59,0,170,0,0,0,1,11,176,192,57,0,0,0,206,197,80,0,209,0,0,0,202,197,80,0,209],[0,0,0,0,5,202,0,25,0,0,0,206,167,112,0,209,0,0,0,206,164,64,0,209,0,0,0,202,164,64,0,209],[0,0,0,0,4,169,0,25,0,0,0,205,9,80,0,65,0,0,0,201,10,80,0,156,0,0,0,0,9,5,160,25],[0,0,0,202,117,112,0,209,0,0,0,0,5,120,0,25,0,0,0,205,7,64,0,65,0,0,0,201,8,64,0,156],[0,0,0,0,7,4,160,25,0,0,0,206,67,48,0,209,0,0,0,202,67,48,0,209,0,0,0,0,4,75,0,25],[0,0,0,205,3,64,0,65,0,0,0,201,8,64,0,156,0,0,0,0,3,4,160,25,0,0,0,0,4,121,0,73],[0,0,0,202,7,64,0,65,0,0,0,205,8,64,0,156,0,0,0,0,4,7,128,25,0,0,0,205,15,80,0,65],[0,0,0,201,7,80,0,156,0,0,0,0,7,1,0,25,0,0,0,0,15,5,160,25,0,0,0,0,10,0,0,25],[0,0,0,2,1,0,0,41,0,0,0,96,0,0,1,61,0,0,0,0,67,34,0,170,0,0,0,1,4,64,192,57],[0,0,0,206,83,48,0,209,0,0,0,202,83,48,0,209,0,0,0,0,3,84,0,25,0,0,0,205,4,48,0,65],[0,0,0,201,5,48,0,156,0,0,0,0,4,3,160,25,0,0,0,1,3,64,2,16,0,0,0,2,5,64,2,16],[0,0,0,211,9,80,0,65,0,0,0,201,3,48,0,156,0,0,0,0,9,5,160,25,0,0,0,0,186,119,0,170],[0,0,0,1,11,176,192,57,0,0,0,0,220,33,0,170,0,0,0,1,13,208,192,57,0,0,0,0,53,39,0,170],[0,0,0,1,3,48,192,57,0,0,0,1,14,144,2,16,0,0,0,211,8,224,0,65,0,0,0,201,9,144,0,156],[0,0,0,0,8,14,160,25,0,0,0,206,169,160,0,209,0,0,0,202,169,144,0,209,0,0,0,0,9,171,0,25],[0,0,0,205,10,144,0,65,0,0,0,201,11,144,0,156,0,0,0,0,10,9,160,25,0,0,0,0,9,10,0,75],[0,0,0,212,185,160,0,209,0,0,0,1,11,176,192,57,0,0,0,206,201,192,0,209,0,0,0,47,202,160,0,201],[0,0,0,202,202,160,0,209,0,0,0,0,10,203,0,25,0,0,0,202,185,144,0,209,0,0,0,0,11,189,0,25],[0,0,0,205,9,160,0,65,0,0,0,201,12,160,0,156,0,0,0,0,9,10,160,25,0,0,0,205,10,176,0,65],[0,0,0,201,12,176,0,156,0,0,0,0,10,11,160,25,0,0,0,1,11,144,2,16,0,0,0,205,12,176,0,65],[0,0,0,213,13,144,0,156,0,0,0,0,12,11,160,25,0,0,0,0,11,156,0,25,0,0,0,205,12,176,0,65],[0,0,0,201,13,176,0,156,0,0,0,0,12,11,160,25,0,0,0,0,11,196,0,73,0,0,0,202,12,176,0,65],[0,0,0,205,13,176,0,156,0,0,0,0,11,12,128,25,0,0,0,0,220,171,0,170,0,0,0,1,13,208,192,57],[0,0,0,0,4,73,0,25,0,0,0,205,10,64,0,65,0,0,0,201,14,64,0,156,0,0,0,0,10,4,160,25],[0,0,0,0,171,171,0,170,0,0,0,1,10,160,192,57,0,0,0,205,14,128,0,65,0,0,0,201,4,128,0,156],[0,0,0,0,14,8,160,25,0,0,0,0,72,233,0,170,0,0,0,1,4,64,192,57,0,0,0,206,149,80,0,209],[0,0,0,202,149,80,0,209,0,0,0,0,3,147,0,25,0,0,0,205,5,48,0,65,0,0,0,201,9,48,0,156],[0,0,0,0,5,3,160,25,0,0,0,0,83,94,0,170,0,0,0,1,5,80,192,57,0,0,0,206,201,192,0,209],[0,0,0,202,201,144,0,209,0,0,0,0,9,205,0,25,0,0,0,1,12,144,2,16,0,0,0,211,13,192,0,65],[0,0,0,201,9,144,0,156,0,0,0,0,13,12,160,25,0,0,0,206,185,176,0,209,0,0,0,206,139,128,0,209],[0,0,0,206,131,48,0,209,0,0,0,202,152,144,0,209,0,0,0,0,9,154,0,25,0,0,0,202,131,48,0,209],[0,0,0,0,3,133,0,25,0,0,0,205,8,48,0,65,0,0,0,201,5,48,0,156,0,0,0,0,8,3,160,25],[0,0,0,202,83,176,0,209,0,0,0,0,3,84,0,25,0,0,0,205,4,208,0,65,0,0,0,201,5,208,0,156],[0,0,0,0,4,13,160,25,0,0,0,205,5,144,0,65,0,0,0,201,10,144,0,156,0,0,0,0,5,9,160,25],[0,0,0,205,9,48,0,65,0,0,0,201,10,48,0,156,0,0,0,0,9,3,160,25,0,0,0,0,3,149,0,25],[0,0,0,205,9,48,0,65,0,0,0,201,5,48,0,156,0,0,0,0,9,3,160,25,0,0,0,0,15,1,0,25],[0,0,0,0,1,4,0,25,0,0,0,0,4,2,0,25,0,0,0,0,2,9,0,25,0,0,0,0,3,7,0,25],[0,0,0,208,0,0,1,61,0,0,0,0,9,1,0,25,0,0,0,0,33,68,0,170,0,0,0,1,2,32,192,57],[0,0,0,206,81,16,0,209,0,0,0,202,81,16,0,209,0,0,0,0,1,82,0,25,0,0,0,205,2,16,0,65],[0,0,0,201,5,16,0,156,0,0,0,0,2,1,160,25,0,0,0,1,1,32,2,16,0,0,0,2,5,32,2,16],[0,0,0,211,7,80,0,65,0,0,0,201,1,16,0,156,0,0,0,0,7,5,160,25,0,0,0,0,133,51,0,170],[0,0,0,1,8,128,192,57,0,0,0,0,169,73,0,170,0,0,0,1,10,160,192,57,0,0,0,0,19,52,0,170],[0,0,0,1,1,16,192,57,0,0,0,1,11,112,2,16,0,0,0,211,4,176,0,65,0,0,0,201,7,112,0,156],[0,0,0,0,4,11,160,25,0,0,0,206,117,80,0,209,0,0,0,202,117,80,0,209,0,0,0,0,5,120,0,25],[0,0,0,205,7,80,0,65,0,0,0,201,8,80,0,156,0,0,0,0,7,5,160,25,0,0,0,0,5,7,0,75],[0,0,0,212,133,112,0,209,0,0,0,1,8,128,192,57,0,0,0,206,149,144,0,209,0,0,0,47,151,112,0,201],[0,0,0,202,151,112,0,209,0,0,0,0,7,152,0,25,0,0,0,202,133,80,0,209,0,0,0,0,8,138,0,25],[0,0,0,205,5,112,0,65,0,0,0,201,9,112,0,156,0,0,0,0,5,7,160,25,0,0,0,205,7,128,0,65],[0,0,0,201,9,128,0,156,0,0,0,0,7,8,160,25,0,0,0,1,8,80,2,16,0,0,0,205,9,128,0,65],[0,0,0,213,10,80,0,156,0,0,0,0,9,8,160,25,0,0,0,0,8,89,0,25,0,0,0,205,9,128,0,65],[0,0,0,201,10,128,0,156,0,0,0,0,9,8,160,25,0,0,0,0,8,146,0,73,0,0,0,202,9,128,0,65],[0,0,0,205,10,128,0,156,0,0,0,0,8,9,128,25,0,0,0,0,169,120,0,170,0,0,0,1,10,160,192,57],[0,0,0,0,2,37,0,25,0,0,0,205,7,32,0,65,0,0,0,201,11,32,0,156,0,0,0,0,7,2,160,25],[0,0,0,0,120,120,0,170,0,0,0,1,7,112,192,57,0,0,0,205,11,64,0,65,0,0,0,201,2,64,0,156],[0,0,0,0,11,4,160,25,0,0,0,0,36,91,0,170,0,0,0,1,2,32,192,57,0,0,0,206,83,48,0,209],[0,0,0,202,83,48,0,209,0,0,0,0,1,81,0,25,0,0,0,205,3,16,0,65,0,0,0,201,5,16,0,156],[0,0,0,0,3,1,160,25,0,0,0,0,49,59,0,170,0,0,0,1,3,48,192,57,0,0,0,206,149,144,0,209],[0,0,0,202,149,80,0,209,0,0,0,0,5,154,0,25,0,0,0,1,9,80,2,16,0,0,0,211,10,144,0,65],[0,0,0,201,5,80,0,156,0,0,0,0,10,9,160,25,0,0,0,206,133,128,0,209,0,0,0,206,132,64,0,209],[0,0,0,206,129,16,0,209,0,0,0,202,133,80,0,209,0,0,0,0,5,135,0,25,0,0,0,202,113,16,0,209],[0,0,0,0,1,115,0,25,0,0,0,205,8,16,0,65,0,0,0,201,3,16,0,156,0,0,0,0,8,1,160,25],[0,0,0,202,49,64,0,209,0,0,0,0,1,50,0,25,0,0,0,205,15,160,0,65,0,0,0,201,2,160,0,156],[0,0,0,0,15,10,160,25,0,0,0,205,2,80,0,65,0,0,0,201,3,80,0,156,0,0,0,0,2,5,160,25],[0,0,0,205,3,16,0,65,0,0,0,201,4,16,0,156,0,0,0,0,3,1,160,25,0,0,0,0,1,50,0,25],[0,0,0,205,4,16,0,65,0,0,0,201,2,16,0,156,0,0,0,0,4,1,160,25,0,0,0,0,1,15,0,25],[0,0,0,0,2,4,0,25,0,0,0,0,3,8,0,25,0,0,0,208,0,0,1,61,0,0,0,0,1,15,0,25],[0,0,0,0,2,4,0,25,3,26,2,108,0,0,4,15,0,2,0,0,0,2,0,29,3,26,2,100,0,0,4,15],[0,1,0,0,0,1,0,29,0,0,0,2,1,0,0,41,3,26,2,100,0,0,4,15,0,0,0,1,2,0,0,41],[0,0,0,0,0,32,4,53,0,0,0,32,0,16,4,63,0,0,0,214,1,0,0,65,0,0,3,27,0,1,4,46],[0,0,0,0,2,1,0,75,0,0,0,206,33,16,0,209,0,0,0,202,33,16,0,209,0,0,0,1,2,32,192,57],[0,0,0,205,1,32,0,65,0,0,0,201,3,32,0,156,0,0,0,0,1,2,160,25,0,0,0,0,0,1,4,45],[0,0,0,0,4,3,0,75,0,0,0,0,5,0,0,25,0,0,0,0,4,0,0,25,0,0,2,169,0,0,97,61],[0,0,0,203,4,0,0,65,0,0,0,1,5,48,0,140,0,0,2,153,0,0,97,61,0,0,0,202,5,0,0,65],[0,0,0,203,4,0,0,65,0,0,0,0,6,0,0,25,0,0,0,1,7,48,1,144,0,0,2,126,0,0,193,61],[0,0,0,1,7,64,1,144,0,0,0,202,4,64,192,65,0,0,0,2,7,48,1,144,0,0,0,1,3,48,2,112],[0,0,0,1,4,64,2,112,0,0,2,120,0,0,97,61,0,0,0,1,7,80,1,144,0,0,2,134,0,0,193,61],[0,0,0,1,7,96,1,144,0,0,0,202,6,96,192,65,0,0,0,2,7,80,1,144,0,0,0,1,5,80,2,112],[0,0,0,1,6,96,2,112,0,0,2,128,0,0,97,61,0,0,0,0,7,53,0,75,0,0,2,142,0,0,161,61],[0,0,0,202,7,96,0,65,0,0,0,0,8,70,0,75,0,0,0,0,7,6,128,25,0,0,0,0,6,71,0,73],[0,0,0,0,5,53,0,73,0,0,2,147,0,0,1,61,0,0,0,202,7,64,0,65,0,0,0,0,8,100,0,75],[0,0,0,0,7,4,128,25,0,0,0,0,4,103,0,73,0,0,0,0,3,83,0,73,0,0,0,1,7,48,0,140],[0,0,2,151,0,0,97,61,0,0,0,1,7,80,0,140,0,0,2,118,0,0,193,61,0,0,0,1,3,48,0,140],[0,0,0,0,4,6,192,25,0,0,0,0,49,20,0,170,0,0,0,1,3,48,192,57,0,0,0,0,66,36,0,170],[0,0,0,1,4,64,192,57,0,0,0,206,82,32,0,209,0,0,0,202,82,32,0,209,0,0,0,0,2,84,0,25],[0,0,0,205,4,32,0,65,0,0,0,201,5,32,0,156,0,0,0,0,4,2,160,25,0,0,0,206,33,16,0,209],[0,0,0,202,33,16,0,209,0,0,0,0,1,35,0,25,0,0,0,205,5,16,0,65,0,0,0,201,2,16,0,156],[0,0,0,0,5,1,160,25,0,0,0,0,1,5,0,25,0,0,0,0,2,4,0,25,0,0,0,0,0,1,4,45],[0,0,0,0,84,34,0,170,0,0,0,1,5,80,192,57,0,0,0,206,100,64,0,209,0,0,0,202,100,64,0,209],[0,0,0,0,5,101,0,25,0,0,0,205,4,80,0,65,0,0,0,201,6,80,0,156,0,0,0,0,4,5,160,25],[0,0,0,1,5,64,2,16,0,0,0,2,6,64,2,16,0,0,0,211,7,96,0,65,0,0,0,201,5,80,0,156],[0,0,0,0,7,6,160,25,0,0,0,0,101,51,0,170,0,0,0,1,6,96,192,57,0,0,0,0,152,18,0,170],[0,0,0,1,9,144,192,57,0,0,0,0,18,35,0,170,0,0,0,1,1,16,192,57,0,0,0,1,10,112,2,16],[0,0,0,211,3,160,0,65,0,0,0,201,7,112,0,156,0,0,0,0,3,10,160,25,0,0,0,206,117,80,0,209],[0,0,0,202,117,80,0,209,0,0,0,0,5,118,0,25,0,0,0,205,6,80,0,65,0,0,0,201,7,80,0,156],[0,0,0,0,6,5,160,25,0,0,0,0,5,6,0,75,0,0,0,212,117,96,0,209,0,0,0,1,7,112,192,57],[0,0,0,206,133,128,0,209,0,0,0,47,134,96,0,201,0,0,0,202,134,96,0,209,0,0,0,0,6,135,0,25],[0,0,0,202,117,80,0,209,0,0,0,0,7,121,0,25,0,0,0,205,5,96,0,65,0,0,0,201,8,96,0,156],[0,0,0,0,5,6,160,25,0,0,0,205,6,112,0,65,0,0,0,201,8,112,0,156,0,0,0,0,6,7,160,25],[0,0,0,1,7,80,2,16,0,0,0,205,8,112,0,65,0,0,0,213,9,80,0,156,0,0,0,0,8,7,160,25],[0,0,0,0,7,88,0,25,0,0,0,205,8,112,0,65,0,0,0,201,9,112,0,156,0,0,0,0,8,7,160,25],[0,0,0,0,7,132,0,73,0,0,0,202,8,112,0,65,0,0,0,205,9,112,0,156,0,0,0,0,7,8,128,25],[0,0,0,0,152,103,0,170,0,0,0,1,9,144,192,57,0,0,0,0,4,69,0,25,0,0,0,205,6,64,0,65],[0,0,0,201,10,64,0,156,0,0,0,0,6,4,160,25,0,0,0,0,103,103,0,170,0,0,0,1,6,96,192,57],[0,0,0,205,10,48,0,65,0,0,0,201,4,48,0,156,0,0,0,0,10,3,160,25,0,0,0,0,67,165,0,170],[0,0,0,1,4,64,192,57,0,0,0,206,82,32,0,209,0,0,0,202,82,32,0,209,0,0,0,0,1,81,0,25],[0,0,0,205,2,16,0,65,0,0,0,201,5,16,0,156,0,0,0,0,2,1,160,25,0,0,0,0,33,42,0,170],[0,0,0,1,2,32,192,57,0,0,0,206,133,128,0,209,0,0,0,202,133,80,0,209,0,0,0,0,5,137,0,25],[0,0,0,1,8,80,2,16,0,0,0,211,9,128,0,65,0,0,0,201,5,80,0,156,0,0,0,0,9,8,160,25],[0,0,0,206,117,112,0,209,0,0,0,206,55,48,0,209,0,0,0,206,49,16,0,209,0,0,0,202,83,80,0,209],[0,0,0,0,5,86,0,25,0,0,0,202,49,16,0,209,0,0,0,0,1,50,0,25,0,0,0,205,3,16,0,65],[0,0,0,201,2,16,0,156,0,0,0,0,3,1,160,25,0,0,0,202,33,112,0,209,0,0,0,0,2,36,0,25],[0,0,0,205,1,144,0,65,0,0,0,201,4,144,0,156,0,0,0,0,1,9,160,25,0,0,0,205,4,80,0,65],[0,0,0,201,6,80,0,156,0,0,0,0,4,5,160,25,0,0,0,205,5,32,0,65,0,0,0,201,6,32,0,156],[0,0,0,0,5,2,160,25,0,0,0,0,4,84,0,25,0,0,0,205,2,64,0,65,0,0,0,201,5,64,0,156],[0,0,0,0,2,4,160,25,0,0,0,0,0,1,4,45,0,0,3,26,0,0,4,50,0,0,3,27,0,1,4,46],[0,0,3,28,0,1,4,48,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,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[48,100,78,114,225,49,160,41,184,80,69,182,129,129,88,93,151,129,106,145,104,113,202,141,60,32,140,22,216,124,253,70],[48,100,78,114,225,49,160,41,184,80,69,182,129,129,88,93,151,129,106,145,104,113,202,141,60,32,140,22,216,124,253,71],[6,216,159,113,202,184,53,31,71,171,30,255,10,65,127,246,181,231,25,17,212,69,1,251,243,44,252,91,83,138,250,137],[74,71,70,38,35,160,74,122,176,116,165,134,128,115,1,58,233,101,225,118,124,212,192,134,243,174,216,161,155,249,14,81],[207,155,177,141,30,206,95,214,71,175,186,73,126,126,167,162,104,126,149,110,151,142,53,114,195,223,115,233,39,131,2,185],[245,122,34,183,145,136,140,107,216,175,203,208,24,51,218,128,158,222,125,101,30,202,106,201,135,210,7,130,228,134,99,137],[42,31,103,68,206,23,157,142,51,75,234,78,105,107,210,132,31,106,193,122,225,85,33,185,122,23,202,169,80,173,40,215],[249,187,24,209,236,229,253,100,122,251,164,151,231,234,122,38,135,233,86,233,120,227,87,44,61,247,62,146,120,48,43,144],[6,68,231,46,19,26,2,155,133,4,91,104,24,21,133,217,120,22,169,22,135,28,168,211,194,8,193,109,135,207,212,111],[14,10,119,193,154,7,223,47,102,110,163,111,120,121,70,44,10,120,235,40,245,199,11,61,211,93,67,141,197,143,13,157],[159,55,99,26,61,156,191,172,143,95,116,146,252,253,79,68,208,253,42,221,47,28,106,229,135,190,231,210,79,6,5,114],[29,149,152,232,167,227,152,87,41,67,51,126,57,64,198,209,47,61,111,77,211,27,208,17,246,6,71,206,65,13,127,247],[24,50,39,57,112,152,208,20,220,40,34,219,64,192,172,46,203,192,181,72,180,56,229,70,158,16,70,11,108,62,126,163],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,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,0,0,0,0,0,0,0,0,0,0,0,0],[136,210,215,145,1,9,72,102,245,6,226,206,231,74,222,121,140,90,74,182,159,125,137,7,252,66,94,207,167,28,22,58]],"0x0000000000000000000000000000000000000002":[[0,0,0,1,2,32,1,144,0,0,0,51,0,0,193,61,0,0,0,0,2,1,0,25,0,0,0,96,3,32,2,112],[0,0,0,31,4,48,1,143,0,0,0,17,2,48,1,151,0,0,0,5,5,32,2,114,0,0,0,16,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59],[0,0,0,0,0,135,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,0,9,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,0,30,0,0,97,61,0,0,0,3,4,64,2,16,0,0,0,5,5,80,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,81,3,79],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,0,18,1,0,0,65,0,0,0,0,0,18,4,53],[0,0,0,8,1,48,0,57,0,0,0,63,1,16,1,143,0,0,0,0,1,18,0,73,0,0,0,195,2,32,2,16],[0,0,0,64,3,16,0,57,0,0,0,0,0,35,4,53,0,0,0,72,1,16,0,57,0,0,0,27,2,16,2,16],[0,0,0,19,2,32,1,151,0,0,0,6,1,16,2,112,0,0,0,192,3,16,2,16,0,0,0,0,2,50,1,159],[0,0,0,20,2,32,1,199,0,0,0,7,49,16,0,201,0,0,0,0,1,18,4,32,0,0,0,0,1,1,0,75],[0,0,0,56,0,0,193,61,0,0,0,0,1,0,0,25,0,0,0,60,0,1,4,48,0,0,0,32,1,0,0,57],[0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,0,16,1,0,0,65,0,0,0,59,0,1,4,46],[0,0,0,21,1,0,0,65,0,0,0,59,0,1,4,46,0,0,0,58,0,0,4,50,0,0,0,59,0,1,4,46],[0,0,0,60,0,1,4,48,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,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,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,0,0,0,0,0,255,255,255,255],[128,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],[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,254,255,255,255,255,255,255,255,255,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,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,32,0,0,0,0,0,0,0,0,0,0,0,0],[163,6,139,9,248,74,233,86,156,89,18,239,176,49,25,58,139,131,161,16,140,157,193,139,157,74,170,24,136,162,125,123]],"0x0000000000000000000000000000000000008009":[[0,2,0,0,0,0,0,2,0,6,0,0,0,0,0,2,0,1,0,0,0,1,3,85,0,0,0,0,6,1,0,25],[0,0,0,96,6,96,2,112,0,0,0,75,0,96,1,157,0,0,0,128,7,0,0,57,0,0,0,64,0,112,4,63],[0,0,0,75,9,96,1,151,0,0,0,0,8,0,4,22,0,0,0,1,7,32,1,144,0,0,0,31,0,0,193,61],[0,0,0,0,7,8,0,75,0,0,0,105,0,0,193,61,0,0,0,2,2,32,1,144,0,0,0,38,0,0,193,61],[0,0,0,0,2,0,4,17,0,0,0,77,2,32,0,156,0,0,0,38,0,0,65,61,0,0,0,90,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,36,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,0,94,1,0,0,65,0,0,0,196,0,16,4,63,0,0,0,95,1,0,0,65],[0,0,0,228,0,16,4,63,0,0,0,96,1,0,0,65,0,0,1,42,0,1,4,48,0,0,0,0,1,8,0,75],[0,0,0,105,0,0,193,61,0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67],[0,0,0,76,1,0,0,65,0,0,1,41,0,1,4,46,0,0,0,78,2,64,1,151,0,0,0,0,4,0,4,16],[0,0,0,0,4,66,0,75,0,0,0,52,0,0,193,61,0,0,0,90,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,30,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,0,92,1,0,0,65,0,0,0,196,0,16,4,63,0,0,0,93,1,0,0,65,0,0,1,42,0,1,4,48],[0,0,0,0,4,3,0,75,0,0,0,0,8,0,4,17,0,0,0,0,7,9,0,25,0,0,0,64,0,0,193,61],[0,0,0,0,0,3,4,23,0,0,0,0,3,0,4,20,0,0,0,0,4,151,0,75,0,0,0,107,0,0,129,61],[0,0,0,87,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57,0,0,0,255,0,0,1,61],[0,3,0,0,0,9,0,29,0,5,0,0,0,5,0,29,0,6,0,0,0,6,0,29,0,0,0,79,1,0,0,65],[0,0,0,160,0,16,4,63,0,1,0,0,0,8,0,29,0,0,0,78,1,128,1,151,0,0,0,164,0,16,4,63],[0,2,0,0,0,2,0,29,0,0,0,196,0,32,4,63,0,4,0,0,0,3,0,29,0,0,0,228,0,48,4,63],[0,0,0,100,1,0,0,57,0,0,0,128,0,16,4,63,0,0,1,32,1,0,0,57,0,0,0,64,0,16,4,63],[0,0,0,75,1,0,0,65,0,0,0,0,2,0,4,20,0,0,0,75,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,0,80,1,16,1,199,0,0,128,10,2,0,0,57,1,40,1,29,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,75,5,48,1,152,0,0,0,127,0,0,193,61],[0,0,0,1,1,32,1,144,0,0,0,6,6,0,0,41,0,0,0,5,5,0,0,41,0,0,0,4,3,0,0,41],[0,0,0,3,9,0,0,41,0,0,0,105,0,0,97,61,0,0,0,83,1,48,0,156,0,0,0,2,2,0,0,41],[0,0,0,1,8,0,0,41,0,0,0,109,0,0,33,61,0,0,0,1,1,0,3,103,0,0,0,0,7,0,0,49],[0,0,0,56,0,0,1,61,0,0,0,0,1,0,0,25,0,0,1,42,0,1,4,48,0,0,0,75,4,48,0,156],[0,0,0,168,0,0,161,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,0,89,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,8,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,0,90,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,0,75,2,0,0,65,0,0,0,75,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,64,1,16,2,16,0,0,0,91,1,16,1,199,0,0,1,42,0,1,4,48,0,0,0,63,3,80,0,57],[0,0,0,81,3,48,1,151,0,0,0,64,4,0,4,61,0,0,0,0,3,52,0,25,0,0,0,0,6,67,0,75],[0,0,0,0,6,0,0,25,0,0,0,1,6,0,64,57,0,0,0,82,7,48,0,156,0,0,0,252,0,0,33,61],[0,0,0,1,6,96,1,144,0,0,0,252,0,0,193,61,0,0,0,64,0,48,4,63,0,0,0,31,3,80,1,143],[0,0,0,0,4,84,4,54,0,0,0,5,5,80,2,114,0,0,0,152,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,116,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,0,144,0,0,65,61],[0,0,0,0,6,3,0,75,0,0,0,92,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,4,84,0,25,0,0,0,3,3,48,2,16,0,0,0,0,5,4,4,51,0,0,0,0,5,53,1,207],[0,0,0,0,5,53,2,47,0,0,0,0,1,1,4,59,0,0,1,0,3,48,0,137,0,0,0,0,1,49,2,47],[0,0,0,0,1,49,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,20,4,53,0,0,0,92,0,0,1,61],[0,0,0,1,4,80,1,144,0,0,0,84,4,0,0,65,0,0,0,85,5,0,0,65,0,0,0,0,5,4,192,25],[0,0,0,192,3,48,2,16,0,0,0,86,3,48,1,151,0,0,0,0,3,83,1,159,0,0,0,0,4,103,0,73],[0,0,0,75,4,64,1,151,0,0,0,0,1,65,3,223,0,0,0,0,1,49,3,175,0,0,0,78,13,128,1,151],[1,40,1,34,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,75,3,48,1,151],[0,0,0,1,2,32,1,144,0,0,1,2,0,0,97,61,0,0,0,63,2,48,0,57,0,0,0,81,4,32,1,151],[0,0,0,64,2,0,4,61,0,0,0,0,4,66,0,25,0,0,0,0,5,36,0,75,0,0,0,0,5,0,0,25],[0,0,0,1,5,0,64,57,0,0,0,82,6,64,0,156,0,0,0,252,0,0,33,61,0,0,0,1,5,80,1,144],[0,0,0,252,0,0,193,61,0,0,0,64,0,64,4,63,0,0,0,0,4,50,4,54,0,0,0,31,5,48,0,57],[0,0,0,5,5,80,2,114,0,0,0,213,0,0,97,61,0,0,0,0,6,0,0,49,0,0,0,1,6,96,3,103],[0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,132,0,25,0,0,0,0,8,134,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,87,0,75],[0,0,0,205,0,0,65,61,0,0,0,0,5,0,0,75,0,0,0,215,0,0,97,61,0,0,0,31,5,48,1,143],[0,0,0,5,3,48,2,114,0,0,0,227,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,116,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,54,0,75,0,0,0,219,0,0,65,61,0,0,0,0,6,5,0,75],[0,0,0,242,0,0,97,61,0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79,0,0,0,0,3,52,0,25],[0,0,0,3,5,80,2,16,0,0,0,0,6,3,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,5,80,0,137,0,0,0,0,1,81,2,47,0,0,0,0,1,81,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,19,4,53,0,0,0,0,1,2,4,51,0,0,0,75,2,0,0,65],[0,0,0,75,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,75,3,64,0,156,0,0,0,0,4,2,128,25],[0,0,0,64,2,64,2,16,0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,1,41,0,1,4,46],[0,0,0,87,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57,0,0,0,4,0,16,4,63],[0,0,0,88,1,0,0,65,0,0,1,42,0,1,4,48,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114],[0,0,1,13,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75],[0,0,1,6,0,0,65,61,0,0,0,0,5,4,0,75,0,0,1,27,0,0,97,61,0,0,0,3,4,64,2,16],[0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47],[0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16],[0,0,1,42,0,1,4,48,0,0,1,32,0,33,4,33,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45],[0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,0,0,15,13,0,25,0,0,1,38,0,33,4,41],[0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45],[0,0,1,40,0,0,4,50,0,0,1,41,0,1,4,46,0,0,1,42,0,1,4,48,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,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,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,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[87,153,82,252,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,160,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,0,0,0,1,255,255,255,224],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[1,0,0,1,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,1,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,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[78,72,123,113,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[79,118,101,114,102,108,111,119,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[8,195,121,160,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0],[77,115,103,86,97,108,117,101,83,105,109,117,108,97,116,111,114,32,99,97,108,108,115,32,105,116,115,101,108,102,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,128,0,0,0,0,0,0,0,0],[84,104,105,115,32,109,101,116,104,111,100,32,114,101,113,117,105,114,101,32,115,121,115,116,101,109,32,99,97,108,108,32],[102,108,97,103,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,128,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,0,0,0,0,0,0,0,0],[104,86,206,249,159,64,233,200,187,185,162,103,175,77,178,97,168,231,132,34,191,2,15,56,177,244,203,85,226,83,209,29]],"0x000000000000000000000000000000000000800b":[[0,1,0,0,0,0,0,2,0,6,0,0,0,0,0,2,0,0,0,0,0,1,3,85,0,0,0,128,4,0,0,57],[0,0,0,64,0,64,4,63,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,1,24,3,48,1,151],[0,0,0,1,2,32,1,144,0,0,0,33,0,0,193,61,0,0,0,4,2,48,0,140,0,0,3,150,0,0,65,61],[0,0,0,0,2,1,4,59,0,0,0,224,2,32,2,112,0,0,1,28,5,32,0,156,0,0,0,52,0,0,33,61],[0,0,1,46,5,32,0,156,0,0,0,67,0,0,161,61,0,0,1,47,4,32,0,156,0,0,0,123,0,0,161,61],[0,0,1,48,4,32,0,156,0,0,0,200,0,0,33,61,0,0,1,51,1,32,0,156,0,0,1,16,0,0,97,61],[0,0,1,52,1,32,0,156,0,0,3,150,0,0,193,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,3,150,0,0,193,61,0,0,1,12,1,0,0,57,0,0,0,0,1,1,4,26,0,0,1,64,1,16,1,151],[0,0,1,241,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61],[0,0,1,24,1,0,0,65,0,0,0,3,2,0,0,57,0,0,0,0,0,18,4,27,0,0,0,4,1,0,0,57],[0,0,0,0,2,1,4,26,0,0,1,25,2,32,1,151,0,0,128,1,2,32,1,191,0,0,0,0,0,33,4,27],[0,0,1,26,1,0,0,65,0,0,0,5,2,0,0,57,0,0,0,0,0,18,4,27,0,0,0,32,1,0,0,57],[0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,1,27,1,0,0,65,0,0,4,90,0,1,4,46],[0,0,1,29,4,32,0,156,0,0,0,99,0,0,161,61,0,0,1,30,4,32,0,156,0,0,0,134,0,0,161,61],[0,0,1,31,4,32,0,156,0,0,0,248,0,0,33,61,0,0,1,34,1,32,0,156,0,0,0,62,0,0,97,61],[0,0,1,35,1,32,0,156,0,0,3,150,0,0,193,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,3,150,0,0,193,61,4,89,4,24,0,0,4,15,0,0,0,111,0,0,1,61,0,0,1,56,5,32,0,156],[0,0,0,156,0,0,33,61,0,0,1,60,5,32,0,156,0,0,1,21,0,0,97,61,0,0,1,61,5,32,0,156],[0,0,1,87,0,0,97,61,0,0,1,62,2,32,0,156,0,0,3,150,0,0,193,61,0,0,0,0,2,0,4,22],[0,0,0,0,2,2,0,75,0,0,3,150,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140],[0,0,3,150,0,0,65,61,0,0,0,0,2,0,4,17,0,0,128,1,2,32,0,140,0,0,2,22,0,0,193,61],[0,0,0,10,2,0,0,57,0,6,0,0,0,2,0,29,0,0,0,0,2,2,4,26,0,0,0,160,0,32,4,63],[0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59,0,0,0,192,0,16,4,63,0,0,0,64,2,0,0,57],[0,0,0,128,0,32,4,63,0,0,0,224,1,0,0,57,0,0,0,64,0,16,4,63,0,0,0,160,1,0,0,57],[4,89,4,62,0,0,4,15,0,0,0,6,2,0,0,41,0,0,1,227,0,0,1,61,0,0,1,39,4,32,0,156],[0,0,0,179,0,0,33,61,0,0,1,43,4,32,0,156,0,0,1,1,0,0,97,61,0,0,1,44,1,32,0,156],[0,0,1,143,0,0,97,61,0,0,1,45,1,32,0,156,0,0,3,150,0,0,193,61,0,0,0,0,1,0,4,22],[0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61,4,89,4,43,0,0,4,15,0,0,1,64,2,32,1,151],[0,0,0,64,3,0,4,61,0,0,0,32,4,48,0,57,0,0,0,0,0,36,4,53,0,0,1,64,1,16,1,151],[0,0,0,0,0,19,4,53,0,0,1,24,1,0,0,65,0,0,1,24,2,48,0,156,0,0,0,0,3,1,128,25],[0,0,0,64,1,48,2,16,0,0,1,65,1,16,1,199,0,0,4,90,0,1,4,46,0,0,1,53,1,32,0,156],[0,0,1,150,0,0,97,61,0,0,1,54,1,32,0,156,0,0,1,162,0,0,97,61,0,0,1,55,1,32,0,156],[0,0,3,150,0,0,193,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61],[0,0,0,6,1,0,0,57,0,0,1,199,0,0,1,61,0,0,1,36,4,32,0,156,0,0,1,169,0,0,97,61],[0,0,1,37,4,32,0,156,0,0,1,174,0,0,97,61,0,0,1,38,1,32,0,156,0,0,3,150,0,0,193,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61,0,0,0,4,1,48,0,138],[0,0,0,32,1,16,0,140,0,0,3,150,0,0,65,61,0,0,0,0,1,0,4,17,0,0,128,1,1,16,0,140],[0,0,0,0,1,0,0,25,0,0,0,1,1,0,96,57,4,89,3,248,0,0,4,15,0,0,0,4,1,0,0,57],[0,0,0,0,1,16,3,103,0,0,0,0,1,1,4,59,0,0,0,2,2,0,0,57,0,0,1,227,0,0,1,61],[0,0,1,57,1,32,0,156,0,0,1,195,0,0,97,61,0,0,1,58,1,32,0,156,0,0,1,201,0,0,97,61],[0,0,1,59,1,32,0,156,0,0,3,150,0,0,193,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,3,150,0,0,193,61,0,0,0,0,1,0,4,17,0,0,128,1,1,16,0,140,0,0,2,22,0,0,193,61],[0,0,1,14,1,0,0,57,0,0,0,0,2,1,4,26,0,0,255,255,3,32,1,143,0,0,255,255,4,48,0,140],[0,0,2,32,0,0,193,61,0,0,1,123,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,1,124,1,0,0,65,0,0,4,91,0,1,4,48,0,0,1,40,1,32,0,156],[0,0,1,230,0,0,97,61,0,0,1,41,1,32,0,156,0,0,1,237,0,0,97,61,0,0,1,42,1,32,0,156],[0,0,3,150,0,0,193,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61],[4,89,4,24,0,0,4,15,0,0,1,64,2,32,1,151,0,0,0,128,1,16,2,16,0,0,0,0,1,33,1,159],[0,0,0,64,2,0,4,61,0,0,0,0,0,18,4,53,0,0,1,24,1,0,0,65,0,0,1,24,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,1,67,1,16,1,199,0,0,4,90,0,1,4,46],[0,0,1,49,4,32,0,156,0,0,1,244,0,0,97,61,0,0,1,50,2,32,0,156,0,0,3,150,0,0,193,61],[0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,3,150,0,0,193,61,0,0,0,4,2,48,0,138],[0,0,0,32,2,32,0,140,0,0,3,150,0,0,65,61,0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59],[0,0,1,12,2,0,0,57,0,0,0,0,2,2,4,26,0,0,0,192,3,0,0,57,0,0,0,64,0,48,4,63],[0,0,0,128,6,32,2,112,0,0,1,13,2,0,0,57,0,0,0,0,3,2,4,26,0,0,1,64,5,48,1,151],[0,0,0,128,0,80,4,63,0,0,0,128,2,48,2,112,0,0,0,160,0,32,4,63,0,0,0,0,4,22,0,75],[0,0,0,0,4,0,0,25,0,0,2,68,0,0,161,61,0,0,0,0,4,22,0,73,0,0,1,1,4,64,0,140],[0,0,0,0,4,0,0,25,0,0,2,68,0,0,129,61,0,0,0,0,4,81,0,75,0,0,2,38,0,0,129,61],[0,0,0,0,0,16,4,53,0,0,0,8,1,0,0,57,0,0,0,32,0,16,4,63,0,0,1,24,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,1,24,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,1,70,1,16,1,199,0,0,128,16,2,0,0,57,4,89,4,84,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,3,150,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,4,1,4,26,0,0,2,68,0,0,1,61],[0,0,1,32,4,32,0,156,0,0,1,1,0,0,97,61,0,0,1,33,1,32,0,156,0,0,3,150,0,0,193,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61,0,0,0,2,1,0,0,57],[0,0,1,199,0,0,1,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,3,150,0,0,193,61],[0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140,0,0,3,150,0,0,65,61,0,0,0,4,1,16,3,112],[0,0,0,0,1,1,4,59,0,0,0,0,0,16,4,53,0,0,0,8,1,0,0,57,0,0,0,32,0,16,4,63],[0,0,0,64,2,0,0,57,0,0,0,0,1,0,0,25,4,89,4,62,0,0,4,15,0,0,1,199,0,0,1,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61,0,0,0,3,1,0,0,57],[0,0,1,199,0,0,1,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,3,150,0,0,193,61],[0,0,0,4,2,48,0,138,0,0,0,128,2,32,0,140,0,0,3,150,0,0,65,61,0,0,0,4,2,16,3,112],[0,0,0,0,3,2,4,59,0,0,0,36,2,16,3,112,0,0,0,0,4,2,4,59,0,0,1,64,2,64,0,156],[0,0,3,150,0,0,33,61,0,0,0,68,1,16,3,112,0,0,0,0,5,1,4,59,0,0,1,64,1,80,0,156],[0,0,3,150,0,0,33,61,0,0,0,0,1,0,4,17,0,0,128,1,1,16,0,140,0,0,2,22,0,0,193,61],[0,0,0,192,1,0,0,57,0,0,0,64,0,16,4,63,0,0,0,7,6,0,0,57,0,0,0,0,1,6,4,26],[0,0,1,64,2,16,1,151,0,0,0,128,0,32,4,63,0,0,0,128,1,16,2,112,0,0,0,160,0,16,4,63],[0,0,0,0,2,36,0,75,0,0,2,76,0,0,161,61,0,0,1,64,2,16,0,156,0,0,0,173,0,0,97,61],[0,0,0,1,2,16,0,57,0,0,0,0,2,82,0,75,0,0,2,85,0,0,193,61,0,3,0,0,0,6,0,29],[0,4,0,0,0,5,0,29,0,6,0,0,0,3,0,29,0,0,0,9,2,0,0,57,0,0,0,0,2,2,4,26],[0,0,1,64,2,32,1,151,0,5,0,0,0,4,0,29,0,0,0,0,2,36,0,75,0,0,2,97,0,0,161,61],[0,0,0,0,0,16,4,53,0,0,0,8,1,0,0,57,0,0,0,32,0,16,4,63,0,0,1,24,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,1,24,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,1,70,1,16,1,199,0,0,128,16,2,0,0,57,4,89,4,84,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,0,6,2,0,0,41,0,0,3,150,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,0,33,4,27],[0,0,0,64,1,0,4,61,0,0,1,94,2,16,0,156,0,0,3,17,0,0,161,61,0,0,1,123,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57,0,0,0,176,0,0,1,61,0,0,0,0,2,0,4,22],[0,0,0,0,2,2,0,75,0,0,3,150,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,160,2,32,0,140],[0,0,3,150,0,0,65,61,0,0,0,4,2,16,3,112,0,0,0,0,6,2,4,59,0,0,1,64,2,96,0,156],[0,0,3,150,0,0,33,61,0,0,0,36,2,16,3,112,0,0,0,0,5,2,4,59,0,0,1,64,2,80,0,156],[0,0,3,150,0,0,33,61,0,0,0,68,2,16,3,112,0,0,0,0,7,2,4,59,0,0,0,100,2,16,3,112],[0,0,0,0,2,2,4,59,0,0,0,0,3,2,0,75,0,0,0,0,3,0,0,25,0,0,0,1,3,0,192,57],[0,0,0,0,3,50,0,75,0,0,3,150,0,0,193,61,0,0,0,132,1,16,3,112,0,0,0,0,3,1,4,59],[0,0,1,64,1,48,0,156,0,0,3,150,0,0,33,61,0,0,0,0,1,0,4,17,0,0,128,1,1,16,0,140],[0,0,2,22,0,0,193,61,0,0,0,0,1,2,0,75,0,6,0,0,0,3,0,29,0,4,0,0,0,7,0,29],[0,0,2,126,0,0,97,61,0,0,0,7,1,0,0,57,0,0,0,0,1,1,4,26,0,0,1,64,1,16,1,151],[0,0,0,0,3,5,0,25,0,0,0,0,1,21,0,75,0,0,2,111,0,0,129,61,0,0,1,71,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,97,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,1,79,1,0,0,65,0,0,0,196,0,16,4,63,0,0,1,80,1,0,0,65],[0,0,0,228,0,16,4,63,0,0,1,81,1,0,0,65,0,0,1,4,0,16,4,63,0,0,1,82,1,0,0,65],[0,0,1,36,0,16,4,63,0,0,1,83,1,0,0,65,0,0,4,91,0,1,4,48,0,0,0,0,1,0,4,22],[0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61,0,0,1,14,1,0,0,57,0,0,0,0,1,1,4,26],[0,0,255,255,1,16,1,143,0,0,1,241,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,3,150,0,0,193,61,0,0,0,0,1,0,4,17,0,0,128,1,1,16,0,140,0,0,0,0,1,0,0,25],[0,0,0,1,1,0,96,57,4,89,3,248,0,0,4,15,0,0,1,14,1,0,0,57,0,0,0,0,2,1,4,26],[0,0,1,75,2,32,1,151,0,0,2,35,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,3,150,0,0,193,61,0,0,1,12,1,0,0,57,0,0,0,0,1,1,4,26,0,0,0,128,1,16,2,112],[0,0,1,241,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61],[0,0,0,4,1,0,0,57,0,0,1,234,0,0,1,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75],[0,0,3,150,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140,0,0,3,150,0,0,65,61],[0,0,0,4,1,16,3,112,0,0,0,0,2,1,4,59,0,0,1,66,1,32,0,156,0,0,3,150,0,0,33,61],[0,0,0,0,1,0,4,17,0,0,128,1,1,16,0,140,0,0,0,0,1,0,0,25,0,0,0,1,1,0,96,57],[0,6,0,0,0,2,0,29,4,89,3,248,0,0,4,15,0,0,0,1,1,0,0,57,0,0,0,0,2,1,4,26],[0,0,1,25,2,32,1,151,0,0,0,6,2,32,1,175,0,0,2,35,0,0,1,61,0,0,0,0,1,0,4,22],[0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61,0,0,0,5,1,0,0,57,0,0,0,0,1,1,4,26],[0,0,1,241,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61],[0,0,0,4,1,48,0,138,0,0,0,96,1,16,0,140,0,0,3,150,0,0,65,61,0,0,0,0,1,0,4,17],[0,0,128,1,1,16,0,140,0,0,0,0,1,0,0,25,0,0,0,1,1,0,96,57,4,89,3,248,0,0,4,15],[0,0,0,64,1,0,4,61,4,89,4,13,0,0,4,15,0,0,0,0,1,0,3,103,0,0,0,36,2,16,3,112],[0,0,0,0,2,2,4,59,0,0,0,128,2,32,2,16,0,0,0,4,3,16,3,112,0,0,0,0,3,3,4,59],[0,0,1,64,3,48,1,151,0,0,0,0,2,35,1,159,0,0,0,7,3,0,0,57,0,0,0,0,0,35,4,27],[0,0,0,68,1,16,3,112,0,0,0,0,1,1,4,59,0,0,0,6,2,0,0,57,0,0,0,0,0,18,4,27],[0,0,0,0,1,0,0,25,0,0,4,90,0,1,4,46,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,3,150,0,0,193,61,0,0,0,1,1,0,0,57,0,0,0,0,1,1,4,26,0,0,1,66,1,16,1,151],[0,0,1,241,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61],[0,0,0,0,1,0,4,26,0,0,0,128,0,16,4,63,0,0,1,63,1,0,0,65,0,0,4,90,0,1,4,46],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61,0,0,0,0,1,0,4,17],[0,0,128,1,1,16,0,140,0,0,2,22,0,0,193,61,0,0,0,7,1,0,0,57,0,0,0,0,3,1,4,26],[0,0,1,64,1,48,1,151,0,0,0,128,0,16,4,63,0,0,0,128,2,48,2,112,0,0,0,160,0,32,4,63],[0,0,1,0,2,0,0,57,0,0,0,64,0,32,4,63,0,0,0,9,2,0,0,57,0,0,0,0,4,2,4,26],[0,0,1,64,2,64,1,151,0,0,0,192,0,32,4,63,0,0,0,128,4,64,2,112,0,0,0,224,0,64,4,63],[0,0,1,64,3,48,0,156,0,0,2,46,0,0,33,61,0,0,1,71,1,0,0,65,0,0,1,0,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,1,4,0,16,4,63,0,0,0,47,1,0,0,57,0,0,1,36,0,16,4,63],[0,0,1,72,1,0,0,65,0,0,1,68,0,16,4,63,0,0,1,73,1,0,0,65,0,0,1,100,0,16,4,63],[0,0,1,74,1,0,0,65,0,0,4,91,0,1,4,48,0,0,1,71,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,31,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,1,114,1,0,0,65,0,0,0,196,0,16,4,63,0,0,1,115,1,0,0,65,0,0,4,91,0,1,4,48],[0,0,1,75,2,32,1,151,0,0,0,1,3,48,0,57,0,0,0,0,2,35,1,159,0,0,0,0,0,33,4,27],[0,0,0,0,1,0,0,25,0,0,4,90,0,1,4,46,0,0,1,68,3,48,0,156,0,0,2,52,0,0,65,61],[0,0,0,0,2,33,0,75,0,0,2,52,0,0,65,61,0,0,1,1,33,16,1,26,0,0,0,11,1,32,0,57],[0,0,0,0,4,1,4,26,0,0,2,68,0,0,1,61,0,0,0,128,1,16,2,16,0,0,0,0,1,18,1,159],[0,0,0,3,2,0,0,57,0,0,0,0,0,18,4,28,0,0,0,0,1,0,0,25,0,0,4,90,0,1,4,46],[0,0,0,224,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,192,0,16,4,63,0,0,1,0,1,0,0,57],[0,0,0,64,0,16,4,63,0,0,1,24,1,0,0,65,0,0,0,0,2,0,4,20,0,0,1,24,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,1,69,1,16,1,199,0,0,128,16,2,0,0,57],[4,89,4,84,0,0,4,15,0,0,0,1,2,32,1,144,0,0,3,150,0,0,97,61,0,0,0,0,4,1,4,59],[0,0,0,64,1,0,4,61,0,0,0,0,0,65,4,53,0,0,1,24,2,0,0,65,0,0,1,24,3,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,1,67,1,16,1,199,0,0,4,90,0,1,4,46],[0,0,1,71,1,0,0,65,0,0,0,192,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,196,0,16,4,63],[0,0,0,228,0,16,4,63,0,0,1,116,1,0,0,65,0,0,1,4,0,16,4,63,0,0,1,85,1,0,0,65],[0,0,4,91,0,1,4,48,0,0,1,71,1,0,0,65,0,0,0,192,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,196,0,16,4,63,0,0,0,40,1,0,0,57,0,0,0,228,0,16,4,63,0,0,1,117,1,0,0,65],[0,0,1,4,0,16,4,63,0,0,1,118,1,0,0,65,0,0,1,36,0,16,4,63,0,0,1,97,1,0,0,65],[0,0,4,91,0,1,4,48,0,0,1,71,1,0,0,65,0,0,0,192,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,196,0,16,4,63,0,0,0,83,1,0,0,57,0,0,0,228,0,16,4,63,0,0,1,119,1,0,0,65],[0,0,1,4,0,16,4,63,0,0,1,120,1,0,0,65,0,0,1,36,0,16,4,63,0,0,1,121,1,0,0,65],[0,0,1,68,0,16,4,63,0,0,1,122,1,0,0,65,0,0,4,91,0,1,4,48,0,0,0,6,1,0,0,107],[0,0,0,0,5,3,0,25,0,0,2,126,0,0,193,61,0,0,1,71,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,63,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,1,76,1,0,0,65,0,0,0,196,0,16,4,63,0,0,1,77,1,0,0,65,0,0,0,228,0,16,4,63],[0,0,1,78,1,0,0,65,0,0,4,91,0,1,4,48,0,2,0,0,0,5,0,29,0,0,0,192,1,0,0,57],[0,0,0,64,0,16,4,63,0,0,0,9,1,0,0,57,0,1,0,0,0,1,0,29,0,0,0,0,3,1,4,26],[0,0,1,64,5,48,1,151,0,0,0,128,0,80,4,63,0,0,0,128,1,48,2,112,0,0,0,160,0,16,4,63],[0,0,1,64,3,48,0,156,0,5,0,0,0,6,0,29,0,3,0,0,0,5,0,29,0,0,2,154,0,0,33,61],[0,0,0,0,3,5,0,75,0,0,2,159,0,0,193,61,0,0,0,0,1,2,0,75,0,0,2,253,0,0,193,61],[0,0,1,71,1,0,0,65,0,0,0,192,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,196,0,16,4,63],[0,0,0,33,1,0,0,57,0,0,0,228,0,16,4,63,0,0,1,112,1,0,0,65,0,0,1,4,0,16,4,63],[0,0,1,113,1,0,0,65,0,0,2,94,0,0,1,61,0,0,0,0,3,97,0,75,0,0,2,161,0,0,97,61],[0,0,1,64,2,16,0,156,0,0,0,173,0,0,97,61,0,0,2,188,0,0,1,61,0,0,0,5,3,16,0,108],[0,0,2,188,0,0,193,61,0,0,0,0,1,2,0,75,0,0,2,243,0,0,193,61,0,0,0,3,2,0,0,41],[0,0,0,2,1,32,0,108,0,0,3,39,0,0,193,61,0,0,0,5,1,0,0,41,0,0,0,1,1,16,0,138],[0,0,1,64,2,16,0,156,0,0,0,173,0,0,33,61,0,0,1,64,1,16,1,151,0,0,1,1,33,16,1,26],[0,0,0,11,1,32,0,57,0,0,0,0,1,1,4,26,0,0,0,4,1,16,0,107,0,0,3,152,0,0,193,61],[0,0,0,6,1,0,0,107,0,0,3,100,0,0,97,61,0,0,1,71,1,0,0,65,0,0,0,192,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,196,0,16,4,63,0,0,0,60,1,0,0,57,0,0,0,228,0,16,4,63],[0,0,1,102,1,0,0,65,0,0,1,4,0,16,4,63,0,0,1,103,1,0,0,65,0,0,2,94,0,0,1,61],[0,0,0,1,2,16,0,57,0,0,0,5,2,32,0,108,0,0,3,9,0,0,193,61,0,0,0,1,2,16,0,138],[0,0,1,64,3,32,0,156,0,0,0,173,0,0,33,61,0,0,0,10,3,0,0,57,0,0,0,0,3,3,4,26],[0,0,1,64,2,32,1,151,0,0,1,1,82,32,1,26,0,0,0,11,2,80,0,57,0,0,0,0,2,2,4,26],[0,0,0,224,0,16,4,63,0,0,0,3,1,0,0,41,0,0,1,0,0,16,4,63,0,0,1,32,0,32,4,63],[0,0,1,64,0,48,4,63,0,0,0,192,0,64,4,63,0,0,1,96,1,0,0,57,0,0,0,64,0,16,4,63],[0,0,1,24,1,0,0,65,0,0,0,0,2,0,4,20,0,0,1,24,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,1,86,1,16,1,199,0,0,128,16,2,0,0,57,4,89,4,84,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,0,4,3,0,0,41,0,0,3,150,0,0,97,61,0,0,0,64,2,0,4,61],[0,0,0,0,1,1,4,59,0,0,0,0,1,19,0,75,0,0,3,162,0,0,193,61,0,0,0,3,3,0,0,41],[0,0,0,2,1,48,0,107,0,0,3,197,0,0,161,61,0,0,1,94,1,32,0,156,0,0,1,83,0,0,33,61],[0,0,0,64,1,32,0,57,0,0,0,64,0,16,4,63,0,0,0,32,1,32,0,57,0,0,0,5,4,0,0,41],[0,0,0,0,0,65,4,53,0,0,0,2,3,0,0,41,0,0,0,0,0,50,4,53,0,0,0,128,1,64,2,16],[0,0,0,0,1,19,1,159,0,0,0,1,2,0,0,41,0,0,0,0,0,18,4,27,0,0,0,1,1,64,0,138],[0,0,1,64,2,16,0,156,0,0,0,173,0,0,33,61,0,0,3,93,0,0,1,61,0,0,1,71,1,0,0,65],[0,0,0,192,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,196,0,16,4,63,0,0,0,53,1,0,0,57],[0,0,0,228,0,16,4,63,0,0,1,95,1,0,0,65,0,0,1,4,0,16,4,63,0,0,1,96,1,0,0,65],[0,0,2,94,0,0,1,61,0,0,0,5,1,0,0,107,0,0,3,49,0,0,193,61,0,0,1,71,1,0,0,65],[0,0,0,192,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,196,0,16,4,63,0,0,0,44,1,0,0,57],[0,0,0,228,0,16,4,63,0,0,1,110,1,0,0,65,0,0,1,4,0,16,4,63,0,0,1,111,1,0,0,65],[0,0,2,94,0,0,1,61,0,0,1,71,1,0,0,65,0,0,0,192,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,196,0,16,4,63,0,0,0,27,1,0,0,57,0,0,0,228,0,16,4,63,0,0,1,84,1,0,0,65],[0,0,2,82,0,0,1,61,0,0,0,64,2,16,0,57,0,0,0,64,0,32,4,63,0,0,0,32,2,16,0,57],[0,0,0,4,3,0,0,41,0,0,0,0,0,50,4,53,0,0,0,5,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,0,128,1,48,2,16,0,0,1,64,2,32,1,151,0,0,0,0,1,18,1,159,0,0,0,3,2,0,0,41],[0,0,0,0,0,18,4,27,0,0,0,100,1,0,0,57,0,0,0,0,1,16,3,103,0,0,0,0,1,1,4,59],[0,0,0,6,2,0,0,57,0,0,0,0,0,18,4,27,0,0,0,4,1,0,0,57,0,0,0,6,2,0,0,41],[0,0,0,0,0,33,4,28,0,0,0,0,1,0,0,25,0,0,4,90,0,1,4,46,0,0,1,71,1,0,0,65],[0,0,0,192,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,196,0,16,4,63,0,0,0,47,1,0,0,57],[0,0,0,228,0,16,4,63,0,0,1,98,1,0,0,65,0,0,1,4,0,16,4,63,0,0,1,99,1,0,0,65],[0,0,2,94,0,0,1,61,0,0,0,5,1,0,0,41,0,0,1,64,1,16,0,65,0,3,0,0,0,1,0,29],[0,0,0,224,1,16,2,16,0,0,0,224,0,16,4,63,0,0,0,4,1,0,0,57,0,0,0,192,0,16,4,63],[0,0,1,0,1,0,0,57,0,0,0,64,0,16,4,63,0,0,1,24,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,1,24,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,1,104,1,16,1,199],[0,0,128,16,2,0,0,57,4,89,4,84,0,0,4,15,0,0,0,1,2,32,1,144,0,0,0,4,3,0,0,41],[0,0,3,150,0,0,97,61,0,0,0,64,2,0,4,61,0,0,0,0,1,1,4,59,0,0,0,0,1,49,0,75],[0,0,3,171,0,0,193,61,0,0,0,3,1,0,0,41,0,0,1,64,1,16,1,151,0,0,1,1,49,16,1,26],[0,0,0,11,1,48,0,57,0,0,0,4,3,0,0,41,0,0,0,0,0,49,4,27,0,0,1,94,1,32,0,156],[0,0,1,83,0,0,33,61,0,0,0,64,1,32,0,57,0,0,0,64,0,16,4,63,0,0,0,32,1,32,0,57],[0,0,0,5,4,0,0,41,0,0,0,0,0,65,4,53,0,0,0,2,3,0,0,41,0,0,0,0,0,50,4,53],[0,0,0,128,1,64,2,16,0,0,0,0,1,19,1,159,0,0,0,1,2,0,0,41,0,0,0,0,0,18,4,27],[0,0,0,1,1,64,0,138,0,0,1,64,1,16,1,151,0,0,1,1,33,16,1,26,0,0,0,11,1,32,0,57],[0,0,0,4,2,0,0,41,0,0,0,0,0,33,4,27,0,0,0,10,1,0,0,57,0,0,0,0,0,1,4,27],[0,0,1,13,1,0,0,57,0,0,0,0,2,1,4,26,0,0,1,68,3,32,0,156,0,0,3,191,0,0,129,61],[0,0,0,64,3,0,4,61,0,0,1,94,4,48,0,156,0,0,1,83,0,0,33,61,0,0,0,64,4,48,0,57],[0,0,0,64,0,64,4,63,0,0,1,12,4,0,0,57,0,0,0,0,6,4,4,26,0,0,1,64,4,96,1,151],[0,0,0,0,4,67,4,54,0,0,0,128,5,96,2,112,0,0,0,0,0,84,4,53,0,0,1,64,6,96,0,156],[0,0,3,220,0,0,33,61,0,0,0,0,6,3,4,51,0,0,1,64,6,96,1,152,0,0,3,220,0,0,193,61],[0,0,0,7,5,0,0,57,0,0,0,0,5,5,4,26,0,0,0,128,5,80,2,112,0,0,0,0,0,84,4,53],[0,0,1,107,2,32,1,151,0,0,0,0,2,37,1,159,0,0,0,0,0,33,4,27,0,0,0,6,6,0,0,107],[0,0,3,223,0,0,193,61,0,0,0,64,1,0,4,61,0,0,0,100,2,16,0,57,0,0,1,108,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,68,2,16,0,57,0,0,1,109,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,40,3,0,0,57,0,0,0,0,0,50,4,53,0,0,1,71,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,1,24,2,0,0,65,0,0,1,24,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16],[0,0,1,89,1,16,1,199,0,0,4,91,0,1,4,48,0,0,0,0,1,0,0,25,0,0,4,91,0,1,4,48],[0,0,1,71,1,0,0,65,0,0,0,192,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,196,0,16,4,63],[0,0,0,51,1,0,0,57,0,0,0,228,0,16,4,63,0,0,1,100,1,0,0,65,0,0,1,4,0,16,4,63],[0,0,1,101,1,0,0,65,0,0,2,94,0,0,1,61,0,0,0,100,1,32,0,57,0,0,1,87,3,0,0,65],[0,0,0,0,0,49,4,53,0,0,0,68,1,32,0,57,0,0,1,88,3,0,0,65,0,0,0,0,0,49,4,53],[0,0,0,36,1,32,0,57,0,0,0,38,3,0,0,57,0,0,3,179,0,0,1,61,0,0,0,100,1,32,0,57],[0,0,1,105,3,0,0,65,0,0,0,0,0,49,4,53,0,0,0,68,1,32,0,57,0,0,1,106,3,0,0,65],[0,0,0,0,0,49,4,53,0,0,0,36,1,32,0,57,0,0,0,39,3,0,0,57,0,0,0,0,0,49,4,53],[0,0,1,71,1,0,0,65,0,0,0,0,0,18,4,53,0,0,0,4,1,32,0,57,0,0,0,32,3,0,0,57],[0,0,0,0,0,49,4,53,0,0,1,24,1,0,0,65,0,0,1,24,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,64,1,32,2,16,0,0,1,89,1,16,1,199,0,0,4,91,0,1,4,48,0,0,0,1,1,0,0,41],[0,0,0,0,1,1,4,26,0,0,1,12,2,0,0,57,0,0,0,0,0,18,4,27,0,0,0,0,1,0,0,25],[0,0,4,90,0,1,4,46,0,0,0,132,1,32,0,57,0,0,1,90,3,0,0,65,0,0,0,0,0,49,4,53],[0,0,0,100,1,32,0,57,0,0,1,91,3,0,0,65,0,0,0,0,0,49,4,53,0,0,0,68,1,32,0,57],[0,0,1,92,3,0,0,65,0,0,0,0,0,49,4,53,0,0,0,36,1,32,0,57,0,0,0,93,3,0,0,57],[0,0,0,0,0,49,4,53,0,0,1,71,1,0,0,65,0,0,0,0,0,18,4,53,0,0,0,4,1,32,0,57],[0,0,0,32,3,0,0,57,0,0,0,0,0,49,4,53,0,0,1,24,1,0,0,65,0,0,1,24,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,1,93,1,16,1,199,0,0,4,91,0,1,4,48],[0,0,0,6,6,0,0,107,0,0,3,225,0,0,193,61,0,0,3,195,0,0,1,61,0,0,0,6,6,0,0,41],[0,6,0,1,0,96,0,146,0,0,0,6,5,80,0,41,0,0,1,64,6,80,0,156,0,0,0,173,0,0,33,61],[0,0,0,0,0,84,4,53,0,0,0,2,5,0,0,41,0,0,0,0,0,83,4,53,0,0,0,0,5,4,4,51],[0,0,1,64,6,80,1,151,0,0,0,5,6,96,0,108,0,0,3,237,0,0,129,61,0,0,0,128,5,80,2,16],[0,0,3,244,0,0,1,61,0,0,0,5,6,0,0,41,0,0,0,128,5,96,2,16,0,0,0,0,2,82,1,159],[0,0,0,0,0,33,4,27,0,0,0,0,0,100,4,53,0,0,0,0,1,3,4,51,0,2,0,0,0,1,0,29],[0,0,0,2,1,0,0,41,0,0,1,64,1,16,1,151,0,0,0,0,1,81,1,159,0,0,3,193,0,0,1,61],[0,0,0,0,1,1,0,75,0,0,3,251,0,0,97,61,0,0,0,0,0,1,4,45,0,0,0,64,1,0,4,61],[0,0,0,68,2,16,0,57,0,0,1,114,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,31,3,0,0,57,0,0,0,0,0,50,4,53,0,0,1,71,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53,0,0,1,24,2,0,0,65],[0,0,1,24,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,1,125,1,16,1,199],[0,0,4,91,0,1,4,48,0,0,1,126,2,16,0,156,0,0,4,18,0,0,129,61,0,0,0,64,1,16,0,57],[0,0,0,64,0,16,4,63,0,0,0,0,0,1,4,45,0,0,1,123,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,65,1,0,0,57,0,0,0,4,0,16,4,63,0,0,1,124,1,0,0,65,0,0,4,91,0,1,4,48],[0,0,0,64,3,0,4,61,0,0,1,126,1,48,0,156,0,0,4,37,0,0,129,61,0,0,0,64,1,48,0,57],[0,0,0,64,0,16,4,63,0,0,0,7,1,0,0,57,0,0,0,0,2,1,4,26,0,0,0,32,4,48,0,57],[0,0,0,128,1,32,2,112,0,0,0,0,0,20,4,53,0,0,1,64,2,32,1,151,0,0,0,0,0,35,4,53],[0,0,0,0,0,1,4,45,0,0,1,123,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,1,124,1,0,0,65,0,0,4,91,0,1,4,48,0,0,0,64,3,0,4,61],[0,0,1,126,1,48,0,156,0,0,4,56,0,0,129,61,0,0,0,64,1,48,0,57,0,0,0,64,0,16,4,63],[0,0,0,9,1,0,0,57,0,0,0,0,2,1,4,26,0,0,0,32,4,48,0,57,0,0,0,128,1,32,2,112],[0,0,0,0,0,20,4,53,0,0,1,64,2,32,1,151,0,0,0,0,0,35,4,53,0,0,0,0,0,1,4,45],[0,0,1,123,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57,0,0,0,4,0,16,4,63],[0,0,1,124,1,0,0,65,0,0,4,91,0,1,4,48,0,0,1,24,3,0,0,65,0,0,1,24,4,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,64,1,16,2,16,0,0,1,24,4,32,0,156,0,0,0,0,2,3,128,25],[0,0,0,96,2,32,2,16,0,0,0,0,1,18,1,159,0,0,0,0,2,0,4,20,0,0,1,24,4,32,0,156],[0,0,0,0,2,3,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,1,127,1,16,1,199],[0,0,128,16,2,0,0,57,4,89,4,84,0,0,4,15,0,0,0,1,2,32,1,144,0,0,4,82,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,0,0,1,4,45,0,0,0,0,1,0,0,25,0,0,4,91,0,1,4,48],[0,0,4,87,0,33,4,35,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25],[0,0,0,0,0,1,4,45,0,0,4,89,0,0,4,50,0,0,4,90,0,1,4,46,0,0,4,91,0,1,4,48],[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],[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,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255,255,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,0,0,0,0,0,0,0,0,0,0,0,0,0,8,225,188,155,240,64,0],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,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,0,0,0,0,0,133,223,81,252],[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,166,174,10,171],[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,208,242,198,98],[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,221,234,168,229],[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,221,234,168,230],[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,254,23,59,151],[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,208,242,198,99],[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,212,164,202,13],[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,166,174,10,172],[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,168,81,174,120],[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,191,31,228,32],[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,147,139,95,49],[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,147,139,95,50],[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,154,138,5,146],[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,160,128,62,247],[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,133,223,81,253],[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,138,200,76,14],[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,142,138,207,135],[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,54,53,243,229],[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,120,119,167,150],[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,124,155,209,242],[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,124,155,209,243],[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,128,180,18,70],[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,120,119,167,151],[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,121,107,137,185],[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,54,53,243,230],[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,66,203,177,92],[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,110,242,92,58],[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,25,202,228,97],[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,25,202,228,98],[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,41,241,114,173],[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,48,229,204,189],[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,2,250,87,121],[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,6,190,208,54],[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,6,231,81,123],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,128,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,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,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,224,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0],[8,195,121,160,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],[84,104,101,32,99,117,114,114,101,110,116,32,98,97,116,99,104,32,110,117,109,98,101,114,32,109,117,115,116,32,98,101],[32,103,114,101,97,116,101,114,32,116,104,97,110,32,48,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,0,0,0,0,132,0,0,1,0,0,0,0,0,0,0,0,0],[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0],[84,104,101,114,101,32,109,117,115,116,32,98,101,32,97,32,118,105,114,116,117,97,108,32,98,108,111,99,107,32,99,114],[101,97,116,101,100,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,98,97,116,99,104,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[84,104,101,32,116,105,109,101,115,116,97,109,112,32,111,102,32,116,104,101,32,76,50,32,98,108,111,99,107,32,109,117],[115,116,32,98,101,32,103,114,101,97,116,101,114,32,116,104,97,110,32,111,114,32,101,113,117,97,108,32,116,111,32,116],[104,101,32,116,105,109,101,115,116,97,109,112,32,111,102,32,116,104,101,32,99,117,114,114,101,110,116,32,98,97,116,99],[104,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,196,0,0,0,128,0,0,0,0,0,0,0,0],[73,110,118,97,108,105,100,32,110,101,119,32,76,50,32,98,108,111,99,107,32,110,117,109,98,101,114,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,192,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,224,0,0,0,0,0,0,0,0],[111,114,114,101,99,116,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],[84,104,101,32,99,117,114,114,101,110,116,32,76,50,32,98,108,111,99,107,32,104,97,115,104,32,105,115,32,105,110,99],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,0,0],[116,97,109,112,32,111,102,32,116,104,101,32,112,114,101,118,105,111,117,115,32,76,50,32,98,108,111,99,107,0,0,0],[107,32,109,117,115,116,32,98,101,32,103,114,101,97,116,101,114,32,116,104,97,110,32,116,104,101,32,116,105,109,101,115],[84,104,101,32,116,105,109,101,115,116,97,109,112,32,111,102,32,116,104,101,32,110,101,119,32,76,50,32,98,108,111,99],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,164,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,0,0,0,0,255,255,255,255,255,255,255,191],[67,97,110,32,110,111,116,32,114,101,117,115,101,32,76,50,32,98,108,111,99,107,32,110,117,109,98,101,114,32,102,114],[111,109,32,116,104,101,32,112,114,101,118,105,111,117,115,32,98,97,116,99,104,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,132,0,0,0,192,0,0,0,0,0,0,0,0],[84,104,101,32,116,105,109,101,115,116,97,109,112,32,111,102,32,116,104,101,32,115,97,109,101,32,76,50,32,98,108,111],[99,107,32,109,117,115,116,32,98,101,32,115,97,109,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[84,104,101,32,112,114,101,118,105,111,117,115,32,104,97,115,104,32,111,102,32,116,104,101,32,115,97,109,101,32,76,50],[32,98,108,111,99,107,32,109,117,115,116,32,98,101,32,115,97,109,101,0,0,0,0,0,0,0,0,0,0,0,0,0],[67,97,110,32,110,111,116,32,99,114,101,97,116,101,32,118,105,114,116,117,97,108,32,98,108,111,99,107,115,32,105,110],[32,116,104,101,32,109,105,100,100,108,101,32,111,102,32,116,104,101,32,109,105,110,105,98,108,111,99,107,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,224,0,0,0,0,0,0,0,0],[99,111,114,114,101,99,116,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],[84,104,101,32,112,114,101,118,105,111,117,115,32,76,50,32,98,108,111,99,107,32,104,97,115,104,32,105,115,32,105,110],[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[97,108,32,98,108,111,99,107,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[67,97,110,39,116,32,105,110,105,116,105,97,108,105,122,101,32,116,104,101,32,102,105,114,115,116,32,118,105,114,116,117],[76,50,32,98,108,111,99,107,32,110,117,109,98,101,114,32,105,115,32,110,101,118,101,114,32,101,120,112,101,99,116,101],[100,32,116,111,32,98,101,32,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[85,112,103,114,97,100,101,32,116,114,97,110,115,97,99,116,105,111,110,32,109,117,115,116,32,98,101,32,102,105,114,115],[116,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],[67,97,108,108,97,98,108,101,32,111,110,108,121,32,98,121,32,116,104,101,32,98,111,111,116,108,111,97,100,101,114,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,128,0,0,0,0,0,0,0,0],[84,105,109,101,115,116,97,109,112,115,32,115,104,111,117,108,100,32,98,101,32,105,110,99,114,101,109,101,110,116,97,108],[84,104,101,32,112,114,111,118,105,100,101,100,32,98,108,111,99,107,32,110,117,109,98,101,114,32,105,115,32,110,111,116],[32,99,111,114,114,101,99,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[84,104,101,32,116,105,109,101,115,116,97,109,112,32,111,102,32,116,104,101,32,98,97,116,99,104,32,109,117,115,116,32],[98,101,32,103,114,101,97,116,101,114,32,116,104,97,110,32,116,104,101,32,116,105,109,101,115,116,97,109,112,32,111,102],[32,116,104,101,32,112,114,101,118,105,111,117,115,32,98,108,111,99,107,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,164,0,0,0,192,0,0,0,0,0,0,0,0],[78,72,123,113,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,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,100,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,0,0,0,0,255,255,255,255,255,255,255,192],[2,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],[24,39,86,27,18,102,204,92,30,2,117,140,74,185,186,92,56,38,42,164,136,173,174,88,124,113,102,32,107,183,146,68]],"0x000000000000000000000000000000000000800c":[[0,2,0,0,0,0,0,2,0,17,0,0,0,0,0,2,0,1,0,0,0,1,3,85,0,0,0,0,3,1,0,25],[0,0,0,96,5,48,2,112,0,0,7,155,0,80,1,157,0,0,0,128,4,0,0,57,0,0,0,64,0,64,4,63],[0,0,7,155,3,80,1,151,0,0,0,1,2,32,1,144,0,0,0,111,0,0,193,61,0,0,0,4,2,48,0,140],[0,0,0,159,0,0,65,61,0,0,0,0,2,1,4,59,0,0,7,157,2,32,1,151,0,0,7,158,2,32,0,156],[0,0,0,159,0,0,193,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,0,159,0,0,193,61],[0,0,0,4,2,48,0,138,0,0,0,32,6,32,0,140,0,0,0,159,0,0,65,61,0,0,0,4,6,16,3,112],[0,0,0,0,13,6,4,59,0,0,7,159,6,208,0,156,0,0,0,159,0,0,33,61,0,0,0,0,2,210,0,73],[0,0,7,160,6,0,0,65,0,0,2,96,7,32,0,140,0,0,0,0,7,0,0,25,0,0,0,0,7,6,64,25],[0,0,7,160,2,32,1,151,0,0,0,0,8,2,0,75,0,0,0,0,6,0,160,25,0,0,7,160,2,32,0,156],[0,0,0,0,6,7,192,25,0,0,0,0,2,6,0,75,0,0,0,159,0,0,193,61,0,0,0,4,12,208,0,57],[0,0,0,0,2,193,3,79,0,0,0,0,2,2,4,59,0,0,0,0,6,2,0,75,0,0,0,119,0,0,193,61],[0,0,0,0,2,49,3,79,0,0,1,0,5,192,0,57,0,0,0,0,4,81,3,79,0,0,0,0,4,4,4,59],[0,0,0,128,6,64,0,140,0,0,0,161,0,0,65,61,0,0,0,128,6,64,2,112,0,0,7,168,7,64,0,156],[0,0,0,0,6,4,160,25,0,0,7,168,7,64,0,156,0,0,0,0,7,0,0,25,0,0,0,16,7,0,32,57],[0,0,0,8,8,112,1,191,0,0,7,159,9,96,0,156,0,0,0,0,8,7,160,25,0,0,0,64,7,96,2,112],[0,0,7,159,9,96,0,156,0,0,0,0,7,6,160,25,0,0,0,4,9,128,1,191,0,0,7,155,6,112,0,156],[0,0,0,0,9,8,160,25,0,0,0,32,8,112,2,112,0,0,7,155,6,112,0,156,0,0,0,0,8,7,160,25],[0,0,0,2,6,144,1,191,0,0,255,255,7,128,0,140,0,0,0,0,6,9,160,25,0,0,0,16,7,128,2,112],[0,0,0,0,7,8,160,25,0,0,0,255,7,112,0,140,0,0,0,1,6,96,32,57,0,0,0,32,7,0,0,138],[0,0,0,193,8,96,0,57,0,0,0,0,7,120,1,111,0,0,0,64,0,112,4,63,0,0,0,2,7,96,0,57],[0,0,0,128,0,112,4,63,0,0,0,33,7,96,0,57,0,0,0,5,7,112,2,114,0,0,0,93,0,0,97,61],[0,0,0,0,8,0,0,25,0,0,0,5,9,128,2,16,0,0,0,0,10,146,3,79,0,0,0,0,10,10,4,59],[0,0,0,160,9,144,0,57,0,0,0,0,0,169,4,53,0,0,0,1,8,128,0,57,0,0,0,0,9,120,0,75],[0,0,0,85,0,0,65,61,0,0,0,0,7,0,0,75,0,0,0,95,0,0,97,61,0,0,0,128,7,0,4,61],[0,0,0,0,7,7,0,75,0,0,1,193,0,0,97,61,0,0,0,160,7,0,4,61,0,0,7,167,7,112,1,151],[0,0,0,248,8,96,2,16,0,0,0,0,7,120,1,159,0,0,7,169,7,112,0,65,0,0,0,160,0,112,4,63],[0,0,0,3,6,96,2,16,0,0,0,248,6,96,0,137,0,0,0,0,4,100,1,207,0,0,0,255,6,96,0,140],[0,0,0,0,4,0,32,25,0,0,0,161,0,64,4,63,0,0,0,174,0,0,1,61,0,0,0,0,1,0,4,22],[0,0,0,0,1,1,0,75,0,0,0,159,0,0,193,61,0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67],[0,0,1,32,0,0,4,67,0,0,7,156,1,0,0,65,0,0,30,105,0,1,4,46,0,0,0,113,6,32,0,140],[0,0,0,251,0,0,193,61,0,0,1,196,2,208,0,57,0,0,0,0,2,33,3,79,0,0,0,0,6,211,0,73],[0,0,0,35,6,96,0,138,0,0,0,0,2,2,4,59,0,0,7,160,7,0,0,65,0,0,0,0,8,98,0,75],[0,0,0,0,8,0,0,25,0,0,0,0,8,7,128,25,0,0,7,160,6,96,1,151,0,0,7,160,9,32,1,151],[0,0,0,0,10,105,0,75,0,0,0,0,7,0,128,25,0,0,0,0,6,105,1,63,0,0,7,160,6,96,0,156],[0,0,0,0,7,8,192,25,0,0,0,0,6,7,0,75,0,0,0,159,0,0,193,61,0,0,0,0,2,194,0,25],[0,0,0,0,6,33,3,79,0,0,0,0,6,6,4,59,0,0,7,159,7,96,0,156,0,0,0,159,0,0,33,61],[0,0,0,0,7,99,0,73,0,0,0,32,2,32,0,57,0,0,7,160,8,0,0,65,0,0,0,0,9,114,0,75],[0,0,0,0,9,0,0,25,0,0,0,0,9,8,32,25,0,0,7,160,7,112,1,151,0,0,7,160,10,32,1,151],[0,0,0,0,11,122,0,75,0,0,0,0,8,0,128,25,0,0,0,0,7,122,1,63,0,0,7,160,7,112,0,156],[0,0,0,0,8,9,192,25,0,0,0,0,7,8,0,75,0,0,2,193,0,0,97,61,0,0,0,0,1,0,0,25],[0,0,30,106,0,1,4,48,0,0,0,248,6,64,2,16,0,0,7,160,7,0,0,65,0,0,0,0,4,4,0,75],[0,0,0,0,7,6,192,25,0,0,0,192,4,0,0,57,0,0,0,64,0,64,4,63,0,0,0,1,4,0,0,57],[0,0,0,128,0,64,4,63,0,0,0,0,4,32,3,80,0,0,0,0,4,4,4,59,0,0,7,167,4,64,1,151],[0,0,0,0,4,116,1,159,0,0,0,160,0,64,4,63,0,13,0,0,0,13,0,29,0,12,0,0,0,12,0,29],[0,0,0,64,4,0,4,61,0,0,0,96,5,80,0,138,0,0,0,0,6,81,3,79,0,0,0,0,6,6,4,59],[0,0,0,128,7,96,0,140,0,0,1,87,0,0,65,61,0,0,0,128,7,96,2,112,0,0,7,168,8,96,0,156],[0,0,0,0,7,6,160,25,0,0,7,168,8,96,0,156,0,0,0,0,8,0,0,25,0,0,0,16,8,0,32,57],[0,0,0,8,9,128,1,191,0,0,7,159,10,112,0,156,0,0,0,0,9,8,160,25,0,0,0,64,8,112,2,112],[0,0,7,159,10,112,0,156,0,0,0,0,8,7,160,25,0,0,0,4,10,144,1,191,0,0,7,155,7,128,0,156],[0,0,0,0,10,9,160,25,0,0,0,32,9,128,2,112,0,0,7,155,7,128,0,156,0,0,0,0,9,8,160,25],[0,0,0,2,7,160,1,191,0,0,255,255,8,144,0,140,0,0,0,0,7,10,160,25,0,0,0,16,8,144,2,112],[0,0,0,0,8,9,160,25,0,0,0,255,8,128,0,140,0,0,0,1,7,112,32,57,0,0,0,32,8,0,0,138],[0,0,0,65,9,112,0,57,0,0,0,0,8,137,1,111,0,0,0,0,8,132,0,25,0,0,0,0,9,72,0,75],[0,0,0,0,9,0,0,25,0,0,0,1,9,0,64,57,0,0,7,159,10,128,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,9,144,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,128,4,63,0,0,0,2,8,112,0,57],[0,0,0,0,8,132,4,54,0,0,0,33,9,112,0,57,0,0,0,5,9,144,2,114,0,0,0,233,0,0,97,61],[0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16,0,0,0,0,12,184,0,25,0,0,0,0,11,178,3,79],[0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53,0,0,0,1,10,160,0,57,0,0,0,0,11,154,0,75],[0,0,0,225,0,0,65,61,0,0,0,0,9,0,0,75,0,0,0,235,0,0,97,61,0,0,0,0,9,4,4,51],[0,0,0,0,9,9,0,75,0,0,1,193,0,0,97,61,0,0,0,0,9,8,4,51,0,0,7,167,9,144,1,151],[0,0,0,248,10,112,2,16,0,0,0,0,9,154,1,159,0,0,7,169,9,144,0,65,0,0,0,0,0,152,4,53],[0,0,0,3,7,112,2,16,0,0,0,248,7,112,0,137,0,0,0,0,6,118,1,207,0,0,0,255,7,112,0,140],[0,0,0,0,6,0,32,25,0,0,0,33,7,64,0,57,0,0,1,215,0,0,1,61,0,0,0,2,1,32,0,140],[0,0,1,93,0,0,193,61,0,13,0,0,0,13,0,29,0,12,0,0,0,12,0,29,0,0,7,164,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,7,155,1,0,0,65,0,0,0,0,2,0,4,20,0,0,7,155,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,7,165,1,16,1,199,0,0,128,11,2,0,0,57],[30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144,0,0,24,107,0,0,97,61,0,0,0,64,3,0,4,61],[0,0,0,0,4,1,4,59,0,0,0,128,1,64,0,140,0,0,2,219,0,0,65,61,0,0,0,128,1,64,2,112],[0,0,7,168,2,64,0,156,0,0,0,0,1,4,160,25,0,0,7,168,2,64,0,156,0,0,0,0,2,0,0,25],[0,0,0,16,2,0,32,57,0,0,0,8,5,32,1,191,0,0,7,159,6,16,0,156,0,0,0,0,5,2,160,25],[0,0,0,64,2,16,2,112,0,0,7,159,6,16,0,156,0,0,0,0,2,1,160,25,0,0,0,4,1,80,1,191],[0,0,7,155,6,32,0,156,0,0,0,0,1,5,160,25,0,0,0,32,6,32,2,112,0,0,7,155,5,32,0,156],[0,0,0,0,6,2,160,25,0,0,0,2,5,16,1,191,0,0,255,255,2,96,0,140,0,0,0,0,5,1,160,25],[0,0,0,16,1,96,2,112,0,0,0,0,1,6,160,25,0,0,0,255,1,16,0,140,0,0,0,1,5,80,32,57],[0,0,0,32,1,0,0,138,0,0,0,65,2,80,0,57,0,0,0,0,1,18,1,111,0,0,0,0,1,19,0,25],[0,0,0,0,2,49,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,7,159,6,16,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,2,32,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,16,4,63],[0,0,0,2,1,80,0,57,0,0,0,0,6,19,4,54,0,0,0,1,1,0,3,103,0,0,0,0,2,0,0,49],[0,0,0,33,7,80,0,57,0,0,0,5,7,112,2,114,0,0,1,69,0,0,97,61,0,0,0,0,8,33,3,79],[0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16,0,0,0,0,11,166,0,25,0,0,0,0,10,168,3,79],[0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75],[0,0,1,61,0,0,65,61,0,0,0,0,7,0,0,75,0,0,1,71,0,0,97,61,0,0,0,0,7,3,4,51],[0,0,0,0,7,7,0,75,0,0,1,193,0,0,97,61,0,0,0,0,7,6,4,51,0,0,7,167,7,112,1,151],[0,0,0,248,8,80,2,16,0,0,0,0,7,120,1,159,0,0,7,169,7,112,0,65,0,0,0,0,0,118,4,53],[0,0,0,3,5,80,2,16,0,0,0,248,5,80,0,137,0,0,0,0,4,84,1,207,0,0,0,255,5,80,0,140],[0,0,0,0,4,0,32,25,0,0,0,33,5,48,0,57,0,0,2,238,0,0,1,61,0,0,7,166,7,64,0,156],[0,0,1,185,0,0,161,61,0,0,7,195,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57],[0,0,1,196,0,0,1,61,0,0,0,1,1,32,0,140,0,0,1,199,0,0,193,61,0,13,0,0,0,13,0,29],[0,12,0,0,0,12,0,29,0,0,7,164,1,0,0,65,0,0,0,0,0,16,4,57,0,0,7,155,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,7,155,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,7,165,1,16,1,199,0,0,128,11,2,0,0,57,30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,24,107,0,0,97,61,0,0,0,64,3,0,4,61,0,0,0,0,4,1,4,59,0,0,0,128,1,64,0,140],[0,0,3,60,0,0,65,61,0,0,0,128,1,64,2,112,0,0,7,168,2,64,0,156,0,0,0,0,1,4,160,25],[0,0,7,168,2,64,0,156,0,0,0,0,2,0,0,25,0,0,0,16,2,0,32,57,0,0,0,8,5,32,1,191],[0,0,7,159,6,16,0,156,0,0,0,0,5,2,160,25,0,0,0,64,2,16,2,112,0,0,7,159,6,16,0,156],[0,0,0,0,2,1,160,25,0,0,0,4,1,80,1,191,0,0,7,155,6,32,0,156,0,0,0,0,1,5,160,25],[0,0,0,32,6,32,2,112,0,0,7,155,5,32,0,156,0,0,0,0,6,2,160,25,0,0,0,2,5,16,1,191],[0,0,255,255,2,96,0,140,0,0,0,0,5,1,160,25,0,0,0,16,1,96,2,112,0,0,0,0,1,6,160,25],[0,0,0,255,1,16,0,140,0,0,0,1,5,80,32,57,0,0,0,32,1,0,0,138,0,0,0,65,2,80,0,57],[0,0,0,0,1,18,1,111,0,0,0,0,1,19,0,25,0,0,0,0,2,49,0,75,0,0,0,0,2,0,0,25],[0,0,0,1,2,0,64,57,0,0,7,159,6,16,0,156,0,0,1,89,0,0,33,61,0,0,0,1,2,32,1,144],[0,0,1,89,0,0,193,61,0,0,0,64,0,16,4,63,0,0,0,2,1,80,0,57,0,0,0,0,6,19,4,54],[0,0,0,1,1,0,3,103,0,0,0,0,2,0,0,49,0,0,0,33,7,80,0,57,0,0,0,5,7,112,2,114],[0,0,1,167,0,0,97,61,0,0,0,0,8,33,3,79,0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16],[0,0,0,0,11,166,0,25,0,0,0,0,10,168,3,79,0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53],[0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75,0,0,1,159,0,0,65,61,0,0,0,0,7,0,0,75],[0,0,1,169,0,0,97,61,0,0,0,0,7,3,4,51,0,0,0,0,7,7,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,7,6,4,51,0,0,7,167,7,112,1,151,0,0,0,248,8,80,2,16,0,0,0,0,7,120,1,159],[0,0,7,169,7,112,0,65,0,0,0,0,0,118,4,53,0,0,0,3,5,80,2,16,0,0,0,248,5,80,0,137],[0,0,0,0,4,84,1,207,0,0,0,255,5,80,0,140,0,0,0,0,4,0,32,25,0,0,0,33,5,48,0,57],[0,0,3,79,0,0,1,61,0,0,0,64,7,64,0,57,0,0,0,64,0,112,4,63,0,0,0,1,7,0,0,58],[0,0,0,0,7,116,4,54,0,0,0,0,8,32,3,80,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53],[0,0,1,209,0,0,193,61,0,0,7,195,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,50,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,7,196,1,0,0,65,0,0,30,106,0,1,4,48,0,0,7,161,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,23,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,7,162,1,0,0,65,0,0,0,196,0,16,4,63,0,0,7,163,1,0,0,65],[0,0,30,106,0,1,4,48,0,0,0,248,9,96,2,16,0,0,7,160,10,0,0,65,0,0,0,0,6,6,0,75],[0,0,0,0,10,9,192,25,0,0,7,167,6,128,1,151,0,0,0,0,6,166,1,159,0,0,0,0,0,103,4,53],[0,0,0,64,5,80,0,138,0,0,0,0,6,81,3,79,0,0,0,64,5,0,4,61,0,0,0,0,6,6,4,59],[0,0,0,128,7,96,0,140,0,0,2,35,0,0,65,61,0,0,0,128,7,96,2,112,0,0,7,168,8,96,0,156],[0,0,0,0,7,6,160,25,0,0,7,168,8,96,0,156,0,0,0,0,8,0,0,25,0,0,0,16,8,0,32,57],[0,0,0,8,9,128,1,191,0,0,7,159,10,112,0,156,0,0,0,0,9,8,160,25,0,0,0,64,8,112,2,112],[0,0,7,159,10,112,0,156,0,0,0,0,8,7,160,25,0,0,0,4,10,144,1,191,0,0,7,155,7,128,0,156],[0,0,0,0,10,9,160,25,0,0,0,32,9,128,2,112,0,0,7,155,7,128,0,156,0,0,0,0,9,8,160,25],[0,0,0,2,7,160,1,191,0,0,255,255,8,144,0,140,0,0,0,0,7,10,160,25,0,0,0,16,8,144,2,112],[0,0,0,0,8,9,160,25,0,0,0,255,8,128,0,140,0,0,0,1,7,112,32,57,0,0,0,32,8,0,0,138],[0,0,0,65,9,112,0,57,0,0,0,0,8,137,1,111,0,0,0,0,8,133,0,25,0,0,0,0,9,88,0,75],[0,0,0,0,9,0,0,25,0,0,0,1,9,0,64,57,0,0,7,159,10,128,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,9,144,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,128,4,63,0,0,0,2,8,112,0,57],[0,0,0,0,8,133,4,54,0,0,0,33,9,112,0,57,0,0,0,5,9,144,2,114,0,0,2,17,0,0,97,61],[0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16,0,0,0,0,12,184,0,25,0,0,0,0,11,178,3,79],[0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53,0,0,0,1,10,160,0,57,0,0,0,0,11,154,0,75],[0,0,2,9,0,0,65,61,0,0,0,0,9,0,0,75,0,0,2,19,0,0,97,61,0,0,0,0,9,5,4,51],[0,0,0,0,9,9,0,75,0,0,1,193,0,0,97,61,0,0,0,0,9,8,4,51,0,0,7,167,9,144,1,151],[0,0,0,248,10,112,2,16,0,0,0,0,9,154,1,159,0,0,7,169,9,144,0,65,0,0,0,0,0,152,4,53],[0,0,0,3,7,112,2,16,0,0,0,248,7,112,0,137,0,0,0,0,6,118,1,207,0,0,0,255,7,112,0,140],[0,0,0,0,6,0,32,25,0,0,0,33,7,80,0,57,0,0,2,51,0,0,1,61,0,0,7,166,7,80,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,7,80,0,57,0,0,0,64,0,112,4,63,0,0,0,1,7,0,0,58],[0,0,0,0,7,117,4,54,0,0,0,0,8,32,3,80,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,9,96,2,16,0,0,7,160,10,0,0,65,0,0,0,0,6,6,0,75],[0,0,0,0,10,9,192,25,0,0,7,167,6,128,1,151,0,0,0,0,6,166,1,159,0,0,0,0,0,103,4,53],[0,0,0,64,11,0,4,61,0,0,0,32,6,176,0,57,0,0,0,0,7,4,4,51,0,0,0,0,8,7,0,75],[0,0,2,65,0,0,97,61,0,0,0,0,8,0,0,25,0,0,0,0,9,104,0,25,0,0,0,32,8,128,0,57],[0,0,0,0,10,72,0,25,0,0,0,0,10,10,4,51,0,0,0,0,0,169,4,53,0,0,0,0,9,120,0,75],[0,0,2,58,0,0,65,61,0,0,0,0,4,103,0,25,0,0,0,0,0,4,4,53,0,0,0,0,6,5,4,51],[0,0,0,0,7,6,0,75,0,0,2,78,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,0,8,71,0,25],[0,0,0,32,7,112,0,57,0,0,0,0,9,87,0,25,0,0,0,0,9,9,4,51,0,0,0,0,0,152,4,53],[0,0,0,0,8,103,0,75,0,0,2,71,0,0,65,61,0,0,0,0,4,70,0,25,0,0,0,0,0,4,4,53],[0,0,0,0,4,180,0,73,0,0,0,32,5,64,0,138,0,0,0,0,0,91,4,53,0,0,0,31,4,64,0,57],[0,10,0,32,0,0,0,146,0,0,0,10,4,64,1,127,0,9,0,0,0,11,0,29,0,0,0,0,5,180,0,25],[0,0,0,0,4,69,0,75,0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57,0,11,0,0,0,5,0,29],[0,0,7,159,5,80,0,156,0,0,1,89,0,0,33,61,0,0,0,1,4,64,1,144,0,0,1,89,0,0,193,61],[0,0,0,11,4,0,0,41,0,0,0,64,0,64,4,63,0,0,7,166,4,64,0,156,0,0,1,89,0,0,33,61],[0,0,0,13,7,0,0,41,0,0,0,68,4,112,0,57,0,0,0,0,4,65,3,79,0,0,0,0,4,4,4,59],[0,0,0,11,8,0,0,41,0,0,0,64,5,128,0,57,0,0,0,64,0,80,4,63,0,0,0,32,5,128,0,57],[0,0,7,170,6,0,0,65,0,0,0,0,0,101,4,53,0,0,0,21,5,0,0,57,0,0,0,0,0,88,4,53],[0,0,0,96,4,64,2,16,0,0,0,33,5,128,0,57,0,0,0,0,0,69,4,53,0,0,1,36,4,112,0,57],[0,0,0,0,5,65,3,79,0,0,0,64,6,0,4,61,0,8,0,0,0,6,0,29,0,0,0,0,5,5,4,59],[0,0,0,128,6,80,0,140,0,0,5,81,0,0,65,61,0,0,0,128,6,80,2,112,0,0,7,168,7,80,0,156],[0,0,0,0,6,5,160,25,0,0,7,168,7,80,0,156,0,0,0,0,7,0,0,25,0,0,0,16,7,0,32,57],[0,0,0,8,8,112,1,191,0,0,7,159,9,96,0,156,0,0,0,0,8,7,160,25,0,0,0,64,7,96,2,112],[0,0,7,159,9,96,0,156,0,0,0,0,7,6,160,25,0,0,0,4,9,128,1,191,0,0,7,155,6,112,0,156],[0,0,0,0,9,8,160,25,0,0,0,32,8,112,2,112,0,0,7,155,6,112,0,156,0,0,0,0,8,7,160,25],[0,0,0,2,6,144,1,191,0,0,255,255,7,128,0,140,0,0,0,0,6,9,160,25,0,0,0,16,7,128,2,112],[0,0,0,0,7,8,160,25,0,0,0,255,7,112,0,140,0,0,0,1,6,96,32,57,0,0,0,65,7,96,0,57],[0,0,0,10,7,112,1,127,0,0,0,8,7,112,0,41,0,0,0,8,8,112,0,108,0,0,0,0,8,0,0,25],[0,0,0,1,8,0,64,57,0,0,7,159,9,112,0,156,0,0,1,89,0,0,33,61,0,0,0,1,8,128,1,144],[0,0,1,89,0,0,193,61,0,0,0,64,0,112,4,63,0,0,0,2,7,96,0,57,0,0,0,8,8,0,0,41],[0,0,0,0,7,120,4,54,0,0,0,33,8,96,0,57,0,0,0,5,8,128,2,114,0,0,2,173,0,0,97,61],[0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16,0,0,0,0,11,167,0,25,0,0,0,0,10,162,3,79],[0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57,0,0,0,0,10,137,0,75],[0,0,2,165,0,0,65,61,0,0,0,0,8,0,0,75,0,0,2,175,0,0,97,61,0,0,0,8,8,0,0,41],[0,0,0,0,8,8,4,51,0,0,0,0,8,8,0,75,0,0,1,193,0,0,97,61,0,0,0,0,8,7,4,51],[0,0,7,167,8,128,1,151,0,0,0,248,9,96,2,16,0,0,0,0,8,137,1,159,0,0,7,169,8,128,0,65],[0,0,0,0,0,135,4,53,0,0,0,3,6,96,2,16,0,0,0,248,6,96,0,137,0,0,0,0,5,101,1,207],[0,0,0,255,6,96,0,140,0,0,0,0,5,0,32,25,0,0,0,8,6,0,0,41,0,0,0,33,6,96,0,57],[0,0,5,99,0,0,1,61,0,0,0,0,7,38,0,26,0,0,0,0,6,0,4,20,0,0,24,103,0,0,65,61],[0,0,0,0,3,115,0,75,0,0,24,103,0,0,65,61,0,13,0,0,0,13,0,29,0,12,0,0,0,12,0,29],[0,0,7,176,3,96,0,156,0,0,3,251,0,0,65,61,0,0,0,68,1,64,0,57,0,0,7,191,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,36,1,64,0,57,0,0,0,8,2,0,0,57,0,0,0,0,0,33,4,53],[0,0,7,161,1,0,0,65,0,0,0,0,0,20,4,53,0,0,0,4,1,64,0,57,0,0,0,32,2,0,0,57],[0,0,0,0,0,33,4,53,0,0,7,155,1,0,0,65,0,0,7,155,2,64,0,156,0,0,0,0,4,1,128,25],[0,0,0,64,1,64,2,16,0,0,7,182,1,16,1,199,0,0,30,106,0,1,4,48,0,0,7,166,1,48,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,1,48,0,57,0,0,0,64,0,16,4,63,0,0,0,1,1,0,0,58],[0,0,0,0,5,19,4,54,0,0,0,0,2,0,0,49,0,0,0,1,1,0,3,103,0,0,0,0,6,33,3,79],[0,0,0,0,6,96,3,80,0,0,0,0,6,6,4,59,0,0,0,0,0,101,4,53,0,0,1,193,0,0,97,61],[0,0,0,248,7,64,2,16,0,0,7,160,8,0,0,65,0,0,0,0,4,4,0,75,0,0,0,0,8,7,192,25],[0,0,7,167,4,96,1,151,0,0,0,0,4,132,1,159,0,0,0,0,0,69,4,53,0,0,0,64,4,0,4,61],[0,0,0,13,5,0,0,41,0,0,1,4,6,80,0,57,0,0,0,0,5,97,3,79,0,0,0,0,5,5,4,59],[0,0,0,128,7,80,0,140,0,0,3,157,0,0,65,61,0,0,0,128,7,80,2,112,0,0,7,168,8,80,0,156],[0,0,0,0,7,5,160,25,0,0,7,168,8,80,0,156,0,0,0,0,8,0,0,25,0,0,0,16,8,0,32,57],[0,0,0,8,9,128,1,191,0,0,7,159,10,112,0,156,0,0,0,0,9,8,160,25,0,0,0,64,8,112,2,112],[0,0,7,159,10,112,0,156,0,0,0,0,8,7,160,25,0,0,0,4,10,144,1,191,0,0,7,155,7,128,0,156],[0,0,0,0,10,9,160,25,0,0,0,32,9,128,2,112,0,0,7,155,7,128,0,156,0,0,0,0,9,8,160,25],[0,0,0,2,7,160,1,191,0,0,255,255,8,144,0,140,0,0,0,0,7,10,160,25,0,0,0,16,8,144,2,112],[0,0,0,0,8,9,160,25,0,0,0,255,8,128,0,140,0,0,0,1,7,112,32,57,0,0,0,32,8,0,0,138],[0,0,0,65,9,112,0,57,0,0,0,0,8,137,1,111,0,0,0,0,8,132,0,25,0,0,0,0,9,72,0,75],[0,0,0,0,9,0,0,25,0,0,0,1,9,0,64,57,0,0,7,159,10,128,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,9,144,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,128,4,63,0,0,0,2,8,112,0,57],[0,0,0,0,8,132,4,54,0,0,0,33,9,112,0,57,0,0,0,5,9,144,2,114,0,0,3,42,0,0,97,61],[0,0,0,0,10,33,3,79,0,0,0,0,11,0,0,25,0,0,0,5,12,176,2,16,0,0,0,0,13,200,0,25],[0,0,0,0,12,202,3,79,0,0,0,0,12,12,4,59,0,0,0,0,0,205,4,53,0,0,0,1,11,176,0,57],[0,0,0,0,12,155,0,75,0,0,3,34,0,0,65,61,0,0,0,0,9,0,0,75,0,0,3,44,0,0,97,61],[0,0,0,0,9,4,4,51,0,0,0,0,9,9,0,75,0,0,1,193,0,0,97,61,0,0,0,0,9,8,4,51],[0,0,7,167,9,144,1,151,0,0,0,248,10,112,2,16,0,0,0,0,9,154,1,159,0,0,7,169,9,144,0,65],[0,0,0,0,0,152,4,53,0,0,0,3,7,112,2,16,0,0,0,248,7,112,0,137,0,0,0,0,5,117,1,207],[0,0,0,255,7,112,0,140,0,0,0,0,5,0,32,25,0,0,0,33,7,64,0,57,0,0,3,174,0,0,1,61],[0,0,7,166,1,48,0,156,0,0,1,89,0,0,33,61,0,0,0,64,1,48,0,57,0,0,0,64,0,16,4,63],[0,0,0,1,1,0,0,58,0,0,0,0,5,19,4,54,0,0,0,0,2,0,0,49,0,0,0,1,1,0,3,103],[0,0,0,0,6,33,3,79,0,0,0,0,6,96,3,80,0,0,0,0,6,6,4,59,0,0,0,0,0,101,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,7,64,2,16,0,0,7,160,8,0,0,65,0,0,0,0,4,4,0,75],[0,0,0,0,8,7,192,25,0,0,7,167,4,96,1,151,0,0,0,0,4,132,1,159,0,0,0,0,0,69,4,53],[0,0,0,64,4,0,4,61,0,0,0,13,5,0,0,41,0,0,1,4,6,80,0,57,0,0,0,0,5,97,3,79],[0,0,0,0,5,5,4,59,0,0,0,128,7,80,0,140,0,0,4,216,0,0,65,61,0,0,0,128,7,80,2,112],[0,0,7,168,8,80,0,156,0,0,0,0,7,5,160,25,0,0,7,168,8,80,0,156,0,0,0,0,8,0,0,25],[0,0,0,16,8,0,32,57,0,0,0,8,9,128,1,191,0,0,7,159,10,112,0,156,0,0,0,0,9,8,160,25],[0,0,0,64,8,112,2,112,0,0,7,159,10,112,0,156,0,0,0,0,8,7,160,25,0,0,0,4,10,144,1,191],[0,0,7,155,7,128,0,156,0,0,0,0,10,9,160,25,0,0,0,32,9,128,2,112,0,0,7,155,7,128,0,156],[0,0,0,0,9,8,160,25,0,0,0,2,7,160,1,191,0,0,255,255,8,144,0,140,0,0,0,0,7,10,160,25],[0,0,0,16,8,144,2,112,0,0,0,0,8,9,160,25,0,0,0,255,8,128,0,140,0,0,0,1,7,112,32,57],[0,0,0,32,8,0,0,138,0,0,0,65,9,112,0,57,0,0,0,0,8,137,1,111,0,0,0,0,8,132,0,25],[0,0,0,0,9,72,0,75,0,0,0,0,9,0,0,25,0,0,0,1,9,0,64,57,0,0,7,159,10,128,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,9,144,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,128,4,63],[0,0,0,2,8,112,0,57,0,0,0,0,8,132,4,54,0,0,0,33,9,112,0,57,0,0,0,5,9,144,2,114],[0,0,3,139,0,0,97,61,0,0,0,0,10,33,3,79,0,0,0,0,11,0,0,25,0,0,0,5,12,176,2,16],[0,0,0,0,13,200,0,25,0,0,0,0,12,202,3,79,0,0,0,0,12,12,4,59,0,0,0,0,0,205,4,53],[0,0,0,1,11,176,0,57,0,0,0,0,12,155,0,75,0,0,3,131,0,0,65,61,0,0,0,0,9,0,0,75],[0,0,3,141,0,0,97,61,0,0,0,0,9,4,4,51,0,0,0,0,9,9,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,9,8,4,51,0,0,7,167,9,144,1,151,0,0,0,248,10,112,2,16,0,0,0,0,9,154,1,159],[0,0,7,169,9,144,0,65,0,0,0,0,0,152,4,53,0,0,0,3,7,112,2,16,0,0,0,248,7,112,0,137],[0,0,0,0,5,117,1,207,0,0,0,255,7,112,0,140,0,0,0,0,5,0,32,25,0,0,0,33,7,64,0,57],[0,0,4,233,0,0,1,61,0,0,7,166,7,64,0,156,0,0,1,89,0,0,33,61,0,0,0,64,7,64,0,57],[0,0,0,64,0,112,4,63,0,0,0,0,8,33,3,79,0,0,0,1,7,0,0,58,0,0,0,0,7,116,4,54],[0,0,0,0,8,128,3,80,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,1,193,0,0,97,61],[0,0,0,248,9,80,2,16,0,0,7,160,10,0,0,65,0,0,0,0,5,5,0,75,0,0,0,0,10,9,192,25],[0,0,7,167,5,128,1,151,0,0,0,0,5,165,1,159,0,0,0,0,0,87,4,53,0,0,0,64,5,0,4,61],[0,0,0,64,7,96,0,138,0,0,0,0,6,113,3,79,0,0,0,0,6,6,4,59,0,0,0,128,8,96,0,140],[0,0,5,170,0,0,65,61,0,0,0,128,8,96,2,112,0,0,7,168,9,96,0,156,0,0,0,0,8,6,160,25],[0,0,7,168,9,96,0,156,0,0,0,0,9,0,0,25,0,0,0,16,9,0,32,57,0,0,0,8,10,144,1,191],[0,0,7,159,11,128,0,156,0,0,0,0,10,9,160,25,0,0,0,64,9,128,2,112,0,0,7,159,11,128,0,156],[0,0,0,0,9,8,160,25,0,0,0,4,11,160,1,191,0,0,7,155,8,144,0,156,0,0,0,0,11,10,160,25],[0,0,0,32,10,144,2,112,0,0,7,155,8,144,0,156,0,0,0,0,10,9,160,25,0,0,0,2,8,176,1,191],[0,0,255,255,9,160,0,140,0,0,0,0,8,11,160,25,0,0,0,16,9,160,2,112,0,0,0,0,9,10,160,25],[0,0,0,255,9,144,0,140,0,0,0,1,8,128,32,57,0,0,0,32,9,0,0,138,0,0,0,65,10,128,0,57],[0,0,0,0,9,154,1,111,0,0,0,0,9,149,0,25,0,0,0,0,10,89,0,75,0,0,0,0,10,0,0,25],[0,0,0,1,10,0,64,57,0,0,7,159,11,144,0,156,0,0,1,89,0,0,33,61,0,0,0,1,10,160,1,144],[0,0,1,89,0,0,193,61,0,0,0,64,0,144,4,63,0,0,0,2,9,128,0,57,0,0,0,0,9,149,4,54],[0,0,0,33,10,128,0,57,0,0,0,5,10,160,2,114,0,0,3,233,0,0,97,61,0,0,0,0,11,33,3,79],[0,0,0,0,12,0,0,25,0,0,0,5,13,192,2,16,0,0,0,0,14,217,0,25,0,0,0,0,13,219,3,79],[0,0,0,0,13,13,4,59,0,0,0,0,0,222,4,53,0,0,0,1,12,192,0,57,0,0,0,0,13,172,0,75],[0,0,3,225,0,0,65,61,0,0,0,0,10,0,0,75,0,0,3,235,0,0,97,61,0,0,0,0,10,5,4,51],[0,0,0,0,10,10,0,75,0,0,1,193,0,0,97,61,0,0,0,0,10,9,4,51,0,0,7,167,10,160,1,151],[0,0,0,248,11,128,2,16,0,0,0,0,10,171,1,159,0,0,7,169,10,160,0,65,0,0,0,0,0,169,4,53],[0,0,0,3,8,128,2,16,0,0,0,248,8,128,0,137,0,0,0,0,6,134,1,207,0,0,0,255,8,128,0,140],[0,0,0,0,6,0,32,25,0,0,0,33,8,80,0,57,0,0,5,187,0,0,1,61,0,0,7,155,2,32,1,151],[0,0,0,0,1,33,3,79,0,0,0,0,2,117,0,73,0,0,7,155,2,32,1,151,0,0,0,0,1,33,3,223],[0,0,0,192,2,96,2,16,0,0,7,177,2,32,1,151,0,0,7,178,2,32,1,199,0,0,0,0,1,33,3,175],[0,0,128,16,2,0,0,57,30,104,30,99,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,7,155,5,48,1,151,0,0,0,1,2,32,1,144,0,0,5,54,0,0,97,61,0,0,0,63,2,80,0,57],[0,0,7,179,2,32,1,151,0,0,0,64,6,0,4,61,0,0,0,0,2,38,0,25,0,0,0,0,3,98,0,75],[0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57,0,0,7,159,4,32,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,3,48,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,32,4,63,0,0,0,0,4,86,4,54],[0,0,0,1,2,0,3,103,0,0,0,0,3,0,0,49,0,0,0,31,7,80,0,57,0,0,0,5,7,112,2,114],[0,0,4,39,0,0,97,61,0,0,0,0,8,50,3,79,0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16],[0,0,0,0,11,164,0,25,0,0,0,0,10,168,3,79,0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53],[0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75,0,0,4,31,0,0,65,61,0,0,0,0,7,0,0,75],[0,0,4,41,0,0,97,61,0,0,0,31,7,80,1,143,0,0,0,5,5,80,2,114,0,0,4,53,0,0,97,61],[0,0,0,0,8,0,0,25,0,0,0,5,9,128,2,16,0,0,0,0,10,148,0,25,0,0,0,0,9,145,3,79],[0,0,0,0,9,9,4,59,0,0,0,0,0,154,4,53,0,0,0,1,8,128,0,57,0,0,0,0,9,88,0,75],[0,0,4,45,0,0,65,61,0,0,0,0,8,7,0,75,0,0,4,68,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,84,0,25,0,0,0,3,7,112,2,16,0,0,0,0,8,5,4,51],[0,0,0,0,8,120,1,207,0,0,0,0,8,120,2,47,0,0,0,0,1,1,4,59,0,0,1,0,7,112,0,137],[0,0,0,0,1,113,2,47,0,0,0,0,1,113,1,207,0,0,0,0,1,129,1,159,0,0,0,0,0,21,4,53],[0,0,0,0,1,6,4,51,0,0,0,32,1,16,0,140,0,0,12,89,0,0,193,61,0,0,0,13,6,0,0,41],[0,0,0,0,1,99,0,73,0,0,0,35,5,16,0,138,0,11,2,4,0,96,0,61,0,0,0,11,1,32,3,96],[0,0,0,0,1,1,4,59,0,0,7,160,6,0,0,65,0,0,0,0,7,81,0,75,0,0,0,0,7,0,0,25],[0,0,0,0,7,6,128,25,0,0,7,160,5,80,1,151,0,0,7,160,8,16,1,151,0,0,0,0,9,88,0,75],[0,0,0,0,6,0,128,25,0,0,0,0,5,88,1,63,0,0,7,160,5,80,0,156,0,0,0,0,6,7,192,25],[0,0,0,0,5,6,0,75,0,0,0,12,5,0,0,41,0,0,0,159,0,0,193,61,0,0,0,0,4,4,4,51],[0,10,0,0,0,4,0,29,0,0,0,0,1,81,0,25,0,0,0,0,4,18,3,79,0,0,0,0,5,4,4,59],[0,0,7,159,4,80,0,156,0,0,0,159,0,0,33,61,0,0,0,5,4,80,2,16,0,0,0,0,3,67,0,73],[0,0,0,32,6,16,0,57,0,0,7,160,1,0,0,65,0,0,0,0,7,54,0,75,0,0,0,0,7,0,0,25],[0,0,0,0,7,1,32,25,0,0,7,160,3,48,1,151,0,0,7,160,8,96,1,151,0,0,0,0,9,56,0,75],[0,0,0,0,1,0,128,25,0,0,0,0,3,56,1,63,0,0,7,160,3,48,0,156,0,0,0,0,1,7,192,25],[0,0,0,0,1,1,0,75,0,0,0,159,0,0,193,61,0,0,0,64,1,0,4,61,0,0,0,32,3,16,0,57],[0,0,7,180,5,80,1,152,0,0,4,128,0,0,97,61,0,0,0,0,2,98,3,79,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,115,0,25,0,0,0,0,7,114,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,4,120,0,0,65,61],[0,0,0,0,2,0,0,75,0,0,4,130,0,0,97,61,0,0,0,0,0,65,4,53,0,0,0,63,2,64,0,57],[0,0,0,32,4,0,0,138,0,0,0,0,2,66,1,111,0,0,0,0,2,33,0,25,0,0,0,0,4,18,0,75],[0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57,0,0,7,159,5,32,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,4,64,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,32,4,63,0,0,7,155,2,0,0,65],[0,0,7,155,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,64,3,48,2,16,0,0,0,0,1,1,4,51],[0,0,7,155,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,49,1,159],[0,0,0,0,3,0,4,20,0,0,7,155,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16],[0,0,0,0,1,18,1,159,0,0,7,175,1,16,1,199,0,0,128,16,2,0,0,57,30,104,30,94,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,0,12,10,0,0,41,0,0,0,13,3,0,0,41,0,0,0,159,0,0,97,61],[0,0,0,0,2,0,0,49,0,0,0,0,3,50,0,73,0,0,0,35,5,48,0,138,0,0,0,11,3,0,0,41],[0,0,0,32,4,48,0,57,0,0,0,1,3,0,3,103,0,0,0,0,4,67,3,79,0,0,0,0,4,4,4,59],[0,0,7,160,6,0,0,65,0,0,0,0,7,84,0,75,0,0,0,0,7,0,0,25,0,0,0,0,7,6,128,25],[0,0,7,160,5,80,1,151,0,0,7,160,8,64,1,151,0,0,0,0,9,88,0,75,0,0,0,0,6,0,128,25],[0,0,0,0,5,88,1,63,0,0,7,160,5,80,0,156,0,0,0,0,6,7,192,25,0,0,0,0,1,1,4,59],[0,11,0,0,0,1,0,29,0,0,0,0,1,6,0,75,0,0,0,159,0,0,193,61,0,0,0,0,1,164,0,25],[0,0,0,0,4,19,3,79,0,0,0,0,4,4,4,59,0,0,7,159,5,64,0,156,0,0,0,159,0,0,33,61],[0,0,0,0,5,66,0,73,0,0,0,32,1,16,0,57,0,0,7,160,6,0,0,65,0,0,0,0,7,81,0,75],[0,0,0,0,7,0,0,25,0,0,0,0,7,6,32,25,0,0,7,160,5,80,1,151,0,0,7,160,8,16,1,151],[0,0,0,0,9,88,0,75,0,0,0,0,6,0,128,25,0,0,0,0,5,88,1,63,0,0,7,160,5,80,0,156],[0,0,0,0,6,7,192,25,0,0,0,0,5,6,0,75,0,0,0,159,0,0,193,61,0,0,0,0,5,20,0,26],[0,0,0,0,4,0,4,20,0,0,24,103,0,0,65,61,0,0,0,0,6,82,0,75,0,0,24,103,0,0,65,61],[0,0,7,176,6,64,0,156,0,0,11,97,0,0,65,61,0,0,0,64,4,0,4,61,0,0,2,202,0,0,1,61],[0,0,7,166,7,64,0,156,0,0,1,89,0,0,33,61,0,0,0,64,7,64,0,57,0,0,0,64,0,112,4,63],[0,0,0,0,8,33,3,79,0,0,0,1,7,0,0,58,0,0,0,0,7,116,4,54,0,0,0,0,8,128,3,80],[0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,1,193,0,0,97,61,0,0,0,248,9,80,2,16],[0,0,7,160,10,0,0,65,0,0,0,0,5,5,0,75,0,0,0,0,10,9,192,25,0,0,7,167,5,128,1,151],[0,0,0,0,5,165,1,159,0,0,0,0,0,87,4,53,0,0,0,64,5,0,4,61,0,0,0,96,6,96,0,138],[0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59,0,0,0,128,8,112,0,140,0,0,6,8,0,0,65,61],[0,0,0,128,8,112,2,112,0,0,7,168,9,112,0,156,0,0,0,0,8,7,160,25,0,0,7,168,9,112,0,156],[0,0,0,0,9,0,0,25,0,0,0,16,9,0,32,57,0,0,0,8,10,144,1,191,0,0,7,159,11,128,0,156],[0,0,0,0,10,9,160,25,0,0,0,64,9,128,2,112,0,0,7,159,11,128,0,156,0,0,0,0,9,8,160,25],[0,0,0,4,11,160,1,191,0,0,7,155,8,144,0,156,0,0,0,0,11,10,160,25,0,0,0,32,10,144,2,112],[0,0,7,155,8,144,0,156,0,0,0,0,10,9,160,25,0,0,0,2,8,176,1,191,0,0,255,255,9,160,0,140],[0,0,0,0,8,11,160,25,0,0,0,16,9,160,2,112,0,0,0,0,9,10,160,25,0,0,0,255,9,144,0,140],[0,0,0,1,8,128,32,57,0,0,0,32,9,0,0,138,0,0,0,65,10,128,0,57,0,0,0,0,9,154,1,111],[0,0,0,0,9,149,0,25,0,0,0,0,10,89,0,75,0,0,0,0,10,0,0,25,0,0,0,1,10,0,64,57],[0,0,7,159,11,144,0,156,0,0,1,89,0,0,33,61,0,0,0,1,10,160,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,144,4,63,0,0,0,2,9,128,0,57,0,0,0,0,9,149,4,54,0,0,0,33,10,128,0,57],[0,0,0,5,10,160,2,114,0,0,5,36,0,0,97,61,0,0,0,0,11,33,3,79,0,0,0,0,12,0,0,25],[0,0,0,5,13,192,2,16,0,0,0,0,14,217,0,25,0,0,0,0,13,219,3,79,0,0,0,0,13,13,4,59],[0,0,0,0,0,222,4,53,0,0,0,1,12,192,0,57,0,0,0,0,13,172,0,75,0,0,5,28,0,0,65,61],[0,0,0,0,10,0,0,75,0,0,5,38,0,0,97,61,0,0,0,0,10,5,4,51,0,0,0,0,10,10,0,75],[0,0,1,193,0,0,97,61,0,0,0,0,10,9,4,51,0,0,7,167,10,160,1,151,0,0,0,248,11,128,2,16],[0,0,0,0,10,171,1,159,0,0,7,169,10,160,0,65,0,0,0,0,0,169,4,53,0,0,0,3,8,128,2,16],[0,0,0,248,8,128,0,137,0,0,0,0,7,135,1,207,0,0,0,255,8,128,0,140,0,0,0,0,7,0,32,25],[0,0,0,33,8,80,0,57,0,0,6,25,0,0,1,61,0,0,0,31,3,80,1,143,0,0,0,5,2,80,2,114],[0,0,5,65,0,0,97,61,0,0,0,0,4,0,0,25,0,0,0,5,6,64,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,0,1,4,64,0,57,0,0,0,0,6,36,0,75],[0,0,5,58,0,0,65,61,0,0,0,0,4,3,0,75,0,0,5,79,0,0,97,61,0,0,0,3,3,48,2,16],[0,0,0,5,2,32,2,16,0,0,0,0,4,2,4,51,0,0,0,0,4,52,1,207,0,0,0,0,4,52,2,47],[0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,0,1,0,3,48,0,137,0,0,0,0,1,49,2,47],[0,0,0,0,1,49,1,207,0,0,0,0,1,65,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,80,2,16],[0,0,30,106,0,1,4,48,0,0,0,8,6,0,0,41,0,0,7,166,6,96,0,156,0,0,1,89,0,0,33,61],[0,0,0,8,7,0,0,41,0,0,0,64,6,112,0,57,0,0,0,64,0,96,4,63,0,0,0,1,6,0,0,58],[0,0,0,0,6,103,4,54,0,0,0,0,7,32,3,80,0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,8,80,2,16,0,0,7,160,9,0,0,65,0,0,0,0,5,5,0,75],[0,0,0,0,9,8,192,25,0,0,7,167,5,112,1,151,0,0,0,0,5,149,1,159,0,0,0,0,0,86,4,53],[0,0,0,12,11,0,0,41,0,0,0,0,5,179,0,73,0,0,0,160,6,64,0,57,0,0,0,0,4,97,3,79],[0,0,0,0,4,4,4,59,0,0,0,31,5,80,0,138,0,0,7,160,7,80,1,151,0,0,7,160,8,64,1,151],[0,0,7,160,9,0,0,65,0,0,0,0,10,120,0,75,0,0,0,0,10,0,0,25,0,0,0,0,10,9,64,25],[0,0,0,0,7,120,1,63,0,0,0,0,8,84,0,75,0,0,0,0,9,0,64,25,0,0,7,160,7,112,0,156],[0,0,0,0,10,9,192,25,0,0,0,0,7,10,0,75,0,0,0,159,0,0,193,61,0,0,0,0,8,180,0,25],[0,0,0,0,7,129,3,79,0,0,0,0,7,7,4,59,0,0,7,159,9,112,0,156,0,0,0,159,0,0,33,61],[0,0,0,0,9,115,0,73,0,0,0,32,8,128,0,57,0,0,7,160,10,0,0,65,0,0,0,0,11,152,0,75],[0,0,0,0,11,0,0,25,0,0,0,0,11,10,32,25,0,0,7,160,9,144,1,151,0,0,7,160,12,128,1,151],[0,0,0,0,13,156,0,75,0,0,0,0,10,0,128,25,0,0,0,0,9,156,1,63,0,0,7,160,9,144,0,156],[0,0,0,0,10,11,192,25,0,0,0,0,9,10,0,75,0,0,0,159,0,0,193,61,0,0,0,1,9,112,0,140],[0,0,7,171,0,0,193,61,0,0,0,0,2,129,3,79,0,0,0,0,2,2,4,59,0,0,0,1,7,0,0,138],[0,0,7,160,8,0,0,65,0,0,0,0,7,114,0,75,0,0,0,0,7,0,0,25,0,0,0,0,7,8,32,25],[0,0,7,160,2,32,1,151,0,0,7,160,9,32,0,156,0,0,0,0,8,0,128,25,0,0,7,160,2,32,1,103],[0,0,7,160,2,32,0,156,0,0,0,0,8,7,192,25,0,7,0,96,0,0,0,61,0,0,0,0,2,8,0,75],[0,0,7,231,0,0,193,61,0,0,0,64,2,0,4,61,0,7,0,0,0,2,0,29,0,0,7,166,2,32,0,156],[0,0,1,89,0,0,33,61,0,0,0,7,8,0,0,41,0,0,0,64,2,128,0,57,0,0,0,64,0,32,4,63],[0,0,0,32,2,128,0,57,0,0,7,169,7,0,0,65,0,0,0,0,0,114,4,53,0,0,0,1,2,0,0,57],[0,0,0,0,0,40,4,53,0,0,7,231,0,0,1,61,0,0,7,166,8,80,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,8,80,0,57,0,0,0,64,0,128,4,63,0,0,0,0,9,33,3,79,0,0,0,1,8,0,0,58],[0,0,0,0,8,133,4,54,0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59,0,0,0,0,0,152,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,10,96,2,16,0,0,7,160,11,0,0,65,0,0,0,0,6,6,0,75],[0,0,0,0,11,10,192,25,0,0,7,167,6,144,1,151,0,0,0,0,6,182,1,159,0,0,0,0,0,104,4,53],[0,0,0,64,6,0,4,61,0,0,0,32,7,112,0,138,0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59],[0,0,0,128,9,128,0,140,0,0,6,102,0,0,65,61,0,0,0,128,9,128,2,112,0,0,7,168,10,128,0,156],[0,0,0,0,9,8,160,25,0,0,7,168,10,128,0,156,0,0,0,0,10,0,0,25,0,0,0,16,10,0,32,57],[0,0,0,8,11,160,1,191,0,0,7,159,12,144,0,156,0,0,0,0,11,10,160,25,0,0,0,64,10,144,2,112],[0,0,7,159,12,144,0,156,0,0,0,0,10,9,160,25,0,0,0,4,12,176,1,191,0,0,7,155,9,160,0,156],[0,0,0,0,12,11,160,25,0,0,0,32,11,160,2,112,0,0,7,155,9,160,0,156,0,0,0,0,11,10,160,25],[0,0,0,2,9,192,1,191,0,0,255,255,10,176,0,140,0,0,0,0,9,12,160,25,0,0,0,16,10,176,2,112],[0,0,0,0,10,11,160,25,0,0,0,255,10,160,0,140,0,0,0,1,9,144,32,57,0,0,0,32,10,0,0,138],[0,0,0,65,11,144,0,57,0,0,0,0,10,171,1,111,0,0,0,0,10,166,0,25,0,0,0,0,11,106,0,75],[0,0,0,0,11,0,0,25,0,0,0,1,11,0,64,57,0,0,7,159,12,160,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,11,176,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,160,4,63,0,0,0,2,10,144,0,57],[0,0,0,0,10,166,4,54,0,0,0,33,11,144,0,57,0,0,0,5,11,176,2,114,0,0,5,246,0,0,97,61],[0,0,0,0,12,33,3,79,0,0,0,0,13,0,0,25,0,0,0,5,14,208,2,16,0,0,0,0,15,234,0,25],[0,0,0,0,14,236,3,79,0,0,0,0,14,14,4,59,0,0,0,0,0,239,4,53,0,0,0,1,13,208,0,57],[0,0,0,0,14,189,0,75,0,0,5,238,0,0,65,61,0,0,0,0,11,0,0,75,0,0,5,248,0,0,97,61],[0,0,0,0,11,6,4,51,0,0,0,0,11,11,0,75,0,0,1,193,0,0,97,61,0,0,0,0,11,10,4,51],[0,0,7,167,11,176,1,151,0,0,0,248,12,144,2,16,0,0,0,0,11,188,1,159,0,0,7,169,11,176,0,65],[0,0,0,0,0,186,4,53,0,0,0,3,9,144,2,16,0,0,0,248,9,144,0,137,0,0,0,0,8,152,1,207],[0,0,0,255,9,144,0,140,0,0,0,0,8,0,32,25,0,0,0,33,9,96,0,57,0,0,6,119,0,0,1,61],[0,0,7,166,8,80,0,156,0,0,1,89,0,0,33,61,0,0,0,64,8,80,0,57,0,0,0,64,0,128,4,63],[0,0,0,0,9,33,3,79,0,0,0,1,8,0,0,58,0,0,0,0,8,133,4,54,0,0,0,0,9,144,3,80],[0,0,0,0,9,9,4,59,0,0,0,0,0,152,4,53,0,0,1,193,0,0,97,61,0,0,0,248,10,112,2,16],[0,0,7,160,11,0,0,65,0,0,0,0,7,7,0,75,0,0,0,0,11,10,192,25,0,0,7,167,7,144,1,151],[0,0,0,0,7,183,1,159,0,0,0,0,0,120,4,53,0,0,0,64,7,0,4,61,0,0,0,64,6,96,0,138],[0,0,0,0,8,97,3,79,0,0,0,0,8,8,4,59,0,0,0,128,9,128,0,140,0,0,6,197,0,0,65,61],[0,0,0,128,9,128,2,112,0,0,7,168,10,128,0,156,0,0,0,0,9,8,160,25,0,0,7,168,10,128,0,156],[0,0,0,0,10,0,0,25,0,0,0,16,10,0,32,57,0,0,0,8,11,160,1,191,0,0,7,159,12,144,0,156],[0,0,0,0,11,10,160,25,0,0,0,64,10,144,2,112,0,0,7,159,12,144,0,156,0,0,0,0,10,9,160,25],[0,0,0,4,12,176,1,191,0,0,7,155,9,160,0,156,0,0,0,0,12,11,160,25,0,0,0,32,11,160,2,112],[0,0,7,155,9,160,0,156,0,0,0,0,11,10,160,25,0,0,0,2,9,192,1,191,0,0,255,255,10,176,0,140],[0,0,0,0,9,12,160,25,0,0,0,16,10,176,2,112,0,0,0,0,10,11,160,25,0,0,0,255,10,160,0,140],[0,0,0,1,9,144,32,57,0,0,0,32,10,0,0,138,0,0,0,65,11,144,0,57,0,0,0,0,10,171,1,111],[0,0,0,0,10,167,0,25,0,0,0,0,11,122,0,75,0,0,0,0,11,0,0,25,0,0,0,1,11,0,64,57],[0,0,7,159,12,160,0,156,0,0,1,89,0,0,33,61,0,0,0,1,11,176,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,160,4,63,0,0,0,2,10,144,0,57,0,0,0,0,10,167,4,54,0,0,0,33,11,144,0,57],[0,0,0,5,11,176,2,114,0,0,6,84,0,0,97,61,0,0,0,0,12,33,3,79,0,0,0,0,13,0,0,25],[0,0,0,5,14,208,2,16,0,0,0,0,15,234,0,25,0,0,0,0,14,236,3,79,0,0,0,0,14,14,4,59],[0,0,0,0,0,239,4,53,0,0,0,1,13,208,0,57,0,0,0,0,14,189,0,75,0,0,6,76,0,0,65,61],[0,0,0,0,11,0,0,75,0,0,6,86,0,0,97,61,0,0,0,0,11,7,4,51,0,0,0,0,11,11,0,75],[0,0,1,193,0,0,97,61,0,0,0,0,11,10,4,51,0,0,7,167,11,176,1,151,0,0,0,248,12,144,2,16],[0,0,0,0,11,188,1,159,0,0,7,169,11,176,0,65,0,0,0,0,0,186,4,53,0,0,0,3,9,144,2,16],[0,0,0,248,9,144,0,137,0,0,0,0,8,152,1,207,0,0,0,255,9,144,0,140,0,0,0,0,8,0,32,25],[0,0,0,33,9,112,0,57,0,0,6,214,0,0,1,61,0,0,7,166,9,96,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,9,96,0,57,0,0,0,64,0,144,4,63,0,0,0,0,10,33,3,79,0,0,0,1,9,0,0,58],[0,0,0,0,9,150,4,54,0,0,0,0,10,160,3,80,0,0,0,0,10,10,4,59,0,0,0,0,0,169,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,11,128,2,16,0,0,7,160,12,0,0,65,0,0,0,0,8,8,0,75],[0,0,0,0,12,11,192,25,0,0,7,167,8,160,1,151,0,0,0,0,8,200,1,159,0,0,0,0,0,137,4,53],[0,0,0,64,8,0,4,61,0,11,0,64,0,112,0,146,0,0,0,11,9,16,3,96,0,0,0,0,9,9,4,59],[0,0,0,128,10,144,0,140,0,0,7,54,0,0,65,61,0,0,0,128,10,144,2,112,0,0,7,168,11,144,0,156],[0,0,0,0,10,9,160,25,0,0,7,168,11,144,0,156,0,0,0,0,11,0,0,25,0,0,0,16,11,0,32,57],[0,0,0,8,12,176,1,191,0,0,7,159,13,160,0,156,0,0,0,0,12,11,160,25,0,0,0,64,11,160,2,112],[0,0,7,159,13,160,0,156,0,0,0,0,11,10,160,25,0,0,0,4,13,192,1,191,0,0,7,155,10,176,0,156],[0,0,0,0,13,12,160,25,0,0,0,32,12,176,2,112,0,0,7,155,10,176,0,156,0,0,0,0,12,11,160,25],[0,0,0,2,10,208,1,191,0,0,255,255,11,192,0,140,0,0,0,0,10,13,160,25,0,0,0,16,11,192,2,112],[0,0,0,0,11,12,160,25,0,0,0,255,11,176,0,140,0,0,0,1,10,160,32,57,0,0,0,32,11,0,0,138],[0,0,0,65,12,160,0,57,0,0,0,0,11,188,1,111,0,0,0,0,11,184,0,25,0,0,0,0,12,139,0,75],[0,0,0,0,12,0,0,25,0,0,0,1,12,0,64,57,0,0,7,159,13,176,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,12,192,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,176,4,63,0,0,0,2,11,160,0,57],[0,0,0,0,11,184,4,54,0,0,0,33,12,160,0,57,0,0,0,5,12,192,2,114,0,0,6,178,0,0,97,61],[0,0,0,0,13,33,3,79,0,0,0,0,14,0,0,25,0,0,0,5,15,224,2,16,0,0,0,0,7,251,0,25],[0,0,0,0,15,253,3,79,0,0,0,0,15,15,4,59,0,0,0,0,0,247,4,53,0,0,0,1,14,224,0,57],[0,0,0,0,7,206,0,75,0,0,6,170,0,0,65,61,0,0,0,0,7,0,0,75,0,0,6,180,0,0,97,61],[0,0,0,0,7,8,4,51,0,0,0,0,7,7,0,75,0,0,1,193,0,0,97,61,0,0,0,0,7,11,4,51],[0,0,7,167,7,112,1,151,0,0,0,248,12,160,2,16,0,0,0,0,7,124,1,159,0,0,7,169,7,112,0,65],[0,0,0,0,0,123,4,53,0,0,0,3,7,160,2,16,0,0,0,248,7,112,0,137,0,0,0,0,9,121,1,207],[0,0,0,255,7,112,0,140,0,0,0,0,9,0,32,25,0,0,0,33,7,128,0,57,0,0,0,0,0,151,4,53],[0,0,7,72,0,0,1,61,0,0,7,166,9,112,0,156,0,0,1,89,0,0,33,61,0,0,0,64,9,112,0,57],[0,0,0,64,0,144,4,63,0,0,0,0,10,33,3,79,0,0,0,1,9,0,0,58,0,0,0,0,9,151,4,54],[0,0,0,0,10,160,3,80,0,0,0,0,10,10,4,59,0,0,0,0,0,169,4,53,0,0,1,193,0,0,97,61],[0,0,0,248,11,128,2,16,0,0,7,160,12,0,0,65,0,0,0,0,8,8,0,75,0,0,0,0,12,11,192,25],[0,0,7,167,8,160,1,151,0,0,0,0,8,200,1,159,0,0,0,0,0,137,4,53,0,0,0,64,9,0,4,61],[0,0,7,166,8,144,0,156,0,0,1,89,0,0,33,61,0,0,0,32,8,96,0,138,0,0,0,0,8,129,3,79],[0,0,0,0,8,8,4,59,0,0,0,64,10,144,0,57,0,0,0,64,0,160,4,63,0,0,0,32,10,144,0,57],[0,0,7,170,11,0,0,65,0,0,0,0,0,186,4,53,0,0,0,21,10,0,0,57,0,0,0,0,0,169,4,53],[0,0,0,96,8,128,2,16,0,0,0,33,10,144,0,57,0,0,0,0,0,138,4,53,0,0,0,192,6,96,0,57],[0,0,0,0,6,97,3,79,0,0,0,64,8,0,4,61,0,0,0,0,6,6,4,59,0,11,0,0,0,6,0,29],[0,0,0,128,10,96,0,140,0,0,8,159,0,0,65,61,0,0,0,11,6,0,0,41,0,0,0,128,10,96,2,112],[0,0,7,168,11,96,0,156,0,0,0,0,10,6,160,25,0,0,7,168,11,96,0,156,0,0,0,0,11,0,0,25],[0,0,0,16,11,0,32,57,0,0,0,8,12,176,1,191,0,0,7,159,13,160,0,156,0,0,0,0,12,11,160,25],[0,0,0,64,11,160,2,112,0,0,7,159,13,160,0,156,0,0,0,0,11,10,160,25,0,0,0,4,13,192,1,191],[0,0,7,155,10,176,0,156,0,0,0,0,13,12,160,25,0,0,0,32,12,176,2,112,0,0,7,155,10,176,0,156],[0,0,0,0,12,11,160,25,0,0,0,2,10,208,1,191,0,0,255,255,11,192,0,140,0,0,0,0,10,13,160,25],[0,0,0,16,11,192,2,112,0,0,0,0,11,12,160,25,0,0,0,255,11,176,0,140,0,0,0,1,10,160,32,57],[0,0,0,32,11,0,0,138,0,0,0,65,12,160,0,57,0,0,0,0,11,188,1,111,0,0,0,0,11,184,0,25],[0,0,0,0,12,139,0,75,0,0,0,0,12,0,0,25,0,0,0,1,12,0,64,57,0,0,7,159,13,176,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,12,192,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,176,4,63],[0,0,0,2,11,160,0,57,0,0,0,0,11,184,4,54,0,0,0,33,12,160,0,57,0,0,0,5,12,192,2,114],[0,0,7,35,0,0,97,61,0,0,0,0,13,33,3,79,0,0,0,0,14,0,0,25,0,0,0,5,15,224,2,16],[0,0,0,0,6,251,0,25,0,0,0,0,15,253,3,79,0,0,0,0,15,15,4,59,0,0,0,0,0,246,4,53],[0,0,0,1,14,224,0,57,0,0,0,0,6,206,0,75,0,0,7,27,0,0,65,61,0,0,0,0,6,0,0,75],[0,0,7,37,0,0,97,61,0,0,0,0,6,8,4,51,0,0,0,0,6,6,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,6,11,4,51,0,0,7,167,6,96,1,151,0,0,0,248,12,160,2,16,0,0,0,0,6,108,1,159],[0,0,7,169,6,96,0,65,0,0,0,0,0,107,4,53,0,0,0,3,6,160,2,16,0,0,0,248,6,96,0,137],[0,0,0,11,10,96,1,239,0,0,0,255,6,96,0,140,0,0,0,0,10,0,32,25,0,0,0,33,6,128,0,57],[0,0,0,0,0,166,4,53,0,0,8,178,0,0,1,61,0,0,7,166,7,128,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,7,128,0,57,0,0,0,64,0,112,4,63,0,0,0,0,7,33,3,79,0,0,0,1,10,0,0,58],[0,0,0,0,10,168,4,54,0,0,0,0,7,112,3,80,0,0,0,0,11,7,4,59,0,0,0,0,0,186,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,7,144,2,16,0,0,7,160,12,0,0,65,0,0,0,0,9,9,0,75],[0,0,0,0,12,7,192,25,0,0,7,167,7,176,1,151,0,0,0,0,7,199,1,159,0,0,0,0,0,122,4,53],[0,0,0,64,10,0,4,61,0,0,7,166,7,160,0,156,0,0,1,89,0,0,33,61,0,0,0,11,12,0,0,41],[0,0,0,32,7,192,0,138,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,64,9,160,0,57],[0,0,0,64,0,144,4,63,0,0,0,32,9,160,0,57,0,0,7,170,11,0,0,65,0,0,0,0,0,185,4,53],[0,0,0,21,9,0,0,57,0,0,0,0,0,154,4,53,0,0,0,96,7,112,2,16,0,0,0,33,9,160,0,57],[0,0,0,0,0,121,4,53,0,0,0,192,7,192,0,57,0,0,0,0,7,113,3,79,0,0,0,64,9,0,4,61],[0,0,0,0,7,7,4,59,0,11,0,0,0,7,0,29,0,0,0,128,11,112,0,140,0,0,9,86,0,0,65,61],[0,0,0,11,7,0,0,41,0,0,0,128,11,112,2,112,0,0,7,168,12,112,0,156,0,0,0,0,11,7,160,25],[0,0,7,168,12,112,0,156,0,0,0,0,12,0,0,25,0,0,0,16,12,0,32,57,0,0,0,8,13,192,1,191],[0,0,7,159,14,176,0,156,0,0,0,0,13,12,160,25,0,0,0,64,12,176,2,112,0,0,7,159,14,176,0,156],[0,0,0,0,12,11,160,25,0,0,0,4,14,208,1,191,0,0,7,155,11,192,0,156,0,0,0,0,14,13,160,25],[0,0,0,32,13,192,2,112,0,0,7,155,11,192,0,156,0,0,0,0,13,12,160,25,0,0,0,2,7,224,1,191],[0,0,255,255,12,208,0,140,0,0,0,0,7,14,160,25,0,0,0,16,12,208,2,112,0,0,0,0,12,13,160,25],[0,0,0,255,12,192,0,140,0,0,0,1,7,112,32,57,0,0,0,32,12,0,0,138,0,10,0,0,0,7,0,29],[0,0,0,65,13,112,0,57,0,0,0,0,12,205,1,111,0,0,0,0,12,201,0,25,0,0,0,0,13,156,0,75],[0,0,0,0,13,0,0,25,0,0,0,1,13,0,64,57,0,0,7,159,14,192,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,13,208,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,192,4,63,0,0,0,10,7,0,0,41],[0,0,0,2,12,112,0,57,0,0,0,0,12,201,4,54,0,0,0,33,13,112,0,57,0,0,0,5,13,208,2,114],[0,0,7,151,0,0,97,61,0,0,0,0,14,33,3,79,0,0,0,0,15,0,0,25,0,0,0,5,7,240,2,16],[0,0,0,0,11,124,0,25,0,0,0,0,7,126,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,123,4,53],[0,0,0,1,15,240,0,57,0,0,0,0,7,223,0,75,0,0,7,143,0,0,65,61,0,0,0,0,7,0,0,75],[0,0,7,153,0,0,97,61,0,0,0,0,7,9,4,51,0,0,0,0,7,7,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,7,12,4,51,0,0,7,167,7,112,1,151,0,0,0,10,13,0,0,41,0,0,0,248,11,208,2,16],[0,0,0,0,7,123,1,159,0,0,7,169,7,112,0,65,0,0,0,0,0,124,4,53,0,0,0,3,7,208,2,16],[0,0,0,248,7,112,0,137,0,0,0,11,11,112,1,239,0,0,0,255,7,112,0,140,0,0,0,0,11,0,32,25],[0,0,0,33,7,144,0,57,0,0,0,0,0,183,4,53,0,0,9,105,0,0,1,61,0,0,0,64,8,0,4,61],[0,7,0,0,0,8,0,29,0,0,0,56,8,112,0,140,0,0,7,214,0,0,65,61,0,0,0,32,9,112,2,112],[0,0,7,155,8,112,0,156,0,0,0,0,9,7,160,25,0,0,7,155,8,112,0,156,0,0,0,0,10,0,0,25],[0,0,0,4,10,0,32,57,0,0,0,2,8,160,1,191,0,0,255,255,11,144,0,140,0,0,0,0,8,10,160,25],[0,0,0,16,10,144,2,112,0,0,0,0,10,9,160,25,0,0,0,255,9,160,0,140,0,0,0,0,9,0,0,25],[0,0,0,1,9,0,32,57,0,0,0,7,10,0,0,41,0,0,7,166,10,160,0,156,0,0,1,89,0,0,33,61],[0,0,0,0,8,152,1,159,0,0,0,7,10,0,0,41,0,0,0,64,9,160,0,57,0,0,0,64,0,144,4,63],[0,0,0,2,9,128,0,58,0,0,0,0,9,154,4,54,0,0,0,0,2,32,3,80,0,0,0,0,2,2,4,59],[0,0,0,0,0,41,4,53,0,0,1,193,0,0,97,61,0,0,7,167,2,32,1,151,0,0,0,248,10,128,2,16],[0,0,0,0,2,42,1,159,0,0,7,171,2,32,1,199,0,0,0,0,0,41,4,53,0,0,0,3,2,128,2,16],[0,0,0,248,2,32,1,95,0,0,0,0,2,39,1,207,0,0,0,7,7,0,0,41,0,0,0,33,7,112,0,57],[0,0,0,0,0,39,4,53,0,0,7,231,0,0,1,61,0,0,0,7,8,0,0,41,0,0,7,166,8,128,0,156],[0,0,1,89,0,0,33,61,0,0,0,7,9,0,0,41,0,0,0,64,8,144,0,57,0,0,0,64,0,128,4,63],[0,0,0,1,8,0,0,58,0,0,0,0,8,137,4,54,0,0,0,0,2,32,3,80,0,0,0,0,2,2,4,59],[0,0,0,0,0,40,4,53,0,0,1,193,0,0,97,61,0,0,0,248,7,112,2,16,0,0,7,167,2,32,1,151],[0,0,0,0,2,114,1,159,0,0,7,160,2,32,1,103,0,0,0,0,0,40,4,53,0,0,0,128,2,96,0,138],[0,0,0,0,6,33,3,79,0,0,0,96,2,0,0,57,0,0,0,0,6,6,4,59,0,0,0,0,6,6,0,75],[0,0,8,72,0,0,193,61,0,0,7,160,6,0,0,65,0,0,0,0,7,84,0,75,0,0,0,0,7,0,0,25],[0,0,0,0,7,6,128,25,0,0,7,160,5,80,1,151,0,0,7,160,8,64,1,151,0,0,0,0,9,88,0,75],[0,0,0,0,6,0,128,25,0,0,0,0,5,88,1,63,0,0,7,160,5,80,0,156,0,0,0,0,6,7,192,25],[0,0,0,0,5,6,0,75,0,0,0,12,5,0,0,41,0,0,0,159,0,0,193,61,0,0,0,9,6,0,0,41],[0,0,0,0,6,6,4,51,0,0,0,128,7,0,4,61,0,0,0,11,8,0,0,41,0,0,0,0,8,8,4,51],[0,0,0,8,9,0,0,41,0,0,0,0,9,9,4,51,0,0,0,7,10,0,0,41,0,0,0,0,10,10,4,51],[0,0,0,0,5,84,0,25,0,0,0,0,4,81,3,79,0,0,0,0,4,4,4,59,0,0,7,159,11,64,0,156],[0,0,0,159,0,0,33,61,0,0,0,0,11,67,0,73,0,0,0,32,5,80,0,57,0,0,7,160,12,0,0,65],[0,0,0,0,13,181,0,75,0,0,0,0,13,0,0,25,0,0,0,0,13,12,32,25,0,0,7,160,11,176,1,151],[0,0,7,160,14,80,1,151,0,0,0,0,15,190,0,75,0,0,0,0,12,0,128,25,0,0,0,0,11,190,1,63],[0,0,7,160,11,176,0,156,0,0,0,0,12,13,192,25,0,0,0,0,11,12,0,75,0,0,0,159,0,0,193,61],[0,0,0,0,6,118,0,25,0,0,0,0,6,134,0,25,0,0,0,0,6,150,0,25,0,0,0,0,6,166,0,25],[0,0,0,0,6,70,0,25,0,0,0,0,7,2,4,51,0,0,0,0,6,118,0,25,0,0,0,64,7,0,4,61],[0,0,7,159,6,96,1,151,0,0,0,56,8,96,0,140,0,0,10,83,0,0,65,61,0,0,0,32,9,96,2,112],[0,0,7,155,8,96,0,156,0,0,0,0,9,6,160,25,0,0,7,155,8,96,0,156,0,0,0,0,10,0,0,25],[0,0,0,4,10,0,32,57,0,0,0,2,8,160,1,191,0,0,255,255,11,144,0,140,0,0,0,0,8,10,160,25],[0,0,0,16,10,144,2,112,0,0,0,0,10,9,160,25,0,0,0,255,9,160,0,140,0,0,0,0,9,0,0,25],[0,0,0,1,9,0,32,57,0,0,7,166,10,112,0,156,0,0,1,89,0,0,33,61,0,0,0,0,8,152,1,159],[0,0,0,64,9,112,0,57,0,0,0,64,0,144,4,63,0,0,0,0,9,49,3,79,0,0,0,2,3,128,0,58],[0,0,0,0,3,55,4,54,0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59,0,0,0,0,0,147,4,53],[0,0,1,193,0,0,97,61,0,0,7,167,9,144,1,151,0,0,0,248,10,128,2,16,0,0,0,0,9,154,1,159],[0,0,7,173,9,144,1,199,0,0,0,0,0,147,4,53,0,0,0,3,3,128,2,16,0,0,0,248,3,48,1,95],[0,0,0,0,3,54,1,207,0,0,0,33,6,112,0,57,0,0,0,0,0,54,4,53,0,0,10,99,0,0,1,61],[0,0,7,164,1,0,0,65,0,0,0,0,0,16,4,57,0,0,7,155,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,7,155,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,7,165,1,16,1,199],[0,0,128,11,2,0,0,57,30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144,0,0,24,107,0,0,97,61],[0,0,0,64,4,0,4,61,0,0,0,0,2,1,4,59,0,0,0,128,1,32,0,140,0,0,10,26,0,0,65,61],[0,0,0,128,1,32,2,112,0,0,7,168,3,32,0,156,0,0,0,0,1,2,160,25,0,0,7,168,3,32,0,156],[0,0,0,0,3,0,0,25,0,0,0,16,3,0,32,57,0,0,0,8,5,48,1,191,0,0,7,159,6,16,0,156],[0,0,0,0,5,3,160,25,0,0,0,64,3,16,2,112,0,0,7,159,6,16,0,156,0,0,0,0,3,1,160,25],[0,0,0,4,1,80,1,191,0,0,7,155,6,48,0,156,0,0,0,0,1,5,160,25,0,0,0,32,6,48,2,112],[0,0,7,155,5,48,0,156,0,0,0,0,6,3,160,25,0,0,0,2,5,16,1,191,0,0,255,255,3,96,0,140],[0,0,0,0,5,1,160,25,0,0,0,16,1,96,2,112,0,0,0,0,1,6,160,25,0,0,0,255,1,16,0,140],[0,0,0,1,5,80,32,57,0,0,0,65,1,80,0,57,0,0,0,10,1,16,1,127,0,0,0,0,1,20,0,25],[0,0,0,0,3,65,0,75,0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57,0,0,7,159,6,16,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,3,48,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,16,4,63],[0,0,0,2,1,80,0,57,0,0,0,0,6,20,4,54,0,0,0,1,1,0,3,103,0,0,0,0,3,0,0,49],[0,0,0,33,7,80,0,57,0,0,0,5,7,112,2,114,0,0,8,141,0,0,97,61,0,0,0,0,8,49,3,79],[0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16,0,0,0,0,11,166,0,25,0,0,0,0,10,168,3,79],[0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75],[0,0,8,133,0,0,65,61,0,0,0,0,7,0,0,75,0,0,8,143,0,0,97,61,0,0,0,0,7,4,4,51],[0,0,0,0,7,7,0,75,0,0,1,193,0,0,97,61,0,0,0,0,7,6,4,51,0,0,7,167,7,112,1,151],[0,0,0,248,8,80,2,16,0,0,0,0,7,120,1,159,0,0,7,169,7,112,0,65,0,0,0,0,0,118,4,53],[0,0,0,3,5,80,2,16,0,0,0,248,5,80,0,137,0,0,0,0,2,82,1,207,0,0,0,255,5,80,0,140],[0,0,0,0,2,0,32,25,0,0,0,33,5,64,0,57,0,0,10,45,0,0,1,61,0,0,7,166,6,128,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,6,128,0,57,0,0,0,64,0,96,4,63,0,0,0,0,6,33,3,79],[0,0,0,1,10,0,0,58,0,0,0,0,10,168,4,54,0,0,0,0,6,96,3,80,0,0,0,0,11,6,4,59],[0,0,0,0,0,186,4,53,0,0,1,193,0,0,97,61,0,0,0,11,13,0,0,41,0,0,0,248,6,208,2,16],[0,0,7,160,12,0,0,65,0,0,0,0,13,13,0,75,0,0,0,0,12,6,192,25,0,0,7,167,6,176,1,151],[0,0,0,0,6,198,1,159,0,0,0,0,0,106,4,53,0,0,0,64,6,0,4,61,0,0,0,32,10,96,0,57],[0,0,0,0,11,3,4,51,0,0,0,0,12,11,0,75,0,0,8,191,0,0,97,61,0,0,0,0,12,0,0,25],[0,0,0,0,13,172,0,25,0,0,0,32,12,192,0,57,0,0,0,0,14,60,0,25,0,0,0,0,14,14,4,51],[0,0,0,0,0,237,4,53,0,0,0,0,13,188,0,75,0,0,8,184,0,0,65,61,0,0,0,0,3,171,0,25],[0,0,0,0,0,3,4,53,0,0,0,0,10,4,4,51,0,0,0,0,11,10,0,75,0,0,8,204,0,0,97,61],[0,0,0,0,11,0,0,25,0,0,0,0,12,59,0,25,0,0,0,32,11,176,0,57,0,0,0,0,13,75,0,25],[0,0,0,0,13,13,4,51,0,0,0,0,0,220,4,53,0,0,0,0,12,171,0,75,0,0,8,197,0,0,65,61],[0,0,0,0,3,58,0,25,0,0,0,0,0,3,4,53,0,0,0,0,4,5,4,51,0,0,0,0,10,4,0,75],[0,0,8,217,0,0,97,61,0,0,0,0,10,0,0,25,0,0,0,0,11,58,0,25,0,0,0,32,10,160,0,57],[0,0,0,0,12,90,0,25,0,0,0,0,12,12,4,51,0,0,0,0,0,203,4,53,0,0,0,0,11,74,0,75],[0,0,8,210,0,0,65,61,0,0,0,0,3,52,0,25,0,0,0,0,0,3,4,53,0,0,0,0,4,7,4,51],[0,0,0,0,5,4,0,75,0,0,8,230,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,0,10,53,0,25],[0,0,0,32,5,80,0,57,0,0,0,0,11,117,0,25,0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53],[0,0,0,0,10,69,0,75,0,0,8,223,0,0,65,61,0,0,0,0,3,52,0,25,0,0,0,0,0,3,4,53],[0,0,0,0,4,9,4,51,0,0,0,0,5,4,0,75,0,0,8,243,0,0,97,61,0,0,0,0,5,0,0,25],[0,0,0,0,7,53,0,25,0,0,0,32,5,80,0,57,0,0,0,0,10,149,0,25,0,0,0,0,10,10,4,51],[0,0,0,0,0,167,4,53,0,0,0,0,7,69,0,75,0,0,8,236,0,0,65,61,0,0,0,0,3,52,0,25],[0,0,0,0,0,3,4,53,0,0,0,0,4,8,4,51,0,0,0,0,5,4,0,75,0,0,9,0,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,0,7,53,0,25,0,0,0,32,5,80,0,57,0,0,0,0,9,133,0,25],[0,0,0,0,9,9,4,51,0,0,0,0,0,151,4,53,0,0,0,0,7,69,0,75,0,0,8,249,0,0,65,61],[0,0,0,0,3,52,0,25,0,0,0,0,0,3,4,53,0,0,0,0,3,99,0,73,0,0,0,32,4,48,0,138],[0,0,0,0,0,70,4,53,0,0,0,31,4,48,0,57,0,0,0,32,3,0,0,138,0,0,0,0,4,52,1,111],[0,0,0,0,7,100,0,25,0,0,0,0,4,71,0,75,0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57],[0,0,7,159,5,112,0,156,0,0,1,89,0,0,33,61,0,0,0,1,4,64,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,112,4,63,0,0,0,13,5,0,0,41,0,0,1,196,4,80,0,57,0,0,0,0,4,65,3,79],[0,0,0,0,5,82,0,73,0,0,0,35,5,80,0,138,0,0,0,0,4,4,4,59,0,0,7,160,8,0,0,65],[0,0,0,0,9,84,0,75,0,0,0,0,9,0,0,25,0,0,0,0,9,8,128,25,0,0,7,160,5,80,1,151],[0,0,7,160,10,64,1,151,0,0,0,0,11,90,0,75,0,0,0,0,8,0,128,25,0,0,0,0,5,90,1,63],[0,0,7,160,5,80,0,156,0,0,0,0,8,9,192,25,0,0,0,0,5,8,0,75,0,0,0,12,5,0,0,41],[0,0,0,159,0,0,193,61,0,0,0,0,5,84,0,25,0,0,0,0,4,81,3,79,0,0,0,0,4,4,4,59],[0,0,7,159,8,64,0,156,0,0,0,159,0,0,33,61,0,0,0,0,8,66,0,73,0,0,0,32,5,80,0,57],[0,0,7,160,9,0,0,65,0,0,0,0,10,133,0,75,0,0,0,0,10,0,0,25,0,0,0,0,10,9,32,25],[0,0,7,160,8,128,1,151,0,0,7,160,11,80,1,151,0,0,0,0,12,139,0,75,0,0,0,0,9,0,128,25],[0,0,0,0,8,139,1,63,0,0,7,160,8,128,0,156,0,0,0,0,9,10,192,25,0,0,0,0,8,9,0,75],[0,0,0,159,0,0,193,61,0,0,0,1,8,64,0,140,0,0,12,107,0,0,193,61,0,0,0,0,8,81,3,79],[0,0,0,0,8,8,4,59,0,0,0,1,9,0,0,138,0,0,7,160,10,0,0,65,0,0,0,0,9,152,0,75],[0,0,0,0,9,0,0,25,0,0,0,0,9,10,32,25,0,0,7,160,8,128,1,151,0,0,7,160,11,128,0,156],[0,0,0,0,10,0,128,25,0,0,7,160,8,128,1,103,0,0,7,160,8,128,0,156,0,0,0,0,10,9,192,25],[0,0,0,96,8,0,0,57,0,0,0,0,9,10,0,75,0,0,12,231,0,0,193,61,0,0,7,166,8,112,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,8,112,0,57,0,0,0,64,0,128,4,63,0,0,0,32,8,112,0,57],[0,0,7,169,9,0,0,65,0,0,0,0,0,152,4,53,0,0,0,1,8,0,0,57,0,0,0,0,0,135,4,53],[0,0,0,0,8,7,0,25,0,0,12,231,0,0,1,61,0,0,7,166,7,144,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,7,144,0,57,0,0,0,64,0,112,4,63,0,0,0,0,7,33,3,79,0,0,0,1,11,0,0,58],[0,0,0,0,11,185,4,54,0,0,0,0,7,112,3,80,0,0,0,0,12,7,4,59,0,0,0,0,0,203,4,53],[0,0,1,193,0,0,97,61,0,0,0,11,14,0,0,41,0,0,0,248,7,224,2,16,0,0,7,160,13,0,0,65],[0,0,0,0,14,14,0,75,0,0,0,0,13,7,192,25,0,0,7,167,7,192,1,151,0,0,0,0,7,215,1,159],[0,0,0,0,0,123,4,53,0,0,0,64,7,0,4,61,0,0,0,32,11,112,0,57,0,0,0,0,12,3,4,51],[0,0,0,0,13,12,0,75,0,0,9,118,0,0,97,61,0,0,0,0,13,0,0,25,0,0,0,0,14,189,0,25],[0,0,0,32,13,208,0,57,0,0,0,0,15,61,0,25,0,0,0,0,15,15,4,51,0,0,0,0,0,254,4,53],[0,0,0,0,14,205,0,75,0,0,9,111,0,0,65,61,0,0,0,0,3,188,0,25,0,0,0,0,0,3,4,53],[0,0,0,0,11,4,4,51,0,0,0,0,12,11,0,75,0,0,9,131,0,0,97,61,0,0,0,0,12,0,0,25],[0,0,0,0,13,60,0,25,0,0,0,32,12,192,0,57,0,0,0,0,14,76,0,25,0,0,0,0,14,14,4,51],[0,0,0,0,0,237,4,53,0,0,0,0,13,188,0,75,0,0,9,124,0,0,65,61,0,0,0,0,3,59,0,25],[0,0,0,0,0,3,4,53,0,0,0,0,4,5,4,51,0,0,0,0,11,4,0,75,0,0,9,144,0,0,97,61],[0,0,0,0,11,0,0,25,0,0,0,0,12,59,0,25,0,0,0,32,11,176,0,57,0,0,0,0,13,91,0,25],[0,0,0,0,13,13,4,51,0,0,0,0,0,220,4,53,0,0,0,0,12,75,0,75,0,0,9,137,0,0,65,61],[0,0,0,0,3,52,0,25,0,0,0,0,0,3,4,53,0,0,0,0,4,6,4,51,0,0,0,0,5,4,0,75],[0,0,9,157,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,0,11,53,0,25,0,0,0,32,5,80,0,57],[0,0,0,0,12,101,0,25,0,0,0,0,12,12,4,51,0,0,0,0,0,203,4,53,0,0,0,0,11,69,0,75],[0,0,9,150,0,0,65,61,0,0,0,0,3,52,0,25,0,0,0,0,0,3,4,53,0,0,0,0,4,8,4,51],[0,0,0,0,5,4,0,75,0,0,9,170,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,0,6,53,0,25],[0,0,0,32,5,80,0,57,0,0,0,0,11,133,0,25,0,0,0,0,11,11,4,51,0,0,0,0,0,182,4,53],[0,0,0,0,6,69,0,75,0,0,9,163,0,0,65,61,0,0,0,0,3,52,0,25,0,0,0,0,0,3,4,53],[0,0,0,0,4,10,4,51,0,0,0,0,5,4,0,75,0,0,9,183,0,0,97,61,0,0,0,0,5,0,0,25],[0,0,0,0,6,53,0,25,0,0,0,32,5,80,0,57,0,0,0,0,8,165,0,25,0,0,0,0,8,8,4,51],[0,0,0,0,0,134,4,53,0,0,0,0,6,69,0,75,0,0,9,176,0,0,65,61,0,0,0,0,3,52,0,25],[0,0,0,0,0,3,4,53,0,0,0,0,4,9,4,51,0,0,0,0,5,4,0,75,0,0,9,196,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,0,6,53,0,25,0,0,0,32,5,80,0,57,0,0,0,0,8,149,0,25],[0,0,0,0,8,8,4,51,0,0,0,0,0,134,4,53,0,0,0,0,6,69,0,75,0,0,9,189,0,0,65,61],[0,0,0,0,3,52,0,25,0,0,0,0,0,3,4,53,0,0,0,0,3,115,0,73,0,0,0,32,4,48,0,138],[0,0,0,0,0,71,4,53,0,0,0,31,4,48,0,57,0,0,0,32,3,0,0,138,0,0,0,0,4,52,1,111],[0,0,0,0,6,116,0,25,0,0,0,0,4,70,0,75,0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57],[0,0,7,159,5,96,0,156,0,0,1,89,0,0,33,61,0,0,0,1,4,64,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,96,4,63,0,0,0,13,5,0,0,41,0,0,1,196,4,80,0,57,0,0,0,0,4,65,3,79],[0,0,0,0,5,82,0,73,0,0,0,35,5,80,0,138,0,0,0,0,4,4,4,59,0,0,7,160,8,0,0,65],[0,0,0,0,9,84,0,75,0,0,0,0,9,0,0,25,0,0,0,0,9,8,128,25,0,0,7,160,5,80,1,151],[0,0,7,160,10,64,1,151,0,0,0,0,11,90,0,75,0,0,0,0,8,0,128,25,0,0,0,0,5,90,1,63],[0,0,7,160,5,80,0,156,0,0,0,0,8,9,192,25,0,0,0,0,5,8,0,75,0,0,0,12,5,0,0,41],[0,0,0,159,0,0,193,61,0,0,0,0,5,84,0,25,0,0,0,0,4,81,3,79,0,0,0,0,4,4,4,59],[0,0,7,159,8,64,0,156,0,0,0,159,0,0,33,61,0,0,0,0,8,66,0,73,0,0,0,32,5,80,0,57],[0,0,7,160,9,0,0,65,0,0,0,0,10,133,0,75,0,0,0,0,10,0,0,25,0,0,0,0,10,9,32,25],[0,0,7,160,8,128,1,151,0,0,7,160,11,80,1,151,0,0,0,0,12,139,0,75,0,0,0,0,9,0,128,25],[0,0,0,0,8,139,1,63,0,0,7,160,8,128,0,156,0,0,0,0,9,10,192,25,0,0,0,0,8,9,0,75],[0,0,0,159,0,0,193,61,0,0,0,1,8,64,0,140,0,0,12,174,0,0,193,61,0,0,0,0,8,81,3,79],[0,0,0,0,8,8,4,59,0,0,0,1,9,0,0,138,0,0,7,160,10,0,0,65,0,0,0,0,9,152,0,75],[0,0,0,0,9,0,0,25,0,0,0,0,9,10,32,25,0,0,7,160,8,128,1,151,0,0,7,160,11,128,0,156],[0,0,0,0,10,0,128,25,0,0,7,160,8,128,1,103,0,0,7,160,8,128,0,156,0,0,0,0,10,9,192,25],[0,0,0,96,8,0,0,57,0,0,0,0,9,10,0,75,0,0,13,135,0,0,193,61,0,0,7,166,8,96,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,8,96,0,57,0,0,0,64,0,128,4,63,0,0,0,32,8,96,0,57],[0,0,7,169,9,0,0,65,0,0,0,0,0,152,4,53,0,0,0,1,8,0,0,57,0,0,0,0,0,134,4,53],[0,0,0,0,8,6,0,25,0,0,13,135,0,0,1,61,0,0,7,166,1,64,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,1,64,0,57,0,0,0,64,0,16,4,63,0,0,0,1,1,0,0,58,0,0,0,0,5,20,4,54],[0,0,0,0,3,0,0,49,0,0,0,1,1,0,3,103,0,0,0,0,6,49,3,79,0,0,0,0,6,96,3,80],[0,0,0,0,6,6,4,59,0,0,0,0,0,101,4,53,0,0,1,193,0,0,97,61,0,0,0,248,7,32,2,16],[0,0,7,160,8,0,0,65,0,0,0,0,2,2,0,75,0,0,0,0,8,7,192,25,0,0,7,167,2,96,1,151],[0,0,0,0,2,130,1,159,0,0,0,0,0,37,4,53,0,0,0,64,2,0,4,61,0,0,0,32,5,32,0,57],[0,0,0,0,6,4,4,51,0,0,0,0,7,6,0,75,0,0,10,59,0,0,97,61,0,0,0,0,7,0,0,25],[0,0,0,0,8,87,0,25,0,0,0,32,7,112,0,57,0,0,0,0,9,71,0,25,0,0,0,0,9,9,4,51],[0,0,0,0,0,152,4,53,0,0,0,0,8,103,0,75,0,0,10,52,0,0,65,61,0,0,0,0,4,86,0,25],[0,0,7,192,5,0,0,65,0,0,0,0,0,84,4,53,0,0,0,0,4,36,0,73,0,0,0,30,5,64,0,138],[0,0,0,0,0,82,4,53,0,0,0,33,4,64,0,57,0,0,0,10,5,64,1,127,0,0,0,0,4,37,0,25],[0,0,0,0,5,84,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57,0,0,7,159,6,64,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,5,80,1,144,0,0,1,89,0,0,193,61,0,0,0,13,6,0,0,41],[0,0,1,196,5,96,0,57,0,0,0,64,0,64,4,63,0,0,0,0,4,81,3,79,0,0,0,0,5,99,0,73],[0,0,0,35,5,80,0,138,0,0,0,0,4,4,4,59,0,0,7,237,0,0,1,61,0,0,7,166,8,112,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,8,112,0,57,0,0,0,64,0,128,4,63,0,0,0,0,8,49,3,79],[0,0,0,1,3,0,0,58,0,0,0,0,3,55,4,54,0,0,0,0,8,128,3,80,0,0,0,0,8,8,4,59],[0,0,0,0,0,131,4,53,0,0,1,193,0,0,97,61,0,0,7,167,8,128,1,151,0,0,0,248,6,96,2,16],[0,0,0,0,6,134,1,159,0,0,7,172,6,96,0,65,0,0,0,0,0,99,4,53,0,0,0,64,3,0,4,61],[0,0,0,32,6,48,0,57,0,0,0,0,8,7,4,51,0,0,0,0,9,8,0,75,0,0,10,112,0,0,97,61],[0,0,0,0,9,0,0,25,0,0,0,0,10,105,0,25,0,0,0,32,9,144,0,57,0,0,0,0,11,121,0,25],[0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53,0,0,0,0,10,137,0,75,0,0,10,105,0,0,65,61],[0,0,0,0,7,104,0,25,0,0,0,0,0,7,4,53,0,0,0,128,8,0,4,61,0,0,0,0,9,8,0,75],[0,0,10,125,0,0,97,61,0,0,0,0,9,0,0,25,0,0,0,0,10,121,0,25,0,0,0,160,11,144,0,57],[0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53,0,0,0,32,9,144,0,57,0,0,0,0,10,137,0,75],[0,0,10,118,0,0,65,61,0,0,0,0,7,120,0,25,0,0,0,0,0,7,4,53,0,0,0,9,12,0,0,41],[0,0,0,0,8,12,4,51,0,0,0,0,9,8,0,75,0,0,10,139,0,0,97,61,0,0,0,0,9,0,0,25],[0,0,0,0,10,121,0,25,0,0,0,32,9,144,0,57,0,0,0,0,11,201,0,25,0,0,0,0,11,11,4,51],[0,0,0,0,0,186,4,53,0,0,0,0,10,137,0,75,0,0,10,132,0,0,65,61,0,0,0,0,7,120,0,25],[0,0,0,0,0,7,4,53,0,0,0,11,12,0,0,41,0,0,0,0,8,12,4,51,0,0,0,0,9,8,0,75],[0,0,10,153,0,0,97,61,0,0,0,0,9,0,0,25,0,0,0,0,10,121,0,25,0,0,0,32,9,144,0,57],[0,0,0,0,11,201,0,25,0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53,0,0,0,0,10,137,0,75],[0,0,10,146,0,0,65,61,0,0,0,0,7,120,0,25,0,0,0,0,0,7,4,53,0,0,0,8,12,0,0,41],[0,0,0,0,8,12,4,51,0,0,0,0,9,8,0,75,0,0,10,167,0,0,97,61,0,0,0,0,9,0,0,25],[0,0,0,0,10,121,0,25,0,0,0,32,9,144,0,57,0,0,0,0,11,201,0,25,0,0,0,0,11,11,4,51],[0,0,0,0,0,186,4,53,0,0,0,0,10,137,0,75,0,0,10,160,0,0,65,61,0,0,0,0,7,120,0,25],[0,0,0,0,0,7,4,53,0,0,0,7,12,0,0,41,0,0,0,0,8,12,4,51,0,0,0,0,9,8,0,75],[0,0,10,181,0,0,97,61,0,0,0,0,9,0,0,25,0,0,0,0,10,121,0,25,0,0,0,32,9,144,0,57],[0,0,0,0,11,201,0,25,0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53,0,0,0,0,10,137,0,75],[0,0,10,174,0,0,65,61,0,0,0,0,5,81,3,79,0,0,0,0,1,120,0,25,0,0,0,31,7,64,1,143],[0,0,0,0,0,1,4,53,0,0,0,5,8,64,2,114,0,0,10,196,0,0,97,61,0,0,0,0,9,0,0,25],[0,0,0,5,10,144,2,16,0,0,0,0,11,161,0,25,0,0,0,0,10,165,3,79,0,0,0,0,10,10,4,59],[0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57,0,0,0,0,10,137,0,75,0,0,10,188,0,0,65,61],[0,0,0,0,9,7,0,75,0,0,10,211,0,0,97,61,0,0,0,5,8,128,2,16,0,0,0,0,5,133,3,79],[0,0,0,0,8,129,0,25,0,0,0,3,7,112,2,16,0,0,0,0,9,8,4,51,0,0,0,0,9,121,1,207],[0,0,0,0,9,121,2,47,0,0,0,0,5,5,4,59,0,0,1,0,7,112,0,137,0,0,0,0,5,117,2,47],[0,0,0,0,5,117,1,207,0,0,0,0,5,149,1,159,0,0,0,0,0,88,4,53,0,0,0,0,1,65,0,25],[0,0,0,0,0,1,4,53,0,0,0,0,4,2,4,51,0,0,0,0,5,4,0,75,0,0,10,224,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,0,7,21,0,25,0,0,0,32,5,80,0,57,0,0,0,0,8,37,0,25],[0,0,0,0,8,8,4,51,0,0,0,0,0,135,4,53,0,0,0,0,7,69,0,75,0,0,10,217,0,0,65,61],[0,0,0,0,1,20,0,25,0,0,0,0,0,1,4,53,0,0,0,0,1,49,0,73,0,0,0,32,2,16,0,138],[0,0,0,0,0,35,4,53,0,0,0,31,1,16,0,57,0,0,0,10,2,16,1,127,0,0,0,0,1,50,0,25],[0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,7,159,4,16,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,2,32,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,16,4,63],[0,0,7,155,1,0,0,65,0,0,7,155,2,96,0,156,0,0,0,0,6,1,128,25,0,0,0,64,2,96,2,16],[0,0,0,0,3,3,4,51,0,0,7,155,4,48,0,156,0,0,0,0,3,1,128,25,0,0,0,96,3,48,2,16],[0,0,0,0,2,35,1,159,0,0,0,0,3,0,4,20,0,0,7,155,4,48,0,156,0,0,0,0,3,1,128,25],[0,0,0,192,1,48,2,16,0,0,0,0,1,33,1,159,0,0,7,175,1,16,1,199,0,0,128,16,2,0,0,57],[30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144,0,0,0,12,3,0,0,41,0,0,0,13,2,0,0,41],[0,0,0,159,0,0,97,61,0,13,0,0,0,2,0,29,0,0,0,1,2,0,3,103,0,12,0,0,0,3,0,29],[0,0,0,0,3,50,3,79,0,0,0,0,1,1,4,59,0,11,0,0,0,1,0,29,0,0,0,0,1,3,4,59],[0,0,0,113,3,16,0,140,0,0,13,34,0,0,193,61,0,0,0,12,9,0,0,41,0,0,1,224,1,144,0,57],[0,0,0,0,3,18,3,79,0,0,0,0,1,0,0,49,0,0,0,13,4,16,0,106,0,0,0,35,4,64,0,138],[0,0,0,0,3,3,4,59,0,0,7,160,5,0,0,65,0,0,0,0,6,67,0,75,0,0,0,0,6,0,0,25],[0,0,0,0,6,5,128,25,0,0,7,160,4,64,1,151,0,0,7,160,7,48,1,151,0,0,0,0,8,71,0,75],[0,0,0,0,5,0,128,25,0,0,0,0,4,71,1,63,0,0,7,160,4,64,0,156,0,0,0,0,5,6,192,25],[0,0,0,0,4,5,0,75,0,0,0,159,0,0,193,61,0,0,0,0,3,147,0,25,0,0,0,0,2,50,3,79],[0,0,0,0,2,2,4,59,0,0,7,159,4,32,0,156,0,0,0,159,0,0,33,61,0,0,0,0,4,33,0,73],[0,0,0,32,1,48,0,57,0,0,7,160,3,0,0,65,0,0,0,0,5,65,0,75,0,0,0,0,5,0,0,25],[0,0,0,0,5,3,32,25,0,0,7,160,4,64,1,151,0,0,7,160,6,16,1,151,0,0,0,0,7,70,0,75],[0,0,0,0,3,0,128,25,0,0,0,0,4,70,1,63,0,0,7,160,4,64,0,156,0,0,0,0,3,5,192,25],[0,0,0,0,3,3,0,75,0,0,0,159,0,0,193,61,30,104,29,198,0,0,4,15,0,0,0,64,2,0,4,61],[0,0,0,64,3,32,0,57,0,0,0,0,0,19,4,53,0,0,0,64,1,0,0,57,0,0,0,0,1,18,4,54],[0,0,0,11,3,0,0,41,0,0,0,0,0,49,4,53,0,0,7,197,3,32,0,156,0,0,1,89,0,0,33,61],[0,0,0,96,3,32,0,57,0,0,0,64,0,48,4,63,0,0,7,155,3,0,0,65,0,0,7,155,4,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,64,1,16,2,16,0,0,0,0,2,2,4,51,0,0,7,155,4,32,0,156],[0,0,0,0,2,3,128,25,0,0,0,96,2,32,2,16,0,0,0,0,1,18,1,159,0,0,0,0,2,0,4,20],[0,0,7,155,4,32,0,156,0,0,0,0,2,3,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,7,175,1,16,1,199,0,0,128,16,2,0,0,57,30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,0,159,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,64,2,0,4,61,0,0,0,32,3,32,0,57],[0,0,0,11,4,0,0,41,0,0,0,0,0,67,4,53,0,0,0,0,0,18,4,53,0,0,7,155,1,0,0,65],[0,0,7,155,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,7,198,1,16,1,199],[0,0,30,105,0,1,4,46,0,0,7,155,1,16,1,151,0,0,0,0,1,19,3,79,0,0,0,0,2,82,0,73],[0,0,7,155,2,32,1,151,0,0,0,0,1,33,3,223,0,0,0,192,2,64,2,16,0,0,7,177,2,32,1,151],[0,0,7,178,2,32,1,199,0,0,0,0,1,33,3,175,0,0,128,16,2,0,0,57,30,104,30,99,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,7,155,4,48,1,151,0,0,0,1,2,32,1,144],[0,0,12,147,0,0,97,61,0,0,0,63,2,64,0,57,0,0,7,179,2,32,1,151,0,0,0,64,5,0,4,61],[0,0,0,0,2,37,0,25,0,0,0,0,3,82,0,75,0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57],[0,0,7,159,6,32,0,156,0,0,1,89,0,0,33,61,0,0,0,1,3,48,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,32,4,63,0,0,0,0,2,69,4,54,0,0,0,1,3,0,3,103,0,0,0,31,6,64,0,57],[0,0,0,5,6,96,2,114,0,0,11,140,0,0,97,61,0,0,0,0,7,48,3,104,0,0,0,0,8,0,0,25],[0,0,0,5,9,128,2,16,0,0,0,0,10,146,0,25,0,0,0,0,9,151,3,79,0,0,0,0,9,9,4,59],[0,0,0,0,0,154,4,53,0,0,0,1,8,128,0,57,0,0,0,0,9,104,0,75,0,0,11,132,0,0,65,61],[0,0,0,0,6,0,0,75,0,0,11,142,0,0,97,61,0,0,0,31,6,64,1,143,0,0,0,5,4,64,2,114],[0,0,11,154,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,130,0,25],[0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,71,0,75,0,0,11,146,0,0,65,61,0,0,0,0,7,6,0,75,0,0,11,169,0,0,97,61],[0,0,0,5,4,64,2,16,0,0,0,0,1,65,3,79,0,0,0,0,4,66,0,25,0,0,0,3,6,96,2,16],[0,0,0,0,7,4,4,51,0,0,0,0,7,103,1,207,0,0,0,0,7,103,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,6,96,0,137,0,0,0,0,1,97,2,47,0,0,0,0,1,97,1,207,0,0,0,0,1,113,1,159],[0,0,0,0,0,20,4,53,0,0,0,0,1,5,4,51,0,0,0,32,1,16,0,140,0,0,12,89,0,0,193,61],[0,0,0,13,11,0,0,41,0,0,0,100,1,176,0,57,0,0,0,0,1,19,3,79,0,0,0,68,4,176,0,57],[0,0,0,0,5,67,3,79,0,0,0,36,4,176,0,57,0,0,0,0,4,67,3,79,0,0,1,36,6,176,0,57],[0,0,0,0,6,99,3,79,0,0,1,4,7,176,0,57,0,0,0,0,7,115,3,79,0,0,0,228,8,176,0,57],[0,0,0,0,8,131,3,79,0,0,0,196,9,176,0,57,0,0,0,0,9,147,3,79,0,0,0,164,10,176,0,57],[0,0,0,0,10,163,3,79,0,0,0,132,11,176,0,57,0,0,0,0,11,179,3,79,0,0,0,12,3,48,3,96],[0,0,0,0,3,3,4,59,0,0,0,0,4,4,4,59,0,0,0,0,5,5,4,59,0,0,0,0,12,1,4,59],[0,0,0,0,11,11,4,59,0,0,0,0,10,10,4,59,0,0,0,0,9,9,4,59,0,0,0,0,8,8,4,59],[0,0,0,0,7,7,4,59,0,0,0,0,6,6,4,59,0,0,0,0,2,2,4,51,0,0,0,64,1,0,4,61],[0,0,1,192,13,16,0,57,0,0,0,0,0,45,4,53,0,0,1,160,2,16,0,57,0,0,0,11,13,0,0,41],[0,0,0,0,0,210,4,53,0,0,1,128,2,16,0,57,0,0,0,10,13,0,0,41,0,0,0,0,0,210,4,53],[0,0,1,96,2,16,0,57,0,0,0,0,0,98,4,53,0,0,1,64,2,16,0,57,0,0,0,0,0,114,4,53],[0,0,1,32,2,16,0,57,0,0,0,0,0,130,4,53,0,0,1,0,2,16,0,57,0,0,0,0,0,146,4,53],[0,0,0,224,2,16,0,57,0,0,0,0,0,162,4,53,0,0,0,192,2,16,0,57,0,0,0,0,0,178,4,53],[0,0,0,160,2,16,0,57,0,0,0,0,0,194,4,53,0,0,0,128,2,16,0,57,0,0,0,0,0,82,4,53],[0,0,0,96,2,16,0,57,0,0,0,0,0,66,4,53,0,0,0,64,2,16,0,57,0,0,0,0,0,50,4,53],[0,0,0,32,2,16,0,57,0,0,7,183,3,0,0,65,0,0,0,0,0,50,4,53,0,0,1,192,3,0,0,57],[0,0,0,0,0,49,4,53,0,0,7,184,3,16,0,156,0,0,1,89,0,0,33,61,0,0,1,224,3,16,0,57],[0,0,0,64,0,48,4,63,0,0,7,155,4,0,0,65,0,0,7,155,3,32,0,156,0,0,0,0,2,4,128,25],[0,0,0,64,2,32,2,16,0,0,0,0,1,1,4,51,0,0,7,155,3,16,0,156,0,0,0,0,1,4,128,25],[0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20,0,0,7,155,3,32,0,156],[0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,7,175,1,16,1,199],[0,0,128,16,2,0,0,57,30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144,0,0,0,159,0,0,97,61],[0,0,0,0,1,1,4,59,0,10,0,0,0,1,0,29,0,0,0,64,1,0,4,61,0,11,0,0,0,1,0,29],[0,0,7,164,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,0,1,0,4,20,0,0,7,155,2,16,0,156],[0,0,7,155,1,0,128,65,0,0,0,192,1,16,2,16,0,0,7,165,1,16,1,199,0,0,128,11,2,0,0,57],[30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144,0,0,24,107,0,0,97,61,0,0,0,11,4,0,0,41],[0,0,0,32,2,64,0,57,0,0,0,0,1,1,4,59,0,0,7,185,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,128,3,64,0,57,0,0,0,0,0,19,4,53,0,0,0,96,1,64,0,57,0,0,7,186,3,0,0,65],[0,0,0,0,0,49,4,53,0,0,0,64,1,64,0,57,0,0,7,187,3,0,0,65,0,0,0,0,0,49,4,53],[0,0,0,128,1,0,0,57,0,0,0,0,0,20,4,53,0,0,7,188,1,64,0,156,0,0,1,89,0,0,33,61],[0,0,0,11,4,0,0,41,0,0,0,160,1,64,0,57,0,0,0,64,0,16,4,63,0,0,7,155,1,0,0,65],[0,0,7,155,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,2,32,2,16,0,0,0,0,3,4,4,51],[0,0,7,155,4,48,0,156,0,0,0,0,3,1,128,25,0,0,0,96,3,48,2,16,0,0,0,0,2,35,1,159],[0,0,0,0,3,0,4,20,0,0,7,155,4,48,0,156,0,0,0,0,3,1,128,25,0,0,0,192,1,48,2,16],[0,0,0,0,1,33,1,159,0,0,7,175,1,16,1,199,0,0,128,16,2,0,0,57,30,104,30,94,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,0,159,0,0,97,61,0,0,0,0,3,1,4,59,0,0,0,64,1,0,4,61],[0,0,0,66,2,16,0,57,0,0,0,10,4,0,0,41,0,0,0,0,0,66,4,53,0,0,0,32,2,16,0,57],[0,0,7,189,4,0,0,65,0,0,0,0,0,66,4,53,0,0,0,34,4,16,0,57,0,0,0,0,0,52,4,53],[0,0,0,66,3,0,0,57,0,0,0,0,0,49,4,53,0,0,7,190,3,16,0,156,0,0,1,89,0,0,33,61],[0,0,0,128,3,16,0,57,0,0,0,64,0,48,4,63,0,0,7,155,3,0,0,65,0,0,7,155,4,32,0,156],[0,0,0,0,2,3,128,25,0,0,0,64,2,32,2,16,0,0,0,0,1,1,4,51,0,0,7,155,4,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20],[0,0,7,155,4,32,0,156,0,0,0,0,2,3,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,10,254,0,0,1,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,7,181,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,31,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,7,161,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,7,155,2,0,0,65,0,0,7,155,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,64,1,16,2,16,0,0,7,182,1,16,1,199,0,0,30,106,0,1,4,48,0,0,0,56,8,64,0,140],[0,0,12,214,0,0,65,61,0,0,0,32,9,64,2,112,0,0,7,155,8,64,0,156,0,0,0,0,9,4,160,25],[0,0,7,155,8,64,0,156,0,0,0,0,10,0,0,25,0,0,0,4,10,0,32,57,0,0,0,2,8,160,1,191],[0,0,255,255,11,144,0,140,0,0,0,0,8,10,160,25,0,0,0,16,10,144,2,112,0,0,0,0,10,9,160,25],[0,0,0,255,9,160,0,140,0,0,0,0,9,0,0,25,0,0,0,1,9,0,32,57,0,0,7,166,10,112,0,156],[0,0,1,89,0,0,33,61,0,0,0,0,8,152,1,159,0,0,0,64,9,112,0,57,0,0,0,64,0,144,4,63],[0,0,0,0,10,33,3,79,0,0,0,2,9,128,0,58,0,0,0,0,9,151,4,54,0,0,0,0,10,160,3,80],[0,0,0,0,10,10,4,59,0,0,0,0,0,169,4,53,0,0,1,193,0,0,97,61,0,0,7,167,10,160,1,151],[0,0,0,248,11,128,2,16,0,0,0,0,10,171,1,159,0,0,7,171,10,160,1,199,0,0,0,0,0,169,4,53],[0,0,0,3,8,128,2,16,0,0,0,248,8,128,1,95,0,0,0,0,8,132,1,207,0,0,0,33,9,112,0,57],[0,0,0,0,0,137,4,53,0,0,0,0,8,7,0,25,0,0,12,231,0,0,1,61,0,0,0,31,3,64,1,143],[0,0,0,5,2,64,2,114,0,0,12,158,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16],[0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57],[0,0,0,0,6,37,0,75,0,0,12,151,0,0,65,61,0,0,0,0,5,3,0,75,0,0,12,172,0,0,97,61],[0,0,0,3,3,48,2,16,0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51,0,0,0,0,5,53,1,207],[0,0,0,0,5,53,2,47,0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,0,1,0,3,48,0,137],[0,0,0,0,1,49,2,47,0,0,0,0,1,49,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53],[0,0,0,96,1,64,2,16,0,0,30,106,0,1,4,48,0,0,0,56,8,64,0,140,0,0,13,118,0,0,65,61],[0,0,0,32,9,64,2,112,0,0,7,155,8,64,0,156,0,0,0,0,9,4,160,25,0,0,7,155,8,64,0,156],[0,0,0,0,10,0,0,25,0,0,0,4,10,0,32,57,0,0,0,2,8,160,1,191,0,0,255,255,11,144,0,140],[0,0,0,0,8,10,160,25,0,0,0,16,10,144,2,112,0,0,0,0,10,9,160,25,0,0,0,255,9,160,0,140],[0,0,0,0,9,0,0,25,0,0,0,1,9,0,32,57,0,0,7,166,10,96,0,156,0,0,1,89,0,0,33,61],[0,0,0,0,8,152,1,159,0,0,0,64,9,96,0,57,0,0,0,64,0,144,4,63,0,0,0,0,10,33,3,79],[0,0,0,2,9,128,0,58,0,0,0,0,9,150,4,54,0,0,0,0,10,160,3,80,0,0,0,0,10,10,4,59],[0,0,0,0,0,169,4,53,0,0,1,193,0,0,97,61,0,0,7,167,10,160,1,151,0,0,0,248,11,128,2,16],[0,0,0,0,10,171,1,159,0,0,7,171,10,160,1,199,0,0,0,0,0,169,4,53,0,0,0,3,8,128,2,16],[0,0,0,248,8,128,1,95,0,0,0,0,8,132,1,207,0,0,0,33,9,96,0,57,0,0,0,0,0,137,4,53],[0,0,0,0,8,6,0,25,0,0,13,135,0,0,1,61,0,0,7,166,8,112,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,8,112,0,57,0,0,0,64,0,128,4,63,0,0,0,0,9,33,3,79,0,0,0,1,8,0,0,58],[0,0,0,0,8,135,4,54,0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59,0,0,0,0,0,152,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,10,64,2,16,0,0,7,167,9,144,1,151,0,0,0,0,9,169,1,159],[0,0,7,160,9,144,1,103,0,0,0,0,0,152,4,53,0,0,0,0,8,7,0,25,0,0,0,64,7,0,4,61],[0,0,7,166,9,112,0,156,0,0,1,89,0,0,33,61,0,0,0,64,9,112,0,57,0,0,0,64,0,144,4,63],[0,0,0,0,2,33,3,79,0,0,0,1,12,0,0,58,0,0,0,0,9,199,4,54,0,0,0,0,2,32,3,80],[0,0,0,0,11,2,4,59,0,0,0,0,0,185,4,53,0,0,1,193,0,0,97,61,0,0,7,167,2,176,1,151],[0,0,7,172,10,32,1,199,0,0,0,0,0,169,4,53,0,0,0,0,9,6,4,51,0,0,0,0,9,73,0,25],[0,0,0,0,10,8,4,51,0,0,0,0,9,169,0,25,0,0,0,0,10,7,4,51,0,0,0,0,9,169,0,25],[0,0,0,64,10,0,4,61,0,0,7,159,9,144,1,151,0,0,0,56,13,144,0,140,0,0,14,30,0,0,65,61],[0,0,0,32,13,144,2,112,0,0,7,155,12,144,0,156,0,0,0,0,13,9,160,25,0,0,7,155,12,144,0,156],[0,0,0,0,14,0,0,25,0,0,0,4,14,0,32,57,0,0,0,2,12,224,1,191,0,0,255,255,15,208,0,140],[0,0,0,0,12,14,160,25,0,0,0,16,14,208,2,112,0,0,0,0,14,13,160,25,0,0,0,255,13,224,0,140],[0,0,0,0,13,0,0,25,0,0,0,1,13,0,32,57,0,0,7,166,14,160,0,156,0,0,1,89,0,0,33,61],[0,0,0,0,12,220,1,159,0,0,0,64,13,160,0,57,0,0,0,64,0,208,4,63,0,0,0,32,13,160,0,57],[0,0,0,0,0,189,4,53,0,0,0,2,11,192,0,58,0,0,0,0,0,186,4,53,0,0,1,193,0,0,97,61],[0,0,0,248,11,192,2,16,0,0,0,0,2,43,1,159,0,0,7,173,2,32,1,199,0,0,0,0,0,45,4,53],[0,0,0,3,2,192,2,16,0,0,0,248,2,32,1,95,0,0,0,0,2,41,1,207,0,0,0,33,9,160,0,57],[0,0,0,0,0,41,4,53,0,0,14,43,0,0,1,61,0,0,0,0,3,1,0,75,0,0,13,194,0,0,193,61],[0,0,0,64,1,0,4,61,0,10,0,0,0,1,0,29,0,0,0,12,1,0,0,41,0,0,1,0,4,16,0,57],[0,0,0,0,1,66,3,79,0,0,0,0,3,1,4,59,0,0,0,128,1,48,0,140,0,0,14,144,0,0,65,61],[0,0,0,128,1,48,2,112,0,0,7,168,5,48,0,156,0,0,0,0,1,3,160,25,0,0,7,168,5,48,0,156],[0,0,0,0,5,0,0,25,0,0,0,16,5,0,32,57,0,0,0,8,6,80,1,191,0,0,7,159,7,16,0,156],[0,0,0,0,6,5,160,25,0,0,0,64,5,16,2,112,0,0,7,159,7,16,0,156,0,0,0,0,5,1,160,25],[0,0,0,4,1,96,1,191,0,0,7,155,7,80,0,156,0,0,0,0,1,6,160,25,0,0,0,32,6,80,2,112],[0,0,7,155,7,80,0,156,0,0,0,0,6,5,160,25,0,0,0,2,5,16,1,191,0,0,255,255,7,96,0,140],[0,0,0,0,5,1,160,25,0,0,0,16,1,96,2,112,0,0,0,0,1,6,160,25,0,0,0,255,1,16,0,140],[0,0,0,1,5,80,32,57,0,0,0,32,1,0,0,138,0,0,0,65,6,80,0,57,0,0,0,0,1,22,1,111],[0,0,0,10,1,16,0,41,0,0,0,10,6,16,0,108,0,0,0,0,6,0,0,25,0,0,0,1,6,0,64,57],[0,0,7,159,7,16,0,156,0,0,1,89,0,0,33,61,0,0,0,1,6,96,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,16,4,63,0,0,0,2,1,80,0,57,0,0,0,10,6,0,0,41,0,0,0,0,6,22,4,54],[0,0,0,0,1,0,0,49,0,0,0,33,7,80,0,57,0,0,0,5,7,112,2,114,0,0,13,98,0,0,97,61],[0,0,0,0,8,18,3,79,0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16,0,0,0,0,11,166,0,25],[0,0,0,0,10,168,3,79,0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57],[0,0,0,0,10,121,0,75,0,0,13,90,0,0,65,61,0,0,0,0,7,0,0,75,0,0,13,100,0,0,97,61],[0,0,0,10,7,0,0,41,0,0,0,0,7,7,4,51,0,0,0,0,7,7,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,7,6,4,51,0,0,7,167,7,112,1,151,0,0,0,248,8,80,2,16,0,0,0,0,7,120,1,159],[0,0,7,169,7,112,0,65,0,0,0,0,0,118,4,53,0,0,0,3,5,80,2,16,0,0,0,248,5,80,0,137],[0,0,0,0,3,83,1,207,0,0,0,255,5,80,0,140,0,0,0,0,3,0,32,25,0,0,0,10,5,0,0,41],[0,0,0,33,5,80,0,57,0,0,14,164,0,0,1,61,0,0,7,166,8,96,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,8,96,0,57,0,0,0,64,0,128,4,63,0,0,0,0,9,33,3,79,0,0,0,1,8,0,0,58],[0,0,0,0,8,134,4,54,0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59,0,0,0,0,0,152,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,10,64,2,16,0,0,7,167,9,144,1,151,0,0,0,0,9,169,1,159],[0,0,7,160,9,144,1,103,0,0,0,0,0,152,4,53,0,0,0,0,8,6,0,25,0,0,0,64,6,0,4,61],[0,0,7,166,9,96,0,156,0,0,1,89,0,0,33,61,0,0,0,64,9,96,0,57,0,0,0,64,0,144,4,63],[0,0,0,0,2,33,3,79,0,0,0,1,12,0,0,58,0,0,0,0,9,198,4,54,0,0,0,0,2,32,3,80],[0,0,0,0,11,2,4,59,0,0,0,0,0,185,4,53,0,0,1,193,0,0,97,61,0,0,7,167,2,176,1,151],[0,0,7,172,10,32,1,199,0,0,0,0,0,169,4,53,0,0,0,0,9,7,4,51,0,0,0,0,9,73,0,25],[0,0,0,0,10,8,4,51,0,0,0,0,9,169,0,25,0,0,0,0,10,6,4,51,0,0,0,0,9,169,0,25],[0,0,0,64,10,0,4,61,0,0,7,159,9,144,1,151,0,0,0,56,13,144,0,140,0,0,15,77,0,0,65,61],[0,0,0,32,13,144,2,112,0,0,7,155,12,144,0,156,0,0,0,0,13,9,160,25,0,0,7,155,12,144,0,156],[0,0,0,0,14,0,0,25,0,0,0,4,14,0,32,57,0,0,0,2,12,224,1,191,0,0,255,255,15,208,0,140],[0,0,0,0,12,14,160,25,0,0,0,16,14,208,2,112,0,0,0,0,14,13,160,25,0,0,0,255,13,224,0,140],[0,0,0,0,13,0,0,25,0,0,0,1,13,0,32,57,0,0,7,166,14,160,0,156,0,0,1,89,0,0,33,61],[0,0,0,0,12,220,1,159,0,0,0,64,13,160,0,57,0,0,0,64,0,208,4,63,0,0,0,32,13,160,0,57],[0,0,0,0,0,189,4,53,0,0,0,2,11,192,0,58,0,0,0,0,0,186,4,53,0,0,1,193,0,0,97,61],[0,0,0,248,11,192,2,16,0,0,0,0,2,43,1,159,0,0,7,173,2,32,1,199,0,0,0,0,0,45,4,53],[0,0,0,3,2,192,2,16,0,0,0,248,2,32,1,95,0,0,0,0,2,41,1,207,0,0,0,33,9,160,0,57],[0,0,0,0,0,41,4,53,0,0,15,90,0,0,1,61,0,0,0,2,2,16,0,140,0,0,14,241,0,0,193,61],[0,0,0,0,1,0,4,21,0,10,0,0,0,1,0,29,0,0,7,164,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,7,155,1,0,0,65,0,0,0,0,2,0,4,20,0,0,7,155,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,7,165,1,16,1,199,0,0,128,11,2,0,0,57,30,104,30,94,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,24,107,0,0,97,61,0,0,0,64,3,0,4,61,0,0,0,0,4,1,4,59],[0,0,0,128,1,64,0,140,0,0,15,208,0,0,65,61,0,0,0,128,1,64,2,112,0,0,7,168,2,64,0,156],[0,0,0,0,1,4,160,25,0,0,7,168,2,64,0,156,0,0,0,0,2,0,0,25,0,0,0,16,2,0,32,57],[0,0,0,8,5,32,1,191,0,0,7,159,6,16,0,156,0,0,0,0,5,2,160,25,0,0,0,64,2,16,2,112],[0,0,7,159,6,16,0,156,0,0,0,0,2,1,160,25,0,0,0,4,1,80,1,191,0,0,7,155,6,32,0,156],[0,0,0,0,1,5,160,25,0,0,0,32,6,32,2,112,0,0,7,155,5,32,0,156,0,0,0,0,6,2,160,25],[0,0,0,2,5,16,1,191,0,0,255,255,2,96,0,140,0,0,0,0,5,1,160,25,0,0,0,16,1,96,2,112],[0,0,0,0,1,6,160,25,0,0,0,255,1,16,0,140,0,0,0,1,5,80,32,57,0,0,0,32,1,0,0,138],[0,0,0,65,2,80,0,57,0,0,0,0,1,18,1,111,0,0,0,0,1,19,0,25,0,0,0,0,2,49,0,75],[0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,7,159,6,16,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,2,32,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,16,4,63,0,0,0,2,1,80,0,57],[0,0,0,0,6,19,4,54,0,0,0,1,1,0,3,103,0,0,0,0,2,0,0,49,0,0,0,33,7,80,0,57],[0,0,0,5,7,112,2,114,0,0,14,12,0,0,97,61,0,0,0,0,8,33,3,79,0,0,0,0,9,0,0,25],[0,0,0,5,10,144,2,16,0,0,0,0,11,166,0,25,0,0,0,0,10,168,3,79,0,0,0,0,10,10,4,59],[0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75,0,0,14,4,0,0,65,61],[0,0,0,0,7,0,0,75,0,0,14,14,0,0,97,61,0,0,0,0,7,3,4,51,0,0,0,0,7,7,0,75],[0,0,1,193,0,0,97,61,0,0,0,0,7,6,4,51,0,0,7,167,7,112,1,151,0,0,0,248,8,80,2,16],[0,0,0,0,7,120,1,159,0,0,7,169,7,112,0,65,0,0,0,0,0,118,4,53,0,0,0,3,5,80,2,16],[0,0,0,248,5,80,0,137,0,0,0,0,4,84,1,207,0,0,0,255,5,80,0,140,0,0,0,0,4,0,32,25],[0,0,0,33,5,48,0,57,0,0,15,227,0,0,1,61,0,0,7,166,13,160,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,13,160,0,57,0,0,0,64,0,208,4,63,0,0,0,32,13,160,0,57,0,0,0,0,0,189,4,53],[0,0,0,0,0,202,4,53,0,0,0,0,11,12,0,75,0,0,1,193,0,0,97,61,0,0,0,248,9,144,2,16],[0,0,0,0,2,41,1,159,0,0,7,172,2,32,0,65,0,0,0,0,0,45,4,53,0,0,0,64,2,0,4,61],[0,0,0,32,9,32,0,57,0,0,7,174,11,0,0,65,0,0,0,0,0,185,4,53,0,0,0,33,11,32,0,57],[0,0,0,0,12,10,4,51,0,0,0,0,13,12,0,75,0,0,14,59,0,0,97,61,0,0,0,0,13,0,0,25],[0,0,0,0,14,189,0,25,0,0,0,32,13,208,0,57,0,0,0,0,15,173,0,25,0,0,0,0,15,15,4,51],[0,0,0,0,0,254,4,53,0,0,0,0,14,205,0,75,0,0,14,52,0,0,65,61,0,0,0,0,10,188,0,25],[0,0,0,0,0,10,4,53,0,0,0,0,11,6,4,51,0,0,0,0,12,11,0,75,0,0,14,72,0,0,97,61],[0,0,0,0,12,0,0,25,0,0,0,0,13,172,0,25,0,0,0,32,12,192,0,57,0,0,0,0,14,108,0,25],[0,0,0,0,14,14,4,51,0,0,0,0,0,237,4,53,0,0,0,0,13,188,0,75,0,0,14,65,0,0,65,61],[0,0,0,0,6,171,0,25,0,0,0,0,0,6,4,53,0,0,0,0,10,8,4,51,0,0,0,0,11,10,0,75],[0,0,14,85,0,0,97,61,0,0,0,0,11,0,0,25,0,0,0,0,12,107,0,25,0,0,0,32,11,176,0,57],[0,0,0,0,13,139,0,25,0,0,0,0,13,13,4,51,0,0,0,0,0,220,4,53,0,0,0,0,12,171,0,75],[0,0,14,78,0,0,65,61,0,0,0,0,5,81,3,79,0,0,0,0,1,106,0,25,0,0,0,31,6,64,1,143],[0,0,0,0,0,1,4,53,0,0,0,5,8,64,2,114,0,0,14,100,0,0,97,61,0,0,0,0,10,0,0,25],[0,0,0,5,11,160,2,16,0,0,0,0,12,177,0,25,0,0,0,0,11,181,3,79,0,0,0,0,11,11,4,59],[0,0,0,0,0,188,4,53,0,0,0,1,10,160,0,57,0,0,0,0,11,138,0,75,0,0,14,92,0,0,65,61],[0,0,0,0,10,6,0,75,0,0,14,115,0,0,97,61,0,0,0,5,8,128,2,16,0,0,0,0,5,133,3,79],[0,0,0,0,8,129,0,25,0,0,0,3,6,96,2,16,0,0,0,0,10,8,4,51,0,0,0,0,10,106,1,207],[0,0,0,0,10,106,2,47,0,0,0,0,5,5,4,59,0,0,1,0,6,96,0,137,0,0,0,0,5,101,2,47],[0,0,0,0,5,101,1,207,0,0,0,0,5,165,1,159,0,0,0,0,0,88,4,53,0,0,0,0,1,65,0,25],[0,0,0,0,0,1,4,53,0,0,0,0,4,7,4,51,0,0,0,0,5,4,0,75,0,0,14,128,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,0,6,21,0,25,0,0,0,32,5,80,0,57,0,0,0,0,8,117,0,25],[0,0,0,0,8,8,4,51,0,0,0,0,0,134,4,53,0,0,0,0,6,69,0,75,0,0,14,121,0,0,65,61],[0,0,0,0,1,20,0,25,0,0,0,0,0,1,4,53,0,0,0,0,1,33,0,73,0,0,0,32,4,16,0,138],[0,0,0,0,0,66,4,53,0,0,0,31,1,16,0,57,0,0,0,0,3,49,1,111,0,0,0,0,1,35,0,25],[0,0,0,0,3,49,0,75,0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57,0,0,7,159,4,16,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,3,48,1,144,0,0,15,190,0,0,97,61,0,0,1,89,0,0,1,61],[0,0,0,10,1,0,0,41,0,0,7,166,1,16,0,156,0,0,1,89,0,0,33,61,0,0,0,10,5,0,0,41],[0,0,0,64,1,80,0,57,0,0,0,64,0,16,4,63,0,0,0,1,1,0,0,58,0,0,0,0,5,21,4,54],[0,0,0,0,1,0,0,49,0,0,0,0,6,18,3,79,0,0,0,0,6,96,3,80,0,0,0,0,6,6,4,59],[0,0,0,0,0,101,4,53,0,0,1,193,0,0,97,61,0,0,0,248,7,48,2,16,0,0,7,160,8,0,0,65],[0,0,0,0,3,3,0,75,0,0,0,0,8,7,192,25,0,0,7,167,3,96,1,151,0,0,0,0,3,131,1,159],[0,0,0,0,0,53,4,53,0,0,0,64,3,0,4,61,0,0,0,96,4,64,0,138,0,0,0,0,5,66,3,79],[0,0,0,0,5,5,4,59,0,0,0,128,6,80,0,140,0,0,16,49,0,0,65,61,0,0,0,128,6,80,2,112],[0,0,7,168,7,80,0,156,0,0,0,0,6,5,160,25,0,0,7,168,7,80,0,156,0,0,0,0,7,0,0,25],[0,0,0,16,7,0,32,57,0,0,0,8,8,112,1,191,0,0,7,159,9,96,0,156,0,0,0,0,8,7,160,25],[0,0,0,64,7,96,2,112,0,0,7,159,9,96,0,156,0,0,0,0,7,6,160,25,0,0,0,4,9,128,1,191],[0,0,7,155,6,112,0,156,0,0,0,0,9,8,160,25,0,0,0,32,8,112,2,112,0,0,7,155,6,112,0,156],[0,0,0,0,8,7,160,25,0,0,0,2,6,144,1,191,0,0,255,255,7,128,0,140,0,0,0,0,6,9,160,25],[0,0,0,16,7,128,2,112,0,0,0,0,7,8,160,25,0,0,0,255,7,112,0,140,0,0,0,1,6,96,32,57],[0,0,0,32,7,0,0,138,0,0,0,65,8,96,0,57,0,0,0,0,7,120,1,111,0,0,0,0,7,115,0,25],[0,0,0,0,8,55,0,75,0,0,0,0,8,0,0,25,0,0,0,1,8,0,64,57,0,0,7,159,9,112,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,8,128,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,112,4,63],[0,0,0,2,7,96,0,57,0,0,0,0,7,115,4,54,0,0,0,33,8,96,0,57,0,0,0,5,8,128,2,114],[0,0,14,223,0,0,97,61,0,0,0,0,9,18,3,79,0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16],[0,0,0,0,12,183,0,25,0,0,0,0,11,185,3,79,0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53],[0,0,0,1,10,160,0,57,0,0,0,0,11,138,0,75,0,0,14,215,0,0,65,61,0,0,0,0,8,0,0,75],[0,0,14,225,0,0,97,61,0,0,0,0,8,3,4,51,0,0,0,0,8,8,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,8,7,4,51,0,0,7,167,8,128,1,151,0,0,0,248,9,96,2,16,0,0,0,0,8,137,1,159],[0,0,7,169,8,128,0,65,0,0,0,0,0,135,4,53,0,0,0,3,6,96,2,16,0,0,0,248,6,96,0,137],[0,0,0,0,5,101,1,207,0,0,0,255,6,96,0,140,0,0,0,0,5,0,32,25,0,0,0,33,6,48,0,57],[0,0,16,66,0,0,1,61,0,0,0,1,1,16,0,140,0,0,15,201,0,0,193,61,0,0,0,0,1,0,4,21],[0,10,0,0,0,1,0,29,0,0,7,164,1,0,0,65,0,0,0,0,0,16,4,57,0,0,7,155,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,7,155,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,7,165,1,16,1,199,0,0,128,11,2,0,0,57,30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,24,107,0,0,97,61,0,0,0,64,3,0,4,61,0,0,0,0,4,1,4,59,0,0,0,128,1,64,0,140],[0,0,16,143,0,0,65,61,0,0,0,128,1,64,2,112,0,0,7,168,2,64,0,156,0,0,0,0,1,4,160,25],[0,0,7,168,2,64,0,156,0,0,0,0,2,0,0,25,0,0,0,16,2,0,32,57,0,0,0,8,5,32,1,191],[0,0,7,159,6,16,0,156,0,0,0,0,5,2,160,25,0,0,0,64,2,16,2,112,0,0,7,159,6,16,0,156],[0,0,0,0,2,1,160,25,0,0,0,4,1,80,1,191,0,0,7,155,6,32,0,156,0,0,0,0,1,5,160,25],[0,0,0,32,6,32,2,112,0,0,7,155,5,32,0,156,0,0,0,0,6,2,160,25,0,0,0,2,5,16,1,191],[0,0,255,255,2,96,0,140,0,0,0,0,5,1,160,25,0,0,0,16,1,96,2,112,0,0,0,0,1,6,160,25],[0,0,0,255,1,16,0,140,0,0,0,1,5,80,32,57,0,0,0,32,1,0,0,138,0,0,0,65,2,80,0,57],[0,0,0,0,1,18,1,111,0,0,0,0,1,19,0,25,0,0,0,0,2,49,0,75,0,0,0,0,2,0,0,25],[0,0,0,1,2,0,64,57,0,0,7,159,6,16,0,156,0,0,1,89,0,0,33,61,0,0,0,1,2,32,1,144],[0,0,1,89,0,0,193,61,0,0,0,64,0,16,4,63,0,0,0,2,1,80,0,57,0,0,0,0,6,19,4,54],[0,0,0,1,1,0,3,103,0,0,0,0,2,0,0,49,0,0,0,33,7,80,0,57,0,0,0,5,7,112,2,114],[0,0,15,59,0,0,97,61,0,0,0,0,8,33,3,79,0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16],[0,0,0,0,11,166,0,25,0,0,0,0,10,168,3,79,0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53],[0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75,0,0,15,51,0,0,65,61,0,0,0,0,7,0,0,75],[0,0,15,61,0,0,97,61,0,0,0,0,7,3,4,51,0,0,0,0,7,7,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,7,6,4,51,0,0,7,167,7,112,1,151,0,0,0,248,8,80,2,16,0,0,0,0,7,120,1,159],[0,0,7,169,7,112,0,65,0,0,0,0,0,118,4,53,0,0,0,3,5,80,2,16,0,0,0,248,5,80,0,137],[0,0,0,0,4,84,1,207,0,0,0,255,5,80,0,140,0,0,0,0,4,0,32,25,0,0,0,33,5,48,0,57],[0,0,16,162,0,0,1,61,0,0,7,166,13,160,0,156,0,0,1,89,0,0,33,61,0,0,0,64,13,160,0,57],[0,0,0,64,0,208,4,63,0,0,0,32,13,160,0,57,0,0,0,0,0,189,4,53,0,0,0,0,0,202,4,53],[0,0,0,0,11,12,0,75,0,0,1,193,0,0,97,61,0,0,0,248,9,144,2,16,0,0,0,0,2,41,1,159],[0,0,7,172,2,32,0,65,0,0,0,0,0,45,4,53,0,0,0,64,2,0,4,61,0,0,0,32,9,32,0,57],[0,0,7,175,11,0,0,65,0,0,0,0,0,185,4,53,0,0,0,33,11,32,0,57,0,0,0,0,12,10,4,51],[0,0,0,0,13,12,0,75,0,0,15,106,0,0,97,61,0,0,0,0,13,0,0,25,0,0,0,0,14,189,0,25],[0,0,0,32,13,208,0,57,0,0,0,0,15,173,0,25,0,0,0,0,15,15,4,51,0,0,0,0,0,254,4,53],[0,0,0,0,14,205,0,75,0,0,15,99,0,0,65,61,0,0,0,0,10,188,0,25,0,0,0,0,0,10,4,53],[0,0,0,0,11,7,4,51,0,0,0,0,12,11,0,75,0,0,15,119,0,0,97,61,0,0,0,0,12,0,0,25],[0,0,0,0,13,172,0,25,0,0,0,32,12,192,0,57,0,0,0,0,14,124,0,25,0,0,0,0,14,14,4,51],[0,0,0,0,0,237,4,53,0,0,0,0,13,188,0,75,0,0,15,112,0,0,65,61,0,0,0,0,7,171,0,25],[0,0,0,0,0,7,4,53,0,0,0,0,10,8,4,51,0,0,0,0,11,10,0,75,0,0,15,132,0,0,97,61],[0,0,0,0,11,0,0,25,0,0,0,0,12,123,0,25,0,0,0,32,11,176,0,57,0,0,0,0,13,139,0,25],[0,0,0,0,13,13,4,51,0,0,0,0,0,220,4,53,0,0,0,0,12,171,0,75,0,0,15,125,0,0,65,61],[0,0,0,0,5,81,3,79,0,0,0,0,1,122,0,25,0,0,0,31,7,64,1,143,0,0,0,0,0,1,4,53],[0,0,0,5,8,64,2,114,0,0,15,147,0,0,97,61,0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16],[0,0,0,0,12,177,0,25,0,0,0,0,11,181,3,79,0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53],[0,0,0,1,10,160,0,57,0,0,0,0,11,138,0,75,0,0,15,139,0,0,65,61,0,0,0,0,10,7,0,75],[0,0,15,162,0,0,97,61,0,0,0,5,8,128,2,16,0,0,0,0,5,133,3,79,0,0,0,0,8,129,0,25],[0,0,0,3,7,112,2,16,0,0,0,0,10,8,4,51,0,0,0,0,10,122,1,207,0,0,0,0,10,122,2,47],[0,0,0,0,5,5,4,59,0,0,1,0,7,112,0,137,0,0,0,0,5,117,2,47,0,0,0,0,5,117,1,207],[0,0,0,0,5,165,1,159,0,0,0,0,0,88,4,53,0,0,0,0,1,65,0,25,0,0,0,0,0,1,4,53],[0,0,0,0,4,6,4,51,0,0,0,0,5,4,0,75,0,0,15,175,0,0,97,61,0,0,0,0,5,0,0,25],[0,0,0,0,7,21,0,25,0,0,0,32,5,80,0,57,0,0,0,0,8,101,0,25,0,0,0,0,8,8,4,51],[0,0,0,0,0,135,4,53,0,0,0,0,7,69,0,75,0,0,15,168,0,0,65,61,0,0,0,0,1,20,0,25],[0,0,0,0,0,1,4,53,0,0,0,0,1,33,0,73,0,0,0,32,4,16,0,138,0,0,0,0,0,66,4,53],[0,0,0,31,1,16,0,57,0,0,0,0,3,49,1,111,0,0,0,0,1,35,0,25,0,0,0,0,3,49,0,75],[0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57,0,0,7,159,4,16,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,3,48,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,16,4,63,0,0,7,155,1,0,0,65],[0,0,7,155,3,144,0,156,0,0,0,0,9,1,128,25,0,0,0,64,3,144,2,16,0,0,0,0,2,2,4,51],[0,0,7,155,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,96,2,32,2,16,0,0,0,0,2,50,1,159],[0,0,10,249,0,0,1,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,7,193,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,19,3,0,0,57,0,0,12,95,0,0,1,61],[0,0,7,166,1,48,0,156,0,0,1,89,0,0,33,61,0,0,0,64,1,48,0,57,0,0,0,64,0,16,4,63],[0,0,0,1,1,0,0,58,0,0,0,0,5,19,4,54,0,0,0,0,2,0,0,49,0,0,0,1,1,0,3,103],[0,0,0,0,6,33,3,79,0,0,0,0,6,96,3,80,0,0,0,0,6,6,4,59,0,0,0,0,0,101,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,7,64,2,16,0,0,7,160,8,0,0,65,0,0,0,0,4,4,0,75],[0,0,0,0,8,7,192,25,0,0,7,167,4,96,1,151,0,0,0,0,4,132,1,159,0,0,0,0,0,69,4,53],[0,0,0,64,5,0,4,61,0,0,0,13,4,0,0,41,0,0,1,4,4,64,0,57,0,0,0,0,6,65,3,79],[0,0,0,0,6,6,4,59,0,0,0,128,7,96,0,140,0,0,16,240,0,0,65,61,0,0,0,128,7,96,2,112],[0,0,7,168,8,96,0,156,0,0,0,0,7,6,160,25,0,0,7,168,8,96,0,156,0,0,0,0,8,0,0,25],[0,0,0,16,8,0,32,57,0,0,0,8,9,128,1,191,0,0,7,159,10,112,0,156,0,0,0,0,9,8,160,25],[0,0,0,64,8,112,2,112,0,0,7,159,10,112,0,156,0,0,0,0,8,7,160,25,0,0,0,4,10,144,1,191],[0,0,7,155,7,128,0,156,0,0,0,0,10,9,160,25,0,0,0,32,9,128,2,112,0,0,7,155,7,128,0,156],[0,0,0,0,9,8,160,25,0,0,0,2,7,160,1,191,0,0,255,255,8,144,0,140,0,0,0,0,7,10,160,25],[0,0,0,16,8,144,2,112,0,0,0,0,8,9,160,25,0,0,0,255,8,128,0,140,0,0,0,1,7,112,32,57],[0,0,0,32,8,0,0,138,0,0,0,65,9,112,0,57,0,0,0,0,8,137,1,111,0,0,0,0,8,133,0,25],[0,0,0,0,9,88,0,75,0,0,0,0,9,0,0,25,0,0,0,1,9,0,64,57,0,0,7,159,10,128,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,9,144,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,128,4,63],[0,0,0,2,8,112,0,57,0,0,0,0,8,133,4,54,0,0,0,33,9,112,0,57,0,0,0,5,9,144,2,114],[0,0,16,31,0,0,97,61,0,0,0,0,10,33,3,79,0,0,0,0,11,0,0,25,0,0,0,5,12,176,2,16],[0,0,0,0,13,200,0,25,0,0,0,0,12,202,3,79,0,0,0,0,12,12,4,59,0,0,0,0,0,205,4,53],[0,0,0,1,11,176,0,57,0,0,0,0,12,155,0,75,0,0,16,23,0,0,65,61,0,0,0,0,9,0,0,75],[0,0,16,33,0,0,97,61,0,0,0,0,9,5,4,51,0,0,0,0,9,9,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,9,8,4,51,0,0,7,167,9,144,1,151,0,0,0,248,10,112,2,16,0,0,0,0,9,154,1,159],[0,0,7,169,9,144,0,65,0,0,0,0,0,152,4,53,0,0,0,3,7,112,2,16,0,0,0,248,7,112,0,137],[0,0,0,0,6,118,1,207,0,0,0,255,7,112,0,140,0,0,0,0,6,0,32,25,0,0,0,33,7,80,0,57],[0,0,17,1,0,0,1,61,0,0,7,166,6,48,0,156,0,0,1,89,0,0,33,61,0,0,0,64,6,48,0,57],[0,0,0,64,0,96,4,63,0,0,0,0,7,18,3,79,0,0,0,1,6,0,0,58,0,0,0,0,6,99,4,54],[0,0,0,0,7,112,3,80,0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,1,193,0,0,97,61],[0,0,0,248,8,80,2,16,0,0,7,160,9,0,0,65,0,0,0,0,5,5,0,75,0,0,0,0,9,8,192,25],[0,0,7,167,5,112,1,151,0,0,0,0,5,149,1,159,0,0,0,0,0,86,4,53,0,0,0,64,4,64,0,138],[0,0,0,0,5,66,3,79,0,0,0,64,4,0,4,61,0,0,0,0,5,5,4,59,0,0,0,128,6,80,0,140],[0,0,17,78,0,0,65,61,0,0,0,128,6,80,2,112,0,0,7,168,7,80,0,156,0,0,0,0,6,5,160,25],[0,0,7,168,7,80,0,156,0,0,0,0,7,0,0,25,0,0,0,16,7,0,32,57,0,0,0,8,8,112,1,191],[0,0,7,159,9,96,0,156,0,0,0,0,8,7,160,25,0,0,0,64,7,96,2,112,0,0,7,159,9,96,0,156],[0,0,0,0,7,6,160,25,0,0,0,4,9,128,1,191,0,0,7,155,6,112,0,156,0,0,0,0,9,8,160,25],[0,0,0,32,8,112,2,112,0,0,7,155,6,112,0,156,0,0,0,0,8,7,160,25,0,0,0,2,6,144,1,191],[0,0,255,255,7,128,0,140,0,0,0,0,6,9,160,25,0,0,0,16,7,128,2,112,0,0,0,0,7,8,160,25],[0,0,0,255,7,112,0,140,0,0,0,1,6,96,32,57,0,0,0,32,7,0,0,138,0,0,0,65,8,96,0,57],[0,0,0,0,7,120,1,111,0,0,0,0,7,116,0,25,0,0,0,0,8,71,0,75,0,0,0,0,8,0,0,25],[0,0,0,1,8,0,64,57,0,0,7,159,9,112,0,156,0,0,1,89,0,0,33,61,0,0,0,1,8,128,1,144],[0,0,1,89,0,0,193,61,0,0,0,64,0,112,4,63,0,0,0,2,7,96,0,57,0,0,0,0,7,116,4,54],[0,0,0,33,8,96,0,57,0,0,0,5,8,128,2,114,0,0,16,125,0,0,97,61,0,0,0,0,9,18,3,79],[0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16,0,0,0,0,12,183,0,25,0,0,0,0,11,185,3,79],[0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53,0,0,0,1,10,160,0,57,0,0,0,0,11,138,0,75],[0,0,16,117,0,0,65,61,0,0,0,0,8,0,0,75,0,0,16,127,0,0,97,61,0,0,0,0,8,4,4,51],[0,0,0,0,8,8,0,75,0,0,1,193,0,0,97,61,0,0,0,0,8,7,4,51,0,0,7,167,8,128,1,151],[0,0,0,248,9,96,2,16,0,0,0,0,8,137,1,159,0,0,7,169,8,128,0,65,0,0,0,0,0,135,4,53],[0,0,0,3,6,96,2,16,0,0,0,248,6,96,0,137,0,0,0,0,5,101,1,207,0,0,0,255,6,96,0,140],[0,0,0,0,5,0,32,25,0,0,0,33,6,64,0,57,0,0,17,95,0,0,1,61,0,0,7,166,1,48,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,1,48,0,57,0,0,0,64,0,16,4,63,0,0,0,1,1,0,0,58],[0,0,0,0,5,19,4,54,0,0,0,0,2,0,0,49,0,0,0,1,1,0,3,103,0,0,0,0,6,33,3,79],[0,0,0,0,6,96,3,80,0,0,0,0,6,6,4,59,0,0,0,0,0,101,4,53,0,0,1,193,0,0,97,61],[0,0,0,248,7,64,2,16,0,0,7,160,8,0,0,65,0,0,0,0,4,4,0,75,0,0,0,0,8,7,192,25],[0,0,7,167,4,96,1,151,0,0,0,0,4,132,1,159,0,0,0,0,0,69,4,53,0,0,0,64,5,0,4,61],[0,0,0,13,4,0,0,41,0,0,1,4,4,64,0,57,0,0,0,0,6,65,3,79,0,0,0,0,6,6,4,59],[0,0,0,128,7,96,0,140,0,0,17,239,0,0,65,61,0,0,0,128,7,96,2,112,0,0,7,168,8,96,0,156],[0,0,0,0,7,6,160,25,0,0,7,168,8,96,0,156,0,0,0,0,8,0,0,25,0,0,0,16,8,0,32,57],[0,0,0,8,9,128,1,191,0,0,7,159,10,112,0,156,0,0,0,0,9,8,160,25,0,0,0,64,8,112,2,112],[0,0,7,159,10,112,0,156,0,0,0,0,8,7,160,25,0,0,0,4,10,144,1,191,0,0,7,155,7,128,0,156],[0,0,0,0,10,9,160,25,0,0,0,32,9,128,2,112,0,0,7,155,7,128,0,156,0,0,0,0,9,8,160,25],[0,0,0,2,7,160,1,191,0,0,255,255,8,144,0,140,0,0,0,0,7,10,160,25,0,0,0,16,8,144,2,112],[0,0,0,0,8,9,160,25,0,0,0,255,8,128,0,140,0,0,0,1,7,112,32,57,0,0,0,32,8,0,0,138],[0,0,0,65,9,112,0,57,0,0,0,0,8,137,1,111,0,0,0,0,8,133,0,25,0,0,0,0,9,88,0,75],[0,0,0,0,9,0,0,25,0,0,0,1,9,0,64,57,0,0,7,159,10,128,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,9,144,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,128,4,63,0,0,0,2,8,112,0,57],[0,0,0,0,8,133,4,54,0,0,0,33,9,112,0,57,0,0,0,5,9,144,2,114,0,0,16,222,0,0,97,61],[0,0,0,0,10,33,3,79,0,0,0,0,11,0,0,25,0,0,0,5,12,176,2,16,0,0,0,0,13,200,0,25],[0,0,0,0,12,202,3,79,0,0,0,0,12,12,4,59,0,0,0,0,0,205,4,53,0,0,0,1,11,176,0,57],[0,0,0,0,12,155,0,75,0,0,16,214,0,0,65,61,0,0,0,0,9,0,0,75,0,0,16,224,0,0,97,61],[0,0,0,0,9,5,4,51,0,0,0,0,9,9,0,75,0,0,1,193,0,0,97,61,0,0,0,0,9,8,4,51],[0,0,7,167,9,144,1,151,0,0,0,248,10,112,2,16,0,0,0,0,9,154,1,159,0,0,7,169,9,144,0,65],[0,0,0,0,0,152,4,53,0,0,0,3,7,112,2,16,0,0,0,248,7,112,0,137,0,0,0,0,6,118,1,207],[0,0,0,255,7,112,0,140,0,0,0,0,6,0,32,25,0,0,0,33,7,80,0,57,0,0,18,0,0,0,1,61],[0,0,7,166,7,80,0,156,0,0,1,89,0,0,33,61,0,0,0,64,7,80,0,57,0,0,0,64,0,112,4,63],[0,0,0,0,8,33,3,79,0,0,0,1,7,0,0,58,0,0,0,0,7,117,4,54,0,0,0,0,8,128,3,80],[0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,1,193,0,0,97,61,0,0,0,248,9,96,2,16],[0,0,7,160,10,0,0,65,0,0,0,0,6,6,0,75,0,0,0,0,10,9,192,25,0,0,7,167,6,128,1,151],[0,0,0,0,6,166,1,159,0,0,0,0,0,103,4,53,0,0,0,64,6,0,4,61,0,0,0,64,4,64,0,138],[0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59,0,0,0,128,8,112,0,140,0,0,18,77,0,0,65,61],[0,0,0,128,8,112,2,112,0,0,7,168,9,112,0,156,0,0,0,0,8,7,160,25,0,0,7,168,9,112,0,156],[0,0,0,0,9,0,0,25,0,0,0,16,9,0,32,57,0,0,0,8,10,144,1,191,0,0,7,159,11,128,0,156],[0,0,0,0,10,9,160,25,0,0,0,64,9,128,2,112,0,0,7,159,11,128,0,156,0,0,0,0,9,8,160,25],[0,0,0,4,11,160,1,191,0,0,7,155,8,144,0,156,0,0,0,0,11,10,160,25,0,0,0,32,10,144,2,112],[0,0,7,155,8,144,0,156,0,0,0,0,10,9,160,25,0,0,0,2,8,176,1,191,0,0,255,255,9,160,0,140],[0,0,0,0,8,11,160,25,0,0,0,16,9,160,2,112,0,0,0,0,9,10,160,25,0,0,0,255,9,144,0,140],[0,0,0,1,8,128,32,57,0,0,0,32,9,0,0,138,0,0,0,65,10,128,0,57,0,0,0,0,9,154,1,111],[0,0,0,0,9,150,0,25,0,0,0,0,10,105,0,75,0,0,0,0,10,0,0,25,0,0,0,1,10,0,64,57],[0,0,7,159,11,144,0,156,0,0,1,89,0,0,33,61,0,0,0,1,10,160,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,144,4,63,0,0,0,2,9,128,0,57,0,0,0,0,9,150,4,54,0,0,0,33,10,128,0,57],[0,0,0,5,10,160,2,114,0,0,17,60,0,0,97,61,0,0,0,0,11,33,3,79,0,0,0,0,12,0,0,25],[0,0,0,5,13,192,2,16,0,0,0,0,14,217,0,25,0,0,0,0,13,219,3,79,0,0,0,0,13,13,4,59],[0,0,0,0,0,222,4,53,0,0,0,1,12,192,0,57,0,0,0,0,13,172,0,75,0,0,17,52,0,0,65,61],[0,0,0,0,10,0,0,75,0,0,17,62,0,0,97,61,0,0,0,0,10,6,4,51,0,0,0,0,10,10,0,75],[0,0,1,193,0,0,97,61,0,0,0,0,10,9,4,51,0,0,7,167,10,160,1,151,0,0,0,248,11,128,2,16],[0,0,0,0,10,171,1,159,0,0,7,169,10,160,0,65,0,0,0,0,0,169,4,53,0,0,0,3,8,128,2,16],[0,0,0,248,8,128,0,137,0,0,0,0,7,135,1,207,0,0,0,255,8,128,0,140,0,0,0,0,7,0,32,25],[0,0,0,33,8,96,0,57,0,0,18,94,0,0,1,61,0,0,7,166,6,64,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,6,64,0,57,0,0,0,64,0,96,4,63,0,0,0,0,7,18,3,79,0,0,0,1,6,0,0,58],[0,0,0,0,6,100,4,54,0,0,0,0,7,112,3,80,0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,8,80,2,16,0,0,7,160,9,0,0,65,0,0,0,0,5,5,0,75],[0,0,0,0,9,8,192,25,0,0,7,167,5,112,1,151,0,0,0,0,5,149,1,159,0,0,0,0,0,86,4,53],[0,0,0,64,5,0,4,61,0,9,0,0,0,5,0,29,0,0,0,32,5,80,0,57,0,0,0,0,6,3,4,51],[0,0,0,0,7,6,0,75,0,0,17,110,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,0,8,87,0,25],[0,0,0,32,7,112,0,57,0,0,0,0,9,55,0,25,0,0,0,0,9,9,4,51,0,0,0,0,0,152,4,53],[0,0,0,0,8,103,0,75,0,0,17,103,0,0,65,61,0,0,0,0,3,86,0,25,0,0,0,0,0,3,4,53],[0,0,0,0,5,4,4,51,0,0,0,0,6,5,0,75,0,0,17,123,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,0,7,54,0,25,0,0,0,32,6,96,0,57,0,0,0,0,8,70,0,25,0,0,0,0,8,8,4,51],[0,0,0,0,0,135,4,53,0,0,0,0,7,86,0,75,0,0,17,116,0,0,65,61,0,0,0,0,3,53,0,25],[0,0,0,0,0,3,4,53,0,0,0,9,5,0,0,41,0,0,0,0,3,83,0,73,0,0,0,32,4,48,0,138],[0,0,0,0,0,69,4,53,0,0,0,31,3,48,0,57,0,7,0,32,0,0,0,146,0,0,0,7,3,48,1,127],[0,0,0,0,4,83,0,25,0,0,0,0,3,52,0,75,0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57],[0,8,0,0,0,4,0,29,0,0,7,159,4,64,0,156,0,0,1,89,0,0,33,61,0,0,0,1,3,48,1,144],[0,0,1,89,0,0,193,61,0,0,0,8,3,0,0,41,0,0,0,64,0,48,4,63,0,0,7,166,3,48,0,156],[0,0,1,89,0,0,33,61,0,0,0,13,6,0,0,41,0,0,0,68,3,96,0,57,0,0,0,0,3,50,3,79],[0,0,0,0,3,3,4,59,0,0,0,8,7,0,0,41,0,0,0,64,4,112,0,57,0,0,0,64,0,64,4,63],[0,0,0,32,4,112,0,57,0,0,7,170,5,0,0,65,0,0,0,0,0,84,4,53,0,0,0,21,4,0,0,57],[0,0,0,0,0,71,4,53,0,0,0,96,3,48,2,16,0,0,0,33,4,112,0,57,0,0,0,0,0,52,4,53],[0,0,1,36,3,96,0,57,0,0,0,0,4,50,3,79,0,0,0,64,5,0,4,61,0,6,0,0,0,5,0,29],[0,0,0,0,4,4,4,59,0,0,0,128,5,64,0,140,0,0,19,9,0,0,65,61,0,0,0,128,5,64,2,112],[0,0,7,168,6,64,0,156,0,0,0,0,5,4,160,25,0,0,7,168,6,64,0,156,0,0,0,0,6,0,0,25],[0,0,0,16,6,0,32,57,0,0,0,8,7,96,1,191,0,0,7,159,8,80,0,156,0,0,0,0,7,6,160,25],[0,0,0,64,6,80,2,112,0,0,7,159,8,80,0,156,0,0,0,0,6,5,160,25,0,0,0,4,8,112,1,191],[0,0,7,155,5,96,0,156,0,0,0,0,8,7,160,25,0,0,0,32,7,96,2,112,0,0,7,155,5,96,0,156],[0,0,0,0,7,6,160,25,0,0,0,2,5,128,1,191,0,0,255,255,6,112,0,140,0,0,0,0,5,8,160,25],[0,0,0,16,6,112,2,112,0,0,0,0,6,7,160,25,0,0,0,255,6,96,0,140,0,0,0,1,5,80,32,57],[0,0,0,65,6,80,0,57,0,0,0,7,6,96,1,127,0,0,0,6,6,96,0,41,0,0,0,6,7,96,0,108],[0,0,0,0,7,0,0,25,0,0,0,1,7,0,64,57,0,0,7,159,8,96,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,7,112,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,96,4,63,0,0,0,2,6,80,0,57],[0,0,0,6,7,0,0,41,0,0,0,0,6,103,4,54,0,0,0,33,7,80,0,57,0,0,0,5,7,112,2,114],[0,0,17,219,0,0,97,61,0,0,0,0,8,18,3,79,0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16],[0,0,0,0,11,166,0,25,0,0,0,0,10,168,3,79,0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53],[0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75,0,0,17,211,0,0,65,61,0,0,0,0,7,0,0,75],[0,0,17,221,0,0,97,61,0,0,0,6,7,0,0,41,0,0,0,0,7,7,4,51,0,0,0,0,7,7,0,75],[0,0,1,193,0,0,97,61,0,0,0,0,7,6,4,51,0,0,7,167,7,112,1,151,0,0,0,248,8,80,2,16],[0,0,0,0,7,120,1,159,0,0,7,169,7,112,0,65,0,0,0,0,0,118,4,53,0,0,0,3,5,80,2,16],[0,0,0,248,5,80,0,137,0,0,0,0,4,84,1,207,0,0,0,255,5,80,0,140,0,0,0,0,4,0,32,25],[0,0,0,6,5,0,0,41,0,0,0,33,5,80,0,57,0,0,19,28,0,0,1,61,0,0,7,166,7,80,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,7,80,0,57,0,0,0,64,0,112,4,63,0,0,0,0,8,33,3,79],[0,0,0,1,7,0,0,58,0,0,0,0,7,117,4,54,0,0,0,0,8,128,3,80,0,0,0,0,8,8,4,59],[0,0,0,0,0,135,4,53,0,0,1,193,0,0,97,61,0,0,0,248,9,96,2,16,0,0,7,160,10,0,0,65],[0,0,0,0,6,6,0,75,0,0,0,0,10,9,192,25,0,0,7,167,6,128,1,151,0,0,0,0,6,166,1,159],[0,0,0,0,0,103,4,53,0,0,0,64,6,0,4,61,0,0,0,96,4,64,0,138,0,0,0,0,7,65,3,79],[0,0,0,0,7,7,4,59,0,0,0,128,8,112,0,140,0,0,18,171,0,0,65,61,0,0,0,128,8,112,2,112],[0,0,7,168,9,112,0,156,0,0,0,0,8,7,160,25,0,0,7,168,9,112,0,156,0,0,0,0,9,0,0,25],[0,0,0,16,9,0,32,57,0,0,0,8,10,144,1,191,0,0,7,159,11,128,0,156,0,0,0,0,10,9,160,25],[0,0,0,64,9,128,2,112,0,0,7,159,11,128,0,156,0,0,0,0,9,8,160,25,0,0,0,4,11,160,1,191],[0,0,7,155,8,144,0,156,0,0,0,0,11,10,160,25,0,0,0,32,10,144,2,112,0,0,7,155,8,144,0,156],[0,0,0,0,10,9,160,25,0,0,0,2,8,176,1,191,0,0,255,255,9,160,0,140,0,0,0,0,8,11,160,25],[0,0,0,16,9,160,2,112,0,0,0,0,9,10,160,25,0,0,0,255,9,144,0,140,0,0,0,1,8,128,32,57],[0,0,0,32,9,0,0,138,0,0,0,65,10,128,0,57,0,0,0,0,9,154,1,111,0,0,0,0,9,150,0,25],[0,0,0,0,10,105,0,75,0,0,0,0,10,0,0,25,0,0,0,1,10,0,64,57,0,0,7,159,11,144,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,10,160,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,144,4,63],[0,0,0,2,9,128,0,57,0,0,0,0,9,150,4,54,0,0,0,33,10,128,0,57,0,0,0,5,10,160,2,114],[0,0,18,59,0,0,97,61,0,0,0,0,11,33,3,79,0,0,0,0,12,0,0,25,0,0,0,5,13,192,2,16],[0,0,0,0,14,217,0,25,0,0,0,0,13,219,3,79,0,0,0,0,13,13,4,59,0,0,0,0,0,222,4,53],[0,0,0,1,12,192,0,57,0,0,0,0,13,172,0,75,0,0,18,51,0,0,65,61,0,0,0,0,10,0,0,75],[0,0,18,61,0,0,97,61,0,0,0,0,10,6,4,51,0,0,0,0,10,10,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,10,9,4,51,0,0,7,167,10,160,1,151,0,0,0,248,11,128,2,16,0,0,0,0,10,171,1,159],[0,0,7,169,10,160,0,65,0,0,0,0,0,169,4,53,0,0,0,3,8,128,2,16,0,0,0,248,8,128,0,137],[0,0,0,0,7,135,1,207,0,0,0,255,8,128,0,140,0,0,0,0,7,0,32,25,0,0,0,33,8,96,0,57],[0,0,18,188,0,0,1,61,0,0,7,166,8,96,0,156,0,0,1,89,0,0,33,61,0,0,0,64,8,96,0,57],[0,0,0,64,0,128,4,63,0,0,0,0,9,33,3,79,0,0,0,1,8,0,0,58,0,0,0,0,8,134,4,54],[0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59,0,0,0,0,0,152,4,53,0,0,1,193,0,0,97,61],[0,0,0,248,10,112,2,16,0,0,7,160,11,0,0,65,0,0,0,0,7,7,0,75,0,0,0,0,11,10,192,25],[0,0,7,167,7,144,1,151,0,0,0,0,7,183,1,159,0,0,0,0,0,120,4,53,0,0,0,64,7,0,4,61],[0,0,0,32,4,64,0,138,0,0,0,0,8,65,3,79,0,0,0,0,8,8,4,59,0,0,0,128,9,128,0,140],[0,0,19,99,0,0,65,61,0,0,0,128,9,128,2,112,0,0,7,168,10,128,0,156,0,0,0,0,9,8,160,25],[0,0,7,168,10,128,0,156,0,0,0,0,10,0,0,25,0,0,0,16,10,0,32,57,0,0,0,8,11,160,1,191],[0,0,7,159,12,144,0,156,0,0,0,0,11,10,160,25,0,0,0,64,10,144,2,112,0,0,7,159,12,144,0,156],[0,0,0,0,10,9,160,25,0,0,0,4,12,176,1,191,0,0,7,155,9,160,0,156,0,0,0,0,12,11,160,25],[0,0,0,32,11,160,2,112,0,0,7,155,9,160,0,156,0,0,0,0,11,10,160,25,0,0,0,2,9,192,1,191],[0,0,255,255,10,176,0,140,0,0,0,0,9,12,160,25,0,0,0,16,10,176,2,112,0,0,0,0,10,11,160,25],[0,0,0,255,10,160,0,140,0,0,0,1,9,144,32,57,0,0,0,32,10,0,0,138,0,0,0,65,11,144,0,57],[0,0,0,0,10,171,1,111,0,0,0,0,10,167,0,25,0,0,0,0,11,122,0,75,0,0,0,0,11,0,0,25],[0,0,0,1,11,0,64,57,0,0,7,159,12,160,0,156,0,0,1,89,0,0,33,61,0,0,0,1,11,176,1,144],[0,0,1,89,0,0,193,61,0,0,0,64,0,160,4,63,0,0,0,2,10,144,0,57,0,0,0,0,10,167,4,54],[0,0,0,33,11,144,0,57,0,0,0,5,11,176,2,114,0,0,18,153,0,0,97,61,0,0,0,0,12,33,3,79],[0,0,0,0,13,0,0,25,0,0,0,5,14,208,2,16,0,0,0,0,15,234,0,25,0,0,0,0,14,236,3,79],[0,0,0,0,14,14,4,59,0,0,0,0,0,239,4,53,0,0,0,1,13,208,0,57,0,0,0,0,14,189,0,75],[0,0,18,145,0,0,65,61,0,0,0,0,11,0,0,75,0,0,18,155,0,0,97,61,0,0,0,0,11,7,4,51],[0,0,0,0,11,11,0,75,0,0,1,193,0,0,97,61,0,0,0,0,11,10,4,51,0,0,7,167,11,176,1,151],[0,0,0,248,12,144,2,16,0,0,0,0,11,188,1,159,0,0,7,169,11,176,0,65,0,0,0,0,0,186,4,53],[0,0,0,3,9,144,2,16,0,0,0,248,9,144,0,137,0,0,0,0,8,152,1,207,0,0,0,255,9,144,0,140],[0,0,0,0,8,0,32,25,0,0,0,33,9,112,0,57,0,0,19,116,0,0,1,61,0,0,7,166,8,96,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,8,96,0,57,0,0,0,64,0,128,4,63,0,0,0,0,9,33,3,79],[0,0,0,1,8,0,0,58,0,0,0,0,8,134,4,54,0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59],[0,0,0,0,0,152,4,53,0,0,1,193,0,0,97,61,0,0,0,248,10,112,2,16,0,0,7,160,11,0,0,65],[0,0,0,0,7,7,0,75,0,0,0,0,11,10,192,25,0,0,7,167,7,144,1,151,0,0,0,0,7,183,1,159],[0,0,0,0,0,120,4,53,0,0,0,64,7,0,4,61,0,0,0,64,4,64,0,138,0,0,0,0,8,65,3,79],[0,0,0,0,8,8,4,59,0,0,0,128,9,128,0,140,0,0,19,194,0,0,65,61,0,0,0,128,9,128,2,112],[0,0,7,168,10,128,0,156,0,0,0,0,9,8,160,25,0,0,7,168,10,128,0,156,0,0,0,0,10,0,0,25],[0,0,0,16,10,0,32,57,0,0,0,8,11,160,1,191,0,0,7,159,12,144,0,156,0,0,0,0,11,10,160,25],[0,0,0,64,10,144,2,112,0,0,7,159,12,144,0,156,0,0,0,0,10,9,160,25,0,0,0,4,12,176,1,191],[0,0,7,155,9,160,0,156,0,0,0,0,12,11,160,25,0,0,0,32,11,160,2,112,0,0,7,155,9,160,0,156],[0,0,0,0,11,10,160,25,0,0,0,2,9,192,1,191,0,0,255,255,10,176,0,140,0,0,0,0,9,12,160,25],[0,0,0,16,10,176,2,112,0,0,0,0,10,11,160,25,0,0,0,255,10,160,0,140,0,0,0,1,9,144,32,57],[0,0,0,32,10,0,0,138,0,0,0,65,11,144,0,57,0,0,0,0,10,171,1,111,0,0,0,0,10,167,0,25],[0,0,0,0,11,122,0,75,0,0,0,0,11,0,0,25,0,0,0,1,11,0,64,57,0,0,7,159,12,160,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,11,176,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,160,4,63],[0,0,0,2,10,144,0,57,0,0,0,0,10,167,4,54,0,0,0,33,11,144,0,57,0,0,0,5,11,176,2,114],[0,0,18,247,0,0,97,61,0,0,0,0,12,33,3,79,0,0,0,0,13,0,0,25,0,0,0,5,14,208,2,16],[0,0,0,0,15,234,0,25,0,0,0,0,14,236,3,79,0,0,0,0,14,14,4,59,0,0,0,0,0,239,4,53],[0,0,0,1,13,208,0,57,0,0,0,0,14,189,0,75,0,0,18,239,0,0,65,61,0,0,0,0,11,0,0,75],[0,0,18,249,0,0,97,61,0,0,0,0,11,7,4,51,0,0,0,0,11,11,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,11,10,4,51,0,0,7,167,11,176,1,151,0,0,0,248,12,144,2,16,0,0,0,0,11,188,1,159],[0,0,7,169,11,176,0,65,0,0,0,0,0,186,4,53,0,0,0,3,9,144,2,16,0,0,0,248,9,144,0,137],[0,0,0,0,8,152,1,207,0,0,0,255,9,144,0,140,0,0,0,0,8,0,32,25,0,0,0,33,9,112,0,57],[0,0,19,211,0,0,1,61,0,0,0,6,5,0,0,41,0,0,7,166,5,80,0,156,0,0,1,89,0,0,33,61],[0,0,0,6,7,0,0,41,0,0,0,64,5,112,0,57,0,0,0,64,0,80,4,63,0,0,0,0,6,18,3,79],[0,0,0,1,5,0,0,58,0,0,0,0,5,87,4,54,0,0,0,0,6,96,3,80,0,0,0,0,6,6,4,59],[0,0,0,0,0,101,4,53,0,0,1,193,0,0,97,61,0,0,0,248,7,64,2,16,0,0,7,160,8,0,0,65],[0,0,0,0,4,4,0,75,0,0,0,0,8,7,192,25,0,0,7,167,4,96,1,151,0,0,0,0,4,132,1,159],[0,0,0,0,0,69,4,53,0,0,0,12,10,0,0,41,0,0,0,0,6,161,0,73,0,0,0,160,4,48,0,57],[0,0,0,0,3,66,3,79,0,0,0,0,5,3,4,59,0,0,0,31,3,96,0,138,0,0,7,160,6,48,1,151],[0,0,7,160,7,80,1,151,0,0,7,160,8,0,0,65,0,0,0,0,9,103,0,75,0,0,0,0,9,0,0,25],[0,0,0,0,9,8,64,25,0,0,0,0,6,103,1,63,0,0,0,0,7,53,0,75,0,0,0,0,8,0,64,25],[0,0,7,160,6,96,0,156,0,0,0,0,9,8,192,25,0,0,0,0,6,9,0,75,0,0,0,159,0,0,193,61],[0,0,0,0,6,165,0,25,0,0,0,0,5,98,3,79,0,0,0,0,5,5,4,59,0,0,7,159,7,80,0,156],[0,0,0,159,0,0,33,61,0,0,0,0,7,81,0,73,0,0,0,32,6,96,0,57,0,0,7,160,8,0,0,65],[0,0,0,0,9,118,0,75,0,0,0,0,9,0,0,25,0,0,0,0,9,8,32,25,0,0,7,160,7,112,1,151],[0,0,7,160,10,96,1,151,0,0,0,0,11,122,0,75,0,0,0,0,8,0,128,25,0,0,0,0,7,122,1,63],[0,0,7,160,7,112,0,156,0,0,0,0,8,9,192,25,0,0,0,0,7,8,0,75,0,0,0,159,0,0,193,61],[0,0,0,1,7,80,0,140,0,0,21,96,0,0,193,61,0,0,0,0,5,98,3,79,0,0,0,0,5,5,4,59],[0,0,0,1,6,0,0,138,0,0,7,160,7,0,0,65,0,0,0,0,6,101,0,75,0,0,0,0,6,0,0,25],[0,0,0,0,6,7,32,25,0,0,7,160,5,80,1,151,0,0,7,160,8,80,0,156,0,0,0,0,7,0,128,25],[0,0,7,160,5,80,1,103,0,0,7,160,5,80,0,156,0,0,0,0,7,6,192,25,0,5,0,96,0,0,0,61],[0,0,0,0,5,7,0,75,0,0,22,99,0,0,193,61,0,0,0,64,5,0,4,61,0,5,0,0,0,5,0,29],[0,0,7,166,5,80,0,156,0,0,1,89,0,0,33,61,0,0,0,5,7,0,0,41,0,0,0,64,5,112,0,57],[0,0,0,64,0,80,4,63,0,0,0,32,5,112,0,57,0,0,7,169,6,0,0,65,0,0,0,0,0,101,4,53],[0,0,0,1,5,0,0,57,0,0,0,0,0,87,4,53,0,0,22,99,0,0,1,61,0,0,7,166,9,112,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,9,112,0,57,0,0,0,64,0,144,4,63,0,0,0,0,10,33,3,79],[0,0,0,1,9,0,0,58,0,0,0,0,9,151,4,54,0,0,0,0,10,160,3,80,0,0,0,0,10,10,4,59],[0,0,0,0,0,169,4,53,0,0,1,193,0,0,97,61,0,0,0,248,11,128,2,16,0,0,7,160,12,0,0,65],[0,0,0,0,8,8,0,75,0,0,0,0,12,11,192,25,0,0,7,167,8,160,1,151,0,0,0,0,8,200,1,159],[0,0,0,0,0,137,4,53,0,0,0,64,8,0,4,61,0,9,0,64,0,64,0,146,0,0,0,9,9,16,3,96],[0,0,0,0,9,9,4,59,0,0,0,128,10,144,0,140,0,0,20,51,0,0,65,61,0,0,0,128,10,144,2,112],[0,0,7,168,11,144,0,156,0,0,0,0,10,9,160,25,0,0,7,168,11,144,0,156,0,0,0,0,11,0,0,25],[0,0,0,16,11,0,32,57,0,0,0,8,12,176,1,191,0,0,7,159,13,160,0,156,0,0,0,0,12,11,160,25],[0,0,0,64,11,160,2,112,0,0,7,159,13,160,0,156,0,0,0,0,11,10,160,25,0,0,0,4,13,192,1,191],[0,0,7,155,10,176,0,156,0,0,0,0,13,12,160,25,0,0,0,32,12,176,2,112,0,0,7,155,10,176,0,156],[0,0,0,0,12,11,160,25,0,0,0,2,10,208,1,191,0,0,255,255,11,192,0,140,0,0,0,0,10,13,160,25],[0,0,0,16,11,192,2,112,0,0,0,0,11,12,160,25,0,0,0,255,11,176,0,140,0,0,0,1,10,160,32,57],[0,0,0,32,11,0,0,138,0,0,0,65,12,160,0,57,0,0,0,0,11,188,1,111,0,0,0,0,11,184,0,25],[0,0,0,0,12,139,0,75,0,0,0,0,12,0,0,25,0,0,0,1,12,0,64,57,0,0,7,159,13,176,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,12,192,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,176,4,63],[0,0,0,2,11,160,0,57,0,0,0,0,11,184,4,54,0,0,0,33,12,160,0,57,0,0,0,5,12,192,2,114],[0,0,19,175,0,0,97,61,0,0,0,0,13,33,3,79,0,0,0,0,14,0,0,25,0,0,0,5,15,224,2,16],[0,0,0,0,4,251,0,25,0,0,0,0,15,253,3,79,0,0,0,0,15,15,4,59,0,0,0,0,0,244,4,53],[0,0,0,1,14,224,0,57,0,0,0,0,4,206,0,75,0,0,19,167,0,0,65,61,0,0,0,0,4,0,0,75],[0,0,19,177,0,0,97,61,0,0,0,0,4,8,4,51,0,0,0,0,4,4,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,4,11,4,51,0,0,7,167,4,64,1,151,0,0,0,248,12,160,2,16,0,0,0,0,4,76,1,159],[0,0,7,169,4,64,0,65,0,0,0,0,0,75,4,53,0,0,0,3,4,160,2,16,0,0,0,248,4,64,0,137],[0,0,0,0,9,73,1,207,0,0,0,255,4,64,0,140,0,0,0,0,9,0,32,25,0,0,0,33,4,128,0,57],[0,0,0,0,0,148,4,53,0,0,20,69,0,0,1,61,0,0,7,166,9,112,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,9,112,0,57,0,0,0,64,0,144,4,63,0,0,0,0,10,33,3,79,0,0,0,1,9,0,0,58],[0,0,0,0,9,151,4,54,0,0,0,0,10,160,3,80,0,0,0,0,10,10,4,59,0,0,0,0,0,169,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,11,128,2,16,0,0,7,160,12,0,0,65,0,0,0,0,8,8,0,75],[0,0,0,0,12,11,192,25,0,0,7,167,8,160,1,151,0,0,0,0,8,200,1,159,0,0,0,0,0,137,4,53],[0,0,0,64,9,0,4,61,0,0,7,166,8,144,0,156,0,0,1,89,0,0,33,61,0,0,0,32,8,64,0,138],[0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,64,10,144,0,57,0,0,0,64,0,160,4,63],[0,0,0,32,10,144,0,57,0,0,7,170,11,0,0,65,0,0,0,0,0,186,4,53,0,0,0,21,10,0,0,57],[0,0,0,0,0,169,4,53,0,0,0,96,8,128,2,16,0,0,0,33,10,144,0,57,0,0,0,0,0,138,4,53],[0,0,0,192,4,64,0,57,0,0,0,0,4,65,3,79,0,0,0,64,8,0,4,61,0,0,0,0,4,4,4,59],[0,9,0,0,0,4,0,29,0,0,0,128,10,64,0,140,0,0,20,168,0,0,65,61,0,0,0,9,4,0,0,41],[0,0,0,128,10,64,2,112,0,0,7,168,11,64,0,156,0,0,0,0,10,4,160,25,0,0,7,168,11,64,0,156],[0,0,0,0,11,0,0,25,0,0,0,16,11,0,32,57,0,0,0,8,12,176,1,191,0,0,7,159,13,160,0,156],[0,0,0,0,12,11,160,25,0,0,0,64,11,160,2,112,0,0,7,159,13,160,0,156,0,0,0,0,11,10,160,25],[0,0,0,4,13,192,1,191,0,0,7,155,10,176,0,156,0,0,0,0,13,12,160,25,0,0,0,32,12,176,2,112],[0,0,7,155,10,176,0,156,0,0,0,0,12,11,160,25,0,0,0,2,10,208,1,191,0,0,255,255,11,192,0,140],[0,0,0,0,10,13,160,25,0,0,0,16,11,192,2,112,0,0,0,0,11,12,160,25,0,0,0,255,11,176,0,140],[0,0,0,1,10,160,32,57,0,0,0,32,11,0,0,138,0,0,0,65,12,160,0,57,0,0,0,0,11,188,1,111],[0,0,0,0,11,184,0,25,0,0,0,0,12,139,0,75,0,0,0,0,12,0,0,25,0,0,0,1,12,0,64,57],[0,0,7,159,13,176,0,156,0,0,1,89,0,0,33,61,0,0,0,1,12,192,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,176,4,63,0,0,0,2,11,160,0,57,0,0,0,0,11,184,4,54,0,0,0,33,12,160,0,57],[0,0,0,5,12,192,2,114,0,0,20,32,0,0,97,61,0,0,0,0,13,33,3,79,0,0,0,0,14,0,0,25],[0,0,0,5,15,224,2,16,0,0,0,0,4,251,0,25,0,0,0,0,15,253,3,79,0,0,0,0,15,15,4,59],[0,0,0,0,0,244,4,53,0,0,0,1,14,224,0,57,0,0,0,0,4,206,0,75,0,0,20,24,0,0,65,61],[0,0,0,0,4,0,0,75,0,0,20,34,0,0,97,61,0,0,0,0,4,8,4,51,0,0,0,0,4,4,0,75],[0,0,1,193,0,0,97,61,0,0,0,0,4,11,4,51,0,0,7,167,4,64,1,151,0,0,0,248,12,160,2,16],[0,0,0,0,4,76,1,159,0,0,7,169,4,64,0,65,0,0,0,0,0,75,4,53,0,0,0,3,4,160,2,16],[0,0,0,248,4,64,0,137,0,0,0,9,10,64,1,239,0,0,0,255,4,64,0,140,0,0,0,0,10,0,32,25],[0,0,0,33,4,128,0,57,0,0,0,0,0,164,4,53,0,0,20,187,0,0,1,61,0,0,7,166,4,128,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,4,128,0,57,0,0,0,64,0,64,4,63,0,0,0,0,4,33,3,79],[0,0,0,1,10,0,0,58,0,0,0,0,10,168,4,54,0,0,0,0,4,64,3,80,0,0,0,0,11,4,4,59],[0,0,0,0,0,186,4,53,0,0,1,193,0,0,97,61,0,0,0,248,4,144,2,16,0,0,7,160,12,0,0,65],[0,0,0,0,9,9,0,75,0,0,0,0,12,4,192,25,0,0,7,167,4,176,1,151,0,0,0,0,4,196,1,159],[0,0,0,0,0,74,4,53,0,0,0,64,10,0,4,61,0,0,7,166,4,160,0,156,0,0,1,89,0,0,33,61],[0,0,0,9,12,0,0,41,0,0,0,32,4,192,0,138,0,0,0,0,4,65,3,79,0,0,0,0,4,4,4,59],[0,0,0,64,9,160,0,57,0,0,0,64,0,144,4,63,0,0,0,32,9,160,0,57,0,0,7,170,11,0,0,65],[0,0,0,0,0,185,4,53,0,0,0,21,9,0,0,57,0,0,0,0,0,154,4,53,0,0,0,96,4,64,2,16],[0,0,0,33,9,160,0,57,0,0,0,0,0,73,4,53,0,0,0,192,4,192,0,57,0,0,0,0,4,65,3,79],[0,0,0,64,9,0,4,61,0,0,0,0,4,4,4,59,0,9,0,0,0,4,0,29,0,0,0,128,11,64,0,140],[0,0,21,140,0,0,65,61,0,0,0,9,4,0,0,41,0,0,0,128,11,64,2,112,0,0,7,168,12,64,0,156],[0,0,0,0,11,4,160,25,0,0,7,168,12,64,0,156,0,0,0,0,12,0,0,25,0,0,0,16,12,0,32,57],[0,0,0,8,13,192,1,191,0,0,7,159,14,176,0,156,0,0,0,0,13,12,160,25,0,0,0,64,12,176,2,112],[0,0,7,159,14,176,0,156,0,0,0,0,12,11,160,25,0,0,0,4,14,208,1,191,0,0,7,155,11,192,0,156],[0,0,0,0,14,13,160,25,0,0,0,32,13,192,2,112,0,0,7,155,11,192,0,156,0,0,0,0,13,12,160,25],[0,0,0,2,4,224,1,191,0,0,255,255,12,208,0,140,0,0,0,0,4,14,160,25,0,0,0,16,12,208,2,112],[0,0,0,0,12,13,160,25,0,0,0,255,12,192,0,140,0,0,0,1,4,64,32,57,0,0,0,32,12,0,0,138],[0,8,0,0,0,4,0,29,0,0,0,65,13,64,0,57,0,0,0,0,12,205,1,111,0,0,0,0,12,201,0,25],[0,0,0,0,13,156,0,75,0,0,0,0,13,0,0,25,0,0,0,1,13,0,64,57,0,0,7,159,14,192,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,13,208,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,192,4,63],[0,0,0,8,4,0,0,41,0,0,0,2,12,64,0,57,0,0,0,0,12,201,4,54,0,0,0,33,13,64,0,57],[0,0,0,5,13,208,2,114,0,0,20,148,0,0,97,61,0,0,0,0,14,33,3,79,0,0,0,0,15,0,0,25],[0,0,0,5,4,240,2,16,0,0,0,0,11,76,0,25,0,0,0,0,4,78,3,79,0,0,0,0,4,4,4,59],[0,0,0,0,0,75,4,53,0,0,0,1,15,240,0,57,0,0,0,0,4,223,0,75,0,0,20,140,0,0,65,61],[0,0,0,0,4,0,0,75,0,0,20,150,0,0,97,61,0,0,0,0,4,9,4,51,0,0,0,0,4,4,0,75],[0,0,1,193,0,0,97,61,0,0,0,0,4,12,4,51,0,0,7,167,4,64,1,151,0,0,0,8,13,0,0,41],[0,0,0,248,11,208,2,16,0,0,0,0,4,75,1,159,0,0,7,169,4,64,0,65,0,0,0,0,0,76,4,53],[0,0,0,3,4,208,2,16,0,0,0,248,4,64,0,137,0,0,0,9,11,64,1,239,0,0,0,255,4,64,0,140],[0,0,0,0,11,0,32,25,0,0,0,33,4,144,0,57,0,0,0,0,0,180,4,53,0,0,21,159,0,0,1,61],[0,0,7,166,4,128,0,156,0,0,1,89,0,0,33,61,0,0,0,64,4,128,0,57,0,0,0,64,0,64,4,63],[0,0,0,0,4,33,3,79,0,0,0,1,10,0,0,58,0,0,0,0,10,168,4,54,0,0,0,0,4,64,3,80],[0,0,0,0,11,4,4,59,0,0,0,0,0,186,4,53,0,0,1,193,0,0,97,61,0,0,0,9,13,0,0,41],[0,0,0,248,4,208,2,16,0,0,7,160,12,0,0,65,0,0,0,0,13,13,0,75,0,0,0,0,12,4,192,25],[0,0,7,167,4,176,1,151,0,0,0,0,4,196,1,159,0,0,0,0,0,74,4,53,0,0,0,64,4,0,4,61],[0,0,0,32,10,64,0,57,0,0,0,0,11,3,4,51,0,0,0,0,12,11,0,75,0,0,20,200,0,0,97,61],[0,0,0,0,12,0,0,25,0,0,0,0,13,172,0,25,0,0,0,32,12,192,0,57,0,0,0,0,14,60,0,25],[0,0,0,0,14,14,4,51,0,0,0,0,0,237,4,53,0,0,0,0,13,188,0,75,0,0,20,193,0,0,65,61],[0,0,0,0,3,171,0,25,0,0,0,0,0,3,4,53,0,0,0,0,10,5,4,51,0,0,0,0,11,10,0,75],[0,0,20,213,0,0,97,61,0,0,0,0,11,0,0,25,0,0,0,0,12,59,0,25,0,0,0,32,11,176,0,57],[0,0,0,0,13,91,0,25,0,0,0,0,13,13,4,51,0,0,0,0,0,220,4,53,0,0,0,0,12,171,0,75],[0,0,20,206,0,0,65,61,0,0,0,0,3,58,0,25,0,0,0,0,0,3,4,53,0,0,0,0,5,6,4,51],[0,0,0,0,10,5,0,75,0,0,20,226,0,0,97,61,0,0,0,0,10,0,0,25,0,0,0,0,11,58,0,25],[0,0,0,32,10,160,0,57,0,0,0,0,12,106,0,25,0,0,0,0,12,12,4,51,0,0,0,0,0,203,4,53],[0,0,0,0,11,90,0,75,0,0,20,219,0,0,65,61,0,0,0,0,3,53,0,25,0,0,0,0,0,3,4,53],[0,0,0,0,5,7,4,51,0,0,0,0,6,5,0,75,0,0,20,239,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,0,10,54,0,25,0,0,0,32,6,96,0,57,0,0,0,0,11,118,0,25,0,0,0,0,11,11,4,51],[0,0,0,0,0,186,4,53,0,0,0,0,10,86,0,75,0,0,20,232,0,0,65,61,0,0,0,0,3,53,0,25],[0,0,0,0,0,3,4,53,0,0,0,0,5,9,4,51,0,0,0,0,6,5,0,75,0,0,20,252,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,0,7,54,0,25,0,0,0,32,6,96,0,57,0,0,0,0,10,150,0,25],[0,0,0,0,10,10,4,51,0,0,0,0,0,167,4,53,0,0,0,0,7,86,0,75,0,0,20,245,0,0,65,61],[0,0,0,0,3,53,0,25,0,0,0,0,0,3,4,53,0,0,0,0,5,8,4,51,0,0,0,0,6,5,0,75],[0,0,21,9,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,0,7,54,0,25,0,0,0,32,6,96,0,57],[0,0,0,0,9,134,0,25,0,0,0,0,9,9,4,51,0,0,0,0,0,151,4,53,0,0,0,0,7,86,0,75],[0,0,21,2,0,0,65,61,0,0,0,0,3,53,0,25,0,0,0,0,0,3,4,53,0,0,0,0,3,67,0,73],[0,0,0,32,5,48,0,138,0,0,0,0,0,84,4,53,0,0,0,31,5,48,0,57,0,0,0,32,3,0,0,138],[0,0,0,0,5,53,1,111,0,0,0,0,7,69,0,25,0,0,0,0,5,87,0,75,0,0,0,0,5,0,0,25],[0,0,0,1,5,0,64,57,0,0,7,159,6,112,0,156,0,0,1,89,0,0,33,61,0,0,0,1,5,80,1,144],[0,0,1,89,0,0,193,61,0,0,0,64,0,112,4,63,0,0,0,12,13,0,0,41,0,0,0,0,6,210,0,73],[0,0,0,13,5,0,0,41,0,0,1,196,12,80,0,57,0,0,0,0,5,193,3,79,0,0,0,0,5,5,4,59],[0,0,0,31,9,96,0,138,0,0,7,160,6,144,1,151,0,0,7,160,8,80,1,151,0,0,7,160,10,0,0,65],[0,0,0,0,11,104,0,75,0,0,0,0,11,0,0,25,0,0,0,0,11,10,64,25,0,0,0,0,6,104,1,63],[0,0,0,0,8,149,0,75,0,0,0,0,10,0,64,25,0,0,7,160,6,96,0,156,0,0,0,0,11,10,192,25],[0,0,0,0,6,11,0,75,0,0,0,159,0,0,193,61,0,0,0,0,6,213,0,25,0,0,0,0,5,97,3,79],[0,0,0,0,5,5,4,59,0,0,7,159,8,80,0,156,0,0,0,159,0,0,33,61,0,0,0,0,8,82,0,73],[0,0,0,32,6,96,0,57,0,0,7,160,10,0,0,65,0,0,0,0,11,134,0,75,0,0,0,0,11,0,0,25],[0,0,0,0,11,10,32,25,0,0,7,160,8,128,1,151,0,13,0,0,0,6,0,29,0,0,7,160,13,96,1,151],[0,0,0,0,14,141,0,75,0,0,0,0,10,0,128,25,0,0,0,0,8,141,1,63,0,0,7,160,8,128,0,156],[0,0,0,0,10,11,192,25,0,0,0,0,8,10,0,75,0,0,0,159,0,0,193,61,0,0,0,1,8,80,0,140],[0,0,23,61,0,0,193,61,0,0,0,13,8,16,3,96,0,0,0,0,8,8,4,59,0,0,0,1,10,0,0,138],[0,0,7,160,11,0,0,65,0,0,0,0,10,168,0,75,0,0,0,0,10,0,0,25,0,0,0,0,10,11,32,25],[0,0,7,160,8,128,1,151,0,0,7,160,13,128,0,156,0,0,0,0,11,0,128,25,0,0,7,160,8,128,1,103],[0,0,7,160,8,128,0,156,0,0,0,0,11,10,192,25,0,0,0,96,8,0,0,57,0,0,0,0,10,11,0,75],[0,0,23,158,0,0,193,61,0,0,7,166,8,112,0,156,0,0,1,89,0,0,33,61,0,0,0,64,8,112,0,57],[0,0,0,64,0,128,4,63,0,0,0,32,8,112,0,57,0,0,7,169,10,0,0,65,0,0,0,0,0,168,4,53],[0,0,0,1,8,0,0,57,0,0,0,0,0,135,4,53,0,0,0,0,8,7,0,25,0,0,23,158,0,0,1,61],[0,0,0,64,6,0,4,61,0,5,0,0,0,6,0,29,0,0,0,56,6,80,0,140,0,0,22,81,0,0,65,61],[0,0,0,32,7,80,2,112,0,0,7,155,6,80,0,156,0,0,0,0,7,5,160,25,0,0,7,155,6,80,0,156],[0,0,0,0,8,0,0,25,0,0,0,4,8,0,32,57,0,0,0,2,6,128,1,191,0,0,255,255,9,112,0,140],[0,0,0,0,6,8,160,25,0,0,0,16,8,112,2,112,0,0,0,0,8,7,160,25,0,0,0,255,7,128,0,140],[0,0,0,0,7,0,0,25,0,0,0,1,7,0,32,57,0,0,0,5,8,0,0,41,0,0,7,166,8,128,0,156],[0,0,1,89,0,0,33,61,0,0,0,0,6,118,1,159,0,0,0,5,9,0,0,41,0,0,0,64,7,144,0,57],[0,0,0,64,0,112,4,63,0,0,0,0,8,18,3,79,0,0,0,2,7,96,0,58,0,0,0,0,7,121,4,54],[0,0,0,0,8,128,3,80,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,1,193,0,0,97,61],[0,0,7,167,8,128,1,151,0,0,0,248,9,96,2,16,0,0,0,0,8,137,1,159,0,0,7,171,8,128,1,199],[0,0,0,0,0,135,4,53,0,0,0,3,6,96,2,16,0,0,0,248,6,96,1,95,0,0,0,0,5,101,1,207],[0,0,0,5,6,0,0,41,0,0,0,33,6,96,0,57,0,0,0,0,0,86,4,53,0,0,22,99,0,0,1,61],[0,0,7,166,4,144,0,156,0,0,1,89,0,0,33,61,0,0,0,64,4,144,0,57,0,0,0,64,0,64,4,63],[0,0,0,0,4,33,3,79,0,0,0,1,11,0,0,58,0,0,0,0,11,185,4,54,0,0,0,0,4,64,3,80],[0,0,0,0,12,4,4,59,0,0,0,0,0,203,4,53,0,0,1,193,0,0,97,61,0,0,0,9,14,0,0,41],[0,0,0,248,4,224,2,16,0,0,7,160,13,0,0,65,0,0,0,0,14,14,0,75,0,0,0,0,13,4,192,25],[0,0,7,167,4,192,1,151,0,0,0,0,4,212,1,159,0,0,0,0,0,75,4,53,0,0,0,64,4,0,4,61],[0,0,0,32,11,64,0,57,0,0,0,0,12,3,4,51,0,0,0,0,13,12,0,75,0,0,21,172,0,0,97,61],[0,0,0,0,13,0,0,25,0,0,0,0,14,189,0,25,0,0,0,32,13,208,0,57,0,0,0,0,15,61,0,25],[0,0,0,0,15,15,4,51,0,0,0,0,0,254,4,53,0,0,0,0,14,205,0,75,0,0,21,165,0,0,65,61],[0,0,0,0,3,188,0,25,0,0,0,0,0,3,4,53,0,0,0,0,11,5,4,51,0,0,0,0,12,11,0,75],[0,0,21,185,0,0,97,61,0,0,0,0,12,0,0,25,0,0,0,0,13,60,0,25,0,0,0,32,12,192,0,57],[0,0,0,0,14,92,0,25,0,0,0,0,14,14,4,51,0,0,0,0,0,237,4,53,0,0,0,0,13,188,0,75],[0,0,21,178,0,0,65,61,0,0,0,0,3,59,0,25,0,0,0,0,0,3,4,53,0,0,0,0,5,6,4,51],[0,0,0,0,11,5,0,75,0,0,21,198,0,0,97,61,0,0,0,0,11,0,0,25,0,0,0,0,12,59,0,25],[0,0,0,32,11,176,0,57,0,0,0,0,13,107,0,25,0,0,0,0,13,13,4,51,0,0,0,0,0,220,4,53],[0,0,0,0,12,91,0,75,0,0,21,191,0,0,65,61,0,0,0,0,3,53,0,25,0,0,0,0,0,3,4,53],[0,0,0,0,5,7,4,51,0,0,0,0,6,5,0,75,0,0,21,211,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,0,11,54,0,25,0,0,0,32,6,96,0,57,0,0,0,0,12,118,0,25,0,0,0,0,12,12,4,51],[0,0,0,0,0,203,4,53,0,0,0,0,11,86,0,75,0,0,21,204,0,0,65,61,0,0,0,0,3,53,0,25],[0,0,0,0,0,3,4,53,0,0,0,0,5,8,4,51,0,0,0,0,6,5,0,75,0,0,21,224,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,0,7,54,0,25,0,0,0,32,6,96,0,57,0,0,0,0,11,134,0,25],[0,0,0,0,11,11,4,51,0,0,0,0,0,183,4,53,0,0,0,0,7,86,0,75,0,0,21,217,0,0,65,61],[0,0,0,0,3,53,0,25,0,0,0,0,0,3,4,53,0,0,0,0,5,10,4,51,0,0,0,0,6,5,0,75],[0,0,21,237,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,0,7,54,0,25,0,0,0,32,6,96,0,57],[0,0,0,0,8,166,0,25,0,0,0,0,8,8,4,51,0,0,0,0,0,135,4,53,0,0,0,0,7,86,0,75],[0,0,21,230,0,0,65,61,0,0,0,0,3,53,0,25,0,0,0,0,0,3,4,53,0,0,0,0,5,9,4,51],[0,0,0,0,6,5,0,75,0,0,21,250,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,0,7,54,0,25],[0,0,0,32,6,96,0,57,0,0,0,0,8,150,0,25,0,0,0,0,8,8,4,51,0,0,0,0,0,135,4,53],[0,0,0,0,7,86,0,75,0,0,21,243,0,0,65,61,0,0,0,0,3,53,0,25,0,0,0,0,0,3,4,53],[0,0,0,0,3,67,0,73,0,0,0,32,5,48,0,138,0,0,0,0,0,84,4,53,0,0,0,31,5,48,0,57],[0,0,0,32,3,0,0,138,0,0,0,0,5,53,1,111,0,0,0,0,7,69,0,25,0,0,0,0,5,87,0,75],[0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57,0,0,7,159,6,112,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,5,80,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,112,4,63,0,0,0,12,13,0,0,41],[0,0,0,0,6,210,0,73,0,0,0,13,5,0,0,41,0,0,1,196,12,80,0,57,0,0,0,0,5,193,3,79],[0,0,0,0,5,5,4,59,0,0,0,31,9,96,0,138,0,0,7,160,6,144,1,151,0,0,7,160,8,80,1,151],[0,0,7,160,10,0,0,65,0,0,0,0,11,104,0,75,0,0,0,0,11,0,0,25,0,0,0,0,11,10,64,25],[0,0,0,0,6,104,1,63,0,0,0,0,8,149,0,75,0,0,0,0,10,0,64,25,0,0,7,160,6,96,0,156],[0,0,0,0,11,10,192,25,0,0,0,0,6,11,0,75,0,0,0,159,0,0,193,61,0,0,0,0,6,213,0,25],[0,0,0,0,5,97,3,79,0,0,0,0,5,5,4,59,0,0,7,159,8,80,0,156,0,0,0,159,0,0,33,61],[0,0,0,0,8,82,0,73,0,0,0,32,6,96,0,57,0,0,7,160,10,0,0,65,0,0,0,0,11,134,0,75],[0,0,0,0,11,0,0,25,0,0,0,0,11,10,32,25,0,0,7,160,8,128,1,151,0,13,0,0,0,6,0,29],[0,0,7,160,13,96,1,151,0,0,0,0,14,141,0,75,0,0,0,0,10,0,128,25,0,0,0,0,8,141,1,63],[0,0,7,160,8,128,0,156,0,0,0,0,10,11,192,25,0,0,0,0,8,10,0,75,0,0,0,159,0,0,193,61],[0,0,0,1,8,80,0,140,0,0,23,101,0,0,193,61,0,0,0,13,8,16,3,96,0,0,0,0,8,8,4,59],[0,0,0,1,10,0,0,138,0,0,7,160,11,0,0,65,0,0,0,0,10,168,0,75,0,0,0,0,10,0,0,25],[0,0,0,0,10,11,32,25,0,0,7,160,8,128,1,151,0,0,7,160,13,128,0,156,0,0,0,0,11,0,128,25],[0,0,7,160,8,128,1,103,0,0,7,160,8,128,0,156,0,0,0,0,11,10,192,25,0,0,0,96,8,0,0,57],[0,0,0,0,10,11,0,75,0,0,24,125,0,0,193,61,0,0,7,166,8,112,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,8,112,0,57,0,0,0,64,0,128,4,63,0,0,0,32,8,112,0,57,0,0,7,169,10,0,0,65],[0,0,0,0,0,168,4,53,0,0,0,1,8,0,0,57,0,0,0,0,0,135,4,53,0,0,0,0,8,7,0,25],[0,0,24,125,0,0,1,61,0,0,0,5,6,0,0,41,0,0,7,166,6,96,0,156,0,0,1,89,0,0,33,61],[0,0,0,5,8,0,0,41,0,0,0,64,6,128,0,57,0,0,0,64,0,96,4,63,0,0,0,0,7,18,3,79],[0,0,0,1,6,0,0,58,0,0,0,0,6,104,4,54,0,0,0,0,7,112,3,80,0,0,0,0,7,7,4,59],[0,0,0,0,0,118,4,53,0,0,1,193,0,0,97,61,0,0,0,248,5,80,2,16,0,0,7,167,7,112,1,151],[0,0,0,0,5,87,1,159,0,0,7,160,5,80,1,103,0,0,0,0,0,86,4,53,0,0,0,32,4,64,0,57],[0,0,0,0,4,66,3,79,0,0,0,0,4,4,4,59,0,0,7,160,5,0,0,65,0,0,0,0,6,52,0,75],[0,0,0,0,6,0,0,25,0,0,0,0,6,5,128,25,0,0,7,160,3,48,1,151,0,0,7,160,7,64,1,151],[0,0,0,0,8,55,0,75,0,0,0,0,5,0,128,25,0,0,0,0,3,55,1,63,0,0,7,160,3,48,0,156],[0,0,0,0,5,6,192,25,0,0,0,0,3,5,0,75,0,0,0,12,3,0,0,41,0,0,0,159,0,0,193,61],[0,0,0,0,4,52,0,25,0,0,0,0,3,66,3,79,0,0,0,0,3,3,4,59,0,0,7,159,5,48,0,156],[0,0,0,159,0,0,33,61,0,0,0,32,5,48,0,140,0,0,0,159,0,0,65,61,0,0,0,0,5,49,0,73],[0,0,0,32,4,64,0,57,0,0,7,160,6,0,0,65,0,0,0,0,7,84,0,75,0,0,0,0,7,0,0,25],[0,0,0,0,7,6,32,25,0,0,7,160,5,80,1,151,0,0,7,160,8,64,1,151,0,0,0,0,9,88,0,75],[0,0,0,0,6,0,128,25,0,0,0,0,5,88,1,63,0,0,7,160,5,80,0,156,0,0,0,0,6,7,192,25],[0,0,0,0,5,6,0,75,0,0,0,159,0,0,193,61,0,0,0,0,5,66,3,79,0,0,0,64,6,0,4,61],[0,4,0,0,0,6,0,29,0,0,0,0,5,5,4,59,0,0,0,128,6,80,0,140,0,0,22,216,0,0,65,61],[0,0,0,128,6,80,2,112,0,0,7,168,7,80,0,156,0,0,0,0,6,5,160,25,0,0,7,168,7,80,0,156],[0,0,0,0,7,0,0,25,0,0,0,16,7,0,32,57,0,0,0,8,8,112,1,191,0,0,7,159,9,96,0,156],[0,0,0,0,8,7,160,25,0,0,0,64,7,96,2,112,0,0,7,159,9,96,0,156,0,0,0,0,7,6,160,25],[0,0,0,4,9,128,1,191,0,0,7,155,6,112,0,156,0,0,0,0,9,8,160,25,0,0,0,32,8,112,2,112],[0,0,7,155,6,112,0,156,0,0,0,0,8,7,160,25,0,0,0,2,6,144,1,191,0,0,255,255,7,128,0,140],[0,0,0,0,6,9,160,25,0,0,0,16,7,128,2,112,0,0,0,0,7,8,160,25,0,0,0,255,7,112,0,140],[0,0,0,1,6,96,32,57,0,0,0,65,7,96,0,57,0,0,0,7,7,112,1,127,0,0,0,4,7,112,0,41],[0,0,0,4,8,112,0,108,0,0,0,0,8,0,0,25,0,0,0,1,8,0,64,57,0,0,7,159,9,112,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,8,128,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,112,4,63],[0,0,0,2,7,96,0,57,0,0,0,4,8,0,0,41,0,0,0,0,7,120,4,54,0,0,0,33,8,96,0,57],[0,0,0,5,8,128,2,114,0,0,22,196,0,0,97,61,0,0,0,0,9,18,3,79,0,0,0,0,10,0,0,25],[0,0,0,5,11,160,2,16,0,0,0,0,12,183,0,25,0,0,0,0,11,185,3,79,0,0,0,0,11,11,4,59],[0,0,0,0,0,188,4,53,0,0,0,1,10,160,0,57,0,0,0,0,11,138,0,75,0,0,22,188,0,0,65,61],[0,0,0,0,8,0,0,75,0,0,22,198,0,0,97,61,0,0,0,4,8,0,0,41,0,0,0,0,8,8,4,51],[0,0,0,0,8,8,0,75,0,0,1,193,0,0,97,61,0,0,0,0,8,7,4,51,0,0,7,167,8,128,1,151],[0,0,0,248,9,96,2,16,0,0,0,0,8,137,1,159,0,0,7,169,8,128,0,65,0,0,0,0,0,135,4,53],[0,0,0,3,6,96,2,16,0,0,0,248,6,96,0,137,0,0,0,0,5,101,1,207,0,0,0,255,6,96,0,140],[0,0,0,0,5,0,32,25,0,0,0,4,6,0,0,41,0,0,0,33,6,96,0,57,0,0,22,235,0,0,1,61],[0,0,0,4,6,0,0,41,0,0,7,166,6,96,0,156,0,0,1,89,0,0,33,61,0,0,0,4,8,0,0,41],[0,0,0,64,6,128,0,57,0,0,0,64,0,96,4,63,0,0,0,0,7,18,3,79,0,0,0,1,6,0,0,58],[0,0,0,0,6,104,4,54,0,0,0,0,7,112,3,80,0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,8,80,2,16,0,0,7,160,9,0,0,65,0,0,0,0,5,5,0,75],[0,0,0,0,9,8,192,25,0,0,7,167,5,112,1,151,0,0,0,0,5,149,1,159,0,0,0,0,0,86,4,53],[0,0,0,64,5,48,0,140,0,0,0,159,0,0,65,61,0,0,0,64,5,0,4,61,0,3,0,0,0,5,0,29],[0,0,0,32,4,64,0,57,0,0,0,0,5,66,3,79,0,0,0,0,5,5,4,59,0,0,0,128,6,80,0,140],[0,0,24,41,0,0,65,61,0,0,0,128,6,80,2,112,0,0,7,168,7,80,0,156,0,0,0,0,6,5,160,25],[0,0,7,168,7,80,0,156,0,0,0,0,7,0,0,25,0,0,0,16,7,0,32,57,0,0,0,8,8,112,1,191],[0,0,7,159,9,96,0,156,0,0,0,0,8,7,160,25,0,0,0,64,7,96,2,112,0,0,7,159,9,96,0,156],[0,0,0,0,7,6,160,25,0,0,0,4,9,128,1,191,0,0,7,155,6,112,0,156,0,0,0,0,9,8,160,25],[0,0,0,32,8,112,2,112,0,0,7,155,6,112,0,156,0,0,0,0,8,7,160,25,0,0,0,2,6,144,1,191],[0,0,255,255,7,128,0,140,0,0,0,0,6,9,160,25,0,0,0,16,7,128,2,112,0,0,0,0,7,8,160,25],[0,0,0,255,7,112,0,140,0,0,0,1,6,96,32,57,0,0,0,65,7,96,0,57,0,0,0,7,7,112,1,127],[0,0,0,3,7,112,0,41,0,0,0,3,8,112,0,108,0,0,0,0,8,0,0,25,0,0,0,1,8,0,64,57],[0,0,7,159,9,112,0,156,0,0,1,89,0,0,33,61,0,0,0,1,8,128,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,112,4,63,0,0,0,2,7,96,0,57,0,0,0,3,8,0,0,41,0,0,0,0,7,120,4,54],[0,0,0,33,8,96,0,57,0,0,0,5,8,128,2,114,0,0,23,41,0,0,97,61,0,0,0,0,1,18,3,79],[0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16,0,0,0,0,11,167,0,25,0,0,0,0,10,161,3,79],[0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57,0,0,0,0,10,137,0,75],[0,0,23,33,0,0,65,61,0,0,0,0,1,0,0,75,0,0,23,43,0,0,97,61,0,0,0,3,1,0,0,41],[0,0,0,0,1,1,4,51,0,0,0,0,1,1,0,75,0,0,1,193,0,0,97,61,0,0,0,0,1,7,4,51],[0,0,7,167,1,16,1,151,0,0,0,248,8,96,2,16,0,0,0,0,1,24,1,159,0,0,7,169,1,16,0,65],[0,0,0,0,0,23,4,53,0,0,0,3,1,96,2,16,0,0,0,248,1,16,0,137,0,0,0,0,5,21,1,207],[0,0,0,255,1,16,0,140,0,0,0,0,5,0,32,25,0,0,0,3,1,0,0,41,0,0,0,33,1,16,0,57],[0,0,24,60,0,0,1,61,0,0,0,56,8,80,0,140,0,0,23,141,0,0,65,61,0,0,0,32,10,80,2,112],[0,0,7,155,8,80,0,156,0,0,0,0,10,5,160,25,0,0,7,155,8,80,0,156,0,0,0,0,11,0,0,25],[0,0,0,4,11,0,32,57,0,0,0,2,8,176,1,191,0,0,255,255,13,160,0,140,0,0,0,0,8,11,160,25],[0,0,0,16,11,160,2,112,0,0,0,0,11,10,160,25,0,0,0,255,10,176,0,140,0,0,0,0,10,0,0,25],[0,0,0,1,10,0,32,57,0,0,7,166,11,112,0,156,0,0,1,89,0,0,33,61,0,0,0,0,8,168,1,159],[0,0,0,64,10,112,0,57,0,0,0,64,0,160,4,63,0,0,0,0,11,33,3,79,0,0,0,2,10,128,0,58],[0,0,0,0,10,167,4,54,0,0,0,0,11,176,3,80,0,0,0,0,11,11,4,59,0,0,0,0,0,186,4,53],[0,0,1,193,0,0,97,61,0,0,7,167,11,176,1,151,0,0,0,248,13,128,2,16,0,0,0,0,11,189,1,159],[0,0,7,171,11,176,1,199,0,0,0,0,0,186,4,53,0,0,0,3,8,128,2,16,0,0,0,248,8,128,1,95],[0,0,0,0,8,133,1,207,0,0,0,33,10,112,0,57,0,0,0,0,0,138,4,53,0,0,0,0,8,7,0,25],[0,0,23,158,0,0,1,61,0,0,0,56,8,80,0,140,0,0,24,108,0,0,65,61,0,0,0,32,10,80,2,112],[0,0,7,155,8,80,0,156,0,0,0,0,10,5,160,25,0,0,7,155,8,80,0,156,0,0,0,0,11,0,0,25],[0,0,0,4,11,0,32,57,0,0,0,2,8,176,1,191,0,0,255,255,13,160,0,140,0,0,0,0,8,11,160,25],[0,0,0,16,11,160,2,112,0,0,0,0,11,10,160,25,0,0,0,255,10,176,0,140,0,0,0,0,10,0,0,25],[0,0,0,1,10,0,32,57,0,0,7,166,11,112,0,156,0,0,1,89,0,0,33,61,0,0,0,0,8,168,1,159],[0,0,0,64,10,112,0,57,0,0,0,64,0,160,4,63,0,0,0,0,11,33,3,79,0,0,0,2,10,128,0,58],[0,0,0,0,10,167,4,54,0,0,0,0,11,176,3,80,0,0,0,0,11,11,4,59,0,0,0,0,0,186,4,53],[0,0,1,193,0,0,97,61,0,0,7,167,11,176,1,151,0,0,0,248,13,128,2,16,0,0,0,0,11,189,1,159],[0,0,7,171,11,176,1,199,0,0,0,0,0,186,4,53,0,0,0,3,8,128,2,16,0,0,0,248,8,128,1,95],[0,0,0,0,8,133,1,207,0,0,0,33,10,112,0,57,0,0,0,0,0,138,4,53,0,0,0,0,8,7,0,25],[0,0,24,125,0,0,1,61,0,0,7,166,8,112,0,156,0,0,1,89,0,0,33,61,0,0,0,64,8,112,0,57],[0,0,0,64,0,128,4,63,0,0,0,0,10,33,3,79,0,0,0,1,8,0,0,58,0,0,0,0,8,135,4,54],[0,0,0,0,10,160,3,80,0,0,0,0,10,10,4,59,0,0,0,0,0,168,4,53,0,0,1,193,0,0,97,61],[0,0,0,248,11,80,2,16,0,0,7,167,10,160,1,151,0,0,0,0,10,186,1,159,0,0,7,160,10,160,1,103],[0,0,0,0,0,168,4,53,0,0,0,0,8,7,0,25,0,0,0,64,7,0,4,61,0,0,7,166,10,112,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,10,112,0,57,0,0,0,64,0,160,4,63,0,0,0,0,13,33,3,79],[0,0,0,1,6,0,0,58,0,7,0,0,0,6,0,29,0,0,0,0,15,103,4,54,0,0,0,0,6,208,3,80],[0,8,0,0,0,6,3,83,0,0,0,0,6,6,4,59,0,9,0,0,0,6,0,29,0,0,0,0,0,111,4,53],[0,0,1,193,0,0,97,61,0,0,0,9,6,0,0,41,0,0,7,167,6,96,1,151,0,6,0,0,0,6,0,29],[0,0,7,172,11,96,1,199,0,0,0,0,0,191,4,53,0,0,0,32,11,192,0,57,0,0,0,0,11,177,3,79],[0,0,0,0,12,11,4,59,0,0,7,160,11,0,0,65,0,0,0,0,15,156,0,75,0,0,0,0,15,0,0,25],[0,0,0,0,15,11,128,25,0,0,7,160,9,144,1,151,0,0,7,160,14,192,1,151,0,0,0,0,10,158,0,75],[0,0,0,0,11,0,128,25,0,0,0,0,9,158,1,63,0,0,7,160,9,144,0,156,0,0,0,0,11,15,192,25],[0,0,0,0,9,11,0,75,0,0,0,12,6,0,0,41,0,0,0,159,0,0,193,61,0,0,0,0,9,108,0,25],[0,0,0,0,10,145,3,79,0,0,0,0,6,10,4,59,0,12,0,0,0,6,0,29,0,0,7,159,10,96,0,156],[0,0,0,159,0,0,33,61,0,0,0,12,6,0,0,41,0,0,0,32,10,96,0,140,0,0,0,159,0,0,65,61],[0,0,0,12,2,32,0,106,0,0,0,32,6,144,0,57,0,0,7,160,9,0,0,65,0,0,0,0,10,38,0,75],[0,0,0,0,10,0,0,25,0,0,0,0,10,9,32,25,0,0,7,160,2,32,1,151,0,4,0,0,0,6,0,29],[0,0,7,160,11,96,1,151,0,0,0,0,12,43,0,75,0,0,0,0,9,0,128,25,0,0,0,0,2,43,1,63],[0,0,7,160,2,32,0,156,0,0,0,0,9,10,192,25,0,0,0,0,2,9,0,75,0,0,0,159,0,0,193,61],[0,0,0,4,9,16,3,96,0,0,0,64,2,0,4,61,0,0,0,0,6,9,4,59,0,5,0,0,0,6,0,29],[0,0,0,128,10,96,0,140,0,0,0,32,15,32,0,57,0,0,25,8,0,0,65,61,0,0,0,5,6,0,0,41],[0,0,0,128,10,96,2,112,0,0,7,168,11,96,0,156,0,0,0,0,10,6,160,25,0,0,7,168,11,96,0,156],[0,0,0,0,11,0,0,25,0,0,0,16,11,0,32,57,0,0,0,8,12,176,1,191,0,0,7,159,14,160,0,156],[0,0,0,0,12,11,160,25,0,0,0,64,11,160,2,112,0,0,7,159,14,160,0,156,0,0,0,0,11,10,160,25],[0,0,0,4,14,192,1,191,0,0,7,155,10,176,0,156,0,0,0,0,14,12,160,25,0,0,0,32,12,176,2,112],[0,0,7,155,10,176,0,156,0,0,0,0,12,11,160,25,0,0,0,2,10,224,1,191,0,0,255,255,11,192,0,140],[0,0,0,0,10,14,160,25,0,0,0,16,11,192,2,112,0,0,0,0,11,12,160,25,0,0,0,255,11,176,0,140],[0,0,0,1,10,160,32,57,0,0,0,65,11,160,0,57,0,0,0,0,11,59,1,111,0,0,0,0,12,178,0,25],[0,0,0,0,11,44,0,75,0,0,0,0,14,0,0,25,0,0,0,1,14,0,64,57,0,0,7,159,11,192,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,11,224,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,192,4,63],[0,0,0,2,11,160,0,57,0,0,0,0,0,178,4,53,0,0,0,33,11,160,0,57,0,0,0,5,14,176,2,114],[0,0,24,22,0,0,97,61,0,0,0,0,12,0,0,25,0,0,0,5,11,192,2,16,0,0,0,0,9,191,0,25],[0,0,0,0,11,189,3,79,0,0,0,0,11,11,4,59,0,0,0,0,0,185,4,53,0,0,0,1,12,192,0,57],[0,0,0,0,9,236,0,75,0,0,24,14,0,0,65,61,0,0,0,0,6,0,0,75,0,0,24,24,0,0,97,61],[0,0,0,0,9,2,4,51,0,0,0,0,9,9,0,75,0,0,1,193,0,0,97,61,0,0,0,0,9,15,4,51],[0,0,7,167,9,144,1,151,0,0,0,248,11,160,2,16,0,0,0,0,9,155,1,159,0,0,7,169,9,144,0,65],[0,0,0,0,0,159,4,53,0,0,0,3,9,160,2,16,0,0,0,248,9,144,0,137,0,0,0,5,10,144,1,239],[0,0,0,255,9,144,0,140,0,0,0,0,10,0,32,25,0,0,0,33,9,32,0,57,0,0,0,0,0,169,4,53],[0,0,25,25,0,0,1,61,0,0,0,3,6,0,0,41,0,0,7,166,6,96,0,156,0,0,1,89,0,0,33,61],[0,0,0,3,7,0,0,41,0,0,0,64,6,112,0,57,0,0,0,64,0,96,4,63,0,0,0,0,6,18,3,79],[0,0,0,1,1,0,0,58,0,0,0,0,1,23,4,54,0,0,0,0,6,96,3,80,0,0,0,0,6,6,4,59],[0,0,0,0,0,97,4,53,0,0,1,193,0,0,97,61,0,0,0,248,7,80,2,16,0,0,7,160,8,0,0,65],[0,0,0,0,5,5,0,75,0,0,0,0,8,7,192,25,0,0,7,167,5,96,1,151,0,0,0,0,5,133,1,159],[0,0,0,0,0,81,4,53,0,0,0,65,1,48,0,140,0,0,1,193,0,0,65,61,0,0,0,32,1,64,0,57],[0,0,0,0,1,18,3,79,0,0,0,0,1,1,4,59,0,0,0,248,1,16,2,112,0,2,0,0,0,1,0,29],[0,0,0,27,1,16,0,138,0,0,0,2,1,16,0,140,0,0,29,6,0,0,129,61,0,0,0,13,1,0,0,41],[0,1,1,68,0,16,0,61,0,0,0,1,1,32,3,96,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75],[0,0,26,146,0,0,97,61,0,0,7,164,1,0,0,65,0,0,0,0,0,16,4,57,0,0,7,155,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,7,155,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,7,165,1,16,1,199,0,0,128,11,2,0,0,57,30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,24,107,0,0,97,61,0,0,0,0,2,1,4,59,0,0,0,1,1,32,2,16,0,0,0,0,3,2,0,75],[0,0,24,99,0,0,97,61,0,0,0,9,3,0,0,138,0,0,0,0,3,49,0,75,0,0,24,103,0,0,33,61],[0,0,0,0,50,33,0,217,0,0,0,2,2,32,0,140,0,0,24,103,0,0,193,61,0,0,0,2,1,16,0,41],[0,0,0,8,3,16,0,57,0,0,0,2,1,48,0,108,0,0,25,110,0,0,129,61,0,0,7,195,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57,0,0,1,196,0,0,1,61,0,0,0,0,0,1,4,47],[0,0,7,166,8,112,0,156,0,0,1,89,0,0,33,61,0,0,0,64,8,112,0,57,0,0,0,64,0,128,4,63],[0,0,0,0,10,33,3,79,0,0,0,1,8,0,0,58,0,0,0,0,8,135,4,54,0,0,0,0,10,160,3,80],[0,0,0,0,10,10,4,59,0,0,0,0,0,168,4,53,0,0,1,193,0,0,97,61,0,0,0,248,11,80,2,16],[0,0,7,167,10,160,1,151,0,0,0,0,10,186,1,159,0,0,7,160,10,160,1,103,0,0,0,0,0,168,4,53],[0,0,0,0,8,7,0,25,0,0,0,64,7,0,4,61,0,0,7,166,10,112,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,10,112,0,57,0,0,0,64,0,160,4,63,0,0,0,0,13,33,3,79,0,0,0,1,6,0,0,58],[0,9,0,0,0,6,0,29,0,0,0,0,10,103,4,54,0,0,0,0,6,208,3,80,0,7,0,0,0,6,3,83],[0,0,0,0,6,6,4,59,0,8,0,0,0,6,0,29,0,0,0,0,0,106,4,53,0,0,1,193,0,0,97,61],[0,0,0,8,6,0,0,41,0,0,7,167,6,96,1,151,0,5,0,0,0,6,0,29,0,0,7,172,15,96,1,199],[0,0,0,0,0,250,4,53,0,0,0,32,10,192,0,57,0,0,0,0,10,161,3,79,0,0,0,0,10,10,4,59],[0,0,7,160,12,0,0,65,0,0,0,0,15,154,0,75,0,0,0,0,15,0,0,25,0,0,0,0,15,12,128,25],[0,0,7,160,9,144,1,151,0,0,7,160,14,160,1,151,0,0,0,0,11,158,0,75,0,0,0,0,12,0,128,25],[0,0,0,0,9,158,1,63,0,0,7,160,9,144,0,156,0,0,0,0,12,15,192,25,0,0,0,0,9,12,0,75],[0,0,0,12,6,0,0,41,0,0,0,159,0,0,193,61,0,0,0,0,9,106,0,25,0,0,0,0,10,145,3,79],[0,0,0,0,6,10,4,59,0,12,0,0,0,6,0,29,0,0,7,159,10,96,0,156,0,0,0,159,0,0,33,61],[0,0,0,12,6,0,0,41,0,0,0,32,10,96,0,140,0,0,0,159,0,0,65,61,0,0,0,12,2,32,0,106],[0,0,0,32,6,144,0,57,0,0,7,160,9,0,0,65,0,0,0,0,10,38,0,75,0,0,0,0,10,0,0,25],[0,0,0,0,10,9,32,25,0,0,7,160,2,32,1,151,0,4,0,0,0,6,0,29,0,0,7,160,11,96,1,151],[0,0,0,0,14,43,0,75,0,0,0,0,9,0,128,25,0,0,0,0,2,43,1,63,0,0,7,160,2,32,0,156],[0,0,0,0,9,10,192,25,0,0,0,0,2,9,0,75,0,0,0,159,0,0,193,61,0,0,0,4,9,16,3,96],[0,0,0,64,2,0,4,61,0,0,0,0,6,9,4,59,0,6,0,0,0,6,0,29,0,0,0,128,10,96,0,140],[0,0,0,32,15,32,0,57,0,0,25,186,0,0,65,61,0,0,0,6,6,0,0,41,0,0,0,128,10,96,2,112],[0,0,7,168,11,96,0,156,0,0,0,0,10,6,160,25,0,0,7,168,11,96,0,156,0,0,0,0,11,0,0,25],[0,0,0,16,11,0,32,57,0,0,0,8,14,176,1,191,0,0,7,159,12,160,0,156,0,0,0,0,14,11,160,25],[0,0,0,64,11,160,2,112,0,0,7,159,12,160,0,156,0,0,0,0,11,10,160,25,0,0,0,4,10,224,1,191],[0,0,7,155,12,176,0,156,0,0,0,0,10,14,160,25,0,0,0,32,12,176,2,112,0,0,7,155,14,176,0,156],[0,0,0,0,12,11,160,25,0,0,0,2,11,160,1,191,0,0,255,255,14,192,0,140,0,0,0,0,11,10,160,25],[0,0,0,16,10,192,2,112,0,0,0,0,10,12,160,25,0,0,0,255,10,160,0,140,0,0,0,1,11,176,32,57],[0,0,0,65,10,176,0,57,0,0,0,0,10,58,1,111,0,0,0,0,10,162,0,25,0,0,0,0,12,42,0,75],[0,0,0,0,14,0,0,25,0,0,0,1,14,0,64,57,0,0,7,159,12,160,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,12,224,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,160,4,63,0,0,0,2,10,176,0,57],[0,0,0,0,0,162,4,53,0,0,0,33,10,176,0,57,0,0,0,5,10,160,2,114,0,0,24,245,0,0,97,61],[0,0,0,0,14,0,0,25,0,0,0,5,12,224,2,16,0,0,0,0,9,207,0,25,0,0,0,0,12,205,3,79],[0,0,0,0,12,12,4,59,0,0,0,0,0,201,4,53,0,0,0,1,14,224,0,57,0,0,0,0,9,174,0,75],[0,0,24,237,0,0,65,61,0,0,0,0,6,0,0,75,0,0,24,247,0,0,97,61,0,0,0,0,9,2,4,51],[0,0,0,0,9,9,0,75,0,0,1,193,0,0,97,61,0,0,0,0,9,15,4,51,0,0,7,167,9,144,1,151],[0,0,0,248,10,176,2,16,0,0,0,0,9,154,1,159,0,0,7,169,9,144,0,65,0,0,0,0,0,159,4,53],[0,0,0,3,9,176,2,16,0,0,0,248,9,144,0,137,0,0,0,6,10,144,1,239,0,0,0,255,9,144,0,140],[0,0,0,0,10,0,32,25,0,0,0,33,9,32,0,57,0,0,0,0,0,169,4,53,0,0,25,203,0,0,1,61],[0,0,7,166,9,32,0,156,0,0,1,89,0,0,33,61,0,0,0,64,9,32,0,57,0,0,0,64,0,144,4,63],[0,0,0,9,6,0,0,41,0,0,0,0,0,111,4,53,0,0,0,7,6,0,0,41,0,0,0,0,0,98,4,53],[0,0,0,0,9,6,0,75,0,0,1,193,0,0,97,61,0,0,0,5,6,0,0,41,0,0,0,248,9,96,2,16],[0,0,7,160,10,0,0,65,0,0,0,0,11,6,0,75,0,0,0,0,10,9,192,25,0,0,0,6,9,160,1,175],[0,0,0,0,0,159,4,53,0,0,0,12,6,0,0,41,0,0,0,64,9,96,0,140,0,0,0,159,0,0,65,61],[0,0,0,64,9,0,4,61,0,0,0,4,6,0,0,41,0,5,0,32,0,96,0,61,0,0,0,5,10,16,3,96],[0,0,0,0,6,10,4,59,0,9,0,0,0,6,0,29,0,0,0,128,10,96,0,140,0,0,0,32,14,144,0,57],[0,0,26,32,0,0,65,61,0,0,0,9,6,0,0,41,0,0,0,128,10,96,2,112,0,0,7,168,11,96,0,156],[0,0,0,0,10,6,160,25,0,0,7,168,11,96,0,156,0,0,0,0,11,0,0,25,0,0,0,16,11,0,32,57],[0,0,0,8,12,176,1,191,0,0,7,159,15,160,0,156,0,0,0,0,12,11,160,25,0,0,0,64,11,160,2,112],[0,0,7,159,15,160,0,156,0,0,0,0,11,10,160,25,0,0,0,4,15,192,1,191,0,0,7,155,10,176,0,156],[0,0,0,0,15,12,160,25,0,0,0,32,12,176,2,112,0,0,7,155,10,176,0,156,0,0,0,0,12,11,160,25],[0,0,0,2,6,240,1,191,0,0,255,255,11,192,0,140,0,0,0,0,6,15,160,25,0,0,0,16,11,192,2,112],[0,0,0,0,11,12,160,25,0,0,0,255,11,176,0,140,0,0,0,1,6,96,32,57,0,6,0,0,0,6,0,29],[0,0,0,65,11,96,0,57,0,0,0,0,11,59,1,111,0,0,0,0,12,185,0,25,0,0,0,0,11,156,0,75],[0,0,0,0,15,0,0,25,0,0,0,1,15,0,64,57,0,0,7,159,11,192,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,11,240,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,192,4,63,0,0,0,6,6,0,0,41],[0,0,0,2,11,96,0,57,0,0,0,0,0,185,4,53,0,0,0,33,11,96,0,57,0,0,0,5,12,176,2,114],[0,0,25,90,0,0,97,61,0,0,0,0,15,0,0,25,0,0,0,5,11,240,2,16,0,0,0,0,10,190,0,25],[0,0,0,0,11,189,3,79,0,0,0,0,11,11,4,59,0,0,0,0,0,186,4,53,0,0,0,1,15,240,0,57],[0,0,0,0,10,207,0,75,0,0,25,82,0,0,65,61,0,0,0,0,6,0,0,75,0,0,25,92,0,0,97,61],[0,0,0,0,10,9,4,51,0,0,0,0,10,10,0,75,0,0,1,193,0,0,97,61,0,0,0,0,10,14,4,51],[0,0,7,167,10,160,1,151,0,0,0,6,6,0,0,41,0,0,0,248,11,96,2,16,0,0,0,0,10,171,1,159],[0,0,7,169,10,160,0,65,0,0,0,0,0,174,4,53,0,0,0,3,10,96,2,16,0,0,0,248,10,160,0,137],[0,0,0,9,11,160,1,239,0,0,0,255,10,160,0,140,0,0,0,0,11,0,32,25,0,0,0,33,10,144,0,57],[0,0,0,0,0,186,4,53,0,0,26,51,0,0,1,61,0,0,0,128,1,48,0,140,0,2,0,0,0,3,0,29],[0,0,26,146,0,0,65,61,0,0,0,128,1,48,2,112,0,0,7,168,2,48,0,156,0,0,0,0,1,3,160,25],[0,0,7,168,2,48,0,156,0,0,0,0,2,0,0,25,0,0,0,16,2,0,32,57,0,0,0,8,4,32,1,191],[0,0,7,159,5,16,0,156,0,0,0,0,4,2,160,25,0,0,0,64,2,16,2,112,0,0,7,159,5,16,0,156],[0,0,0,0,2,1,160,25,0,0,0,4,1,64,1,191,0,0,7,155,5,32,0,156,0,0,0,0,1,4,160,25],[0,0,0,32,4,32,2,112,0,0,7,155,5,32,0,156,0,0,0,0,4,2,160,25,0,0,0,2,5,16,1,191],[0,0,255,255,2,64,0,140,0,0,0,0,5,1,160,25,0,0,0,16,1,64,2,112,0,0,0,0,1,4,160,25],[0,0,0,255,1,16,0,140,0,0,0,1,5,80,32,57,0,0,0,65,1,80,0,57,0,0,0,7,2,16,1,127],[0,0,0,64,1,0,4,61,0,0,0,0,2,33,0,25,0,0,0,0,4,18,0,75,0,0,0,0,4,0,0,25],[0,0,0,1,4,0,64,57,0,0,7,159,6,32,0,156,0,0,1,89,0,0,33,61,0,0,0,1,4,64,1,144],[0,0,1,89,0,0,193,61,0,0,0,64,0,32,4,63,0,0,0,2,2,80,0,57,0,0,0,0,6,33,4,54],[0,0,0,1,2,0,3,103,0,0,0,0,4,0,0,49,0,0,0,33,7,80,0,57,0,0,0,5,7,112,2,114],[0,0,25,167,0,0,97,61,0,0,0,0,8,66,3,79,0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16],[0,0,0,0,11,166,0,25,0,0,0,0,10,168,3,79,0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53],[0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75,0,0,25,159,0,0,65,61,0,0,0,0,7,0,0,75],[0,0,25,169,0,0,97,61,0,0,0,0,7,1,4,51,0,0,0,0,7,7,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,7,6,4,51,0,0,7,167,7,112,1,151,0,0,0,248,8,80,2,16,0,0,0,0,7,120,1,159],[0,0,7,169,7,112,0,65,0,0,0,0,0,118,4,53,0,0,0,3,5,80,2,16,0,0,0,248,5,80,0,137],[0,0,0,0,3,83,1,207,0,0,0,255,5,80,0,140,0,0,0,0,3,0,32,25,0,0,0,33,5,16,0,57],[0,0,0,0,0,53,4,53,0,0,26,168,0,0,1,61,0,0,7,166,9,32,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,9,32,0,57,0,0,0,64,0,144,4,63,0,0,0,8,6,0,0,41,0,0,0,0,0,111,4,53],[0,0,0,9,6,0,0,41,0,0,0,0,0,98,4,53,0,0,0,0,9,6,0,75,0,0,1,193,0,0,97,61],[0,0,0,6,6,0,0,41,0,0,0,248,9,96,2,16,0,0,7,160,10,0,0,65,0,0,0,0,11,6,0,75],[0,0,0,0,10,9,192,25,0,0,0,5,9,160,1,175,0,0,0,0,0,159,4,53,0,0,0,12,6,0,0,41],[0,0,0,64,9,96,0,140,0,0,0,159,0,0,65,61,0,0,0,64,9,0,4,61,0,0,0,4,6,0,0,41],[0,5,0,32,0,96,0,61,0,0,0,5,10,16,3,96,0,0,0,0,6,10,4,59,0,8,0,0,0,6,0,29],[0,0,0,128,10,96,0,140,0,0,0,32,14,144,0,57,0,0,27,17,0,0,65,61,0,0,0,8,6,0,0,41],[0,0,0,128,10,96,2,112,0,0,7,168,11,96,0,156,0,0,0,0,10,6,160,25,0,0,7,168,11,96,0,156],[0,0,0,0,11,0,0,25,0,0,0,16,11,0,32,57,0,0,0,8,12,176,1,191,0,0,7,159,15,160,0,156],[0,0,0,0,12,11,160,25,0,0,0,64,11,160,2,112,0,0,7,159,15,160,0,156,0,0,0,0,11,10,160,25],[0,0,0,4,10,192,1,191,0,0,7,155,15,176,0,156,0,0,0,0,10,12,160,25,0,0,0,32,12,176,2,112],[0,0,7,155,15,176,0,156,0,0,0,0,12,11,160,25,0,0,0,2,6,160,1,191,0,0,255,255,15,192,0,140],[0,0,0,0,6,10,160,25,0,0,0,16,10,192,2,112,0,0,0,0,10,12,160,25,0,0,0,255,10,160,0,140],[0,0,0,1,6,96,32,57,0,6,0,0,0,6,0,29,0,0,0,65,10,96,0,57,0,0,0,0,10,58,1,111],[0,0,0,0,10,169,0,25,0,0,0,0,12,154,0,75,0,0,0,0,12,0,0,25,0,0,0,1,12,0,64,57],[0,0,7,159,15,160,0,156,0,0,1,89,0,0,33,61,0,0,0,1,12,192,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,160,4,63,0,0,0,6,6,0,0,41,0,0,0,2,10,96,0,57,0,0,0,0,0,169,4,53],[0,0,0,33,10,96,0,57,0,0,0,5,10,160,2,114,0,0,26,12,0,0,97,61,0,0,0,0,12,0,0,25],[0,0,0,5,15,192,2,16,0,0,0,0,11,254,0,25,0,0,0,0,15,253,3,79,0,0,0,0,15,15,4,59],[0,0,0,0,0,251,4,53,0,0,0,1,12,192,0,57,0,0,0,0,11,172,0,75,0,0,26,4,0,0,65,61],[0,0,0,0,6,0,0,75,0,0,26,14,0,0,97,61,0,0,0,0,10,9,4,51,0,0,0,0,10,10,0,75],[0,0,1,193,0,0,97,61,0,0,0,0,10,14,4,51,0,0,7,167,10,160,1,151,0,0,0,6,6,0,0,41],[0,0,0,248,11,96,2,16,0,0,0,0,10,171,1,159,0,0,7,169,10,160,0,65,0,0,0,0,0,174,4,53],[0,0,0,3,10,96,2,16,0,0,0,248,10,160,0,137,0,0,0,8,11,160,1,239,0,0,0,255,10,160,0,140],[0,0,0,0,11,0,32,25,0,0,0,33,10,144,0,57,0,0,0,0,0,186,4,53,0,0,27,36,0,0,1,61],[0,0,7,166,10,144,0,156,0,0,1,89,0,0,33,61,0,0,0,64,10,144,0,57,0,0,0,64,0,160,4,63],[0,0,0,7,11,0,0,41,0,0,0,0,0,185,4,53,0,0,0,8,6,0,3,95,0,0,0,0,10,6,4,59],[0,0,0,0,0,174,4,53,0,0,0,0,11,11,0,75,0,0,1,193,0,0,97,61,0,0,0,9,6,0,0,41],[0,0,0,248,11,96,2,16,0,0,7,160,12,0,0,65,0,0,0,0,13,6,0,75,0,0,0,0,12,11,192,25],[0,0,7,167,10,160,1,151,0,0,0,0,10,202,1,159,0,0,0,0,0,174,4,53,0,0,0,12,6,0,0,41],[0,0,0,65,10,96,0,140,0,0,1,193,0,0,65,61,0,0,0,5,6,0,0,41,0,0,0,32,10,96,0,57],[0,0,0,0,11,161,3,79,0,0,0,0,10,0,4,21,0,0,0,17,10,160,0,138,0,0,0,32,10,160,0,201],[0,0,7,160,13,0,0,65,0,0,0,0,11,11,4,59,0,0,0,248,12,176,2,112,0,0,0,27,11,192,0,140],[0,0,26,71,0,0,97,61,0,0,0,0,10,0,4,21,0,0,0,16,10,160,0,138,0,0,0,32,10,160,0,201],[0,0,7,174,13,0,0,65,0,0,0,28,11,192,0,140,0,0,29,6,0,0,193,61,0,0,0,64,12,0,4,61],[0,0,7,166,11,192,0,156,0,0,1,89,0,0,33,61,0,0,0,64,11,192,0,57,0,0,0,64,0,176,4,63],[0,0,0,7,11,0,0,41,0,0,0,0,14,188,4,54,0,0,0,8,6,0,3,95,0,0,0,0,15,6,4,59],[0,0,0,0,0,254,4,53,0,0,0,0,11,11,0,75,0,0,1,193,0,0,97,61,0,0,7,167,11,240,1,151],[0,0,0,0,11,219,1,159,0,0,0,0,0,190,4,53,0,0,0,0,11,4,4,51,0,0,0,0,13,8,4,51],[0,0,0,5,10,160,2,112,0,0,0,0,10,12,0,31,0,0,0,0,10,93,0,25,0,0,0,0,10,186,0,25],[0,0,0,0,11,7,4,51,0,0,0,0,10,186,0,25,0,0,0,0,11,2,4,51,0,0,0,0,10,186,0,25],[0,0,0,0,11,9,4,51,0,0,0,0,10,186,0,25,0,0,0,0,11,12,4,51,0,0,0,0,10,186,0,25],[0,0,0,64,13,0,4,61,0,0,7,159,6,160,1,151,0,9,0,0,0,6,0,29,0,0,0,56,11,96,0,140],[0,6,0,64,0,208,0,61,0,12,0,32,0,208,0,61,0,0,27,129,0,0,65,61,0,0,0,9,6,0,0,41],[0,0,0,32,15,96,2,112,0,0,7,155,11,96,0,156,0,0,0,0,15,6,160,25,0,0,7,155,11,96,0,156],[0,0,0,0,14,0,0,25,0,0,0,4,14,0,32,57,0,0,0,2,11,224,1,191,0,0,255,255,10,240,0,140],[0,0,0,0,11,14,160,25,0,0,0,16,10,240,2,112,0,0,0,0,10,15,160,25,0,0,0,255,10,160,0,140],[0,0,0,0,15,0,0,25,0,0,0,1,15,0,32,57,0,0,7,166,10,208,0,156,0,0,1,89,0,0,33,61],[0,0,0,0,11,251,1,159,0,0,0,6,6,0,0,41,0,0,0,64,0,96,4,63,0,0,0,2,10,176,0,58],[0,0,0,0,0,173,4,53,0,0,0,8,6,0,3,95,0,0,0,0,15,6,4,59,0,0,0,12,6,0,0,41],[0,0,0,0,0,246,4,53,0,0,1,193,0,0,97,61,0,0,7,167,10,240,1,151,0,0,0,248,14,176,2,16],[0,0,0,0,10,174,1,159,0,0,7,173,10,160,1,199,0,0,0,12,6,0,0,41,0,0,0,0,0,166,4,53],[0,0,0,3,10,176,2,16,0,0,0,248,10,160,1,95,0,0,0,9,10,160,1,239,0,0,0,33,11,208,0,57],[0,0,0,0,0,171,4,53,0,0,27,148,0,0,1,61,0,0,0,64,1,0,4,61,0,0,7,166,2,16,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,2,16,0,57,0,0,0,64,0,32,4,63,0,0,0,1,2,0,0,58],[0,0,0,0,3,33,4,54,0,0,0,0,4,0,0,49,0,0,0,1,2,0,3,103,0,0,0,0,5,66,3,79],[0,0,0,0,5,80,3,80,0,0,0,0,5,5,4,59,0,0,0,0,0,83,4,53,0,0,1,193,0,0,97,61],[0,0,0,2,8,0,0,41,0,0,0,248,6,128,2,16,0,0,7,160,7,0,0,65,0,0,0,0,8,8,0,75],[0,0,0,0,7,6,192,25,0,0,7,167,5,80,1,151,0,0,0,0,5,117,1,159,0,0,0,0,0,83,4,53],[0,0,0,1,3,0,0,41,0,0,0,128,3,48,0,57,0,0,0,0,3,50,3,79,0,0,0,13,5,64,0,106],[0,0,0,35,5,80,0,138,0,0,0,0,3,3,4,59,0,0,7,160,6,0,0,65,0,0,0,0,7,83,0,75],[0,0,0,0,7,0,0,25,0,0,0,0,7,6,128,25,0,0,7,160,5,80,1,151,0,0,7,160,8,48,1,151],[0,0,0,0,9,88,0,75,0,0,0,0,6,0,128,25,0,0,0,0,5,88,1,63,0,0,7,160,5,80,0,156],[0,0,0,0,6,7,192,25,0,0,0,0,5,6,0,75,0,0,0,12,6,0,0,41,0,0,0,159,0,0,193,61],[0,0,0,10,5,0,0,41,0,0,0,0,5,5,4,51,0,0,0,9,7,0,0,41,0,0,0,0,7,7,4,51],[0,0,0,8,8,0,0,41,0,0,0,0,8,8,4,51,0,0,0,6,9,0,0,41,0,0,0,0,9,9,4,51],[0,0,0,5,10,0,0,41,0,0,0,0,10,10,4,51,0,0,0,0,6,99,0,25,0,0,0,0,3,98,3,79],[0,0,0,0,3,3,4,59,0,0,7,159,11,48,0,156,0,0,0,159,0,0,33,61,0,0,0,0,11,52,0,73],[0,0,0,32,6,96,0,57,0,0,7,160,12,0,0,65,0,0,0,0,13,182,0,75,0,0,0,0,13,0,0,25],[0,0,0,0,13,12,32,25,0,0,7,160,11,176,1,151,0,0,7,160,14,96,1,151,0,0,0,0,15,190,0,75],[0,0,0,0,12,0,128,25,0,0,0,0,11,190,1,63,0,0,7,160,11,176,0,156,0,0,0,0,12,13,192,25],[0,0,0,0,11,12,0,75,0,0,0,159,0,0,193,61,0,0,0,0,5,87,0,25,0,0,0,0,5,133,0,25],[0,0,0,0,5,149,0,25,0,0,0,0,5,165,0,25,0,0,0,0,5,53,0,25,0,0,0,4,7,0,0,41],[0,0,0,0,7,7,4,51,0,0,0,0,5,117,0,25,0,0,0,3,7,0,0,41,0,0,0,0,7,7,4,51],[0,0,0,0,5,117,0,25,0,0,0,0,7,1,4,51,0,0,0,0,5,117,0,25,0,0,0,64,7,0,4,61],[0,0,7,159,5,80,1,151,0,0,0,56,8,80,0,140,0,0,0,64,9,112,0,57,0,0,0,0,8,66,3,79],[0,0,0,32,4,112,0,57,0,0,28,57,0,0,65,61,0,0,0,32,11,80,2,112,0,0,7,155,10,80,0,156],[0,0,0,0,11,5,160,25,0,0,7,155,10,80,0,156,0,0,0,0,12,0,0,25,0,0,0,4,12,0,32,57],[0,0,0,2,10,192,1,191,0,0,255,255,13,176,0,140,0,0,0,0,10,12,160,25,0,0,0,16,12,176,2,112],[0,0,0,0,12,11,160,25,0,0,0,255,11,192,0,140,0,0,0,0,11,0,0,25,0,0,0,1,11,0,32,57],[0,0,7,166,12,112,0,156,0,0,1,89,0,0,33,61,0,0,0,0,10,186,1,159,0,0,0,64,0,144,4,63],[0,0,0,2,9,160,0,58,0,0,0,0,0,151,4,53,0,0,0,0,8,128,3,80,0,0,0,0,8,8,4,59],[0,0,0,0,0,132,4,53,0,0,1,193,0,0,97,61,0,0,7,167,8,128,1,151,0,0,0,248,9,160,2,16],[0,0,0,0,8,137,1,159,0,0,7,173,8,128,1,199,0,0,0,0,0,132,4,53,0,0,0,3,4,160,2,16],[0,0,0,248,4,64,1,95,0,0,0,0,4,69,1,207,0,0,0,33,5,112,0,57,0,0,0,0,0,69,4,53],[0,0,28,71,0,0,1,61,0,0,7,166,10,144,0,156,0,0,1,89,0,0,33,61,0,0,0,64,10,144,0,57],[0,0,0,64,0,160,4,63,0,0,0,9,6,0,0,41,0,0,0,0,0,105,4,53,0,0,0,7,10,0,3,95],[0,0,0,0,10,10,4,59,0,0,0,0,0,174,4,53,0,0,0,0,11,6,0,75,0,0,1,193,0,0,97,61],[0,0,0,8,6,0,0,41,0,0,0,248,11,96,2,16,0,0,7,160,12,0,0,65,0,0,0,0,13,6,0,75],[0,0,0,0,12,11,192,25,0,0,7,167,10,160,1,151,0,0,0,0,10,202,1,159,0,0,0,0,0,174,4,53],[0,0,0,12,6,0,0,41,0,0,0,65,10,96,0,140,0,0,1,193,0,0,65,61,0,0,0,5,6,0,0,41],[0,0,0,32,10,96,0,57,0,0,0,0,10,161,3,79,0,0,0,0,11,0,4,21,0,0,0,15,11,176,0,138],[0,0,0,32,11,176,0,201,0,0,7,160,13,0,0,65,0,0,0,0,10,10,4,59,0,0,0,248,10,160,2,112],[0,0,0,27,12,160,0,140,0,0,27,56,0,0,97,61,0,0,0,0,11,0,4,21,0,0,0,14,11,176,0,138],[0,0,0,32,11,176,0,201,0,0,7,174,13,0,0,65,0,0,0,28,10,160,0,140,0,0,29,6,0,0,193,61],[0,0,0,64,12,0,4,61,0,0,7,166,10,192,0,156,0,0,1,89,0,0,33,61,0,0,0,64,10,192,0,57],[0,0,0,64,0,160,4,63,0,0,0,9,6,0,0,41,0,0,0,0,10,108,4,54,0,0,0,7,14,0,3,95],[0,0,0,0,14,14,4,59,0,8,0,0,0,14,0,29,0,0,0,0,0,234,4,53,0,0,0,0,14,6,0,75],[0,0,1,193,0,0,97,61,0,0,0,8,6,0,0,41,0,7,7,167,0,96,1,155,0,0,0,7,13,208,1,175],[0,0,0,0,0,218,4,53,0,0,0,0,10,4,4,51,0,0,0,0,13,8,4,51,0,0,0,5,11,176,2,112],[0,0,0,0,11,12,0,31,0,0,0,0,11,93,0,25,0,0,0,0,10,171,0,25,0,0,0,0,11,7,4,51],[0,0,0,0,10,186,0,25,0,0,0,0,11,2,4,51,0,0,0,0,10,186,0,25,0,0,0,0,11,9,4,51],[0,0,0,0,10,186,0,25,0,0,0,0,11,12,4,51,0,0,0,0,10,186,0,25,0,0,0,64,13,0,4,61],[0,0,7,159,15,160,1,151,0,0,0,56,10,240,0,140,0,6,0,64,0,208,0,61,0,12,0,32,0,208,0,61],[0,0,29,13,0,0,65,61,0,0,0,32,14,240,2,112,0,0,7,155,10,240,0,156,0,0,0,0,14,15,160,25],[0,0,7,155,10,240,0,156,0,0,0,0,6,0,0,25,0,0,0,4,6,0,32,57,0,0,0,2,10,96,1,191],[0,0,255,255,11,224,0,140,0,0,0,0,10,6,160,25,0,0,0,16,11,224,2,112,0,0,0,0,11,14,160,25],[0,0,0,255,11,176,0,140,0,0,0,0,14,0,0,25,0,0,0,1,14,0,32,57,0,0,7,166,11,208,0,156],[0,0,1,89,0,0,33,61,0,0,0,0,10,234,1,159,0,0,0,6,6,0,0,41,0,0,0,64,0,96,4,63],[0,0,0,8,6,0,0,41,0,0,0,12,11,0,0,41,0,0,0,0,0,107,4,53,0,0,0,2,11,160,0,58],[0,0,0,0,0,189,4,53,0,0,1,193,0,0,97,61,0,0,0,248,11,160,2,16,0,0,0,7,11,176,1,175],[0,0,7,173,11,176,1,199,0,0,0,12,6,0,0,41,0,0,0,0,0,182,4,53,0,0,0,3,10,160,2,16],[0,0,0,248,10,160,1,95,0,0,0,0,10,175,1,207,0,0,0,33,11,208,0,57,0,0,0,0,0,171,4,53],[0,0,29,29,0,0,1,61,0,0,7,166,10,208,0,156,0,0,1,89,0,0,33,61,0,0,0,6,6,0,0,41],[0,0,0,64,0,96,4,63,0,0,0,7,10,0,0,41,0,0,0,0,0,173,4,53,0,0,0,8,6,0,3,95],[0,0,0,0,15,6,4,59,0,0,0,12,6,0,0,41,0,0,0,0,0,246,4,53,0,0,0,0,10,10,0,75],[0,0,1,193,0,0,97,61,0,0,7,167,10,240,1,151,0,0,0,9,6,0,0,41,0,0,0,248,11,96,2,16],[0,0,0,0,10,171,1,159,0,0,7,172,10,160,0,65,0,0,0,12,6,0,0,41,0,0,0,0,0,166,4,53],[0,0,0,64,6,0,4,61,0,0,0,32,10,96,0,57,0,0,7,174,11,0,0,65,0,9,0,0,0,10,0,29],[0,0,0,0,0,186,4,53,0,12,0,0,0,6,0,29,0,0,0,33,14,96,0,57,0,0,0,0,15,13,4,51],[0,0,0,0,11,15,0,75,0,0,27,166,0,0,97,61,0,0,0,0,11,0,0,25,0,0,0,0,10,235,0,25],[0,0,0,32,11,176,0,57,0,0,0,0,6,219,0,25,0,0,0,0,6,6,4,51,0,0,0,0,0,106,4,53],[0,0,0,0,6,251,0,75,0,0,27,159,0,0,65,61,0,0,0,0,13,239,0,25,0,0,0,0,0,13,4,53],[0,0,0,0,14,4,4,51,0,0,0,0,6,14,0,75,0,0,27,179,0,0,97,61,0,0,0,0,11,0,0,25],[0,0,0,0,6,219,0,25,0,0,0,32,11,176,0,57,0,0,0,0,10,75,0,25,0,0,0,0,10,10,4,51],[0,0,0,0,0,166,4,53,0,0,0,0,6,235,0,75,0,0,27,172,0,0,65,61,0,0,0,0,13,222,0,25],[0,0,0,0,0,13,4,53,0,0,0,0,14,8,4,51,0,0,0,0,4,14,0,75,0,0,27,192,0,0,97,61],[0,0,0,0,4,0,0,25,0,0,0,0,6,212,0,25,0,0,0,32,4,64,0,57,0,0,0,0,10,132,0,25],[0,0,0,0,10,10,4,51,0,0,0,0,0,166,4,53,0,0,0,0,6,228,0,75,0,0,27,185,0,0,65,61],[0,0,0,13,4,16,3,96,0,0,0,0,1,222,0,25,0,0,0,31,6,80,1,143,0,0,0,0,0,1,4,53],[0,0,0,5,8,80,2,114,0,0,27,207,0,0,97,61,0,0,0,0,13,0,0,25,0,0,0,5,10,208,2,16],[0,0,0,0,11,161,0,25,0,0,0,0,10,164,3,79,0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53],[0,0,0,1,13,208,0,57,0,0,0,0,10,141,0,75,0,0,27,199,0,0,65,61,0,0,0,0,10,6,0,75],[0,0,27,222,0,0,97,61,0,0,0,5,8,128,2,16,0,0,0,0,4,132,3,79,0,0,0,0,8,129,0,25],[0,0,0,3,6,96,2,16,0,0,0,0,10,8,4,51,0,0,0,0,10,106,1,207,0,0,0,0,10,106,2,47],[0,0,0,0,4,4,4,59,0,0,1,0,6,96,0,137,0,0,0,0,4,100,2,47,0,0,0,0,4,100,1,207],[0,0,0,0,4,164,1,159,0,0,0,0,0,72,4,53,0,0,0,0,1,81,0,25,0,0,0,0,0,1,4,53],[0,0,0,0,4,7,4,51,0,0,0,0,5,4,0,75,0,0,27,235,0,0,97,61,0,0,0,0,5,0,0,25],[0,0,0,0,6,21,0,25,0,0,0,32,5,80,0,57,0,0,0,0,8,117,0,25,0,0,0,0,8,8,4,51],[0,0,0,0,0,134,4,53,0,0,0,0,6,69,0,75,0,0,27,228,0,0,65,61,0,0,0,0,1,20,0,25],[0,0,0,0,0,1,4,53,0,0,0,0,4,12,4,51,0,0,0,0,5,4,0,75,0,0,27,248,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,0,6,21,0,25,0,0,0,32,5,80,0,57,0,0,0,0,7,197,0,25],[0,0,0,0,7,7,4,51,0,0,0,0,0,118,4,53,0,0,0,0,6,69,0,75,0,0,27,241,0,0,65,61],[0,0,0,0,1,20,0,25,0,0,0,0,0,1,4,53,0,0,0,0,4,2,4,51,0,0,0,0,5,4,0,75],[0,0,28,5,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,0,6,21,0,25,0,0,0,32,5,80,0,57],[0,0,0,0,7,37,0,25,0,0,0,0,7,7,4,51,0,0,0,0,0,118,4,53,0,0,0,0,6,69,0,75],[0,0,27,254,0,0,65,61,0,0,0,0,1,20,0,25,0,0,0,0,0,1,4,53,0,0,0,0,2,9,4,51],[0,0,0,0,4,2,0,75,0,0,28,18,0,0,97,61,0,0,0,0,4,0,0,25,0,0,0,0,5,20,0,25],[0,0,0,32,4,64,0,57,0,0,0,0,6,148,0,25,0,0,0,0,6,6,4,51,0,0,0,0,0,101,4,53],[0,0,0,0,5,36,0,75,0,0,28,11,0,0,65,61,0,0,0,0,1,18,0,25,0,0,0,0,0,1,4,53],[0,0,0,12,4,0,0,41,0,0,0,0,1,65,0,73,0,0,0,32,2,16,0,138,0,0,0,0,0,36,4,53],[0,0,0,31,1,16,0,57,0,0,0,0,2,49,1,111,0,0,0,0,1,66,0,25,0,0,0,0,2,33,0,75],[0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,7,159,3,16,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,2,32,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,16,4,63,0,0,7,155,1,0,0,65],[0,0,0,9,3,0,0,41,0,0,7,155,2,48,0,156,0,0,0,0,3,1,128,25,0,0,0,64,2,48,2,16],[0,0,0,12,3,0,0,41,0,0,0,0,3,3,4,51,0,0,7,155,4,48,0,156,0,0,0,0,3,1,128,25],[0,0,0,96,3,48,2,16,0,0,0,0,2,35,1,159,0,0,0,0,3,0,4,20,0,0,7,155,4,48,0,156],[0,0,0,0,3,1,128,25,0,0,0,192,1,48,2,16,0,0,0,0,1,33,1,159,0,0,7,175,1,16,1,199],[0,0,128,16,2,0,0,57,30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144,0,0,0,159,0,0,97,61],[0,0,29,193,0,0,1,61,0,0,7,166,10,112,0,156,0,0,1,89,0,0,33,61,0,0,0,64,0,144,4,63],[0,0,0,1,9,0,0,58,0,0,0,0,0,151,4,53,0,0,0,0,8,128,3,80,0,0,0,0,8,8,4,59],[0,0,0,0,0,132,4,53,0,0,1,193,0,0,97,61,0,0,7,167,8,128,1,151,0,0,0,248,5,80,2,16],[0,0,0,0,5,133,1,159,0,0,7,172,5,80,0,65,0,0,0,0,0,84,4,53,0,0,0,64,4,0,4,61],[0,0,0,32,5,64,0,57,0,0,0,0,8,7,4,51,0,0,0,0,9,8,0,75,0,0,28,84,0,0,97,61],[0,0,0,0,9,0,0,25,0,0,0,0,10,89,0,25,0,0,0,32,9,144,0,57,0,0,0,0,11,121,0,25],[0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53,0,0,0,0,10,137,0,75,0,0,28,77,0,0,65,61],[0,0,0,0,7,88,0,25,0,0,0,0,0,7,4,53,0,0,0,10,8,0,0,41,0,0,0,0,8,8,4,51],[0,0,0,0,9,8,0,75,0,0,28,98,0,0,97,61,0,0,0,0,9,0,0,25,0,0,0,0,10,121,0,25],[0,0,0,32,9,144,0,57,0,0,0,10,11,144,0,41,0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53],[0,0,0,0,10,137,0,75,0,0,28,91,0,0,65,61,0,0,0,0,7,120,0,25,0,0,0,0,0,7,4,53],[0,0,0,9,8,0,0,41,0,0,0,0,8,8,4,51,0,0,0,0,9,8,0,75,0,0,28,112,0,0,97,61],[0,0,0,0,9,0,0,25,0,0,0,0,10,121,0,25,0,0,0,32,9,144,0,57,0,0,0,9,11,144,0,41],[0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53,0,0,0,0,10,137,0,75,0,0,28,105,0,0,65,61],[0,0,0,0,7,120,0,25,0,0,0,0,0,7,4,53,0,0,0,8,8,0,0,41,0,0,0,0,8,8,4,51],[0,0,0,0,9,8,0,75,0,0,28,126,0,0,97,61,0,0,0,0,9,0,0,25,0,0,0,0,10,121,0,25],[0,0,0,32,9,144,0,57,0,0,0,8,11,144,0,41,0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53],[0,0,0,0,10,137,0,75,0,0,28,119,0,0,65,61,0,0,0,0,7,120,0,25,0,0,0,0,0,7,4,53],[0,0,0,6,8,0,0,41,0,0,0,0,8,8,4,51,0,0,0,0,9,8,0,75,0,0,28,140,0,0,97,61],[0,0,0,0,9,0,0,25,0,0,0,0,10,121,0,25,0,0,0,32,9,144,0,57,0,0,0,6,11,144,0,41],[0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53,0,0,0,0,10,137,0,75,0,0,28,133,0,0,65,61],[0,0,0,0,7,120,0,25,0,0,0,0,0,7,4,53,0,0,0,5,8,0,0,41,0,0,0,0,8,8,4,51],[0,0,0,0,9,8,0,75,0,0,28,154,0,0,97,61,0,0,0,0,9,0,0,25,0,0,0,0,10,121,0,25],[0,0,0,32,9,144,0,57,0,0,0,5,11,144,0,41,0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53],[0,0,0,0,10,137,0,75,0,0,28,147,0,0,65,61,0,0,0,0,6,98,3,79,0,0,0,0,2,120,0,25],[0,0,0,31,7,48,1,143,0,0,0,0,0,2,4,53,0,0,0,5,8,48,2,114,0,0,28,169,0,0,97,61],[0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16,0,0,0,0,11,162,0,25,0,0,0,0,10,166,3,79],[0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57,0,0,0,0,10,137,0,75],[0,0,28,161,0,0,65,61,0,0,0,0,9,7,0,75,0,0,28,184,0,0,97,61,0,0,0,5,8,128,2,16],[0,0,0,0,6,134,3,79,0,0,0,0,8,130,0,25,0,0,0,3,7,112,2,16,0,0,0,0,9,8,4,51],[0,0,0,0,9,121,1,207,0,0,0,0,9,121,2,47,0,0,0,0,6,6,4,59,0,0,1,0,7,112,0,137],[0,0,0,0,6,118,2,47,0,0,0,0,6,118,1,207,0,0,0,0,6,150,1,159,0,0,0,0,0,104,4,53],[0,0,0,0,2,50,0,25,0,0,0,0,0,2,4,53,0,0,0,0,3,1,4,51,0,0,0,0,6,3,0,75],[0,0,28,197,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,0,7,38,0,25,0,0,0,32,6,96,0,57],[0,0,0,0,8,22,0,25,0,0,0,0,8,8,4,51,0,0,0,0,0,135,4,53,0,0,0,0,7,54,0,75],[0,0,28,190,0,0,65,61,0,0,0,0,1,35,0,25,0,0,0,0,0,1,4,53,0,0,0,4,2,0,0,41],[0,0,0,0,2,2,4,51,0,0,0,0,3,2,0,75,0,0,28,211,0,0,97,61,0,0,0,0,3,0,0,25],[0,0,0,0,6,19,0,25,0,0,0,32,3,48,0,57,0,0,0,4,7,48,0,41,0,0,0,0,7,7,4,51],[0,0,0,0,0,118,4,53,0,0,0,0,6,35,0,75,0,0,28,204,0,0,65,61,0,0,0,0,1,18,0,25],[0,0,0,0,0,1,4,53,0,0,0,3,2,0,0,41,0,0,0,0,2,2,4,51,0,0,0,0,3,2,0,75],[0,0,28,225,0,0,97,61,0,0,0,0,3,0,0,25,0,0,0,0,6,19,0,25,0,0,0,32,3,48,0,57],[0,0,0,3,7,48,0,41,0,0,0,0,7,7,4,51,0,0,0,0,0,118,4,53,0,0,0,0,6,35,0,75],[0,0,28,218,0,0,65,61,0,0,0,0,1,18,0,25,0,0,0,0,0,1,4,53,0,0,0,0,1,65,0,73],[0,0,0,32,2,16,0,138,0,0,0,0,0,36,4,53,0,0,0,31,1,16,0,57,0,0,0,7,2,16,1,127],[0,0,0,0,1,66,0,25,0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57],[0,0,7,159,3,16,0,156,0,0,1,89,0,0,33,61,0,0,0,1,2,32,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,16,4,63,0,0,7,155,1,0,0,65,0,0,7,155,2,80,0,156,0,0,0,0,5,1,128,25],[0,0,0,64,2,80,2,16,0,0,0,0,3,4,4,51,0,0,7,155,4,48,0,156,0,0,0,0,3,1,128,25],[0,0,0,96,3,48,2,16,0,0,0,0,2,35,1,159,0,0,0,0,3,0,4,20,0,0,7,155,4,48,0,156],[0,0,0,0,3,1,128,25,0,0,0,192,1,48,2,16,0,0,0,0,1,33,1,159,0,0,7,175,1,16,1,199],[0,0,128,16,2,0,0,57,30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144,0,0,0,159,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,11,86,0,0,1,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57],[0,0,7,194,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,15,3,0,0,57],[0,0,12,95,0,0,1,61,0,0,7,166,10,208,0,156,0,0,1,89,0,0,33,61,0,0,0,6,6,0,0,41],[0,0,0,64,0,96,4,63,0,0,0,8,6,0,0,41,0,0,0,12,10,0,0,41,0,0,0,0,0,106,4,53],[0,0,0,9,6,0,0,41,0,0,0,0,0,109,4,53,0,0,0,0,10,6,0,75,0,0,1,193,0,0,97,61],[0,0,0,248,10,240,2,16,0,0,0,7,10,160,1,175,0,0,7,172,10,160,0,65,0,0,0,12,6,0,0,41],[0,0,0,0,0,166,4,53,0,0,0,64,6,0,4,61,0,0,0,32,10,96,0,57,0,0,7,175,11,0,0,65],[0,9,0,0,0,10,0,29,0,0,0,0,0,186,4,53,0,12,0,0,0,6,0,29,0,0,0,33,14,96,0,57],[0,0,0,0,15,13,4,51,0,0,0,0,11,15,0,75,0,0,29,47,0,0,97,61,0,0,0,0,11,0,0,25],[0,0,0,0,10,235,0,25,0,0,0,32,11,176,0,57,0,0,0,0,6,219,0,25,0,0,0,0,6,6,4,51],[0,0,0,0,0,106,4,53,0,0,0,0,6,251,0,75,0,0,29,40,0,0,65,61,0,0,0,0,13,239,0,25],[0,0,0,0,0,13,4,53,0,0,0,0,14,4,4,51,0,0,0,0,6,14,0,75,0,0,29,60,0,0,97,61],[0,0,0,0,11,0,0,25,0,0,0,0,6,219,0,25,0,0,0,32,11,176,0,57,0,0,0,0,10,75,0,25],[0,0,0,0,10,10,4,51,0,0,0,0,0,166,4,53,0,0,0,0,6,235,0,75,0,0,29,53,0,0,65,61],[0,0,0,0,13,222,0,25,0,0,0,0,0,13,4,53,0,0,0,0,14,8,4,51,0,0,0,0,4,14,0,75],[0,0,29,73,0,0,97,61,0,0,0,0,4,0,0,25,0,0,0,0,6,212,0,25,0,0,0,32,4,64,0,57],[0,0,0,0,10,132,0,25,0,0,0,0,10,10,4,51,0,0,0,0,0,166,4,53,0,0,0,0,6,228,0,75],[0,0,29,66,0,0,65,61,0,0,0,13,4,16,3,96,0,0,0,0,1,222,0,25,0,0,0,31,6,80,1,143],[0,0,0,0,0,1,4,53,0,0,0,5,8,80,2,114,0,0,29,88,0,0,97,61,0,0,0,0,13,0,0,25],[0,0,0,5,10,208,2,16,0,0,0,0,11,161,0,25,0,0,0,0,10,164,3,79,0,0,0,0,10,10,4,59],[0,0,0,0,0,171,4,53,0,0,0,1,13,208,0,57,0,0,0,0,10,141,0,75,0,0,29,80,0,0,65,61],[0,0,0,0,10,6,0,75,0,0,29,103,0,0,97,61,0,0,0,5,8,128,2,16,0,0,0,0,4,132,3,79],[0,0,0,0,8,129,0,25,0,0,0,3,6,96,2,16,0,0,0,0,10,8,4,51,0,0,0,0,10,106,1,207],[0,0,0,0,10,106,2,47,0,0,0,0,4,4,4,59,0,0,1,0,6,96,0,137,0,0,0,0,4,100,2,47],[0,0,0,0,4,100,1,207,0,0,0,0,4,164,1,159,0,0,0,0,0,72,4,53,0,0,0,0,1,81,0,25],[0,0,0,0,0,1,4,53,0,0,0,0,4,7,4,51,0,0,0,0,5,4,0,75,0,0,29,116,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,0,6,21,0,25,0,0,0,32,5,80,0,57,0,0,0,0,8,117,0,25],[0,0,0,0,8,8,4,51,0,0,0,0,0,134,4,53,0,0,0,0,6,69,0,75,0,0,29,109,0,0,65,61],[0,0,0,0,1,20,0,25,0,0,0,0,0,1,4,53,0,0,0,0,4,12,4,51,0,0,0,0,5,4,0,75],[0,0,29,129,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,0,6,21,0,25,0,0,0,32,5,80,0,57],[0,0,0,0,7,197,0,25,0,0,0,0,7,7,4,51,0,0,0,0,0,118,4,53,0,0,0,0,6,69,0,75],[0,0,29,122,0,0,65,61,0,0,0,0,1,20,0,25,0,0,0,0,0,1,4,53,0,0,0,0,4,2,4,51],[0,0,0,0,5,4,0,75,0,0,29,142,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,0,6,21,0,25],[0,0,0,32,5,80,0,57,0,0,0,0,7,37,0,25,0,0,0,0,7,7,4,51,0,0,0,0,0,118,4,53],[0,0,0,0,6,69,0,75,0,0,29,135,0,0,65,61,0,0,0,0,1,20,0,25,0,0,0,0,0,1,4,53],[0,0,0,0,2,9,4,51,0,0,0,0,4,2,0,75,0,0,29,155,0,0,97,61,0,0,0,0,4,0,0,25],[0,0,0,0,5,20,0,25,0,0,0,32,4,64,0,57,0,0,0,0,6,148,0,25,0,0,0,0,6,6,4,51],[0,0,0,0,0,101,4,53,0,0,0,0,5,36,0,75,0,0,29,148,0,0,65,61,0,0,0,0,1,18,0,25],[0,0,0,0,0,1,4,53,0,0,0,12,4,0,0,41,0,0,0,0,1,65,0,73,0,0,0,32,2,16,0,138],[0,0,0,0,0,36,4,53,0,0,0,31,1,16,0,57,0,0,0,0,2,49,1,111,0,0,0,0,1,66,0,25],[0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,7,159,3,16,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,2,32,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,16,4,63],[0,0,7,155,1,0,0,65,0,0,0,9,3,0,0,41,0,0,7,155,2,48,0,156,0,0,0,0,3,1,128,25],[0,0,0,64,2,48,2,16,0,0,0,12,3,0,0,41,0,0,0,0,3,3,4,51,0,0,7,155,4,48,0,156],[0,0,0,0,3,1,128,25,0,0,0,96,3,48,2,16,0,0,0,0,2,35,1,159,0,0,0,0,3,0,4,20],[0,0,7,155,4,48,0,156,0,0,0,0,3,1,128,25,0,0,0,192,1,48,2,16,0,0,0,0,1,33,1,159],[0,0,7,175,1,16,1,199,0,0,128,16,2,0,0,57,30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,0,159,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,2,0,4,21,0,0,0,10,2,32,0,105],[0,0,0,0,2,0,0,2,0,0,11,86,0,0,1,61,0,0,0,0,3,0,4,20,0,0,0,0,4,18,0,25],[0,0,0,0,2,36,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57,0,0,7,155,2,16,1,151],[0,0,0,1,1,80,1,144,0,0,30,31,0,0,193,61,0,0,0,0,1,0,0,49,0,0,0,0,5,65,0,75],[0,0,30,31,0,0,65,61,0,0,0,1,2,32,3,103,0,0,7,176,5,48,0,156,0,0,30,35,0,0,129,61],[0,0,0,0,1,65,0,73,0,0,7,155,1,16,1,151,0,0,0,0,1,18,3,223,0,0,0,192,2,48,2,16],[0,0,7,177,2,32,1,151,0,0,7,178,2,32,1,199,0,0,0,0,1,33,3,175,0,0,128,16,2,0,0,57],[30,104,30,99,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,7,155,3,48,1,151],[0,0,0,1,2,32,1,144,0,0,30,42,0,0,97,61,0,0,0,63,2,48,0,57,0,0,7,179,4,32,1,151],[0,0,0,64,2,0,4,61,0,0,0,0,4,66,0,25,0,0,0,0,5,36,0,75,0,0,0,0,5,0,0,25],[0,0,0,1,5,0,64,57,0,0,7,159,6,64,0,156,0,0,30,69,0,0,33,61,0,0,0,1,5,80,1,144],[0,0,30,69,0,0,193,61,0,0,0,64,0,64,4,63,0,0,0,0,4,50,4,54,0,0,0,31,5,48,0,57],[0,0,0,5,5,80,2,114,0,0,29,253,0,0,97,61,0,0,0,0,6,0,0,49,0,0,0,1,6,96,3,103],[0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,132,0,25,0,0,0,0,8,134,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,87,0,75],[0,0,29,245,0,0,65,61,0,0,0,0,5,0,0,75,0,0,29,255,0,0,97,61,0,0,0,31,5,48,1,143],[0,0,0,5,3,48,2,114,0,0,30,11,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,116,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,54,0,75,0,0,30,3,0,0,65,61,0,0,0,0,6,5,0,75],[0,0,30,26,0,0,97,61,0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79,0,0,0,0,3,52,0,25],[0,0,0,3,5,80,2,16,0,0,0,0,6,3,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,5,80,0,137,0,0,0,0,1,81,2,47,0,0,0,0,1,81,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,19,4,53,0,0,0,0,1,2,4,51,0,0,0,32,1,16,0,140],[0,0,30,75,0,0,193,61,0,0,0,0,1,4,4,51,0,0,0,0,0,1,4,45,0,0,7,195,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57,0,0,30,72,0,0,1,61,0,0,0,64,1,0,4,61],[0,0,0,68,2,16,0,57,0,0,7,191,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,8,3,0,0,57,0,0,30,81,0,0,1,61,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114],[0,0,30,53,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75],[0,0,30,46,0,0,65,61,0,0,0,0,5,4,0,75,0,0,30,67,0,0,97,61,0,0,0,3,4,64,2,16],[0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47],[0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16],[0,0,30,106,0,1,4,48,0,0,7,195,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,7,196,1,0,0,65,0,0,30,106,0,1,4,48,0,0,0,64,1,0,4,61],[0,0,0,68,2,16,0,57,0,0,7,181,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,31,3,0,0,57,0,0,0,0,0,50,4,53,0,0,7,161,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53,0,0,7,155,2,0,0,65],[0,0,7,155,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,7,182,1,16,1,199],[0,0,30,106,0,1,4,48,0,0,0,0,0,1,4,47,0,0,30,97,0,33,4,35,0,0,0,1,2,0,0,57],[0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,30,102,0,33,4,35],[0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45],[0,0,30,104,0,0,4,50,0,0,30,105,0,1,4,46,0,0,30,106,0,1,4,48,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,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[255,255,255,255,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],[235,228,163,215,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255],[128,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],[8,195,121,160,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],[69,110,99,111,100,105,110,103,32,117,110,115,117,112,112,111,114,116,101,100,32,116,120,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,100,0,0,0,128,0,0,0,0,0,0,0,0],[154,138,5,146,172,137,197,173,59,198,223,130,36,193,123,72,89,118,245,151,223,16,78,226,13,13,244,21,36,31,103,11],[2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,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,0,0,0,0,255,255,255,255,255,255,255,191],[0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[129,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],[148,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],[184,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],[192,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],[248,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],[1,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],[2,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,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,1,0,0,0,0],[0,0,0,0,255,255,255,255,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,1,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,255,255,255,224],[7,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[107,101,99,99,97,107,50,53,54,32,114,101,116,117,114,110,101,100,32,105,110,118,97,108,105,100,32,100,97,116,97,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0],[132,142,27,250,26,196,227,87,107,114,139,218,103,33,178,21,199,10,119,153,165,180,134,98,130,167,27,171,149,75,170,200],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,254,31],[194,248,120,113,118,184,172,107,247,33,91,74,220,193,224,105,191,74,184,45,154,177,223,5,165,122,145,212,37,147,91,110],[173,124,91,239,2,120,22,168,0,218,23,54,68,79,181,138,128,126,244,201,96,59,120,72,103,63,126,58,104,235,20,165],[25,180,83,206,69,170,170,243,163,0,245,169,236,149,134,155,79,40,171,16,67,11,87,46,226,24,195,166,165,224,125,111],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,95],[25,1,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,127],[79,118,101,114,102,108,111,119,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[128,128,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],[85,110,115,117,112,112,111,114,116,101,100,32,116,120,32,116,121,112,101,0,0,0,0,0,0,0,0,0,0,0,0,0],[73,110,118,97,108,105,100,32,118,32,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[78,72,123,113,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,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,0,0,0,0,255,255,255,255,255,255,255,159],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,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,0,0,0,0,0,0,0,0,0,0,0,0],[161,135,70,180,171,129,132,196,113,180,222,52,244,51,34,63,179,4,137,162,144,246,227,135,212,103,1,116,178,89,133,86]],"0x000000000000000000000000000000000000800e":[[0,2,0,0,0,0,0,2,0,12,0,0,0,0,0,2,0,1,0,0,0,1,3,85,0,0,0,0,3,1,0,25],[0,0,0,96,4,48,2,112,0,0,1,44,0,64,1,157,0,0,0,128,3,0,0,57,0,0,0,64,0,48,4,63],[0,2,0,0,0,4,0,29,0,0,1,44,3,64,1,151,0,0,0,1,2,32,1,144,0,0,1,242,0,0,193,61],[0,0,0,4,2,48,0,140,0,0,2,74,0,0,65,61,0,0,0,0,2,1,4,59,0,0,0,224,2,32,2,112],[0,0,1,46,4,32,0,156,0,0,1,128,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,128,2,32,0,140],[0,0,2,74,0,0,65,61,0,0,0,4,2,16,3,112,0,0,0,0,8,2,4,59,0,0,0,68,2,16,3,112],[0,0,0,0,4,2,4,59,0,0,0,36,2,16,3,112,0,0,0,0,14,2,4,59,0,7,0,0,0,4,0,29],[0,0,1,48,2,64,0,156,0,0,2,74,0,0,33,61,0,0,0,7,2,0,0,41,0,0,0,35,2,32,0,57],[0,0,1,49,4,0,0,65,0,0,0,0,5,50,0,75,0,0,0,0,5,0,0,25,0,0,0,0,5,4,128,25],[0,0,1,49,2,32,1,151,0,0,0,0,6,2,0,75,0,0,0,0,4,0,128,25,0,0,1,49,2,32,0,156],[0,0,0,0,4,5,192,25,0,0,0,0,2,4,0,75,0,0,2,74,0,0,193,61,0,0,0,7,2,0,0,41],[0,0,0,4,2,32,0,57,0,0,0,0,2,33,3,79,0,0,0,0,6,2,4,59,0,0,1,48,2,96,0,156],[0,0,2,74,0,0,33,61,0,0,0,7,2,0,0,41,0,0,0,36,5,32,0,57,0,1,0,0,0,86,0,29],[0,0,0,1,2,48,0,108,0,0,2,74,0,0,65,61,0,0,0,100,2,16,3,112,0,0,0,0,2,2,4,59],[0,9,0,0,0,2,0,29,0,0,1,48,2,32,0,156,0,0,2,74,0,0,33,61,0,0,0,9,2,0,0,41],[0,0,0,35,2,32,0,57,0,0,1,49,4,0,0,65,0,0,0,0,7,50,0,75,0,0,0,0,7,0,0,25],[0,0,0,0,7,4,128,25,0,0,1,49,2,32,1,151,0,0,0,0,9,2,0,75,0,0,0,0,4,0,128,25],[0,0,1,49,2,32,0,156,0,0,0,0,4,7,192,25,0,0,0,0,2,4,0,75,0,0,2,74,0,0,193,61],[0,0,0,9,2,0,0,41,0,0,0,4,2,32,0,57,0,0,0,0,2,33,3,79,0,0,0,0,2,2,4,59],[0,11,0,0,0,2,0,29,0,0,1,48,2,32,0,156,0,0,2,74,0,0,33,61,0,0,0,9,2,0,0,41],[0,0,0,36,4,32,0,57,0,10,0,0,0,4,0,29,0,0,0,11,2,64,0,41,0,0,0,0,2,50,0,75],[0,0,2,74,0,0,33,61,0,0,0,0,2,0,4,17,0,0,128,8,2,32,0,140,0,0,1,250,0,0,193,61],[0,0,0,9,2,224,0,140,0,0,2,2,0,0,129,61,0,12,0,2,0,0,0,61,0,0,1,16,41,128,0,201],[0,0,1,17,10,0,0,138,0,8,0,0,0,0,0,29,0,0,0,0,7,0,0,25,0,6,0,0,0,14,0,29],[0,0,0,0,2,8,0,75,0,0,0,101,0,0,97,61,0,0,0,0,50,137,0,217,0,0,1,16,2,32,0,140],[0,0,2,239,0,0,193,61,0,0,0,0,2,151,0,75,0,0,0,206,0,0,129,61,0,0,0,0,2,167,0,75],[0,0,2,239,0,0,33,61,0,0,1,16,4,112,0,57,0,0,0,0,2,100,0,75,0,0,2,74,0,0,33,61],[0,0,0,0,2,87,0,25,0,0,0,60,2,32,0,57,0,0,0,0,3,33,3,79,0,0,0,0,3,3,4,59],[0,0,1,48,3,48,1,152,0,0,0,0,7,4,0,25,0,0,0,96,0,0,193,61,0,0,0,1,15,0,0,138],[0,0,0,8,3,240,0,107,0,0,2,239,0,0,97,61,0,0,0,12,11,0,0,41,0,0,0,10,3,176,0,41],[0,0,0,0,7,49,3,79,0,0,0,8,3,32,0,138,0,0,0,0,2,49,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,2,2,4,59,0,0,0,0,2,114,0,75,0,0,2,42,0,0,193,61,0,0,0,33,2,0,0,138],[0,0,0,0,2,43,0,75,0,0,2,239,0,0,33,61,0,0,0,12,11,0,0,41,0,0,0,32,2,176,0,57],[0,0,0,11,7,32,0,108,0,0,1,86,0,0,129,61,0,0,0,10,2,32,0,41,0,0,0,0,2,33,3,79],[0,0,0,0,2,2,4,59,0,0,0,251,7,32,2,112,0,0,0,248,2,32,2,112,0,0,0,7,13,32,1,144],[0,0,0,32,7,0,96,57,0,0,0,33,2,176,0,57,0,12,0,0,0,39,0,30,0,0,2,239,0,0,65,61],[0,0,0,12,12,0,0,41,0,0,0,11,12,192,0,108,0,0,2,74,0,0,33,61,0,0,0,10,2,32,0,41],[0,0,0,72,12,48,0,57,0,0,0,0,12,193,3,79,0,0,0,40,3,48,0,57,0,0,0,0,14,49,3,79],[0,0,0,0,2,33,3,79,0,0,0,0,3,2,4,59,0,0,0,0,2,14,4,59,0,5,0,0,0,2,0,29],[0,0,0,6,14,0,0,41,0,0,0,0,11,12,4,59,0,0,0,31,2,112,0,140,0,0,0,3,2,112,2,16],[0,0,0,171,0,0,33,61,0,0,1,0,12,32,0,137,0,0,0,0,12,207,1,207,0,0,0,0,14,32,0,73],[0,0,1,0,15,0,0,138,0,0,0,0,14,254,0,75,0,0,0,6,14,0,0,41,0,0,0,0,12,0,64,25],[0,0,0,0,3,195,1,111,0,0,0,0,12,7,0,75,0,0,0,204,0,0,97,61,0,0,1,0,12,32,0,140],[0,0,2,239,0,0,33,61,0,0,0,0,199,114,0,217,0,0,0,8,7,112,0,140,0,0,2,239,0,0,193,61],[0,0,1,0,7,32,0,137,0,0,0,0,3,115,2,47,0,0,0,0,2,2,0,75,0,0,0,0,3,0,96,25],[0,0,0,8,2,0,0,41,0,8,0,1,0,32,0,61,0,0,0,0,2,13,0,75,0,0,0,193,0,0,97,61],[0,0,0,3,2,208,0,140,0,0,0,193,0,0,97,61,0,0,0,1,2,208,0,140,0,0,0,197,0,0,193,61],[0,0,0,5,2,48,0,41,0,0,0,0,2,178,0,75,0,0,0,0,7,4,0,25,0,0,0,96,0,0,97,61],[0,0,1,108,0,0,1,61,0,0,0,0,2,179,0,75,0,0,0,0,7,4,0,25,0,0,0,96,0,0,97,61],[0,0,1,90,0,0,1,61,0,0,0,2,2,208,0,140,0,0,1,100,0,0,193,61,0,0,0,5,2,48,0,105],[0,0,0,0,2,178,0,75,0,0,0,0,7,4,0,25,0,0,0,96,0,0,97,61,0,0,1,118,0,0,1,61],[0,0,0,0,3,0,0,25,0,0,0,180,0,0,1,61,0,0,0,9,2,0,0,41,0,0,0,6,2,32,0,57],[0,0,0,0,2,33,3,79,0,0,0,0,2,2,4,59,0,0,255,255,2,32,1,143,0,0,0,8,2,32,0,107],[0,0,2,12,0,0,193,61,0,0,0,3,3,224,2,16,0,0,1,0,2,48,0,137,0,0,0,1,4,0,0,138],[0,8,0,0,0,2,0,29,0,4,0,0,0,4,0,29,0,0,0,0,4,36,1,207,0,0,0,0,2,48,0,73],[0,3,1,0,0,0,0,146,0,0,0,3,2,32,0,108,0,0,0,0,4,0,64,25,0,5,0,0,0,4,0,29],[0,9,0,0,0,3,0,29,0,0,1,0,2,48,0,140,0,0,2,22,0,0,33,61,0,0,0,0,3,0,0,25],[0,0,0,232,0,0,1,61,0,0,0,0,2,210,0,75,0,0,0,0,3,4,0,25,0,0,1,90,0,0,193,61],[0,0,0,0,2,8,0,75,0,0,0,237,0,0,97,61,0,0,0,0,66,137,0,217,0,0,1,16,2,32,0,140],[0,0,2,239,0,0,193,61,0,0,0,0,2,147,0,75,0,0,2,76,0,0,129,61,0,0,0,0,2,163,0,75],[0,0,2,239,0,0,33,61,0,0,1,16,4,48,0,57,0,0,0,0,2,100,0,75,0,0,2,74,0,0,33,61],[0,0,0,0,2,83,0,25,0,0,0,60,13,32,0,57,0,0,0,0,2,209,3,79,0,0,0,0,2,2,4,59],[0,0,1,48,7,32,1,152,0,0,0,0,3,4,0,25,0,0,0,232,0,0,97,61,0,0,0,12,15,224,0,42],[0,0,2,239,0,0,65,61,0,0,0,11,2,240,0,108,0,0,2,74,0,0,33,61,0,0,0,10,3,0,0,41],[0,0,0,12,2,48,0,41,0,0,0,0,2,33,3,79,0,0,0,0,2,2,4,59,0,0,0,31,3,224,0,140],[0,0,1,8,0,0,33,61,0,0,0,5,2,32,1,127,0,0,0,0,3,14,0,75,0,0,2,231,0,0,97,61],[0,0,0,9,179,224,0,249,0,0,0,8,3,48,0,140,0,0,2,239,0,0,193,61,0,0,0,9,3,0,0,107],[0,0,2,231,0,0,97,61,0,0,0,8,2,32,2,80,0,0,0,0,2,39,0,75,0,0,2,231,0,0,193,61],[0,0,0,11,2,240,0,108,0,0,1,86,0,0,129,61,0,0,0,10,2,240,0,41,0,0,0,0,2,33,3,79],[0,0,0,0,2,2,4,59,0,0,0,251,7,32,2,112,0,0,0,248,2,32,2,112,0,0,0,7,3,32,1,144],[0,0,0,32,7,0,96,57,0,0,0,1,2,240,0,57,0,12,0,0,0,39,0,29,0,0,0,12,12,240,0,107],[0,0,2,239,0,0,161,61,0,0,0,12,12,0,0,41,0,0,0,11,12,192,0,108,0,0,2,74,0,0,33,61],[0,0,0,10,2,32,0,41,0,0,0,64,12,208,0,57,0,0,0,0,12,193,3,79,0,0,0,32,13,208,0,57],[0,0,0,0,13,209,3,79,0,0,0,0,2,33,3,79,0,0,0,0,2,2,4,59,0,0,0,0,15,13,4,59],[0,0,0,0,13,12,4,59,0,0,0,31,12,112,0,140,0,0,0,3,12,112,2,16,0,0,1,57,0,0,33,61],[0,0,1,0,14,192,0,137,0,0,0,4,14,224,1,239,0,0,0,0,11,192,0,73,0,7,0,0,0,13,0,29],[0,0,0,0,13,15,0,25,0,0,0,3,11,176,0,108,0,0,0,0,15,13,0,25,0,0,0,7,13,0,0,41],[0,0,0,0,14,0,64,25,0,0,0,0,2,226,1,111,0,0,0,6,14,0,0,41,0,0,0,0,11,7,0,75],[0,0,1,84,0,0,97,61,0,0,1,0,11,192,0,140,0,0,2,239,0,0,33,61,0,0,0,0,183,124,0,217],[0,0,0,8,7,112,0,140,0,0,2,239,0,0,193,61,0,0,1,0,7,192,0,137,0,0,0,0,2,114,2,47],[0,0,0,0,7,12,0,75,0,0,0,0,2,0,96,25,0,0,0,0,7,3,0,75,0,0,0,229,0,0,97,61],[0,0,0,3,7,48,0,140,0,0,0,229,0,0,97,61,0,0,0,1,7,48,0,140,0,0,1,77,0,0,193,61],[0,0,0,0,2,242,0,25,0,0,0,0,2,210,0,75,0,0,0,0,3,4,0,25,0,0,0,232,0,0,97,61],[0,0,1,108,0,0,1,61,0,0,0,2,3,48,0,140,0,0,1,100,0,0,193,61,0,0,0,0,2,47,0,73],[0,0,0,0,2,210,0,75,0,0,0,0,3,4,0,25,0,0,0,232,0,0,97,61,0,0,1,118,0,0,1,61],[0,0,0,0,2,0,0,25,0,0,1,66,0,0,1,61,0,0,1,88,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,50,1,0,0,57,0,0,2,242,0,0,1,61,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,58,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,1,92,1,0,0,65,0,0,0,196,0,16,4,63,0,0,1,93,1,0,0,65,0,0,2,101,0,0,1,61],[0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63],[0,0,0,21,1,0,0,57,0,0,0,164,0,16,4,63,0,0,1,94,1,0,0,65,0,0,2,89,0,0,1,61],[0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63],[0,0,0,46,1,0,0,57,0,0,0,164,0,16,4,63,0,0,1,97,1,0,0,65,0,0,0,196,0,16,4,63],[0,0,1,98,1,0,0,65,0,0,2,101,0,0,1,61,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,47,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,1,95,1,0,0,65,0,0,0,196,0,16,4,63,0,0,1,96,1,0,0,65,0,0,2,101,0,0,1,61],[0,0,1,47,2,32,0,156,0,0,2,74,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,64,2,32,0,140],[0,0,2,74,0,0,65,61,0,0,0,4,2,16,3,112,0,0,0,0,5,2,4,59,0,0,1,48,2,80,0,156],[0,0,2,74,0,0,33,61,0,0,0,35,2,80,0,57,0,0,1,49,4,0,0,65,0,0,0,0,6,50,0,75],[0,0,0,0,6,0,0,25,0,0,0,0,6,4,128,25,0,0,1,49,2,32,1,151,0,0,0,0,7,2,0,75],[0,0,0,0,4,0,128,25,0,0,1,49,2,32,0,156,0,0,0,0,4,6,192,25,0,0,0,0,2,4,0,75],[0,0,2,74,0,0,193,61,0,0,0,4,2,80,0,57,0,0,0,0,2,33,3,79,0,0,0,0,2,2,4,59],[0,11,0,0,0,2,0,29,0,0,1,48,2,32,0,156,0,0,2,74,0,0,33,61,0,0,0,36,4,80,0,57],[0,0,0,11,2,64,0,41,0,0,0,0,6,35,0,75,0,0,2,74,0,0,65,61,0,0,0,36,6,16,3,112],[0,0,0,0,6,6,4,59,0,0,1,48,7,96,0,156,0,0,2,74,0,0,33,61,0,0,0,35,7,96,0,57],[0,0,1,49,8,0,0,65,0,0,0,0,9,55,0,75,0,0,0,0,9,0,0,25,0,0,0,0,9,8,128,25],[0,0,1,49,7,112,1,151,0,0,0,0,10,7,0,75,0,0,0,0,8,0,128,25,0,0,1,49,7,112,0,156],[0,0,0,0,8,9,192,25,0,0,0,0,7,8,0,75,0,0,2,74,0,0,193,61,0,0,0,4,7,96,0,57],[0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59,0,10,0,0,0,8,0,29,0,0,1,48,8,128,0,156],[0,0,2,74,0,0,33,61,0,0,0,36,9,96,0,57,0,9,0,0,0,9,0,29,0,0,0,10,8,144,0,41],[0,0,0,0,3,56,0,75,0,0,2,74,0,0,33,61,0,0,0,0,3,0,4,17,0,0,128,1,3,48,0,140],[0,0,2,245,0,0,193,61,0,0,0,2,3,112,0,57,0,0,0,0,3,49,3,79,0,0,0,0,3,3,4,59],[0,0,0,3,3,48,2,16,0,0,1,53,3,48,1,151,0,0,0,2,8,48,1,191,0,0,0,10,7,128,0,107],[0,0,2,74,0,0,65,61,0,0,0,10,7,128,0,105,0,0,0,2,9,112,2,16,0,0,0,11,9,144,0,108],[0,0,2,253,0,0,193,61,0,0,0,10,9,128,0,107,0,0,1,228,0,0,97,61,0,0,0,6,9,96,0,57],[0,0,0,0,8,152,0,25,0,0,0,14,6,96,0,57,0,0,0,12,5,80,0,57,0,0,0,0,9,0,0,25],[0,0,0,0,10,152,0,25,0,0,0,0,10,161,3,79,0,0,0,0,10,10,4,59,0,0,0,3,10,160,2,16],[0,0,1,53,10,160,1,151,0,0,0,0,11,58,0,75,0,0,3,19,0,0,129,61,0,0,0,0,10,166,0,25],[0,0,0,2,11,144,2,16,0,0,0,0,11,181,0,25,0,0,0,0,11,177,3,79,0,0,0,0,10,161,3,79],[0,0,0,0,10,10,4,59,0,0,0,0,11,11,4,59,0,0,0,0,10,186,1,63,0,0,1,48,10,160,1,152],[0,0,3,29,0,0,193,61,0,0,0,2,9,144,0,57,0,0,0,0,10,121,0,75,0,0,1,208,0,0,65,61],[0,0,0,11,3,0,0,41,0,0,0,31,3,48,1,144,0,0,3,11,0,0,193,61,0,0,0,11,3,0,0,41],[0,0,1,64,3,48,0,156,0,0,3,39,0,0,65,61,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,2,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,1,80,1,0,0,65,0,0,2,89,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,2,74,0,0,193,61,0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67],[0,0,1,45,1,0,0,65,0,0,4,170,0,1,4,46,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,20,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,1,81,1,0,0,65,0,0,2,89,0,0,1,61,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,35,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,1,99,1,0,0,65,0,0,0,196,0,16,4,63,0,0,1,100,1,0,0,65,0,0,2,101,0,0,1,61],[0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63],[0,0,0,41,1,0,0,57,0,0,0,164,0,16,4,63,0,0,1,82,1,0,0,65,0,0,0,196,0,16,4,63],[0,0,1,83,1,0,0,65,0,0,2,101,0,0,1,61,0,0,0,0,2,8,0,75,0,0,2,50,0,0,193,61],[0,0,0,7,2,0,0,41,0,0,0,96,2,32,0,57,0,0,0,0,3,0,0,25,0,0,0,6,8,0,0,41],[0,0,0,0,4,147,0,75,0,0,2,76,0,0,129,61,0,0,0,0,4,163,0,75,0,0,2,239,0,0,33,61],[0,0,1,16,4,48,0,57,0,0,0,0,7,100,0,75,0,0,2,74,0,0,33,61,0,0,0,0,3,50,0,25],[0,0,0,0,3,49,3,79,0,0,0,0,3,3,4,59,0,0,1,48,3,48,1,152,0,0,0,0,3,4,0,25],[0,0,2,28,0,0,97,61,0,0,2,70,0,0,1,61,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,24,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,1,91,1,0,0,65,0,0,2,89,0,0,1,61,0,0,0,0,50,137,0,217,0,0,1,16,2,32,0,140],[0,0,0,6,8,0,0,41,0,0,2,239,0,0,193,61,0,0,0,7,2,0,0,41,0,0,0,96,2,32,0,57],[0,0,0,0,3,0,0,25,0,0,0,0,4,147,0,75,0,0,2,76,0,0,129,61,0,0,0,0,4,163,0,75],[0,0,2,239,0,0,33,61,0,0,1,16,4,48,0,57,0,0,0,0,7,100,0,75,0,0,2,74,0,0,33,61],[0,0,0,0,3,50,0,25,0,0,0,0,3,49,3,79,0,0,0,0,3,3,4,59,0,0,1,48,3,48,1,152],[0,0,0,0,3,4,0,25,0,0,2,57,0,0,97,61,0,0,0,12,1,128,0,42,0,0,2,239,0,0,65,61],[0,0,0,11,1,16,0,108,0,0,2,229,0,0,161,61,0,0,0,0,1,0,0,25,0,0,4,171,0,1,4,48],[0,0,0,12,3,0,0,41,0,0,0,11,2,48,0,108,0,0,2,92,0,0,193,61,0,0,0,0,2,0,4,20],[0,0,1,86,3,32,0,156,0,0,2,104,0,0,65,61,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,8,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,1,89,1,0,0,65,0,0,0,196,0,16,4,63,0,0,1,52,1,0,0,65,0,0,4,171,0,1,4,48],[0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63],[0,0,0,35,1,0,0,57,0,0,0,164,0,16,4,63,0,0,1,84,1,0,0,65,0,0,0,196,0,16,4,63],[0,0,1,85,1,0,0,65,0,0,0,228,0,16,4,63,0,0,1,60,1,0,0,65,0,0,4,171,0,1,4,48],[0,0,1,44,3,80,1,151,0,0,0,0,1,49,3,79,0,0,0,1,4,0,0,41,0,0,0,2,3,64,0,105],[0,0,1,44,3,48,1,151,0,0,0,0,1,49,3,223,0,0,0,192,2,32,2,16,0,0,1,65,2,32,1,151],[0,0,1,66,2,32,1,199,0,0,0,0,1,33,3,175,0,0,128,16,2,0,0,57,4,169,4,164,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,1,44,3,48,1,151,0,0,0,1,2,32,1,144],[0,0,2,189,0,0,97,61,0,0,0,63,2,48,0,57,0,0,1,67,4,32,1,151,0,0,0,64,2,0,4,61],[0,0,0,0,4,66,0,25,0,0,0,0,5,36,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57],[0,0,1,48,6,64,0,156,0,0,4,32,0,0,33,61,0,0,0,1,5,80,1,144,0,0,4,32,0,0,193,61],[0,0,0,64,0,64,4,63,0,0,0,0,4,50,4,54,0,0,0,31,5,48,0,57,0,0,0,5,5,80,2,114],[0,0,2,148,0,0,97,61,0,0,0,0,6,0,0,49,0,0,0,1,6,96,3,103,0,0,0,0,7,0,0,25],[0,0,0,5,8,112,2,16,0,0,0,0,9,132,0,25,0,0,0,0,8,134,3,79,0,0,0,0,8,8,4,59],[0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,87,0,75,0,0,2,140,0,0,65,61],[0,0,0,0,5,0,0,75,0,0,2,150,0,0,97,61,0,0,0,31,5,48,1,143,0,0,0,5,3,48,2,114],[0,0,2,162,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,116,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,54,0,75,0,0,2,154,0,0,65,61,0,0,0,0,6,5,0,75,0,0,2,177,0,0,97,61],[0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79,0,0,0,0,3,52,0,25,0,0,0,3,5,80,2,16],[0,0,0,0,6,3,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,1,81,2,47,0,0,0,0,1,81,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,19,4,53,0,0,1,44,3,0,0,65,0,0,0,64,1,0,4,61,0,0,1,44,5,16,0,156],[0,0,0,0,3,1,64,25,0,0,0,64,3,48,2,16,0,0,0,0,2,2,4,51,0,0,0,32,2,32,0,140],[0,0,2,216,0,0,193,61,0,0,0,0,2,4,4,51,0,0,0,0,0,33,4,53,0,0,1,78,1,48,1,199],[0,0,4,170,0,1,4,46,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114,0,0,2,200,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75,0,0,2,193,0,0,65,61],[0,0,0,0,5,4,0,75,0,0,2,214,0,0,97,61,0,0,0,3,4,64,2,16,0,0,0,5,2,32,2,16],[0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47,0,0,0,0,1,33,3,79],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16,0,0,4,171,0,1,4,48],[0,0,0,68,2,16,0,57,0,0,1,87,4,0,0,65,0,0,0,0,0,66,4,53,0,0,0,36,2,16,0,57],[0,0,0,31,4,0,0,57,0,0,0,0,0,66,4,53,0,0,1,50,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,4,1,16,0,57,0,0,0,32,2,0,0,57,0,0,0,0,0,33,4,53,0,0,1,69,1,48,1,199],[0,0,4,171,0,1,4,48,0,0,0,0,1,8,0,75,0,0,2,239,0,0,193,61,0,0,1,50,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,21,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,1,90,1,0,0,65,0,0,2,89,0,0,1,61,0,0,1,88,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57,0,0,0,4,0,16,4,63,0,0,1,77,1,0,0,65],[0,0,4,171,0,1,4,48,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,132,0,16,4,63,0,0,0,31,1,0,0,57,0,0,0,164,0,16,4,63,0,0,1,51,1,0,0,65],[0,0,2,89,0,0,1,61,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,132,0,16,4,63,0,0,0,72,1,0,0,57,0,0,0,164,0,16,4,63,0,0,1,54,1,0,0,65],[0,0,0,196,0,16,4,63,0,0,1,55,1,0,0,65,0,0,0,228,0,16,4,63,0,0,1,56,1,0,0,65],[0,0,1,4,0,16,4,63,0,0,1,57,1,0,0,65,0,0,4,171,0,1,4,48,0,0,1,50,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,2,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,1,63,1,0,0,65,0,0,2,89,0,0,1,61,0,0,1,50,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,36,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,1,58,1,0,0,65,0,0,0,196,0,16,4,63,0,0,1,59,1,0,0,65],[0,0,2,101,0,0,1,61,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,132,0,16,4,63,0,0,0,50,1,0,0,57,0,0,0,164,0,16,4,63,0,0,1,61,1,0,0,65],[0,0,0,196,0,16,4,63,0,0,1,62,1,0,0,65,0,0,2,101,0,0,1,61,0,0,0,11,3,0,0,41],[0,0,0,32,3,48,1,144,0,0,3,50,0,0,193,61,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,2,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,1,79,1,0,0,65,0,0,2,89,0,0,1,61,0,0,0,0,3,0,4,20,0,0,1,44,5,48,0,156],[0,0,2,82,0,0,33,61,0,0,1,44,4,64,1,151,0,0,0,0,1,65,3,79,0,0,0,2,2,32,0,105],[0,0,1,44,2,32,1,151,0,0,0,0,1,33,3,223,0,0,0,192,2,48,2,16,0,0,1,65,2,32,1,151],[0,0,1,66,2,32,1,199,0,0,0,0,1,33,3,175,0,0,0,2,2,0,0,57,4,169,4,164,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,1,44,3,48,1,151,0,0,0,1,2,32,1,144],[0,0,4,36,0,0,97,61,0,0,0,63,2,48,0,57,0,0,1,67,4,32,1,151,0,0,0,64,2,0,4,61],[0,0,0,0,4,66,0,25,0,0,0,0,5,36,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57],[0,0,1,48,6,64,0,156,0,0,4,32,0,0,33,61,0,0,0,1,5,80,1,144,0,0,4,32,0,0,193,61],[0,0,0,64,0,64,4,63,0,0,0,0,5,50,4,54,0,0,0,1,4,0,3,103,0,0,0,31,6,48,0,57],[0,0,0,5,6,96,2,114,0,0,3,96,0,0,97,61,0,0,0,0,7,64,3,104,0,0,0,0,8,0,0,25],[0,0,0,5,9,128,2,16,0,0,0,0,10,149,0,25,0,0,0,0,9,151,3,79,0,0,0,0,9,9,4,59],[0,0,0,0,0,154,4,53,0,0,0,1,8,128,0,57,0,0,0,0,9,104,0,75,0,0,3,88,0,0,65,61],[0,0,0,0,6,0,0,75,0,0,3,98,0,0,97,61,0,0,0,31,6,48,1,143,0,0,0,5,3,48,2,114],[0,0,3,110,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,133,0,25],[0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,55,0,75,0,0,3,102,0,0,65,61,0,0,0,0,7,6,0,75,0,0,3,125,0,0,97,61],[0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79,0,0,0,0,3,53,0,25,0,0,0,3,6,96,2,16],[0,0,0,0,7,3,4,51,0,0,0,0,7,103,1,207,0,0,0,0,7,103,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,6,96,0,137,0,0,0,0,1,97,2,47,0,0,0,0,1,97,1,207,0,0,0,0,1,113,1,159],[0,0,0,0,0,19,4,53,0,0,0,64,6,0,4,61,0,0,0,68,1,96,0,57,0,0,0,36,3,96,0,57],[0,12,0,0,0,6,0,29,0,0,0,4,6,96,0,57,0,0,0,0,2,2,4,51,0,0,0,32,2,32,0,140],[0,0,4,63,0,0,193,61,0,0,0,0,5,5,4,51,0,0,1,70,2,0,0,65,0,0,0,12,7,0,0,41],[0,0,0,0,0,39,4,53,0,0,0,32,2,0,0,57,0,0,0,0,0,38,4,53,0,0,0,10,6,0,0,41],[0,0,0,0,0,99,4,53,0,0,0,9,2,64,3,96,0,0,1,71,3,80,1,151,0,0,0,11,4,0,0,41],[0,0,0,219,4,64,2,16,0,0,1,72,4,64,1,151,0,0,0,0,4,52,1,159,0,0,0,31,3,96,1,143],[0,11,1,73,0,64,1,203,0,0,0,5,4,96,2,114,0,0,3,160,0,0,97,61,0,0,0,0,5,0,0,25],[0,0,0,5,6,80,2,16,0,0,0,0,7,97,0,25,0,0,0,0,6,98,3,79,0,0,0,0,6,6,4,59],[0,0,0,0,0,103,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,69,0,75,0,0,3,152,0,0,65,61],[0,0,0,0,5,3,0,75,0,0,3,175,0,0,97,61,0,0,0,5,4,64,2,16,0,0,0,0,2,66,3,79],[0,0,0,0,4,65,0,25,0,0,0,3,3,48,2,16,0,0,0,0,5,4,4,51,0,0,0,0,5,53,1,207],[0,0,0,0,5,53,2,47,0,0,0,0,2,2,4,59,0,0,1,0,3,48,0,137,0,0,0,0,2,50,2,47],[0,0,0,0,2,50,1,207,0,0,0,0,2,82,1,159,0,0,0,0,0,36,4,53,0,0,0,10,2,0,0,41],[0,0,0,0,1,33,0,25,0,0,0,0,0,1,4,53,0,0,0,31,1,32,0,57,0,0,0,32,2,0,0,138],[0,0,0,0,1,33,1,111,0,0,1,44,2,0,0,65,0,0,0,12,4,0,0,41,0,0,1,44,3,64,0,156],[0,0,0,0,3,2,0,25,0,0,0,0,3,4,64,25,0,0,0,64,3,48,2,16,0,0,0,68,1,16,0,57],[0,0,1,44,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,19,1,159],[0,0,0,0,3,0,4,20,0,0,1,44,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16],[0,0,0,0,1,18,1,159,0,0,128,8,2,0,0,57,4,169,4,154,0,0,4,15,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,1,44,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25],[0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114,0,0,3,217,0,0,97,61],[0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,12,9,128,0,41,0,0,0,0,8,129,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75],[0,0,3,209,0,0,65,61,0,0,0,0,7,5,0,75,0,0,3,232,0,0,97,61,0,0,0,5,6,96,2,16],[0,0,0,0,7,97,3,79,0,0,0,12,6,96,0,41,0,0,0,3,5,80,2,16,0,0,0,0,8,6,4,51],[0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137],[0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53],[0,0,0,1,2,32,1,144,0,0,4,78,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,2,16,1,143],[0,0,0,12,1,32,0,41,0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57],[0,0,1,48,4,16,0,156,0,0,4,32,0,0,33,61,0,0,0,1,2,32,1,144,0,0,4,32,0,0,193,61],[0,0,0,64,0,16,4,63,0,0,0,32,1,48,0,140,0,0,2,74,0,0,65,61,0,0,1,74,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,128,4,1,0,0,57,0,0,0,4,0,16,4,67,0,0,1,44,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,1,44,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,1,75,1,16,1,199,0,0,128,2,2,0,0,57,4,169,4,159,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,4,113,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,2,74,0,0,97,61],[0,0,0,64,4,0,4,61,0,0,1,76,1,0,0,65,0,0,0,0,0,20,4,53,0,0,0,4,1,64,0,57],[0,0,0,11,2,0,0,41,0,0,0,0,0,33,4,53,0,0,1,44,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,1,44,3,32,0,156,0,0,0,0,2,1,128,25,0,0,1,44,3,64,0,156,0,12,0,0,0,4,0,29],[0,0,0,0,1,4,64,25,0,10,0,64,0,16,2,24,0,0,0,192,1,32,2,16,0,0,0,10,1,16,1,175],[0,0,1,77,1,16,1,199,0,0,128,4,2,0,0,57,4,169,4,154,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,4,114,0,0,97,61,0,0,0,12,1,0,0,41,0,0,1,48,1,16,0,156,0,0,4,146,0,0,161,61],[0,0,1,88,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57,0,0,2,242,0,0,1,61],[0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114,0,0,4,47,0,0,97,61,0,0,0,0,5,0,0,25],[0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53],[0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75,0,0,4,40,0,0,65,61,0,0,0,0,5,4,0,75],[0,0,4,61,0,0,97,61,0,0,0,3,4,64,2,16,0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51],[0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47,0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159],[0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16,0,0,4,171,0,1,4,48,0,0,1,50,2,0,0,65],[0,0,0,12,4,0,0,41,0,0,0,0,0,36,4,53,0,0,0,32,2,0,0,57,0,0,0,0,0,38,4,53],[0,0,0,25,2,0,0,57,0,0,0,0,0,35,4,53,0,0,1,68,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,1,44,1,0,0,65,0,0,1,44,2,64,0,156,0,0,0,0,4,1,128,25,0,0,0,64,1,64,2,16],[0,0,1,69,1,16,1,199,0,0,4,171,0,1,4,48,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143],[0,0,0,5,5,48,2,114,0,0,4,91,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,4,83,0,0,65,61,0,0,0,0,6,4,0,75],[0,0,4,106,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25],[0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,1,44,1,0,0,65,0,0,1,44,4,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,0,96,2,48,2,16,0,0,0,0,1,33,1,159],[0,0,4,171,0,1,4,48,0,0,0,0,0,1,4,47,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,0,31,4,48,1,143,0,0,1,44,3,48,1,151,0,0,0,5,5,48,2,114],[0,0,4,130,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,4,122,0,0,65,61,0,0,0,0,6,4,0,75,0,0,4,145,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,4,106,0,0,1,61,0,0,0,12,2,0,0,41,0,0,0,64,0,32,4,63],[0,0,0,11,1,0,0,41,0,0,0,0,0,18,4,53,0,0,0,10,1,0,0,41,0,0,1,78,1,16,1,199],[0,0,4,170,0,1,4,46,0,0,0,0,0,1,4,47,0,0,4,157,0,33,4,33,0,0,0,1,2,0,0,57],[0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,4,162,0,33,4,35],[0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45],[0,0,4,167,0,33,4,35,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25],[0,0,0,0,0,1,4,45,0,0,4,169,0,0,4,50,0,0,4,170,0,1,4,46,0,0,4,171,0,1,4,48],[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],[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,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,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,0,0,0,0,0,96,6,216,181],[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,245,230,154,71],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255],[128,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],[8,195,121,160,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],[67,97,108,108,97,98,108,101,32,111,110,108,121,32,98,121,32,116,104,101,32,98,111,111,116,108,111,97,100,101,114,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,128,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,0,0,0,0,0,7,255,248],[69,110,99,111,100,101,100,32,100,97,116,97,32,108,101,110,103,116,104,32,115,104,111,117,108,100,32,98,101,32,52,32],[116,105,109,101,115,32,115,104,111,114,116,101,114,32,116,104,97,110,32,116,104,101,32,111,114,105,103,105,110,97,108,32],[98,121,116,101,99,111,100,101,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,0,0,0,0,0,0,0,0,0,0,0,164,0,0,0,128,0,0,0,0,0,0,0,0],[69,110,99,111,100,101,100,32,99,104,117,110,107,32,105,110,100,101,120,32,105,115,32,111,117,116,32,111,102,32,98,111],[117,110,100,115,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[69,110,99,111,100,101,100,32,99,104,117,110,107,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,116,104,101],[32,111,114,105,103,105,110,97,108,32,98,121,116,101,99,111,100,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[112,111,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,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,32,0,0],[0,0,0,0,255,255,255,255,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,1,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,255,255,255,224],[115,104,97,32,114,101,116,117,114,110,101,100,32,105,110,118,97,108,105,100,32,100,97,116,97,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,100,0,0,0,0,0,0,0,0,0,0,0,0],[98,248,75,36,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,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[254,255,255,255,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],[1,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],[24,6,170,24,150,187,242,101,104,232,132,167,55,75,65,224,2,80,9,98,202,186,106,21,2,58,141,144,232,80,139,131],[2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[121,196,249,41,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,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,32,0,0,0,0,0,0,0,0,0,0,0,0],[112,114,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],[112,112,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],[73,110,97,112,112,114,111,112,114,105,97,116,101,32,99,97,108,108,101,114,0,0,0,0,0,0,0,0,0,0,0,0],[73,110,99,111,114,114,101,99,116,32,110,117,109,98,101,114,32,111,102,32,105,110,105,116,105,97,108,32,115,116,111,114],[97,103,101,32,100,105,102,102,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[69,120,116,114,97,32,100,97,116,97,32,105,110,32,95,99,111,109,112,114,101,115,115,101,100,83,116,97,116,101,68,105],[102,102,115,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0],[107,101,99,99,97,107,50,53,54,32,114,101,116,117,114,110,101,100,32,105,110,118,97,108,105,100,32,100,97,116,97,0],[78,72,123,113,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],[79,118,101,114,102,108,111,119,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[114,119,58,32,101,110,117,109,32,107,101,121,32,109,105,115,109,97,116,99,104,0,0,0,0,0,0,0,0,0,0,0],[105,119,58,32,105,110,105,116,105,97,108,32,107,101,121,32,109,105,115,109,97,116,99,104,0,0,0,0,0,0,0,0],[116,114,97,110,115,102,111,114,109,32,111,114,32,110,111,32,99,111,109,112,114,101,115,115,105,111,110,58,32,99,111,109],[112,114,101,115,115,101,100,32,97,110,100,32,102,105,110,97,108,32,109,105,115,109,97,116,99,104,0,0,0,0,0,0],[117,110,115,117,112,112,111,114,116,101,100,32,111,112,101,114,97,116,105,111,110,0,0,0,0,0,0,0,0,0,0,0],[115,117,98,58,32,105,110,105,116,105,97,108,32,109,105,110,117,115,32,99,111,110,118,101,114,116,101,100,32,110,111,116],[32,101,113,117,97,108,32,116,111,32,102,105,110,97,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[97,100,100,58,32,105,110,105,116,105,97,108,32,112,108,117,115,32,99,111,110,118,101,114,116,101,100,32,110,111,116,32],[101,113,117,97,108,32,116,111,32,102,105,110,97,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[101,110,117,109,101,114,97,116,105,111,110,32,105,110,100,101,120,32,115,105,122,101,32,105,115,32,116,111,111,32,108,97],[114,103,101,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,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],[147,237,218,30,222,226,171,166,87,171,181,200,3,117,136,80,212,87,97,62,0,250,54,95,145,189,19,44,198,68,90,138]],"0x0000000000000000000000000000000000008005":[[0,1,0,0,0,0,0,2,0,7,0,0,0,0,0,2,0,0,0,0,7,1,3,79,0,0,0,0,0,7,3,85],[0,0,0,128,1,0,0,57,0,0,0,64,0,16,4,63,0,0,0,0,1,7,0,25,0,0,0,96,1,16,2,112],[0,0,0,47,1,16,1,151,0,0,0,1,2,32,1,144,0,0,0,45,0,0,193,61,0,0,0,4,2,16,0,140],[0,0,0,92,0,0,65,61,0,0,0,0,2,7,4,59,0,0,0,224,2,32,2,112,0,0,0,49,3,32,0,156],[0,0,0,53,0,0,97,61,0,0,0,50,2,32,0,156,0,0,0,92,0,0,193,61,0,0,0,0,2,0,4,22],[0,0,0,0,2,2,0,75,0,0,0,92,0,0,193,61,0,0,0,4,1,16,0,138,0,0,0,64,1,16,0,140],[0,0,0,92,0,0,65,61,0,0,0,4,1,112,3,112,0,0,0,0,1,1,4,59,0,0,0,51,2,16,0,156],[0,0,0,92,0,0,33,61,0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,0,0,1,0,0,25],[0,7,0,0,0,7,3,83,0,184,0,161,0,0,4,15,0,0,0,7,2,0,3,95,0,0,0,36,2,32,3,112],[0,0,0,0,2,2,4,59,0,0,0,0,0,32,4,53,0,0,0,32,0,16,4,63,0,0,0,0,1,0,0,25],[0,184,0,161,0,0,4,15,0,0,0,0,1,1,4,26,0,0,0,128,0,16,4,63,0,0,0,59,1,0,0,65],[0,0,0,185,0,1,4,46,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,0,92,0,0,193,61],[0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,0,48,1,0,0,65],[0,0,0,185,0,1,4,46,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,0,92,0,0,193,61],[0,0,0,4,2,16,0,138,0,0,0,64,2,32,0,140,0,0,0,92,0,0,65,61,0,0,0,4,2,112,3,112],[0,0,0,0,2,2,4,59,0,3,0,0,0,2,0,29,0,0,0,51,2,32,0,156,0,0,0,92,0,0,33,61],[0,0,0,36,2,112,3,112,0,0,0,0,2,2,4,59,0,0,0,52,3,32,0,156,0,0,0,92,0,0,33,61],[0,0,0,35,3,32,0,57,0,0,0,53,4,0,0,65,0,0,0,0,5,19,0,75,0,0,0,0,5,0,0,25],[0,0,0,0,5,4,128,25,0,0,0,53,3,48,1,151,0,0,0,0,6,3,0,75,0,0,0,0,4,0,128,25],[0,0,0,53,3,48,0,156,0,0,0,0,4,5,192,25,0,0,0,0,3,4,0,75,0,0,0,92,0,0,193,61],[0,0,0,4,3,32,0,57,0,0,0,0,3,55,3,79,0,0,0,0,3,3,4,59,0,2,0,0,0,3,0,29],[0,0,0,52,3,48,0,156,0,0,0,92,0,0,33,61,0,1,0,36,0,32,0,61,0,0,0,2,2,0,0,41],[0,0,0,6,2,32,2,16,0,0,0,1,2,32,0,41,0,0,0,0,1,18,0,75,0,0,0,94,0,0,161,61],[0,0,0,0,1,0,0,25,0,0,0,186,0,1,4,48,0,0,0,0,1,0,4,17,0,0,128,6,1,16,0,140],[0,0,0,149,0,0,193,61,0,0,0,2,1,0,0,107,0,0,0,147,0,0,97,61,0,0,0,47,4,0,0,65],[0,0,128,16,5,0,0,57,0,0,0,0,2,0,0,25,0,7,0,0,0,5,0,29,0,5,0,0,0,2,0,29],[0,0,0,6,1,32,2,16,0,0,0,1,1,16,0,41,0,0,0,32,2,16,0,57,0,0,0,0,2,32,3,103],[0,0,0,0,1,16,3,103,0,0,0,0,1,1,4,59,0,6,0,0,0,1,0,29,0,0,0,0,1,2,4,59],[0,4,0,0,0,1,0,29,0,0,0,3,1,0,0,41,0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63],[0,0,0,0,1,0,4,20,0,0,0,47,2,16,0,156,0,0,0,0,1,4,128,25,0,0,0,192,1,16,2,16],[0,0,0,58,1,16,1,199,0,0,0,0,2,5,0,25,0,184,0,179,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,0,92,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,6,2,0,0,41,0,0,0,0,0,32,4,53],[0,0,0,32,0,16,4,63,0,0,0,0,1,0,4,20,0,0,0,47,2,16,0,156,0,0,0,47,1,0,128,65],[0,0,0,192,1,16,2,16,0,0,0,58,1,16,1,199,0,0,0,7,2,0,0,41,0,184,0,179,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,0,92,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,4,2,0,0,41],[0,0,0,0,0,33,4,27,0,0,0,5,2,0,0,41,0,0,0,1,2,32,0,57,0,0,0,2,1,32,0,108],[0,0,0,47,4,0,0,65,0,0,0,7,5,0,0,41,0,0,0,103,0,0,65,61,0,0,0,0,1,0,0,25],[0,0,0,185,0,1,4,46,0,0,0,54,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,132,0,16,4,63,0,0,0,45,1,0,0,57,0,0,0,164,0,16,4,63,0,0,0,55,1,0,0,65],[0,0,0,196,0,16,4,63,0,0,0,56,1,0,0,65,0,0,0,228,0,16,4,63,0,0,0,57,1,0,0,65],[0,0,0,186,0,1,4,48,0,0,0,47,2,0,0,65,0,0,0,47,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,0,3,0,4,20,0,0,0,47,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16],[0,0,0,64,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,58,1,16,1,199,0,0,128,16,2,0,0,57],[0,184,0,179,0,0,4,15,0,0,0,1,2,32,1,144,0,0,0,177,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,0,1,4,45,0,0,0,0,1,0,0,25,0,0,0,186,0,1,4,48,0,0,0,182,0,33,4,35],[0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45],[0,0,0,184,0,0,4,50,0,0,0,185,0,1,4,46,0,0,0,186,0,1,4,48,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,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,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,0,0,0,0,0,173,126,35,46],[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,49,10,176,137],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255],[128,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],[8,195,121,160,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],[67,97,108,108,97,98,108,101,32,111,110,108,121,32,98,121,32,116,104,101,32,100,101,112,108,111,121,101,114,32,115,121],[115,116,101,109,32,99,111,110,116,114,97,99,116,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,0,0,0,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,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,32,0,0,0,128,0,0,0,0,0,0,0,0],[45,190,79,211,31,131,177,86,189,1,11,166,220,219,188,181,72,177,28,249,224,128,88,180,255,86,83,72,18,128,54,40]],"0x0000000000000000000000000000000000008002":[[0,2,0,0,0,0,0,2,0,0,0,128,4,0,0,57,0,0,0,64,0,64,4,63,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,0,87,3,48,1,151,0,0,0,1,2,32,1,144,0,0,0,32,0,0,193,61],[0,0,0,4,2,48,0,140,0,0,0,219,0,0,65,61,0,0,0,0,2,1,4,59,0,0,0,224,2,32,2,112],[0,0,0,89,5,32,0,156,0,0,0,40,0,0,33,61,0,0,0,93,4,32,0,156,0,0,0,128,0,0,97,61],[0,0,0,94,4,32,0,156,0,0,0,155,0,0,97,61,0,0,0,95,2,32,0,156,0,0,0,219,0,0,193,61],[0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,0,219,0,0,193,61,0,0,0,4,2,48,0,138],[0,0,0,32,2,32,0,140,0,0,0,219,0,0,65,61,0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59],[0,0,0,97,2,16,0,156,0,0,0,219,0,0,33,61,0,0,0,0,1,1,4,26,0,0,0,178,0,0,1,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,0,219,0,0,193,61,0,0,0,32,1,0,0,57],[0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,0,88,1,0,0,65,0,0,1,86,0,1,4,46],[0,0,0,90,5,32,0,156,0,0,0,181,0,0,97,61,0,0,0,91,5,32,0,156,0,0,0,209,0,0,97,61],[0,0,0,92,2,32,0,156,0,0,0,219,0,0,193,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75],[0,0,0,219,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140,0,0,0,219,0,0,65,61],[0,0,0,96,3,0,0,65,0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59,0,0,0,97,1,16,1,151],[0,0,1,0,2,16,0,140,0,0,0,124,0,0,65,61,0,0,0,128,4,0,0,57,0,0,0,0,5,1,4,26],[0,0,0,0,2,5,0,75,0,0,0,120,0,0,193,61,0,2,0,0,0,5,0,29,0,0,0,98,2,0,0,65],[0,0,0,128,0,32,4,63,0,0,0,132,0,16,4,63,0,0,0,87,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,0,87,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,0,99,1,16,1,199],[0,0,128,3,2,0,0,57,1,85,1,80,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,87,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57],[0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114,0,0,0,92,0,0,97,61,0,0,0,0,7,0,0,25],[0,0,0,5,8,112,2,16,0,0,0,0,9,129,3,79,0,0,0,0,9,9,4,59,0,0,0,128,8,128,0,57],[0,0,0,0,0,152,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,0,84,0,0,65,61],[0,0,0,0,7,5,0,75,0,0,0,107,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79],[0,0,0,3,5,80,2,16,0,0,0,128,6,96,0,57,0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207],[0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144],[0,0,0,253,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,1,16,1,143,0,0,0,128,4,16,1,191],[0,0,0,64,0,64,4,63,0,0,0,32,1,48,0,140,0,0,0,219,0,0,65,61,0,0,0,128,1,0,4,61],[0,0,0,0,1,1,0,75,0,0,0,96,3,0,0,65,0,0,0,2,5,0,0,41,0,0,0,124,0,0,193,61],[0,0,0,100,1,80,1,151,0,0,0,96,3,0,0,65,0,0,0,101,1,16,0,156,0,0,0,0,3,5,192,25],[0,0,0,0,0,52,4,53,0,0,0,64,1,64,2,16,0,0,0,102,1,16,1,199,0,0,1,86,0,1,4,46],[0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,0,219,0,0,193,61,0,0,0,4,2,48,0,138],[0,0,0,64,2,32,0,140,0,0,0,219,0,0,65,61,0,0,0,4,2,16,3,112,0,0,0,0,2,2,4,59],[0,0,0,97,3,32,0,156,0,0,0,219,0,0,33,61,0,0,0,36,1,16,3,112,0,0,0,0,1,1,4,59],[0,0,0,0,3,0,4,17,0,0,128,6,3,48,0,140,0,0,0,241,0,0,193,61,0,0,0,100,3,16,1,152],[0,0,0,238,0,0,97,61,0,0,0,106,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,132,0,16,4,63,0,0,0,43,1,0,0,57,0,0,0,164,0,16,4,63,0,0,0,110,1,0,0,65],[0,0,0,196,0,16,4,63,0,0,0,111,1,0,0,65,0,0,0,250,0,0,1,61,0,0,0,0,2,0,4,22],[0,0,0,0,2,2,0,75,0,0,0,219,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140],[0,0,0,219,0,0,65,61,0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59,0,0,0,97,1,16,1,151],[0,0,1,0,2,16,0,140,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,0,0,1,1,4,26],[0,0,0,0,3,1,0,75,0,0,0,1,2,32,97,191,0,0,0,100,3,16,1,151,0,0,0,101,3,48,0,156],[0,0,0,0,3,0,0,25,0,0,0,1,3,0,96,57,0,0,0,0,2,50,1,160,0,0,0,219,1,16,2,112],[0,0,0,105,1,16,1,151,0,0,0,0,1,0,192,25,0,0,0,128,0,16,4,63,0,0,0,104,1,0,0,65],[0,0,1,86,0,1,4,46,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,0,219,0,0,193,61],[0,0,0,4,2,48,0,138,0,0,0,64,2,32,0,140,0,0,0,219,0,0,65,61,0,0,0,4,2,16,3,112],[0,0,0,0,3,2,4,59,0,0,0,97,2,48,0,156,0,0,0,219,0,0,33,61,0,0,0,36,1,16,3,112],[0,0,0,0,1,1,4,59,0,2,0,0,0,1,0,29,0,0,0,0,1,0,4,17,0,0,128,6,1,16,0,140],[0,0,0,0,1,0,0,25,0,0,0,1,1,0,96,57,0,1,0,0,0,3,0,29,1,85,1,32,0,0,4,15],[0,0,0,2,1,0,0,41,0,0,0,100,1,16,1,151,0,0,0,101,1,16,0,156,0,0,0,0,1,0,0,25],[0,0,0,1,1,0,96,57,1,85,1,56,0,0,4,15,0,0,0,2,1,0,0,41,0,0,0,1,2,0,0,41],[0,0,0,238,0,0,1,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,0,219,0,0,193,61],[0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140,0,0,0,219,0,0,65,61,0,0,0,4,1,16,3,112],[0,0,0,0,2,1,4,59,0,0,0,97,1,32,0,156,0,0,0,221,0,0,161,61,0,0,0,0,1,0,0,25],[0,0,1,87,0,1,4,48,0,0,0,0,1,0,4,17,0,0,128,6,1,16,0,140,0,0,0,0,1,0,0,25],[0,0,0,1,1,0,96,57,0,2,0,0,0,2,0,29,1,85,1,32,0,0,4,15,0,0,0,2,1,0,0,41],[0,0,0,0,1,1,4,26,0,1,0,0,0,1,0,29,0,0,0,100,1,16,1,151,0,0,0,101,1,16,0,156],[0,0,0,0,1,0,0,25,0,0,0,1,1,0,96,57,1,85,1,56,0,0,4,15,0,0,0,1,1,0,0,41],[0,0,0,103,1,16,1,151,0,0,0,2,2,0,0,41,0,0,0,0,0,18,4,27,0,0,0,0,1,0,0,25],[0,0,1,86,0,1,4,46,0,0,0,106,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,132,0,16,4,63,0,0,0,45,1,0,0,57,0,0,0,164,0,16,4,63,0,0,0,107,1,0,0,65],[0,0,0,196,0,16,4,63,0,0,0,108,1,0,0,65,0,0,0,228,0,16,4,63,0,0,0,109,1,0,0,65],[0,0,1,87,0,1,4,48,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114],[0,0,1,10,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,1,2,0,0,65,61,0,0,0,0,6,4,0,75,0,0,1,25,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,0,87,1,0,0,65,0,0,0,87,4,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,64,1,32,2,16,0,0,0,96,2,48,2,16,0,0,0,0,1,33,1,159,0,0,1,87,0,1,4,48],[0,0,0,0,1,1,0,75,0,0,1,35,0,0,97,61,0,0,0,0,0,1,4,45,0,0,0,64,1,0,4,61],[0,0,0,100,2,16,0,57,0,0,0,108,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,68,2,16,0,57],[0,0,0,107,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,45,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,0,106,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57],[0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53,0,0,0,87,2,0,0,65,0,0,0,87,3,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,0,112,1,16,1,199,0,0,1,87,0,1,4,48],[0,0,0,0,1,1,0,75,0,0,1,59,0,0,97,61,0,0,0,0,0,1,4,45,0,0,0,64,1,0,4,61],[0,0,0,100,2,16,0,57,0,0,0,113,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,68,2,16,0,57],[0,0,0,114,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,46,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,0,106,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57],[0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53,0,0,0,87,2,0,0,65,0,0,0,87,3,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,0,112,1,16,1,199,0,0,1,87,0,1,4,48],[0,0,1,83,0,33,4,35,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25],[0,0,0,0,0,1,4,45,0,0,1,85,0,0,4,50,0,0,1,86,0,1,4,46,0,0,1,87,0,1,4,48],[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],[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,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,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,0,0,0,0,0,79,30,27,223],[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,79,30,27,224],[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,194,228,255,151],[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,224,63,225,119],[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,13,70,81,170],[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,24,6,170,24],[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,77,226,228,104],[197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[90,169,182,181,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,128,0,0,0,0,0,0,0,0],[0,255,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,1,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[255,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,128,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,0,0,0,0,0,31,255,224],[8,195,121,160,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],[67,97,108,108,97,98,108,101,32,111,110,108,121,32,98,121,32,116,104,101,32,100,101,112,108,111,121,101,114,32,115,121],[115,116,101,109,32,99,111,110,116,114,97,99,116,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,0,0,0,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[67,111,100,101,32,104,97,115,104,32,105,115,32,110,111,116,32,102,111,114,32,97,32,99,111,110,115,116,114,117,99,116],[101,100,32,99,111,110,116,114,97,99,116,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,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,0,0],[111,110,32,99,111,110,115,116,114,117,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[67,111,100,101,32,104,97,115,104,32,105,115,32,110,111,116,32,102,111,114,32,97,32,99,111,110,116,114,97,99,116,32],[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],[15,243,112,141,14,128,123,204,107,242,108,43,72,61,107,108,176,29,30,252,146,140,189,19,149,85,233,118,103,32,255,241]],"0x0000000000000000000000000000000000008008":[[0,2,0,0,0,0,0,2,0,14,0,0,0,0,0,2,0,1,0,0,0,1,3,85,0,0,0,0,3,1,0,25],[0,0,0,96,5,48,2,112,0,0,2,60,0,80,1,157,0,0,0,128,4,0,0,57,0,0,0,64,0,64,4,63],[0,0,2,60,3,80,1,151,0,0,0,1,2,32,1,144,0,0,0,49,0,0,193,61,0,0,0,4,2,48,0,140],[0,0,1,37,0,0,65,61,0,0,0,0,2,1,4,59,0,0,0,224,2,32,2,112,0,0,2,62,6,32,0,156],[0,0,0,57,0,0,33,61,0,0,2,65,4,32,0,156,0,0,0,113,0,0,97,61,0,0,2,66,2,32,0,156],[0,0,1,37,0,0,193,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,1,37,0,0,193,61],[0,0,0,4,2,48,0,138,0,0,0,96,2,32,0,140,0,0,1,37,0,0,65,61,0,0,0,4,1,16,3,112],[0,0,0,0,3,1,4,59,0,0,0,0,1,3,0,75,0,0,0,0,1,0,0,25,0,0,0,1,1,0,192,57],[0,0,0,0,1,19,0,75,0,0,1,37,0,0,193,61,0,0,0,0,2,0,4,17,0,0,2,129,1,32,0,156],[0,0,0,236,0,0,65,61,0,0,2,87,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,132,0,16,4,63,0,0,0,52,1,0,0,57,0,0,0,164,0,16,4,63,0,0,2,131,1,0,0,65],[0,0,0,196,0,16,4,63,0,0,2,132,1,0,0,65,0,0,0,228,0,16,4,63,0,0,2,133,1,0,0,65],[0,0,8,236,0,1,4,48,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,1,37,0,0,193,61],[0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,2,61,1,0,0,65],[0,0,8,235,0,1,4,46,0,0,2,63,6,32,0,156,0,0,0,174,0,0,97,61,0,0,2,64,2,32,0,156],[0,0,1,37,0,0,193,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,1,37,0,0,193,61],[0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140,0,0,1,37,0,0,65,61,0,0,0,4,2,16,3,112],[0,0,0,0,2,2,4,59,0,0,2,67,6,32,0,156,0,0,1,37,0,0,33,61,0,0,0,35,6,32,0,57],[0,0,2,68,7,0,0,65,0,0,0,0,8,54,0,75,0,0,0,0,8,0,0,25,0,0,0,0,8,7,128,25],[0,0,2,68,6,96,1,151,0,0,0,0,9,6,0,75,0,0,0,0,7,0,128,25,0,0,2,68,6,96,0,156],[0,0,0,0,7,8,192,25,0,0,0,0,6,7,0,75,0,0,1,37,0,0,193,61,0,0,0,4,6,32,0,57],[0,0,0,0,6,97,3,79,0,0,0,0,7,6,4,59,0,0,2,67,6,112,0,156,0,0,1,37,0,0,33,61],[0,0,0,36,8,32,0,57,0,0,0,0,2,135,0,25,0,0,0,0,3,35,0,75,0,0,1,37,0,0,65,61],[0,0,0,0,9,0,4,20,0,0,0,0,3,0,4,20,0,0,2,69,6,48,0,156,0,0,1,74,0,0,65,61],[0,0,0,68,1,64,0,57,0,0,2,89,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,36,1,64,0,57],[0,0,0,8,2,0,0,57,0,0,0,0,0,33,4,53,0,0,2,87,1,0,0,65,0,0,0,0,0,20,4,53],[0,0,0,4,1,64,0,57,0,0,0,32,2,0,0,57,0,0,0,0,0,33,4,53,0,0,2,60,1,0,0,65],[0,0,2,60,2,64,0,156,0,0,0,0,4,1,128,25,0,0,0,64,1,64,2,16,0,0,2,88,1,16,1,199],[0,0,8,236,0,1,4,48,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,1,37,0,0,193,61],[0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140,0,0,1,37,0,0,65,61,0,0,0,0,2,0,4,17],[0,0,128,4,2,32,0,140,0,0,0,226,0,0,193,61,0,0,0,4,1,16,3,112,0,0,0,0,2,1,4,59],[0,0,0,3,1,0,0,57,0,13,0,0,0,1,0,29,0,0,0,0,1,1,4,26,0,0,0,160,0,16,4,63],[0,14,0,0,0,2,0,29,0,0,0,192,0,32,4,63,0,0,0,64,1,0,0,57,0,0,0,128,0,16,4,63],[0,0,0,224,1,0,0,57,0,0,0,64,0,16,4,63,0,0,2,60,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,2,60,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,2,135,1,16,1,199],[0,0,128,16,2,0,0,57,8,234,8,224,0,0,4,15,0,0,0,1,2,32,1,144,0,0,1,37,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,13,2,0,0,41,0,0,0,0,0,18,4,27,0,0,0,0,1,0,4,19],[0,0,2,60,3,16,1,151,0,0,0,14,6,0,0,41,0,0,0,224,1,96,2,112,0,0,255,255,2,16,1,143],[0,0,0,5,1,32,2,16,0,0,0,4,4,16,1,191,0,0,0,0,81,67,0,169,0,0,0,0,84,65,0,217],[0,0,0,0,3,67,0,75,0,0,1,157,0,0,193,61,0,0,0,1,2,32,2,112,0,0,0,1,3,32,0,57],[0,0,0,7,66,48,0,201,0,0,0,7,84,32,1,26,0,0,0,0,3,67,0,75,0,0,1,157,0,0,193,61],[0,0,0,0,1,33,0,25,0,0,2,136,2,16,0,156,0,0,1,223,0,0,65,61,0,0,0,64,1,0,4,61],[0,0,0,68,2,16,0,57,0,0,2,89,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,8,3,0,0,57,0,0,5,238,0,0,1,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75],[0,0,1,37,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140,0,0,1,37,0,0,65,61],[0,0,0,4,2,16,3,112,0,0,0,0,2,2,4,59,0,0,2,67,4,32,0,156,0,0,1,37,0,0,33,61],[0,0,0,35,4,32,0,57,0,0,2,68,5,0,0,65,0,0,0,0,6,52,0,75,0,0,0,0,6,0,0,25],[0,0,0,0,6,5,128,25,0,0,2,68,4,64,1,151,0,0,0,0,7,4,0,75,0,0,0,0,5,0,128,25],[0,0,2,68,4,64,0,156,0,0,0,0,5,6,192,25,0,0,0,0,4,5,0,75,0,0,1,37,0,0,193,61],[0,0,0,4,4,32,0,57,0,0,0,0,5,65,3,79,0,0,0,0,5,5,4,59,0,11,0,0,0,5,0,29],[0,0,2,67,5,80,0,156,0,0,1,37,0,0,33,61,0,0,0,36,2,32,0,57,0,10,0,0,0,2,0,29],[0,0,0,11,2,32,0,41,0,0,0,0,2,50,0,75,0,0,1,37,0,0,33,61,0,0,0,0,2,0,4,17],[0,0,128,1,2,32,0,140,0,0,1,163,0,0,193,61,0,0,0,11,2,0,0,41,0,0,0,4,2,32,0,140],[0,0,1,37,0,0,65,61,0,0,0,32,2,64,0,57,0,0,0,0,2,33,3,79,0,0,0,0,4,2,4,59],[0,0,2,92,2,64,0,156,0,0,2,155,0,0,65,61,0,0,2,87,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,20,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,2,128,1,0,0,65,0,0,0,233,0,0,1,61,0,0,2,87,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,20,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,2,134,1,0,0,65,0,0,0,196,0,16,4,63,0,0,2,91,1,0,0,65,0,0,8,236,0,1,4,48],[0,14,0,0,0,3,0,29,0,13,0,0,0,2,0,29,0,0,2,75,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,2,60,1,0,0,65,0,0,0,0,2,0,4,20,0,0,2,60,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,2,130,1,16,1,199,0,0,128,11,2,0,0,57,8,234,8,224,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,2,60,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114],[0,0,1,10,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,129,3,79],[0,0,0,0,9,9,4,59,0,0,0,128,8,128,0,57,0,0,0,0,0,152,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,103,0,75,0,0,1,2,0,0,65,61,0,0,0,0,7,5,0,75,0,0,1,25,0,0,97,61],[0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,3,5,80,2,16,0,0,0,128,6,96,0,57],[0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159],[0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144,0,0,1,39,0,0,97,61,0,0,0,31,1,64,0,57],[0,0,0,96,2,16,1,143,0,0,0,128,8,32,1,191,0,0,0,64,0,128,4,63,0,0,0,32,1,48,0,140],[0,0,0,14,5,0,0,41,0,0,1,37,0,0,65,61,0,0,0,128,1,0,4,61,0,0,255,255,3,16,0,140],[0,0,1,171,0,0,161,61,0,0,0,0,1,0,0,25,0,0,8,236,0,1,4,48,0,0,0,64,2,0,4,61],[0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,1,52,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,1,44,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,1,67,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,2,60,1,0,0,65],[0,0,2,60,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,0,96,2,48,2,16],[0,0,0,0,1,33,1,159,0,0,8,236,0,1,4,48,0,14,0,0,0,9,0,29,0,13,0,0,0,7,0,29],[0,12,0,0,0,8,0,29,0,0,2,60,4,128,1,151,0,0,0,0,1,65,3,79,0,0,0,0,2,37,0,73],[0,0,2,60,2,32,1,151,0,0,0,0,1,33,3,223,0,0,0,192,2,48,2,16,0,0,2,70,2,32,1,151],[0,0,2,71,2,32,1,199,0,0,0,0,1,33,3,175,0,0,128,16,2,0,0,57,8,234,8,229,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,2,60,3,48,1,151,0,0,0,1,2,32,1,144],[0,0,1,234,0,0,97,61,0,0,0,63,2,48,0,57,0,0,2,72,4,32,1,151,0,0,0,64,2,0,4,61],[0,0,0,0,4,66,0,25,0,0,0,0,5,36,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57],[0,0,2,67,6,64,0,156,0,0,1,219,0,0,33,61,0,0,0,1,5,80,1,144,0,0,1,219,0,0,193,61],[0,0,0,64,0,64,4,63,0,0,0,0,4,50,4,54,0,0,0,31,5,48,0,57,0,0,0,5,5,80,2,114],[0,0,1,120,0,0,97,61,0,0,0,0,6,0,0,49,0,0,0,1,6,96,3,103,0,0,0,0,7,0,0,25],[0,0,0,5,8,112,2,16,0,0,0,0,9,132,0,25,0,0,0,0,8,134,3,79,0,0,0,0,8,8,4,59],[0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,87,0,75,0,0,1,112,0,0,65,61],[0,0,0,0,5,0,0,75,0,0,1,122,0,0,97,61,0,0,0,31,5,48,1,143,0,0,0,5,3,48,2,114],[0,0,0,14,9,0,0,41,0,0,1,135,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,116,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,54,0,75,0,0,1,127,0,0,65,61,0,0,0,0,6,5,0,75],[0,0,1,150,0,0,97,61,0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79,0,0,0,0,3,52,0,25],[0,0,0,3,5,80,2,16,0,0,0,0,6,3,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,5,80,0,137,0,0,0,0,1,81,2,47,0,0,0,0,1,81,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,19,4,53,0,0,0,0,1,2,4,51,0,0,0,32,1,16,0,140],[0,0,5,232,0,0,193,61,0,0,0,0,4,4,4,51,0,0,0,0,2,0,4,20,0,0,0,0,1,41,0,75],[0,0,3,173,0,0,129,61,0,0,2,126,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,2,127,1,0,0,65,0,0,8,236,0,1,4,48,0,0,2,87,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,31,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,2,90,1,0,0,65,0,0,0,233,0,0,1,61,0,0,1,64,3,32,0,57],[0,0,0,64,0,48,4,63,0,0,0,0,0,8,4,53,0,0,0,160,3,32,0,57,0,11,0,0,0,3,0,29],[0,0,0,0,0,83,4,53,0,0,2,79,4,0,0,65,0,0,0,0,3,5,0,75,0,0,0,0,4,0,96,25],[0,0,0,224,3,32,0,57,0,14,0,0,0,3,0,29,0,0,0,13,9,0,0,41,0,0,0,0,0,147,4,53],[0,0,0,192,3,32,0,57,0,9,0,0,0,3,0,29,0,0,0,0,0,19,4,53,0,0,0,1,3,0,3,103],[0,0,0,36,5,48,3,112,0,0,0,0,5,5,4,59,0,0,1,32,7,32,0,57,0,0,1,0,2,32,1,191],[0,10,0,0,0,2,0,29,0,0,0,0,0,82,4,53,0,0,0,68,2,48,3,112,0,0,0,0,6,2,4,59],[0,12,0,0,0,7,0,29,0,0,0,0,0,103,4,53,0,0,0,0,2,8,4,51,0,0,0,248,7,32,2,16],[0,0,0,64,2,0,4,61,0,0,0,32,3,32,0,57,0,0,0,0,0,115,4,53,0,0,0,33,7,32,0,57],[0,0,0,0,0,71,4,53,0,0,0,240,1,16,2,16,0,0,0,34,4,32,0,57,0,0,0,0,0,20,4,53],[0,0,0,96,1,144,2,16,0,0,0,36,4,32,0,57,0,0,0,0,0,20,4,53,0,0,0,88,1,32,0,57],[0,0,0,0,0,97,4,53,0,0,0,56,1,32,0,57,0,0,0,0,0,81,4,53,0,0,0,88,1,0,0,57],[0,0,0,0,0,18,4,53,0,0,2,80,1,32,0,156,0,0,2,5,0,0,161,61,0,0,2,126,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57,0,0,1,160,0,0,1,61,0,0,0,40,1,16,0,57],[0,0,0,0,2,16,4,32,0,0,0,64,1,0,4,61,0,0,0,0,2,2,0,75,0,0,2,136,0,0,193,61],[0,0,0,68,2,16,0,57,0,0,2,86,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,20,3,0,0,57,0,0,5,238,0,0,1,61,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114],[0,0,1,245,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75],[0,0,1,238,0,0,65,61,0,0,0,0,5,4,0,75,0,0,2,3,0,0,97,61,0,0,0,3,4,64,2,16],[0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47],[0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16],[0,0,8,236,0,1,4,48,0,0,0,128,1,32,0,57,0,0,0,64,0,16,4,63,0,0,2,60,1,0,0,65],[0,0,2,60,4,48,0,156,0,0,0,0,3,1,128,25,0,0,0,64,3,48,2,16,0,0,0,0,2,2,4,51],[0,0,2,60,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,96,2,32,2,16,0,0,0,0,2,50,1,159],[0,0,0,0,3,0,4,20,0,0,2,60,4,48,0,156,0,0,0,0,3,1,128,25,0,0,0,192,1,48,2,16],[0,0,0,0,1,33,1,159,0,0,2,74,1,16,1,199,0,0,128,16,2,0,0,57,0,13,0,0,0,8,0,29],[8,234,8,224,0,0,4,15,0,0,0,1,2,32,1,144,0,0,1,37,0,0,97,61,0,0,0,0,2,1,4,59],[0,0,0,64,1,0,4,61,0,0,0,64,3,16,0,57,0,0,0,0,4,0,4,26,0,0,0,0,0,35,4,53],[0,0,0,32,2,16,0,57,0,0,0,0,0,66,4,53,0,0,0,64,3,0,0,57,0,0,0,0,0,49,4,53],[0,0,2,73,3,16,0,156,0,0,1,219,0,0,33,61,0,0,0,96,3,16,0,57,0,0,0,64,0,48,4,63],[0,0,2,60,3,0,0,65,0,0,2,60,4,32,0,156,0,0,0,0,2,3,128,25,0,0,0,64,2,32,2,16],[0,0,0,0,1,1,4,51,0,0,2,60,4,16,0,156,0,0,0,0,1,3,128,25,0,0,0,96,1,16,2,16],[0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20,0,0,2,60,4,32,0,156,0,0,0,0,2,3,128,25],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,2,74,1,16,1,199,0,0,128,16,2,0,0,57],[8,234,8,224,0,0,4,15,0,0,0,1,2,32,1,144,0,0,1,37,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,0,16,4,27,0,0,0,1,3,0,0,57,0,0,0,0,2,3,4,26,0,0,0,1,1,0,0,138],[0,8,0,0,0,2,0,29,0,0,0,0,1,18,0,75,0,0,1,157,0,0,97,61,0,0,0,8,1,0,0,41],[0,0,0,1,1,16,0,57,0,0,0,0,0,19,4,27,0,0,0,13,1,0,0,41,0,0,0,0,1,1,4,51],[0,0,0,255,1,16,1,143,0,0,0,64,2,0,4,61,0,0,0,0,1,18,4,54,0,0,0,11,4,0,0,41],[0,0,0,0,4,4,4,51,0,0,0,0,4,4,0,75,0,0,0,0,4,0,0,25,0,0,0,1,4,0,192,57],[0,0,0,0,0,65,4,53,0,0,0,9,1,0,0,41,0,0,0,0,1,1,4,51,0,0,255,255,1,16,1,143],[0,0,0,64,4,32,0,57,0,0,0,0,0,20,4,53,0,0,0,14,1,0,0,41,0,0,0,0,1,1,4,51],[0,0,2,78,1,16,1,151,0,0,0,96,4,32,0,57,0,0,0,0,0,20,4,53,0,0,0,10,1,0,0,41],[0,0,0,0,1,1,4,51,0,0,0,128,4,32,0,57,0,0,0,0,0,20,4,53,0,0,0,12,1,0,0,41],[0,0,0,0,1,1,4,51,0,0,0,160,4,32,0,57,0,0,0,0,0,20,4,53,0,0,2,60,5,0,0,65],[0,0,2,60,1,32,0,156,0,0,0,0,2,5,128,25,0,0,0,0,1,0,4,20,0,0,2,60,4,16,0,156],[0,0,0,0,1,5,128,25,0,0,0,64,2,32,2,16,0,0,0,192,1,16,2,16,0,0,0,0,1,33,1,159],[0,0,2,81,1,16,1,199,0,0,128,13,2,0,0,57,0,0,2,82,4,0,0,65,8,234,8,219,0,0,4,15],[0,0,0,1,1,32,1,144,0,0,1,37,0,0,97,61,0,0,0,120,1,0,0,57,0,0,0,0,3,16,4,32],[0,0,0,64,1,0,4,61,0,0,2,60,2,16,0,156,0,0,2,60,2,0,0,65,0,0,0,0,2,1,64,25],[0,0,0,64,2,32,2,16,0,0,0,0,3,3,0,75,0,0,5,2,0,0,193,61,0,0,0,68,3,16,0,57],[0,0,2,86,4,0,0,65,0,0,0,0,0,67,4,53,0,0,0,36,3,16,0,57,0,0,0,20,4,0,0,57],[0,0,0,0,0,67,4,53,0,0,2,87,3,0,0,65,0,0,0,0,0,49,4,53,0,0,0,4,1,16,0,57],[0,0,0,32,3,0,0,57,0,0,0,0,0,49,4,53,0,0,2,88,1,32,1,199,0,0,8,236,0,1,4,48],[0,0,0,0,0,97,4,53,0,0,2,60,2,0,0,65,0,0,0,0,3,0,4,20,0,0,2,60,4,48,0,156],[0,0,0,0,3,2,128,25,0,0,2,60,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16],[0,0,0,192,2,48,2,16,0,0,0,0,1,18,1,159,0,0,2,137,1,16,1,199,0,0,128,13,2,0,0,57],[0,0,0,1,3,0,0,57,0,0,2,138,4,0,0,65,8,234,8,219,0,0,4,15,0,0,0,1,1,32,1,144],[0,0,1,37,0,0,97,61,0,0,0,0,1,0,0,25,0,0,8,235,0,1,4,46,0,0,0,0,1,49,3,79],[0,6,0,0,0,4,0,29,0,0,0,224,6,64,2,112,0,0,2,93,2,0,0,65,0,0,0,64,0,32,4,63],[0,0,8,0,2,0,0,57,0,7,0,0,0,2,0,29,0,0,0,128,0,32,4,63,0,0,0,160,2,0,0,57],[0,0,0,0,3,0,0,25,0,0,0,5,4,48,2,16,0,0,0,0,4,65,3,79,0,0,0,0,4,4,4,59],[0,0,0,0,2,66,4,54,0,0,0,1,3,48,0,57,0,0,8,0,4,48,0,140,0,0,2,165,0,0,65,61],[0,0,0,4,2,0,0,57,0,0,0,6,1,0,0,41,0,0,2,71,1,16,0,156,0,0,0,0,8,0,0,25],[0,0,3,10,0,0,129,61,0,0,0,0,1,0,4,26,0,0,0,0,1,24,0,75,0,0,3,152,0,0,193,61],[0,13,0,0,0,2,0,29,0,0,0,6,1,0,0,41,0,0,2,97,1,16,0,156,0,0,2,194,0,0,33,61],[0,0,2,98,1,0,0,65,0,0,0,128,2,0,4,61,0,0,0,0,2,98,0,75,0,0,3,6,0,0,161,61],[0,0,0,5,2,96,2,16,0,0,0,160,2,32,0,57,0,0,0,0,0,18,4,53,0,0,7,255,2,96,0,140],[0,0,0,1,6,96,0,57,0,0,2,185,0,0,65,61,0,9,0,64,0,0,0,61,0,8,128,16,0,0,0,61],[0,0,0,7,1,0,0,41,0,6,0,0,0,1,0,29,0,7,0,1,0,16,2,120,0,0,0,0,4,0,0,25],[0,0,0,1,1,64,2,16,0,0,0,128,2,0,4,61,0,0,0,0,3,18,0,75,0,0,3,6,0,0,161,61],[0,0,0,1,1,16,1,191,0,0,0,0,2,18,0,75,0,0,3,6,0,0,161,61,0,0,0,5,1,16,2,16],[0,0,0,160,1,16,0,57,0,0,0,0,2,1,4,51,0,14,0,0,0,4,0,29,0,0,0,6,1,64,2,16],[0,0,0,160,1,16,0,57,0,12,0,0,0,1,0,29,0,0,0,0,3,1,4,51,0,0,0,64,1,0,4,61],[0,0,0,64,4,16,0,57,0,0,0,0,0,36,4,53,0,0,0,32,2,16,0,57,0,0,0,0,0,50,4,53],[0,0,0,9,3,0,0,41,0,0,0,0,0,49,4,53,0,0,2,73,3,16,0,156,0,0,1,219,0,0,33,61],[0,0,0,96,3,16,0,57,0,0,0,64,0,48,4,63,0,0,2,60,3,32,0,156,0,0,2,60,4,0,0,65],[0,0,0,0,2,4,128,25,0,0,0,64,2,32,2,16,0,0,0,0,1,1,4,51,0,0,2,60,3,16,0,156],[0,0,0,0,1,4,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20],[0,0,2,60,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,2,74,1,16,1,199,0,0,0,8,2,0,0,41,8,234,8,224,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,1,37,0,0,97,61,0,0,0,128,2,0,4,61,0,0,0,14,4,0,0,41,0,0,0,0,2,66,0,75],[0,0,3,6,0,0,161,61,0,0,0,5,2,64,2,16,0,0,0,12,2,32,0,105,0,0,0,0,1,1,4,59],[0,0,0,0,0,18,4,53,0,0,0,1,4,64,0,57,0,0,0,7,1,64,0,108,0,0,2,200,0,0,65,61],[0,0,0,6,1,0,0,41,0,0,0,3,1,16,0,140,0,0,2,196,0,0,33,61,0,0,0,128,1,0,4,61],[0,0,0,0,1,1,0,75,0,0,5,6,0,0,193,61,0,0,2,126,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,50,1,0,0,57,0,0,1,160,0,0,1,61,0,0,0,4,1,0,0,57,0,9,0,89,0,0,0,146],[0,0,0,0,7,0,0,25,0,0,0,0,8,0,0,25,0,8,0,0,0,6,0,29,0,0,0,88,3,16,0,57],[0,13,0,0,0,3,0,29,0,0,0,11,2,48,0,108,0,0,1,37,0,0,33,61,0,0,0,10,2,16,0,41],[0,0,0,0,1,0,4,20,0,0,2,60,3,32,1,151,0,0,0,9,4,32,0,108,0,0,1,157,0,0,33,61],[0,0,0,88,2,32,0,57,0,0,0,0,4,0,0,49,0,0,0,0,5,36,0,75,0,0,1,157,0,0,65,61],[0,12,0,0,0,8,0,29,0,14,0,0,0,7,0,29,0,0,0,1,3,48,3,103,0,0,2,60,5,16,0,156],[0,0,0,167,0,0,33,61,0,0,0,0,2,36,0,73,0,0,2,60,2,32,1,151,0,0,0,0,2,35,3,223],[0,0,0,192,1,16,2,16,0,0,2,70,1,16,1,151,0,0,2,71,1,16,1,199,0,0,0,0,1,18,3,175],[0,0,128,16,2,0,0,57,8,234,8,229,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,2,60,3,48,1,151,0,0,0,1,2,32,1,144,0,0,4,202,0,0,97,61,0,0,0,63,2,48,0,57],[0,0,2,72,4,32,1,151,0,0,0,64,2,0,4,61,0,0,0,0,4,66,0,25,0,0,0,0,5,36,0,75],[0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57,0,0,2,67,6,64,0,156,0,0,1,219,0,0,33,61],[0,0,0,1,5,80,1,144,0,0,1,219,0,0,193,61,0,0,0,64,0,64,4,63,0,0,0,0,4,50,4,54],[0,0,0,31,5,48,0,57,0,0,0,5,5,80,2,114,0,0,3,74,0,0,97,61,0,0,0,0,6,0,0,49],[0,0,0,1,6,96,3,103,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,132,0,25],[0,0,0,0,8,134,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,87,0,75,0,0,3,66,0,0,65,61,0,0,0,0,5,0,0,75,0,0,3,76,0,0,97,61],[0,0,0,5,5,48,2,114,0,0,3,87,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,116,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,3,79,0,0,65,61,0,0,0,31,3,48,1,144],[0,0,3,102,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,84,0,25],[0,0,0,3,3,48,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,54,1,207,0,0,0,0,6,54,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,3,48,0,137,0,0,0,0,1,49,2,47,0,0,0,0,1,49,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,0,0,1,2,4,51,0,0,0,32,1,16,0,140],[0,0,0,14,3,0,0,41,0,0,0,12,5,0,0,41,0,0,5,232,0,0,193,61,0,0,0,128,1,0,4,61],[0,0,0,0,1,49,0,75,0,0,3,6,0,0,161,61,0,0,0,0,2,4,4,51,0,0,0,5,1,48,2,16],[0,0,0,160,1,16,0,57,0,0,0,0,0,33,4,53,0,0,0,64,1,0,4,61,0,0,0,64,3,16,0,57],[0,0,0,0,0,35,4,53,0,0,0,64,2,0,0,57,0,0,0,0,2,33,4,54,0,0,0,0,0,82,4,53],[0,0,2,73,3,16,0,156,0,0,1,219,0,0,33,61,0,0,0,96,3,16,0,57,0,0,0,64,0,48,4,63],[0,0,2,60,3,32,0,156,0,0,2,60,4,0,0,65,0,0,0,0,2,4,128,25,0,0,0,64,2,32,2,16],[0,0,0,0,1,1,4,51,0,0,2,60,3,16,0,156,0,0,0,0,1,4,128,25,0,0,0,96,1,16,2,16],[0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20,0,0,2,60,3,32,0,156,0,0,0,0,2,4,128,25],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,2,74,1,16,1,199,0,0,128,16,2,0,0,57],[8,234,8,224,0,0,4,15,0,0,0,1,2,32,1,144,0,0,0,8,6,0,0,41,0,0,0,14,7,0,0,41],[0,0,1,37,0,0,97,61,0,0,0,0,8,1,4,59,0,0,0,1,7,112,0,57,0,0,0,0,1,103,0,75],[0,0,0,13,2,0,0,41,0,0,0,0,1,2,0,25,0,0,3,15,0,0,65,61,0,0,2,177,0,0,1,61],[0,0,0,64,1,0,4,61,0,0,0,100,2,16,0,57,0,0,2,94,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,68,2,16,0,57,0,0,2,95,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,60,3,0,0,57,0,0,0,0,0,50,4,53,0,0,2,87,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53,0,0,2,60,2,0,0,65],[0,0,2,60,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,2,96,1,16,1,199],[0,0,8,236,0,1,4,48,0,8,0,0,0,2,0,29,0,0,0,2,1,0,0,57,0,11,0,0,0,1,0,29],[0,0,0,0,3,1,4,26,0,0,0,64,1,0,4,61,0,0,0,64,2,16,0,57,0,10,0,0,0,4,0,29],[0,0,0,0,0,66,4,53,0,0,0,32,2,16,0,57,0,0,0,0,0,50,4,53,0,0,0,64,3,0,0,57],[0,9,0,0,0,3,0,29,0,0,0,0,0,49,4,53,0,0,2,73,3,16,0,156,0,0,1,219,0,0,33,61],[0,0,0,96,3,16,0,57,0,0,0,64,0,48,4,63,0,0,2,60,4,0,0,65,0,0,2,60,3,32,0,156],[0,0,0,0,2,4,128,25,0,0,0,64,2,32,2,16,0,0,0,0,1,1,4,51,0,0,2,60,3,16,0,156],[0,0,0,0,1,4,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20],[0,0,2,60,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,2,74,1,16,1,199,0,0,128,16,2,0,0,57,8,234,8,224,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,1,37,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,11,2,0,0,41,0,0,0,0,0,18,4,27],[0,0,2,75,1,0,0,65,0,0,0,64,4,0,4,61,0,11,0,0,0,4,0,29,0,0,0,0,0,20,4,53],[0,0,0,0,1,0,4,20,0,0,2,60,2,16,0,156,0,0,2,60,3,0,0,65,0,0,0,0,1,3,128,25],[0,0,2,60,2,64,0,156,0,0,0,0,3,4,64,25,0,0,0,64,2,48,2,16,0,0,0,192,1,16,2,16],[0,0,0,0,1,33,1,159,0,0,2,76,1,16,1,199,0,0,128,11,2,0,0,57,8,234,8,224,0,0,4,15],[0,0,0,11,10,0,0,41,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,2,60,3,48,1,151],[0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143],[0,0,0,5,6,64,2,114,0,0,3,247,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16],[0,0,0,0,9,138,0,25,0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53],[0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,3,239,0,0,65,61,0,0,0,0,9,10,0,25],[0,0,0,0,7,5,0,75,0,0,4,7,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,6,105,0,25,0,0,0,3,5,80,2,16,0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207],[0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144],[0,0,4,229,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,1,16,1,143,0,0,0,0,2,145,0,25],[0,0,0,0,1,18,0,75,0,0,0,0,1,0,0,25,0,0,0,1,1,0,64,57,0,7,0,0,0,2,0,29],[0,0,2,67,2,32,0,156,0,0,1,219,0,0,33,61,0,0,0,1,1,16,1,144,0,0,1,219,0,0,193,61],[0,0,0,7,1,0,0,41,0,0,0,64,0,16,4,63,0,0,0,32,1,48,0,140,0,0,1,37,0,0,65,61],[0,0,0,0,1,9,4,51,0,0,255,255,2,16,0,140,0,0,1,37,0,0,33,61,0,0,0,7,2,0,0,41],[0,0,2,77,2,32,0,156,0,0,1,219,0,0,33,61,0,0,0,7,3,0,0,41,0,0,0,192,2,48,0,57],[0,0,0,64,0,32,4,63,0,0,0,0,4,0,4,16,0,0,2,78,2,64,1,151,0,0,0,96,5,48,0,57],[0,5,0,0,0,5,0,29,0,0,0,0,0,37,4,53,0,0,0,32,5,48,0,57,0,0,0,1,2,0,0,57],[0,11,0,0,0,2,0,29,0,3,0,0,0,5,0,29,0,0,0,0,0,37,4,53,0,0,0,160,2,48,0,57],[0,0,0,10,7,0,0,41,0,6,0,0,0,2,0,29,0,0,0,0,0,114,4,53,0,0,0,128,2,48,0,57],[0,0,0,0,8,0,4,17,0,4,0,0,0,2,0,29,0,0,0,0,0,130,4,53,0,0,0,0,0,3,4,53],[0,0,0,64,2,48,0,57,0,2,0,0,0,2,0,29,0,0,0,0,0,18,4,53,0,0,0,64,2,0,4,61],[0,0,0,32,3,32,0,57,0,0,0,0,0,3,4,53,0,0,0,33,5,32,0,57,0,0,2,79,6,0,0,65],[0,0,0,0,0,101,4,53,0,0,0,240,1,16,2,16,0,0,0,34,5,32,0,57,0,0,0,0,0,21,4,53],[0,0,0,96,1,64,2,16,0,0,0,36,4,32,0,57,0,0,0,0,0,20,4,53,0,0,0,88,1,32,0,57],[0,0,0,0,0,113,4,53,0,0,0,88,1,0,0,57,0,0,0,0,0,18,4,53,0,0,0,56,1,32,0,57],[0,1,0,0,0,8,0,29,0,0,0,0,0,129,4,53,0,0,2,80,1,32,0,156,0,0,1,219,0,0,33,61],[0,0,0,128,1,32,0,57,0,0,0,64,0,16,4,63,0,0,2,60,1,0,0,65,0,0,2,60,4,48,0,156],[0,0,0,0,3,1,128,25,0,0,0,64,3,48,2,16,0,0,0,0,2,2,4,51,0,0,2,60,4,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,96,2,32,2,16,0,0,0,0,2,50,1,159,0,0,0,0,3,0,4,20],[0,0,2,60,4,48,0,156,0,0,0,0,3,1,128,25,0,0,0,192,1,48,2,16,0,0,0,0,1,33,1,159],[0,0,2,74,1,16,1,199,0,0,128,16,2,0,0,57,8,234,8,224,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,1,37,0,0,97,61,0,0,0,0,2,1,4,59,0,0,0,64,1,0,4,61,0,0,0,64,3,16,0,57],[0,0,0,0,4,0,4,26,0,0,0,0,0,35,4,53,0,0,0,32,2,16,0,57,0,0,0,0,0,66,4,53],[0,0,0,9,3,0,0,41,0,0,0,0,0,49,4,53,0,0,2,73,3,16,0,156,0,0,1,219,0,0,33,61],[0,0,0,96,3,16,0,57,0,0,0,64,0,48,4,63,0,0,2,60,3,0,0,65,0,0,2,60,4,32,0,156],[0,0,0,0,2,3,128,25,0,0,0,64,2,32,2,16,0,0,0,0,1,1,4,51,0,0,2,60,4,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20],[0,0,2,60,4,32,0,156,0,0,0,0,2,3,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,2,74,1,16,1,199,0,0,128,16,2,0,0,57,8,234,8,224,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,1,37,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,0,16,4,27,0,0,0,11,1,0,0,41],[0,0,0,0,1,1,4,26,0,0,0,1,2,0,0,138,0,0,0,0,2,33,0,75,0,0,1,157,0,0,97,61],[0,0,0,1,1,16,0,57,0,0,0,11,3,0,0,41,0,0,0,0,0,19,4,27,0,0,0,7,1,0,0,41],[0,0,0,0,1,1,4,51,0,0,0,255,1,16,1,143,0,0,0,64,2,0,4,61,0,0,0,0,1,18,4,54],[0,0,0,3,4,0,0,41,0,0,0,0,4,4,4,51,0,0,0,0,4,4,0,75,0,0,0,0,4,0,0,25],[0,0,0,1,4,0,192,57,0,0,0,0,0,65,4,53,0,0,0,2,1,0,0,41,0,0,0,0,1,1,4,51],[0,0,255,255,1,16,1,143,0,0,0,64,4,32,0,57,0,0,0,0,0,20,4,53,0,0,0,5,1,0,0,41],[0,0,0,0,1,1,4,51,0,0,2,78,1,16,1,151,0,0,0,96,4,32,0,57,0,0,0,0,0,20,4,53],[0,0,0,4,1,0,0,41,0,0,0,0,1,1,4,51,0,0,0,128,4,32,0,57,0,0,0,0,0,20,4,53],[0,0,0,6,1,0,0,41,0,0,0,0,1,1,4,51,0,0,0,160,4,32,0,57,0,0,0,0,0,20,4,53],[0,0,2,60,1,0,0,65,0,0,2,60,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,0,5,0,4,20],[0,0,2,60,4,80,0,156,0,0,0,0,5,1,128,25,0,0,0,64,1,32,2,16,0,0,0,192,2,80,2,16],[0,0,0,0,1,18,1,159,0,0,2,81,1,16,1,199,0,0,128,13,2,0,0,57,0,0,2,82,4,0,0,65],[8,234,8,219,0,0,4,15,0,0,0,1,1,32,1,144,0,0,0,13,1,0,0,41,0,0,1,37,0,0,97,61],[0,0,0,92,2,16,0,57,0,0,0,0,1,0,4,19,0,0,2,60,3,16,1,151,0,0,0,0,65,35,0,169],[0,0,2,83,2,32,1,151,0,0,2,83,4,16,1,151,0,0,0,0,66,36,0,217,0,0,0,0,2,35,0,75],[0,0,0,8,3,0,0,41,0,0,1,157,0,0,193,61,0,0,0,14,2,48,0,105,0,0,0,160,1,16,0,57],[0,0,0,0,1,33,0,26,0,0,1,157,0,0,65,61,0,0,2,69,2,16,0,156,0,0,6,200,0,0,65,61],[0,0,0,64,4,0,4,61,0,0,0,96,0,0,1,61,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114],[0,0,4,213,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75],[0,0,4,206,0,0,65,61,0,0,0,0,5,4,0,75,0,0,4,227,0,0,97,61,0,0,0,3,4,64,2,16],[0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47],[0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16],[0,0,8,236,0,1,4,48,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114],[0,0,4,242,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,4,234,0,0,65,61,0,0,0,0,6,4,0,75,0,0,5,1,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,1,67,0,0,1,61,0,0,0,8,3,0,0,41,0,0,0,0,0,49,4,53],[0,0,2,85,1,32,1,199,0,0,8,235,0,1,4,46,0,0,0,5,1,0,0,138,0,8,0,0,0,1,0,29],[0,0,0,13,1,16,0,107,0,0,1,157,0,0,33,61,0,0,0,13,1,0,0,41,0,0,0,4,3,16,0,57],[0,0,0,11,1,48,0,108,0,0,1,37,0,0,33,61,0,0,0,160,1,0,4,61,0,5,0,0,0,1,0,29],[0,0,0,13,2,0,0,41,0,0,0,10,1,32,0,41,0,0,0,1,1,16,3,103,0,0,0,0,1,1,4,59],[0,0,2,71,2,16,0,156,0,0,0,0,9,0,0,25,0,0,5,90,0,0,129,61,0,0,0,2,1,0,0,57],[0,4,0,0,0,1,0,29,0,0,0,0,1,1,4,26,0,0,0,0,1,25,0,75,0,0,5,250,0,0,193,61],[0,0,0,0,2,3,0,25,0,0,0,8,1,32,0,108,0,0,1,157,0,0,33,61,0,0,0,4,3,32,0,57],[0,0,0,11,1,48,0,108,0,0,1,37,0,0,33,61,0,0,0,10,1,32,0,41,0,0,0,1,1,16,3,103],[0,0,0,0,1,1,4,59,0,0,2,71,2,16,0,156,0,0,0,0,9,0,0,25,0,0,6,45,0,0,129,61],[0,0,0,0,5,3,0,25,0,0,0,3,1,0,0,57,0,13,0,0,0,1,0,29,0,0,0,0,1,1,4,26],[0,0,0,0,1,25,0,75,0,0,6,205,0,0,193,61,0,0,0,11,1,80,0,108,0,0,3,6,0,0,129,61],[0,0,0,10,1,80,0,41,0,0,0,1,2,0,3,103,0,0,0,0,3,18,3,79,0,0,0,0,3,3,4,59],[0,0,2,116,3,48,1,151,0,0,2,79,3,48,0,156,0,0,7,32,0,0,193,61,0,0,0,0,4,5,0,25],[0,0,0,8,3,64,0,108,0,0,1,157,0,0,33,61,0,0,0,4,3,64,0,57,0,0,0,11,4,48,0,108],[0,0,1,37,0,0,33,61,0,0,0,1,1,16,0,57,0,0,0,0,1,18,3,79,0,0,0,0,1,1,4,59],[0,0,0,11,4,48,0,108,0,0,3,6,0,0,129,61,0,0,0,232,1,16,2,112,0,0,0,10,3,48,0,41],[0,0,0,0,4,50,3,79,0,0,0,5,3,80,0,57,0,12,0,0,0,49,0,30,0,0,0,0,5,4,4,59],[0,0,1,157,0,0,65,61,0,0,0,12,6,0,0,41,0,0,0,11,4,96,0,108,0,0,1,37,0,0,33,61],[0,0,0,12,4,0,0,41,0,0,2,119,4,64,0,156,0,0,7,90,0,0,65,61,0,0,0,64,1,0,4,61],[0,0,0,68,2,16,0,57,0,0,2,125,3,0,0,65,0,0,0,0,0,50,4,53,0,0,2,87,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,36,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,0,4,2,16,0,57,0,0,5,243,0,0,1,61,0,7,0,224,0,16,2,120,0,0,0,0,8,0,0,25],[0,0,0,0,9,0,0,25,0,0,0,8,1,48,0,108,0,0,1,157,0,0,33,61,0,0,0,4,2,48,0,57],[0,0,0,11,1,32,0,108,0,0,1,37,0,0,33,61,0,0,0,10,3,48,0,41,0,0,0,1,1,0,3,103],[0,0,0,0,3,49,3,79,0,0,0,0,3,3,4,59,0,0,0,224,3,48,2,112,0,0,0,0,7,35,0,26],[0,0,1,157,0,0,65,61,0,0,0,11,4,112,0,108,0,0,1,37,0,0,33,61,0,0,0,10,2,32,0,41],[0,0,0,0,3,35,0,26,0,0,2,60,4,32,1,151,0,0,0,0,2,0,4,20,0,0,1,157,0,0,65,61],[0,0,0,0,5,0,0,49,0,0,0,0,6,53,0,75,0,0,1,157,0,0,65,61,0,14,0,0,0,9,0,29],[0,12,0,0,0,8,0,29,0,13,0,0,0,7,0,29,0,0,2,60,6,32,0,156,0,0,0,167,0,0,33,61],[0,0,0,0,1,65,3,79,0,0,0,0,3,53,0,73,0,0,2,60,3,48,1,151,0,0,0,0,1,49,3,223],[0,0,0,192,2,32,2,16,0,0,2,70,2,32,1,151,0,0,2,71,2,32,1,199,0,0,0,0,1,33,3,175],[0,0,128,16,2,0,0,57,8,234,8,229,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,2,60,3,48,1,151,0,0,0,1,2,32,1,144,0,0,6,18,0,0,97,61,0,0,0,63,2,48,0,57],[0,0,2,72,4,32,1,151,0,0,0,64,2,0,4,61,0,0,0,0,4,66,0,25,0,0,0,0,5,36,0,75],[0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57,0,0,2,67,6,64,0,156,0,0,1,219,0,0,33,61],[0,0,0,1,5,80,1,144,0,0,1,219,0,0,193,61,0,0,0,64,0,64,4,63,0,0,0,0,4,50,4,54],[0,0,0,31,5,48,0,57,0,0,0,5,5,80,2,114,0,0,5,162,0,0,97,61,0,0,0,0,6,0,0,49],[0,0,0,1,6,96,3,103,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,132,0,25],[0,0,0,0,8,134,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,87,0,75,0,0,5,154,0,0,65,61,0,0,0,0,5,0,0,75,0,0,5,164,0,0,97,61],[0,0,0,5,5,48,2,114,0,0,0,14,9,0,0,41,0,0,5,176,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,116,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,5,168,0,0,65,61],[0,0,0,31,3,48,1,144,0,0,5,191,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,84,0,25,0,0,0,3,3,48,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,54,1,207],[0,0,0,0,6,54,2,47,0,0,0,0,1,1,4,59,0,0,1,0,3,48,0,137,0,0,0,0,1,49,2,47],[0,0,0,0,1,49,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,0,0,1,2,4,51],[0,0,0,32,1,16,0,140,0,0,5,232,0,0,193,61,0,0,0,0,2,4,4,51,0,0,0,64,1,0,4,61],[0,0,0,64,3,16,0,57,0,0,0,0,0,35,4,53,0,0,0,32,2,16,0,57,0,0,0,0,0,146,4,53],[0,0,0,9,3,0,0,41,0,0,0,0,0,49,4,53,0,0,2,73,3,16,0,156,0,0,1,219,0,0,33,61],[0,0,0,96,3,16,0,57,0,0,0,64,0,48,4,63,0,0,2,60,3,32,0,156,0,0,2,60,4,0,0,65],[0,0,0,0,2,4,128,25,0,0,0,64,2,32,2,16,0,0,0,0,1,1,4,51,0,0,2,60,3,16,0,156],[0,0,0,0,1,4,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20],[0,0,2,60,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,2,74,1,16,1,199,0,0,128,16,2,0,0,57,8,234,8,224,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,0,13,3,0,0,41,0,0,0,12,8,0,0,41,0,0,1,37,0,0,97,61,0,0,0,0,9,1,4,59],[0,0,0,1,8,128,0,57,0,0,0,7,1,128,0,108,0,0,5,93,0,0,65,61,0,0,5,23,0,0,1,61],[0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,2,99,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,31,3,0,0,57,0,0,0,0,0,50,4,53,0,0,2,87,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,2,60,2,0,0,65,0,0,2,60,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16],[0,0,2,88,1,16,1,199,0,0,8,236,0,1,4,48,0,0,0,64,1,0,4,61,0,0,0,132,2,16,0,57],[0,0,2,100,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,100,2,16,0,57,0,0,2,101,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,68,2,16,0,57,0,0,2,102,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,68,3,0,0,57,0,0,0,0,0,50,4,53,0,0,2,87,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,2,60,2,0,0,65,0,0,2,60,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16],[0,0,2,103,1,16,1,199,0,0,8,236,0,1,4,48,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114],[0,0,6,29,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75],[0,0,6,22,0,0,65,61,0,0,0,0,5,4,0,75,0,0,6,43,0,0,97,61,0,0,0,3,4,64,2,16],[0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47],[0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16],[0,0,8,236,0,1,4,48,0,6,0,224,0,16,2,120,0,0,0,0,8,0,0,25,0,0,0,0,9,0,0,25],[0,0,0,8,1,48,0,108,0,0,1,157,0,0,33,61,0,0,0,4,2,48,0,57,0,0,0,11,1,32,0,108],[0,0,1,37,0,0,33,61,0,0,0,10,3,48,0,41,0,0,0,1,1,0,3,103,0,0,0,0,3,49,3,79],[0,0,0,0,3,3,4,59,0,0,0,224,10,48,2,112,0,0,0,0,7,42,0,26,0,0,1,157,0,0,65,61],[0,0,0,11,4,112,0,108,0,0,1,37,0,0,33,61,0,0,2,104,4,48,1,152,0,0,7,42,0,0,193,61],[0,0,2,106,4,48,0,156,0,0,7,46,0,0,129,61,0,0,2,107,3,48,1,152,0,0,7,50,0,0,97,61],[0,0,0,10,2,32,0,41,0,0,0,0,3,42,0,26,0,0,2,60,4,32,1,151,0,0,0,0,2,0,4,20],[0,0,1,157,0,0,65,61,0,0,0,0,5,0,0,49,0,0,0,0,6,53,0,75,0,0,1,157,0,0,65,61],[0,13,0,0,0,10,0,29,0,14,0,0,0,9,0,29,0,7,0,0,0,8,0,29,0,12,0,0,0,7,0,29],[0,0,2,60,6,32,0,156,0,0,0,167,0,0,33,61,0,0,0,0,1,65,3,79,0,0,0,0,3,53,0,73],[0,0,2,60,3,48,1,151,0,0,0,0,1,49,3,223,0,0,0,192,2,32,2,16,0,0,2,70,2,32,1,151],[0,0,2,71,2,32,1,199,0,0,0,0,1,33,3,175,0,0,0,2,2,0,0,57,8,234,8,229,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,2,60,3,48,1,151,0,0,0,1,2,32,1,144],[0,0,7,57,0,0,97,61,0,0,0,63,2,48,0,57,0,0,2,72,4,32,1,151,0,0,0,64,2,0,4,61],[0,0,0,0,4,66,0,25,0,0,0,0,5,36,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57],[0,0,2,67,6,64,0,156,0,0,1,219,0,0,33,61,0,0,0,1,5,80,1,144,0,0,1,219,0,0,193,61],[0,0,0,64,0,64,4,63,0,0,0,0,4,50,4,54,0,0,0,31,5,48,0,57,0,0,0,5,5,80,2,114],[0,0,0,13,10,0,0,41,0,0,6,125,0,0,97,61,0,0,0,0,6,0,0,49,0,0,0,1,6,96,3,103],[0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,132,0,25,0,0,0,0,8,134,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,87,0,75],[0,0,6,117,0,0,65,61,0,0,0,0,5,0,0,75,0,0,6,127,0,0,97,61,0,0,0,5,5,48,2,114],[0,0,0,14,9,0,0,41,0,0,6,139,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,116,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,6,131,0,0,65,61,0,0,0,31,3,48,1,144],[0,0,6,154,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,84,0,25],[0,0,0,3,3,48,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,54,1,207,0,0,0,0,6,54,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,3,48,0,137,0,0,0,0,1,49,2,47,0,0,0,0,1,49,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,0,64,1,0,4,61,0,0,0,0,2,2,4,51],[0,0,0,32,2,32,0,140,0,0,7,84,0,0,193,61,0,0,0,0,2,4,4,51,0,0,2,109,2,32,1,151],[0,0,0,219,3,160,2,16,0,0,2,110,3,48,1,151,0,0,0,0,2,35,1,159,0,0,2,79,2,32,1,199],[0,0,0,64,3,16,0,57,0,0,0,0,0,35,4,53,0,0,0,32,2,16,0,57,0,0,0,0,0,146,4,53],[0,0,0,9,3,0,0,41,0,0,0,0,0,49,4,53,0,0,2,73,3,16,0,156,0,0,1,219,0,0,33,61],[0,0,0,96,3,16,0,57,0,0,0,64,0,48,4,63,0,0,2,60,3,32,0,156,0,0,2,60,4,0,0,65],[0,0,0,0,2,4,128,25,0,0,0,64,2,32,2,16,0,0,0,0,1,1,4,51,0,0,2,60,3,16,0,156],[0,0,0,0,1,4,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20],[0,0,2,60,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,2,74,1,16,1,199,0,0,128,16,2,0,0,57,8,234,8,224,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,0,12,3,0,0,41,0,0,0,7,8,0,0,41,0,0,1,37,0,0,97,61,0,0,0,0,9,1,4,59],[0,0,0,1,8,128,0,57,0,0,0,6,1,128,0,108,0,0,6,48,0,0,65,61,0,0,5,40,0,0,1,61],[0,0,0,0,2,16,4,32,0,0,0,64,1,0,4,61,0,0,0,0,2,2,0,75,0,0,6,218,0,0,193,61],[0,0,1,228,0,0,1,61,0,0,0,64,1,0,4,61,0,0,0,132,2,16,0,57,0,0,2,113,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,100,2,16,0,57,0,0,2,114,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,68,2,16,0,57,0,0,2,115,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,94,3,0,0,57,0,0,6,6,0,0,1,61,0,0,0,32,2,0,0,57,0,0,0,0,2,33,4,54],[0,0,0,13,5,0,0,41,0,0,0,0,0,82,4,53,0,0,0,31,3,80,1,143,0,0,0,64,2,16,0,57],[0,0,0,12,4,0,0,41,0,0,0,1,4,64,3,103,0,0,0,5,5,80,2,114,0,0,6,237,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,116,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,6,229,0,0,65,61,0,0,0,0,6,3,0,75,0,0,6,252,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,4,84,3,79,0,0,0,0,5,82,0,25,0,0,0,3,3,48,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,54,1,207,0,0,0,0,6,54,2,47,0,0,0,0,4,4,4,59,0,0,1,0,3,48,0,137],[0,0,0,0,4,52,2,47,0,0,0,0,3,52,1,207,0,0,0,0,3,99,1,159,0,0,0,0,0,53,4,53],[0,0,0,13,3,0,0,41,0,0,0,0,2,50,0,25,0,0,0,0,0,2,4,53,0,0,0,95,2,48,0,57],[0,0,0,32,3,0,0,138,0,0,0,0,2,50,1,111,0,0,2,60,4,0,0,65,0,0,2,60,3,16,0,156],[0,0,0,0,1,4,128,25,0,0,0,64,1,16,2,16,0,0,2,60,3,32,0,156,0,0,0,0,2,4,128,25],[0,0,0,96,2,32,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20,0,0,2,60,3,32,0,156],[0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,2,74,1,16,1,199],[0,0,128,13,2,0,0,57,0,0,0,3,3,0,0,57,0,0,2,84,4,0,0,65,0,0,0,1,5,0,0,41],[0,0,0,10,6,0,0,41,8,234,8,219,0,0,4,15,0,0,0,1,1,32,1,144,0,0,1,37,0,0,97,61],[0,0,0,64,1,0,4,61,0,0,0,10,2,0,0,41,0,0,0,0,0,33,4,53,0,0,2,60,2,16,0,156],[0,0,2,60,1,0,128,65,0,0,0,64,1,16,2,16,0,0,2,85,1,16,1,199,0,0,8,235,0,1,4,46],[0,0,0,64,1,0,4,61,0,0,0,100,2,16,0,57,0,0,2,117,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,68,2,16,0,57,0,0,2,118,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,39,3,0,0,57,0,0,3,161,0,0,1,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57],[0,0,2,105,3,0,0,65,0,0,7,53,0,0,1,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57],[0,0,2,112,3,0,0,65,0,0,7,53,0,0,1,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57],[0,0,2,111,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,4,3,0,0,41],[0,0,5,238,0,0,1,61,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114,0,0,7,68,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75,0,0,7,61,0,0,65,61],[0,0,0,0,5,4,0,75,0,0,7,82,0,0,97,61,0,0,0,3,4,64,2,16,0,0,0,5,2,32,2,16],[0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47,0,0,0,0,1,33,3,79],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16,0,0,8,236,0,1,4,48],[0,0,0,68,2,16,0,57,0,0,2,108,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,25,3,0,0,57,0,0,5,238,0,0,1,61,0,0,0,12,4,0,0,41,0,0,0,4,6,64,0,57],[0,0,0,11,4,96,0,108,0,0,1,37,0,0,33,61,0,0,0,12,7,0,0,41,0,0,0,10,4,112,0,41],[0,0,0,0,4,66,3,79,0,0,0,0,8,4,4,59,0,0,0,224,7,128,2,112,0,0,1,16,148,112,0,201],[0,0,2,71,8,128,0,156,0,0,7,105,0,0,65,61,0,0,0,0,152,116,0,217,0,0,1,16,8,128,0,140],[0,0,1,157,0,0,193,61,0,0,0,0,9,100,0,25,0,9,0,0,0,9,0,29,0,0,0,11,8,144,0,108],[0,0,1,37,0,0,33,61,0,0,0,248,5,80,2,112,0,0,0,64,10,0,4,61,0,0,0,68,8,160,0,57],[0,0,0,128,9,0,0,57,0,0,0,0,0,152,4,53,0,0,0,36,8,160,0,57,0,0,0,0,0,88,4,53],[0,0,2,120,5,0,0,65,0,0,0,0,0,90,4,53,0,0,0,10,6,96,0,41,0,0,0,132,5,160,0,57],[0,0,0,0,0,69,4,53,0,0,0,4,5,160,0,57,0,0,0,0,0,117,4,53,0,0,0,0,8,98,3,79],[0,0,0,31,7,64,1,143,0,14,0,0,0,10,0,29,0,0,0,164,6,160,0,57,0,0,0,5,9,64,2,114],[0,0,7,138,0,0,97,61,0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16,0,0,0,0,12,182,0,25],[0,0,0,0,11,184,3,79,0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53,0,0,0,1,10,160,0,57],[0,0,0,0,11,154,0,75,0,0,7,130,0,0,65,61,0,0,0,10,3,48,0,41,0,0,0,0,10,7,0,75],[0,0,7,154,0,0,97,61,0,0,0,5,9,144,2,16,0,0,0,0,8,152,3,79,0,0,0,0,9,150,0,25],[0,0,0,3,7,112,2,16,0,0,0,0,10,9,4,51,0,0,0,0,10,122,1,207,0,0,0,0,10,122,2,47],[0,0,0,0,8,8,4,59,0,0,1,0,7,112,0,137,0,0,0,0,8,120,2,47,0,0,0,0,7,120,1,207],[0,0,0,0,7,167,1,159,0,0,0,0,0,121,4,53,0,0,0,0,7,70,0,25,0,0,0,0,0,7,4,53],[0,0,0,31,4,64,0,57,0,0,2,121,4,64,1,151,0,0,0,0,6,70,0,25,0,0,0,0,4,86,0,73],[0,0,0,14,5,0,0,41,0,0,0,100,5,80,0,57,0,0,0,0,0,69,4,53,0,0,0,0,4,50,3,79],[0,0,0,31,3,16,1,143,0,0,0,0,2,22,4,54,0,0,0,5,5,16,2,114,0,0,7,177,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,116,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,7,169,0,0,65,61,0,0,0,0,6,3,0,75,0,0,7,192,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,4,84,3,79,0,0,0,0,5,82,0,25,0,0,0,3,3,48,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,54,1,207,0,0,0,0,6,54,2,47,0,0,0,0,4,4,4,59,0,0,1,0,3,48,0,137],[0,0,0,0,4,52,2,47,0,0,0,0,3,52,1,207,0,0,0,0,3,99,1,159,0,0,0,0,0,53,4,53],[0,0,0,0,3,18,0,25,0,0,0,0,0,3,4,53,0,0,0,31,1,16,0,57,0,0,2,122,1,16,1,151],[0,0,0,14,4,0,0,41,0,0,0,0,1,65,0,73,0,0,0,0,1,33,0,25,0,0,2,60,2,0,0,65],[0,0,2,60,3,64,0,156,0,0,0,0,3,2,0,25,0,0,0,0,3,4,64,25,0,0,0,64,3,48,2,16],[0,0,2,60,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,49,1,159],[0,0,0,0,3,0,4,20,0,0,2,60,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16],[0,0,0,0,1,18,1,159,0,0,128,14,2,0,0,57,8,234,8,219,0,0,4,15,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,2,60,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25],[0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114,0,0,7,233,0,0,97,61],[0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,14,9,128,0,41,0,0,0,0,8,129,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75],[0,0,7,225,0,0,65,61,0,0,0,0,7,5,0,75,0,0,7,248,0,0,97,61,0,0,0,5,6,96,2,16],[0,0,0,0,7,97,3,79,0,0,0,14,6,96,0,41,0,0,0,3,5,80,2,16,0,0,0,0,8,6,4,51],[0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137],[0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53],[0,0,0,1,2,32,1,144,0,0,8,30,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,2,16,1,143],[0,0,0,14,1,32,0,41,0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57],[0,0,2,67,4,16,0,156,0,0,1,219,0,0,33,61,0,0,0,1,2,32,1,144,0,0,1,219,0,0,193,61],[0,0,0,64,0,16,4,63,0,0,0,32,2,48,0,140,0,0,1,37,0,0,65,61,0,0,0,9,3,0,0,41],[0,0,0,11,2,48,0,108,0,0,8,59,0,0,193,61,0,0,0,14,1,0,0,41,0,0,0,0,1,1,4,51],[0,14,0,0,0,1,0,29,0,0,0,5,1,0,0,41,0,0,0,0,0,16,4,29,0,0,0,10,1,0,0,41],[0,0,0,12,2,0,0,41,8,234,8,68,0,0,4,15,0,0,0,1,2,0,0,57,0,0,0,0,0,18,4,29],[0,0,0,4,1,0,0,41,0,0,0,14,3,0,0,41,0,0,0,0,0,49,4,29,0,0,0,0,0,0,4,27],[0,0,0,0,0,2,4,27,0,0,0,0,0,1,4,27,0,0,0,13,1,0,0,41,0,0,0,0,0,1,4,27],[0,0,0,0,1,0,0,25,0,0,8,235,0,1,4,46,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143],[0,0,0,5,5,48,2,114,0,0,8,43,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,8,35,0,0,65,61,0,0,0,0,6,4,0,75],[0,0,8,58,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25],[0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,1,67,0,0,1,61,0,0,0,100,2,16,0,57],[0,0,2,123,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,68,2,16,0,57,0,0,2,124,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,42,3,0,0,57,0,0,3,161,0,0,1,61],[0,0,0,0,3,0,4,20,0,0,0,0,4,18,0,25,0,0,0,0,2,36,0,75,0,0,0,0,5,0,0,25],[0,0,0,1,5,0,64,57,0,0,2,60,2,16,1,151,0,0,0,1,1,80,1,144,0,0,8,157,0,0,193,61],[0,0,0,0,1,0,0,49,0,0,0,0,5,65,0,75,0,0,8,157,0,0,65,61,0,0,0,1,2,32,3,103],[0,0,2,69,5,48,0,156,0,0,8,161,0,0,129,61,0,0,0,0,1,65,0,73,0,0,2,60,1,16,1,151],[0,0,0,0,1,18,3,223,0,0,0,192,2,48,2,16,0,0,2,70,2,32,1,151,0,0,2,71,2,32,1,199],[0,0,0,0,1,33,3,175,0,0,128,16,2,0,0,57,8,234,8,229,0,0,4,15,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,2,60,3,48,1,151,0,0,0,1,2,32,1,144,0,0,8,168,0,0,97,61],[0,0,0,63,2,48,0,57,0,0,2,72,4,32,1,151,0,0,0,64,2,0,4,61,0,0,0,0,4,66,0,25],[0,0,0,0,5,36,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57,0,0,2,67,6,64,0,156],[0,0,8,195,0,0,33,61,0,0,0,1,5,80,1,144,0,0,8,195,0,0,193,61,0,0,0,64,0,64,4,63],[0,0,0,0,4,50,4,54,0,0,0,31,5,48,0,57,0,0,0,5,5,80,2,114,0,0,8,123,0,0,97,61],[0,0,0,0,6,0,0,49,0,0,0,1,6,96,3,103,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16],[0,0,0,0,9,132,0,25,0,0,0,0,8,134,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53],[0,0,0,1,7,112,0,57,0,0,0,0,8,87,0,75,0,0,8,115,0,0,65,61,0,0,0,0,5,0,0,75],[0,0,8,125,0,0,97,61,0,0,0,31,5,48,1,143,0,0,0,5,3,48,2,114,0,0,8,137,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,116,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,54,0,75],[0,0,8,129,0,0,65,61,0,0,0,0,6,5,0,75,0,0,8,152,0,0,97,61,0,0,0,5,3,48,2,16],[0,0,0,0,1,49,3,79,0,0,0,0,3,52,0,25,0,0,0,3,5,80,2,16,0,0,0,0,6,3,4,51],[0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47,0,0,0,0,1,1,4,59,0,0,1,0,5,80,0,137],[0,0,0,0,1,81,2,47,0,0,0,0,1,81,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,19,4,53],[0,0,0,0,1,2,4,51,0,0,0,32,1,16,0,140,0,0,8,201,0,0,193,61,0,0,0,0,1,4,4,51],[0,0,0,0,0,1,4,45,0,0,2,126,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57],[0,0,8,198,0,0,1,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,2,89,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,8,3,0,0,57,0,0,8,207,0,0,1,61],[0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114,0,0,8,179,0,0,97,61,0,0,0,0,5,0,0,25],[0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53],[0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75,0,0,8,172,0,0,65,61,0,0,0,0,5,4,0,75],[0,0,8,193,0,0,97,61,0,0,0,3,4,64,2,16,0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51],[0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47,0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159],[0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16,0,0,8,236,0,1,4,48,0,0,2,126,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57,0,0,0,4,0,16,4,63,0,0,2,127,1,0,0,65],[0,0,8,236,0,1,4,48,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,2,99,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,31,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,2,87,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,2,60,2,0,0,65,0,0,2,60,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,64,1,16,2,16,0,0,2,88,1,16,1,199,0,0,8,236,0,1,4,48,0,0,8,222,0,33,4,33],[0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45],[0,0,8,227,0,33,4,35,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25],[0,0,0,0,0,1,4,45,0,0,8,232,0,33,4,35,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45],[0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,8,234,0,0,4,50,0,0,8,235,0,1,4,46],[0,0,8,236,0,1,4,48,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,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,0,0,0,0,0,98,139,99,109],[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,98,139,99,110],[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,98,248,75,36],[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,57,179,76,110],[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,86,7,154,200],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255],[128,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,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,1,0,0,0,0],[0,0,0,0,255,255,255,255,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,1,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,255,255,255,224],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,159],[2,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],[138,200,76,14,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,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,0,0,0,0,255,255,255,255,255,255,255,63],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[1,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,127],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,0,0,0,0,0,0,0,0,0,0,0,0],[39,254,140,11,73,244,149,7,185,212,254,89,104,201,244,158,223,229,201,223,39,125,67,58,7,160,113,126,222,151,99,141],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[58,54,228,114,145,244,32,31,175,19,127,171,8,29,146,41,91,206,45,83,190,44,108,166,139,168,44,127,170,156,226,65],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[70,97,105,108,101,100,32,116,111,32,99,104,97,114,103,101,32,103,97,115,0,0,0,0,0,0,0,0,0,0,0,0],[8,195,121,160,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0],[79,118,101,114,102,108,111,119,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[67,97,108,108,97,98,108,101,32,111,110,108,121,32,98,121,32,116,104,101,32,98,111,111,116,108,111,97,100,101,114,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,128,0,0,0,0,0,0,0,0],[0,0,8,1,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,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,1,0,160],[110,111,116,32,101,113,117,97,108,32,116,111,32,99,104,97,105,110,101,100,76,111,103,115,72,97,115,104,0,0,0,0],[114,101,99,111,110,115,116,114,117,99,116,101,100,67,104,97,105,110,101,100,76,111,103,115,72,97,115,104,32,105,115,32],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,7,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[114,171,238,69,181,158,52,74,248,166,229,32,36,28,71,68,175,242,110,212,17,244,196,176,15,138,240,154,218,218,67,186],[107,101,99,99,97,107,50,53,54,32,114,101,116,117,114,110,101,100,32,105,110,118,97,108,105,100,32,100,97,116,97,0],[72,97,115,104,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],[32,105,115,32,110,111,116,32,101,113,117,97,108,32,116,111,32,99,104,97,105,110,101,100,77,101,115,115,97,103,101,115],[114,101,99,111,110,115,116,114,117,99,116,101,100,67,104,97,105,110,101,100,77,101,115,115,97,103,101,115,72,97,115,104],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,164,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,31,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],[112,111,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,32,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,0,32,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],[115,104,97,32,114,101,116,117,114,110,101,100,32,105,110,118,97,108,105,100,32,100,97,116,97,0,0,0,0,0,0,0],[0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[6,255,255,255,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],[112,114,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],[112,112,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],[97,105,110,101,100,76,49,66,121,116,101,99,111,100,101,115,82,101,118,101,97,108,68,97,116,97,72,97,115,104,0,0],[101,118,101,97,108,68,97,116,97,72,97,115,104,32,105,115,32,110,111,116,32,101,113,117,97,108,32,116,111,32,99,104],[114,101,99,111,110,115,116,114,117,99,116,101,100,67,104,97,105,110,101,100,76,49,66,121,116,101,99,111,100,101,115,82],[255,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],[105,115,109,97,116,99,104,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],[115,116,97,116,101,32,100,105,102,102,32,99,111,109,112,114,101,115,115,105,111,110,32,118,101,114,115,105,111,110,32,109],[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,7,239,65],[96,6,216,181,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,255,255,255,255,224],[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,1,255,255,224],[100,97,116,97,32,97,114,114,97,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[69,120,116,114,97,32,100,97,116,97,32,105,110,32,116,104,101,32,116,111,116,97,108,76,50,84,111,76,49,80,117,98],[76,49,32,77,101,115,115,101,110,103,101,114,32,112,117,98,100,97,116,97,32,105,115,32,116,111,111,32,108,111,110,103],[78,72,123,113,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[84,111,111,32,109,97,110,121,32,76,50,45,62,76,49,32,108,111,103,115,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,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,128,0,0,0,0,0,0,0,0],[84,104,105,115,32,109,101,116,104,111,100,32,114,101,113,117,105,114,101,32,116,104,101,32,99,97,108,108,101,114,32,116],[111,32,98,101,32,115,121,115,116,101,109,32,99,111,110,116,114,97,99,116,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,132,0,0,0,128,0,0,0,0,0,0,0,0],[73,110,97,112,112,114,111,112,114,105,97,116,101,32,99,97,108,108,101,114,0,0,0,0,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,160,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,0,0,0,0,255,255,255,216],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[72,13,60,159,114,123,94,92,18,3,212,198,31,177,133,211,127,8,230,178,220,94,155,191,152,89,27,26,122,221,245,124],[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],[66,161,119,40,165,254,105,218,53,173,40,68,15,131,115,148,66,216,50,91,200,159,71,53,210,245,157,216,211,14,134,167]],"0x0000000000000000000000000000000000008010":[[0,0,0,1,2,32,1,144,0,0,0,20,0,0,193,61,0,0,0,96,2,16,2,16,0,0,0,9,2,32,1,151],[0,0,0,64,3,16,2,112,0,0,0,10,4,48,1,151,0,0,0,0,2,66,1,159,0,0,0,11,3,48,1,151],[0,0,0,0,2,50,1,159,0,0,0,12,2,32,1,199,0,0,0,96,1,16,2,112,0,0,0,10,1,16,1,151],[0,0,0,136,49,16,1,26,0,0,0,40,49,16,0,201,0,0,0,40,1,16,0,57,0,0,0,0,1,18,4,32],[0,0,0,0,1,1,0,75,0,0,0,25,0,0,193,61,0,0,0,0,1,0,0,25,0,0,0,29,0,1,4,48],[0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,0,8,1,0,0,65],[0,0,0,28,0,1,4,46,0,0,0,13,1,0,0,65,0,0,0,28,0,1,4,46,0,0,0,27,0,0,4,50],[0,0,0,28,0,1,4,46,0,0,0,29,0,1,4,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,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,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,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,32,0,0,0,0,0,0,0,0,0,0,0,0],[231,235,90,132,103,57,44,46,94,80,157,131,248,179,91,153,186,138,67,197,69,4,157,187,159,87,148,17,34,213,184,114]],"0x000000000000000000000000000000000000800f":[[0,3,0,0,0,0,0,2,0,4,0,0,0,0,0,2,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,65,3,48,1,151,0,2,0,0,0,49,3,85,0,1,0,0,0,1,3,85,0,0,0,128,8,0,0,57],[0,0,0,64,0,128,4,63,0,0,0,1,2,32,1,144,0,0,0,90,0,0,193,61,0,0,0,4,2,48,0,140],[0,0,0,98,0,0,65,61,0,0,0,0,2,1,4,59,0,0,0,67,2,32,1,151,0,0,0,68,2,32,0,156],[0,0,0,98,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,64,2,32,0,140,0,0,0,98,0,0,65,61],[0,0,0,4,2,16,3,112,0,0,0,0,9,2,4,59,0,0,0,69,2,144,0,156,0,0,0,98,0,0,33,61],[0,0,0,36,2,16,3,112,0,0,0,0,2,2,4,59,0,0,0,70,4,32,0,156,0,0,0,98,0,0,33,61],[0,0,0,35,4,32,0,57,0,0,0,71,5,0,0,65,0,0,0,0,6,52,0,75,0,0,0,0,6,0,0,25],[0,0,0,0,6,5,128,25,0,0,0,71,4,64,1,151,0,0,0,0,7,4,0,75,0,0,0,0,5,0,128,25],[0,0,0,71,4,64,0,156,0,0,0,0,5,6,192,25,0,0,0,0,4,5,0,75,0,0,0,98,0,0,193,61],[0,0,0,4,5,32,0,57,0,0,0,0,1,81,3,79,0,0,0,0,4,1,4,59,0,0,0,70,1,64,0,156],[0,0,0,98,0,0,33,61,0,0,0,0,1,66,0,25,0,0,0,36,1,16,0,57,0,0,0,0,1,49,0,75],[0,0,0,98,0,0,33,61,0,0,0,0,1,0,4,17,0,0,128,7,1,16,0,140,0,0,0,100,0,0,193,61],[0,1,0,0,0,5,0,29,0,2,0,0,0,4,0,29,0,4,0,0,0,8,0,29,0,0,0,76,1,0,0,65],[0,0,0,0,0,16,4,57,0,3,0,0,0,9,0,29,0,0,0,4,0,144,4,67,0,0,0,65,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,0,65,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,0,77,1,16,1,199,0,0,128,2,2,0,0,57,0,253,0,243,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,0,112,0,0,97,61,0,0,0,64,8,0,4,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75],[0,0,0,113,0,0,193,61,0,0,0,68,1,128,0,57,0,0,0,81,3,0,0,65,0,0,0,0,0,49,4,53],[0,0,0,36,1,128,0,57,0,0,0,19,3,0,0,57,0,0,0,0,0,49,4,53,0,0,0,72,1,0,0,65],[0,0,0,0,0,24,4,53,0,0,0,4,1,128,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,49,4,53],[0,0,0,65,1,0,0,65,0,0,0,65,3,128,0,156,0,0,0,0,8,1,128,25,0,0,0,64,1,128,2,16],[0,0,0,82,1,16,1,199,0,0,0,255,0,1,4,48,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,0,98,0,0,193,61,0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67],[0,0,0,66,1,0,0,65,0,0,0,254,0,1,4,46,0,0,0,0,1,0,0,25,0,0,0,255,0,1,4,48],[0,0,0,72,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63],[0,0,0,36,1,0,0,57,0,0,0,164,0,16,4,63,0,0,0,73,1,0,0,65,0,0,0,196,0,16,4,63],[0,0,0,74,1,0,0,65,0,0,0,228,0,16,4,63,0,0,0,75,1,0,0,65,0,0,0,255,0,1,4,48],[0,0,0,0,0,1,4,47,0,0,0,2,9,0,0,41,0,0,0,31,1,144,1,143,0,0,0,1,2,0,0,41],[0,0,0,32,3,32,0,57,0,0,0,1,3,48,3,103,0,0,0,5,4,144,2,114,0,0,0,129,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,104,0,25,0,0,0,0,6,99,3,79],[0,0,0,0,6,6,4,59,0,0,0,0,0,103,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,69,0,75],[0,0,0,121,0,0,65,61,0,0,0,0,5,1,0,75,0,0,0,3,2,0,0,41,0,0,0,145,0,0,97,61],[0,0,0,5,4,64,2,16,0,0,0,0,3,67,3,79,0,0,0,0,4,72,0,25,0,0,0,3,1,16,2,16],[0,0,0,0,5,4,4,51,0,0,0,0,5,21,1,207,0,0,0,0,5,21,2,47,0,0,0,0,3,3,4,59],[0,0,1,0,1,16,0,137,0,0,0,0,3,19,2,47,0,0,0,0,1,19,1,207,0,0,0,0,1,81,1,159],[0,0,0,0,0,20,4,53,0,0,0,0,1,152,0,25,0,0,0,0,0,1,4,53,0,0,0,0,1,0,4,20],[0,0,0,4,3,32,0,140,0,0,0,153,0,0,193,61,0,0,0,0,3,0,0,49,0,0,0,0,2,0,0,25],[0,0,0,171,0,0,1,61,0,0,0,65,3,0,0,65,0,0,0,65,4,144,0,156,0,0,0,0,9,3,128,25],[0,0,0,96,4,144,2,16,0,0,0,65,5,128,0,156,0,0,0,0,8,3,128,25,0,0,0,64,5,128,2,16],[0,0,0,0,5,69,1,159,0,0,0,65,4,16,0,156,0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16],[0,0,0,0,1,81,1,159,0,253,0,248,0,0,4,15,0,0,0,1,2,32,1,95,0,2,0,0,0,1,3,85],[0,0,0,96,1,16,2,112,0,0,0,65,0,16,1,157,0,0,0,65,3,16,1,151,0,0,0,4,9,0,0,41],[0,0,0,96,1,0,0,57,0,0,0,0,4,3,0,75,0,0,0,187,0,0,193,61,0,0,0,1,2,32,1,144],[0,0,0,240,0,0,97,61,0,0,0,0,1,1,4,51,0,0,0,65,2,0,0,65,0,0,0,65,3,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,65,3,144,0,156,0,0,0,0,9,2,128,25,0,0,0,64,2,144,2,16],[0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,255,0,1,4,48,0,0,0,78,1,48,0,156],[0,0,0,234,0,0,129,61,0,0,0,31,1,48,0,57,0,0,0,32,4,0,0,138,0,0,0,0,1,65,1,111],[0,0,0,63,1,16,0,57,0,0,0,0,4,65,1,111,0,0,0,64,1,0,4,61,0,0,0,0,4,65,0,25],[0,0,0,0,5,20,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57,0,0,0,70,6,64,0,156],[0,0,0,234,0,0,33,61,0,0,0,1,5,80,1,144,0,0,0,234,0,0,193,61,0,0,0,64,0,64,4,63],[0,0,0,31,4,48,1,143,0,0,0,0,9,49,4,54,0,0,0,2,5,0,3,103,0,0,0,5,3,48,2,114],[0,0,0,218,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,121,0,25],[0,0,0,0,7,117,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,54,0,75,0,0,0,210,0,0,65,61,0,0,0,0,6,4,0,75,0,0,0,175,0,0,97,61],[0,0,0,5,3,48,2,16,0,0,0,0,5,53,3,79,0,0,0,0,3,57,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,3,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,5,5,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,5,69,2,47,0,0,0,0,4,69,1,207,0,0,0,0,4,100,1,159],[0,0,0,0,0,67,4,53,0,0,0,175,0,0,1,61,0,0,0,79,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,65,1,0,0,57,0,0,0,4,0,16,4,63,0,0,0,80,1,0,0,65,0,0,0,255,0,1,4,48],[0,0,0,0,1,0,0,25,0,0,0,254,0,1,4,46,0,0,0,0,0,1,4,47,0,0,0,246,0,33,4,35],[0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45],[0,0,0,251,0,33,4,37,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25],[0,0,0,0,0,1,4,45,0,0,0,253,0,0,4,50,0,0,0,254,0,1,4,46,0,0,0,255,0,1,4,48],[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],[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,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[255,255,255,255,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],[201,135,51,108,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,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255],[128,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],[8,195,121,160,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],[67,97,110,32,111,110,108,121,32,98,101,32,99,97,108,108,101,100,32,98,121,32,70,79,82,67,69,95,68,69,80,76],[79,89,69,82,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[24,6,170,24,150,187,242,101,104,232,132,167,55,75,65,224,2,80,9,98,202,186,106,21,2,58,141,144,232,80,139,131],[2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,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,0,0,0,1,0,0,0,0,0,0,0,0],[78,72,123,113,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[68,101,108,101,103,97,116,101,101,32,105,115,32,97,110,32,69,79,65,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,100,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,0,0,0,0,0,0,0,0,0,0,0,0],[94,172,127,106,21,129,232,232,50,239,172,10,104,228,35,38,191,75,43,199,44,72,89,61,240,13,144,112,197,100,2,171]],"0x0000000000000000000000000000000000008003":[[0,1,0,0,0,0,0,2,0,5,0,0,0,0,0,2,0,0,0,0,6,1,3,79,0,0,0,0,0,6,3,85],[0,0,0,128,1,0,0,57,0,0,0,64,0,16,4,63,0,0,0,0,1,6,0,25,0,0,0,96,1,16,2,112],[0,0,0,187,1,16,1,151,0,0,0,1,3,32,1,144,0,0,0,38,0,0,193,61,0,0,0,4,3,16,0,140],[0,0,2,107,0,0,65,61,0,0,0,0,3,6,4,59,0,0,0,224,3,48,2,112,0,0,0,189,4,48,0,156],[0,0,0,46,0,0,33,61,0,0,0,196,4,48,0,156,0,0,0,71,0,0,161,61,0,0,0,197,4,48,0,156],[0,0,1,0,0,0,97,61,0,0,0,198,2,48,0,156,0,0,1,25,0,0,97,61,0,0,0,199,2,48,0,156],[0,0,2,107,0,0,193,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,2,107,0,0,193,61],[0,0,0,4,1,16,0,138,0,0,0,32,1,16,0,140,0,0,2,107,0,0,65,61,0,0,0,4,1,96,3,112],[0,0,0,0,1,1,4,59,0,0,0,202,2,16,0,156,0,0,2,107,0,0,33,61,0,0,0,0,0,16,4,53],[0,0,0,32,0,0,4,63,0,0,1,43,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,2,107,0,0,193,61,0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67],[0,0,0,188,1,0,0,65,0,0,2,231,0,1,4,46,0,0,0,190,4,48,0,156,0,0,0,99,0,0,161,61],[0,0,0,191,4,48,0,156,0,0,1,49,0,0,97,61,0,0,0,192,4,48,0,156,0,0,1,66,0,0,97,61],[0,0,0,193,2,48,0,156,0,0,2,107,0,0,193,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75],[0,0,2,107,0,0,193,61,0,0,0,4,1,16,0,138,0,0,0,32,1,16,0,140,0,0,2,107,0,0,65,61],[0,0,0,4,1,96,3,112,0,0,0,0,1,1,4,59,0,0,0,202,2,16,0,156,0,0,2,107,0,0,33,61],[0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,0,0,1,0,0,25,2,230,2,202,0,0,4,15],[0,0,0,0,1,1,4,26,0,0,0,128,1,16,2,112,0,0,1,46,0,0,1,61,0,0,0,200,4,48,0,156],[0,0,0,115,0,0,97,61,0,0,0,201,2,48,0,156,0,0,2,107,0,0,193,61,0,0,0,0,2,0,4,22],[0,0,0,0,2,2,0,75,0,0,2,107,0,0,193,61,0,0,0,4,1,16,0,138,0,0,0,32,1,16,0,140],[0,0,2,107,0,0,65,61,0,0,0,4,1,96,3,112,0,0,0,0,1,1,4,59,0,0,0,202,2,16,0,156],[0,0,2,107,0,0,33,61,0,0,0,0,2,0,4,17,0,0,128,6,2,32,0,140,0,0,1,178,0,0,193,61],[0,5,0,0,0,1,0,29,2,230,2,109,0,0,4,15,0,0,0,0,1,1,4,26,0,4,0,0,0,1,0,29],[0,0,0,5,1,0,0,41,2,230,2,109,0,0,4,15,0,0,0,4,3,0,0,41,0,0,0,218,2,48,0,65],[0,0,0,0,0,33,4,27,0,0,0,128,1,48,2,112,0,0,1,135,0,0,1,61,0,0,0,194,2,48,0,156],[0,0,0,207,0,0,97,61,0,0,0,195,2,48,0,156,0,0,2,107,0,0,193,61,0,0,0,0,2,0,4,22],[0,0,0,0,2,2,0,75,0,0,2,107,0,0,193,61,0,0,0,4,1,16,0,138,0,0,0,32,1,16,0,140],[0,0,2,107,0,0,65,61,0,0,0,4,1,96,3,112,0,0,0,0,1,1,4,59,0,0,0,202,2,16,0,156],[0,0,2,107,0,0,33,61,2,230,2,125,0,0,4,15,0,0,1,135,0,0,1,61,0,0,0,0,3,0,4,22],[0,0,0,0,3,3,0,75,0,0,2,107,0,0,193,61,0,0,0,4,1,16,0,138,0,0,0,64,1,16,0,140],[0,0,2,107,0,0,65,61,0,0,0,0,3,0,4,17,0,0,0,36,1,96,3,112,0,0,0,0,5,1,4,59],[0,0,0,4,1,96,3,112,0,0,0,0,4,1,4,59,0,0,0,2,1,32,1,144,0,0,0,130,0,0,193,61],[0,0,0,219,1,48,0,156,0,0,1,77,0,0,129,61,0,5,0,0,0,5,0,29,0,4,0,0,0,4,0,29],[0,0,0,220,1,0,0,65,0,0,0,128,0,16,4,63,0,3,0,0,0,3,0,29,0,0,0,202,1,48,1,151],[0,2,0,0,0,1,0,29,0,0,0,132,0,16,4,63,0,0,0,187,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,0,187,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,0,221,1,16,1,199],[0,0,128,6,2,0,0,57,2,230,2,225,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,187,3,48,1,151,0,0,0,64,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,64,4,0,128,57],[0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114,0,0,0,164,0,0,97,61,0,0,0,0,7,0,0,25],[0,0,0,5,8,112,2,16,0,0,0,0,9,129,3,79,0,0,0,0,9,9,4,59,0,0,0,128,8,128,0,57],[0,0,0,0,0,152,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,0,156,0,0,65,61],[0,0,0,0,7,5,0,75,0,0,0,179,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79],[0,0,0,3,5,80,2,16,0,0,0,128,6,96,0,57,0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207],[0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144],[0,0,1,143,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,224,1,16,1,143,0,0,0,128,2,16,0,57],[0,0,0,64,0,32,4,63,0,0,0,64,3,48,0,140,0,0,2,107,0,0,65,61,0,0,0,192,3,16,0,57],[0,0,0,64,0,48,4,63,0,0,0,128,3,0,4,61,0,0,0,1,4,48,0,140,0,0,2,107,0,0,33,61],[0,0,0,0,0,50,4,53,0,0,0,160,2,0,4,61,0,0,0,1,3,32,0,140,0,0,2,107,0,0,33,61],[0,0,0,160,1,16,0,57,0,0,0,0,0,33,4,53,0,0,0,5,1,0,0,107,0,0,1,245,0,0,193,61],[0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,0,225,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,30,3,0,0,57,0,0,1,194,0,0,1,61,0,0,0,0,2,0,4,22],[0,0,0,0,2,2,0,75,0,0,2,107,0,0,193,61,0,0,0,4,1,16,0,138,0,0,0,96,1,16,0,140],[0,0,2,107,0,0,65,61,0,0,0,4,1,96,3,112,0,0,0,0,3,1,4,59,0,0,0,202,1,48,0,156],[0,0,2,107,0,0,33,61,0,0,0,68,1,96,3,112,0,0,0,0,2,1,4,59,0,0,0,0,1,2,0,75],[0,0,0,0,1,0,0,25,0,0,0,1,1,0,192,57,0,5,0,0,0,2,0,29,0,0,0,0,1,18,0,75],[0,0,2,107,0,0,193,61,0,0,0,36,1,96,3,112,0,0,0,0,1,1,4,59,0,3,0,0,0,1,0,29],[0,0,0,0,0,48,4,53,0,0,0,32,0,0,4,63,0,0,0,187,1,0,0,65,0,0,0,0,2,0,4,20],[0,4,0,0,0,3,0,29,0,0,0,187,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,0,204,1,16,1,199,0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15,0,0,0,4,3,0,0,41],[0,0,0,1,2,32,1,144,0,0,2,107,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,4,26],[0,0,0,205,1,16,1,151,0,0,0,3,1,16,0,108,0,0,1,206,0,0,161,61,0,0,0,5,1,0,0,107],[0,0,2,63,0,0,193,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,0,211,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,28,3,0,0,57,0,0,1,194,0,0,1,61],[0,0,0,0,3,0,4,22,0,0,0,0,3,3,0,75,0,0,2,107,0,0,193,61,0,0,0,4,1,16,0,138],[0,0,0,32,1,16,0,140,0,0,2,107,0,0,65,61,0,0,0,4,1,96,3,112,0,0,0,0,3,1,4,59],[0,0,0,2,1,32,1,144,0,0,1,13,0,0,193,61,0,0,0,0,1,0,4,17,0,0,255,255,1,16,0,140],[0,0,1,77,0,0,33,61,0,0,0,212,1,48,0,156,0,0,1,120,0,0,65,61,0,0,0,207,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,48,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,0,213,1,0,0,65,0,0,0,196,0,16,4,63,0,0,0,214,1,0,0,65],[0,0,1,86,0,0,1,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,2,107,0,0,193,61],[0,0,0,4,1,16,0,138,0,0,0,32,1,16,0,140,0,0,2,107,0,0,65,61,0,0,0,0,1,0,4,17],[0,0,0,0,0,16,4,53,0,0,0,1,1,0,0,57,0,0,0,32,0,16,4,63,0,0,0,0,1,0,0,25],[0,5,0,0,0,6,3,83,2,230,2,202,0,0,4,15,0,0,0,5,2,0,3,95,0,0,0,4,2,32,3,112],[0,0,0,0,2,2,4,59,0,0,0,0,0,32,4,53,0,0,0,32,0,16,4,63,0,0,0,0,1,0,0,25],[2,230,2,202,0,0,4,15,0,0,0,0,1,1,4,26,0,0,0,128,0,16,4,63,0,0,0,203,1,0,0,65],[0,0,2,231,0,1,4,46,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,2,107,0,0,193,61],[0,0,0,4,1,16,0,138,0,0,0,64,1,16,0,140,0,0,2,107,0,0,65,61,0,0,0,4,1,96,3,112],[0,0,0,0,1,1,4,59,0,0,0,202,2,16,0,156,0,0,2,107,0,0,33,61,0,0,0,36,2,96,3,112],[0,0,0,0,2,2,4,59,2,230,2,144,0,0,4,15,0,0,0,0,1,1,0,75,0,0,0,0,1,0,0,25],[0,0,0,1,1,0,192,57,0,0,1,135,0,0,1,61,0,0,0,0,3,0,4,22,0,0,0,0,3,3,0,75],[0,0,2,107,0,0,193,61,0,0,0,4,1,16,0,138,0,0,0,32,1,16,0,140,0,0,2,107,0,0,65,61],[0,0,0,0,3,0,4,17,0,0,0,2,1,32,1,144,0,0,1,89,0,0,193,61,0,0,255,255,1,48,0,140],[0,0,1,89,0,0,161,61,0,0,0,207,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,132,0,16,4,63,0,0,0,36,1,0,0,57,0,0,0,164,0,16,4,63,0,0,0,226,1,0,0,65],[0,0,0,196,0,16,4,63,0,0,0,227,1,0,0,65,0,0,0,228,0,16,4,63,0,0,0,215,1,0,0,65],[0,0,2,232,0,1,4,48,0,5,0,0,0,3,0,29,0,0,0,0,0,48,4,53,0,0,0,32,0,0,4,63],[0,0,0,187,1,0,0,65,0,0,0,0,2,0,4,20,0,0,0,187,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,0,204,1,16,1,199,0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,2,107,0,0,97,61,0,0,0,4,2,0,0,57,0,0,0,0,2,32,3,103],[0,0,0,0,2,2,4,59,0,0,0,0,1,1,4,59,0,0,0,0,1,1,4,26,0,0,0,205,3,16,1,151],[0,0,0,0,2,35,0,75,0,0,1,188,0,0,193,61,0,0,0,5,2,0,0,41,0,0,0,0,0,32,4,53],[0,0,0,32,0,0,4,63,0,5,0,1,0,16,0,61,0,0,0,0,1,0,0,25,2,230,2,202,0,0,4,15],[0,0,0,5,2,0,0,41,0,0,0,0,0,33,4,27,0,0,0,0,1,0,0,25,0,0,2,231,0,1,4,46],[0,0,0,0,1,0,4,17,0,4,0,0,0,1,0,29,0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63],[0,0,0,0,1,0,0,25,0,5,0,0,0,3,0,29,2,230,2,202,0,0,4,15,0,0,0,0,1,1,4,26],[0,3,0,0,0,1,0,29,0,0,0,4,1,0,0,41,2,230,2,109,0,0,4,15,0,0,0,3,3,0,0,41],[0,0,0,5,2,48,0,41,0,0,0,0,0,33,4,27,0,0,0,205,1,48,1,151,0,0,0,64,2,0,4,61],[0,0,0,0,0,18,4,53,0,0,0,187,1,0,0,65,0,0,0,187,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,64,1,32,2,16,0,0,0,209,1,16,1,199,0,0,2,231,0,1,4,46,0,0,0,64,2,0,4,61],[0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,1,156,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,1,148,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,1,171,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,0,187,1,0,0,65],[0,0,0,187,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,0,96,2,48,2,16],[0,0,0,0,1,33,1,159,0,0,2,232,0,1,4,48,0,0,0,207,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,61,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,0,216,1,0,0,65,0,0,0,196,0,16,4,63,0,0,0,217,1,0,0,65,0,0,1,86,0,0,1,61],[0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,0,206,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,15,3,0,0,57,0,0,0,0,0,50,4,53,0,0,0,207,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,0,187,2,0,0,65,0,0,0,187,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16],[0,0,0,208,1,16,1,199,0,0,2,232,0,1,4,48,0,0,0,0,0,48,4,53,0,0,0,1,1,0,0,57],[0,0,0,32,0,16,4,63,0,0,0,187,3,0,0,65,0,0,0,0,1,0,4,20,0,0,0,187,2,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,0,204,1,16,1,199,0,0,128,16,2,0,0,57],[2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144,0,0,2,107,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,3,2,0,0,41,0,0,0,0,0,32,4,53,0,0,0,32,0,16,4,63,0,0,0,0,1,0,4,20],[0,0,0,187,2,16,0,156,0,0,0,187,1,0,128,65,0,0,0,192,1,16,2,16,0,0,0,204,1,16,1,199],[0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144,0,0,2,107,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,0,1,1,4,26,0,0,0,0,1,1,0,75,0,0,0,247,0,0,193,61],[0,0,0,5,1,0,0,107,0,0,2,63,0,0,97,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57],[0,0,0,210,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,29,3,0,0,57],[0,0,1,194,0,0,1,61,0,0,0,0,1,2,0,75,0,0,2,13,0,0,193,61,0,0,0,4,1,0,0,107],[0,0,2,13,0,0,97,61,0,0,0,2,1,0,0,41,0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63],[0,0,0,187,1,0,0,65,0,0,0,0,2,0,4,20,0,0,0,187,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,0,204,1,16,1,199,0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,2,107,0,0,97,61,0,0,0,4,2,0,0,41,0,1,0,1,0,32,0,146],[0,0,0,0,1,1,4,59,0,0,0,0,1,1,4,26,0,0,0,205,1,16,1,151,0,0,0,1,1,16,0,108],[0,0,2,65,0,0,161,61,0,0,0,3,1,0,0,41,0,0,0,0,0,16,4,53,0,0,0,1,1,0,0,57],[0,0,0,32,0,16,4,63,0,0,0,187,3,0,0,65,0,0,0,0,1,0,4,20,0,0,0,187,2,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,0,204,1,16,1,199,0,0,128,16,2,0,0,57],[2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144,0,0,2,107,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,4,2,0,0,41,0,0,0,0,0,32,4,53,0,0,0,32,0,16,4,63,0,0,0,0,1,0,4,20],[0,0,0,187,2,16,0,156,0,0,0,187,1,0,128,65,0,0,0,192,1,16,2,16,0,0,0,204,1,16,1,199],[0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144,0,0,2,107,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,5,2,0,0,41,0,0,0,0,0,33,4,27,0,0,0,64,1,0,4,61],[0,0,0,0,0,33,4,53,0,0,0,187,2,0,0,65,0,0,0,0,3,0,4,20,0,0,0,187,4,48,0,156],[0,0,0,0,3,2,128,25,0,0,0,187,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16],[0,0,0,192,2,48,2,16,0,0,0,0,1,18,1,159,0,0,0,223,1,16,1,199,0,0,128,13,2,0,0,57],[0,0,0,3,3,0,0,57,0,0,0,224,4,0,0,65,0,0,0,3,5,0,0,41,0,0,0,4,6,0,0,41],[2,230,2,220,0,0,4,15,0,0,0,1,1,32,1,144,0,0,2,107,0,0,97,61,0,0,0,0,1,0,0,25],[0,0,2,231,0,1,4,46,0,0,0,2,1,0,0,41,0,0,0,0,0,16,4,53,0,0,0,1,1,0,0,57],[0,0,0,32,0,16,4,63,0,0,0,187,3,0,0,65,0,0,0,0,1,0,4,20,0,0,0,187,2,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,0,204,1,16,1,199,0,0,128,16,2,0,0,57],[2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144,0,0,2,107,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,1,2,0,0,41,0,0,0,0,0,32,4,53,0,0,0,32,0,16,4,63,0,0,0,0,1,0,4,20],[0,0,0,187,2,16,0,156,0,0,0,187,1,0,128,65,0,0,0,192,1,16,2,16,0,0,0,204,1,16,1,199],[0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144,0,0,2,107,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,0,1,1,4,26,0,0,0,0,1,1,0,75,0,0,2,13,0,0,193,61],[0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,0,222,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,207,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,36,2,16,0,57,0,0,0,32,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,0,4,2,16,0,57,0,0,1,199,0,0,1,61,0,0,0,0,1,0,0,25],[0,0,2,232,0,1,4,48,0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,0,187,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,0,187,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,0,204,1,16,1,199,0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,2,123,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,0,1,4,45,0,0,0,0,1,0,0,25],[0,0,2,232,0,1,4,48,0,0,0,202,1,16,1,151,0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63],[0,0,0,187,1,0,0,65,0,0,0,0,2,0,4,20,0,0,0,187,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,0,204,1,16,1,199,0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,2,142,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,4,26],[0,0,0,205,1,16,1,151,0,0,0,0,0,1,4,45,0,0,0,0,1,0,0,25,0,0,2,232,0,1,4,48],[0,2,0,0,0,0,0,2,0,2,0,0,0,2,0,29,0,0,0,202,1,16,1,151,0,1,0,0,0,1,0,29],[0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,0,187,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,0,187,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,0,204,1,16,1,199],[0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144,0,0,2,200,0,0,97,61],[0,0,0,1,2,0,0,57,0,0,0,0,1,1,4,59,0,0,0,0,1,1,4,26,0,0,0,205,1,16,1,151],[0,0,0,2,1,16,0,108,0,0,2,198,0,0,33,61,0,0,0,1,1,0,0,41,0,0,0,0,0,16,4,53],[0,0,0,1,1,0,0,57,0,0,0,32,0,16,4,63,0,0,0,187,4,0,0,65,0,0,0,0,1,0,4,20],[0,0,0,187,2,16,0,156,0,0,0,0,1,4,128,25,0,0,0,192,1,16,2,16,0,0,0,204,1,16,1,199],[0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144,0,0,2,200,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,2,2,0,0,41,0,0,0,0,0,32,4,53,0,0,0,32,0,16,4,63],[0,0,0,0,1,0,4,20,0,0,0,187,2,16,0,156,0,0,0,187,1,0,128,65,0,0,0,192,1,16,2,16],[0,0,0,204,1,16,1,199,0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,2,200,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,4,26,0,0,0,0,1,1,0,75],[0,0,0,0,2,0,0,25,0,0,0,1,2,0,192,57,0,0,0,1,1,32,1,143,0,0,0,0,0,1,4,45],[0,0,0,0,1,0,0,25,0,0,2,232,0,1,4,48,0,0,0,187,2,0,0,65,0,0,0,187,3,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,0,3,0,4,20,0,0,0,187,4,48,0,156,0,0,0,0,3,2,128,25],[0,0,0,192,2,48,2,16,0,0,0,64,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,204,1,16,1,199],[0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144,0,0,2,218,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,0,0,1,4,45,0,0,0,0,1,0,0,25,0,0,2,232,0,1,4,48],[0,0,2,223,0,33,4,33,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25],[0,0,0,0,0,1,4,45,0,0,2,228,0,33,4,35,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45],[0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,2,230,0,0,4,50,0,0,2,231,0,1,4,46],[0,0,2,232,0,1,4,48,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,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,0,0,0,0,0,110,225,220,31],[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,202,183,232,234],[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,202,183,232,235],[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,225,35,156,216],[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,251,26,154,87],[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,110,225,220,32],[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,137,105,9,220],[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,56,167,128,145],[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,56,167,128,146],[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,85,211,93,24],[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,90,169,182,181],[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,21,95,210,122],[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,48,99,149,198],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,128,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,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,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[73,110,99,111,114,114,101,99,116,32,110,111,110,99,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[8,195,121,160,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,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,32,0,0,0,0,0,0,0,0,0,0,0,0],[84,104,101,32,110,111,110,99,101,32,119,97,115,32,110,111,116,32,115,101,116,32,97,115,32,117,115,101,100,0,0,0],[82,101,117,115,105,110,103,32,116,104,101,32,115,97,109,101,32,110,111,110,99,101,32,116,119,105,99,101,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,1,0,0,0,1],[84,104,101,32,118,97,108,117,101,32,102,111,114,32,105,110,99,114,101,109,101,110,116,105,110,103,32,116,104,101,32,110],[111,110,99,101,32,105,115,32,116,111,111,32,104,105,103,104,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,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[79,110,108,121,32,116,104,101,32,99,111,110,116,114,97,99,116,32,100,101,112,108,111,121,101,114,32,99,97,110,32,105],[110,99,114,101,109,101,110,116,32,116,104,101,32,100,101,112,108,111,121,109,101,110,116,32,110,111,110,99,101,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,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,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0],[123,81,15,232,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,128,0,0,0,0,0,0,0,0],[80,114,101,118,105,111,117,115,32,110,111,110,99,101,32,104,97,115,32,110,111,116,32,98,101,101,110,32,117,115,101,100],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[218,43,113,110,90,93,95,96,43,154,88,66,188,216,156,33,91,18,82,88,223,234,39,26,3,229,224,232,1,217,58,140],[78,111,110,99,101,32,118,97,108,117,101,32,99,97,110,110,111,116,32,98,101,32,115,101,116,32,116,111,32,48,0,0],[84,104,105,115,32,109,101,116,104,111,100,32,114,101,113,117,105,114,101,32,115,121,115,116,101,109,32,99,97,108,108,32],[102,108,97,103,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],[205,38,218,213,70,69,248,169,15,229,84,69,140,55,53,181,164,198,188,161,173,181,140,218,24,152,223,38,173,188,41,218]]}} \ No newline at end of file diff --git a/prover/vk_setup_data_generator_server_fri/src/commitment_generator.rs b/prover/vk_setup_data_generator_server_fri/src/commitment_generator.rs index dffa1981d1c8..f2dd53b85283 100644 --- a/prover/vk_setup_data_generator_server_fri/src/commitment_generator.rs +++ b/prover/vk_setup_data_generator_server_fri/src/commitment_generator.rs @@ -1,8 +1,8 @@ -use anyhow::Context as _; -use zksync_prover_utils::vk_commitment_helper::{ - get_toml_formatted_value, read_contract_toml, write_contract_toml, +use anyhow::Context; +use zksync_vk_setup_data_server_fri::{ + commitment_utils::generate_commitments, + vk_commitment_helper::{get_toml_formatted_value, read_contract_toml, write_contract_toml}, }; -use zksync_vk_setup_data_server_fri::commitment_utils::generate_commitments; fn main() -> anyhow::Result<()> { tracing::info!("Starting commitment generation!"); diff --git a/prover/vk_setup_data_generator_server_fri/src/lib.rs b/prover/vk_setup_data_generator_server_fri/src/lib.rs index 19fab9af470b..b3d286314582 100644 --- a/prover/vk_setup_data_generator_server_fri/src/lib.rs +++ b/prover/vk_setup_data_generator_server_fri/src/lib.rs @@ -9,6 +9,13 @@ use circuit_definitions::circuit_definitions::aux_layer::{ }; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use zkevm_test_harness::prover_utils::create_base_layer_setup_data; +use zkevm_test_harness_1_3_3::{ + abstract_zksync_circuit::concrete_circuits::ZkSyncCircuit, + bellman::{ + bn256::Bn256, plonk::better_better_cs::setup::VerificationKey as SnarkVerificationKey, + }, + witness::oracle::VmWitnessOracle as SnarkWitnessOracle, +}; use zksync_config::configs::FriProverConfig; use zksync_env_config::FromEnv; use zksync_prover_fri_types::{ @@ -44,21 +51,13 @@ use zksync_prover_fri_types::{ }, ProverServiceDataKey, }; -use zksync_types::{ - proofs::AggregationRound, - zkevm_test_harness::{ - abstract_zksync_circuit::concrete_circuits::ZkSyncCircuit, - bellman::{ - bn256::Bn256, plonk::better_better_cs::setup::VerificationKey as SnarkVerificationKey, - }, - witness::oracle::VmWitnessOracle as SnarkWitnessOracle, - }, -}; +use zksync_types::basic_fri_types::AggregationRound; #[cfg(feature = "gpu")] use {shivini::cs::GpuSetup, std::alloc::Global}; pub mod commitment_utils; pub mod utils; +pub mod vk_commitment_helper; #[derive(Debug, Serialize, Deserialize)] #[serde( @@ -371,7 +370,7 @@ pub fn get_finalization_hints( key: ProverServiceDataKey, ) -> anyhow::Result { let mut key = key; - // For NodeAggregation round we have only 1 finalization hints for all circuit type. + // For `NodeAggregation` round we have only 1 finalization hints for all circuit type. if key.round == AggregationRound::NodeAggregation { key.circuit_id = ZkSyncRecursionLayerStorageType::NodeLayerCircuit as u8; } diff --git a/prover/vk_setup_data_generator_server_fri/src/main.rs b/prover/vk_setup_data_generator_server_fri/src/main.rs index 158a4390a967..ec4ef461d653 100644 --- a/prover/vk_setup_data_generator_server_fri/src/main.rs +++ b/prover/vk_setup_data_generator_server_fri/src/main.rs @@ -14,7 +14,7 @@ use zksync_prover_fri_types::{ }, ProverServiceDataKey, }; -use zksync_types::proofs::AggregationRound; +use zksync_types::basic_fri_types::AggregationRound; use zksync_vk_setup_data_server_fri::{ get_round_for_recursive_circuit_type, save_base_layer_vk, save_finalization_hints, save_recursive_layer_vk, save_snark_vk, diff --git a/prover/vk_setup_data_generator_server_fri/src/setup_data_generator.rs b/prover/vk_setup_data_generator_server_fri/src/setup_data_generator.rs index 5df4b75b3a65..bd36e8e2b3b9 100644 --- a/prover/vk_setup_data_generator_server_fri/src/setup_data_generator.rs +++ b/prover/vk_setup_data_generator_server_fri/src/setup_data_generator.rs @@ -14,7 +14,7 @@ use zksync_prover_fri_types::{ }, ProverServiceDataKey, }; -use zksync_types::proofs::AggregationRound; +use zksync_types::basic_fri_types::AggregationRound; use zksync_vk_setup_data_server_fri::{ generate_cpu_base_layer_setup_data, get_finalization_hints, get_recursive_layer_vk_for_circuit_type, get_round_for_recursive_circuit_type, save_setup_data, diff --git a/prover/vk_setup_data_generator_server_fri/src/tests.rs b/prover/vk_setup_data_generator_server_fri/src/tests.rs index 3d6a203ed97c..0059a646fd87 100644 --- a/prover/vk_setup_data_generator_server_fri/src/tests.rs +++ b/prover/vk_setup_data_generator_server_fri/src/tests.rs @@ -8,7 +8,7 @@ use zksync_prover_fri_types::{ }, ProverServiceDataKey, }; -use zksync_types::proofs::AggregationRound; +use zksync_types::basic_fri_types::AggregationRound; use zksync_vk_setup_data_server_fri::{ get_base_layer_vk_for_circuit_type, get_base_path, get_file_path, get_finalization_hints, get_recursive_layer_vk_for_circuit_type, get_round_for_recursive_circuit_type, @@ -65,14 +65,14 @@ proptest! { } -// Test get_base_path method +// Test `get_base_path` method #[test] fn test_get_base_path() { let base_path = get_base_path(); assert!(!base_path.is_empty(), "Base path should not be empty"); } -// Test get_file_path method +// Test `get_file_path` method #[test] fn test_get_file_path() { let key = ProverServiceDataKey::new(1, AggregationRound::BasicCircuits); @@ -80,7 +80,7 @@ fn test_get_file_path() { assert!(!file_path.is_empty(), "File path should not be empty"); } -// Test ProverServiceDataKey::new method +// Test `ProverServiceDataKey::new` method #[test] fn test_proverservicedatakey_new() { let key = ProverServiceDataKey::new(1, AggregationRound::BasicCircuits); @@ -95,7 +95,7 @@ fn test_proverservicedatakey_new() { ); } -// Test get_round_for_recursive_circuit_type method +// Test `get_round_for_recursive_circuit_type` method #[test] fn test_get_round_for_recursive_circuit_type() { let round = get_round_for_recursive_circuit_type( diff --git a/prover/vk_setup_data_generator_server_fri/src/utils.rs b/prover/vk_setup_data_generator_server_fri/src/utils.rs index 01b40de33943..8278d9e9eb56 100644 --- a/prover/vk_setup_data_generator_server_fri/src/utils.rs +++ b/prover/vk_setup_data_generator_server_fri/src/utils.rs @@ -4,6 +4,7 @@ use std::{ }; use anyhow::Context as _; +use circuit_definitions::circuit_definitions::recursion_layer::scheduler::SchedulerCircuit; use itertools::Itertools; use zkevm_test_harness::{ compute_setups::{generate_base_layer_vks_and_proofs, generate_recursive_layer_vks_and_proofs}, @@ -14,10 +15,6 @@ use zkevm_test_harness::{ sha3::{Digest, Keccak256}, toolset::GeometryConfig, witness::{ - full_block_artifact::{ - BlockBasicCircuits, BlockBasicCircuitsPublicCompactFormsWitnesses, - BlockBasicCircuitsPublicInputs, - }, recursive_aggregation::compute_leaf_params, tree::{BinarySparseStorageTree, ZKSyncTestingTree}, }, @@ -26,10 +23,9 @@ use zksync_prover_fri_types::circuit_definitions::{ aux_definitions::witness_oracle::VmWitnessOracle, base_layer_proof_config, boojum::{ - field::goldilocks::{GoldilocksExt2, GoldilocksField}, + field::goldilocks::GoldilocksField, gadgets::{ queue::full_state_queue::FullStateCircuitQueueRawWitness, - recursion::recursive_tree_hasher::CircuitGoldilocksPoseidon2Sponge, traits::allocatable::CSAllocatable, }, }, @@ -38,9 +34,8 @@ use zksync_prover_fri_types::circuit_definitions::{ recursion_layer::{ base_circuit_type_into_recursive_leaf_circuit_type, leaf_layer::ZkSyncLeafLayerRecursiveCircuit, - node_layer::ZkSyncNodeLayerRecursiveCircuit, scheduler::SchedulerCircuit, - ZkSyncRecursionLayerStorageType, ZkSyncRecursionProof, ZkSyncRecursiveLayerCircuit, - RECURSION_ARITY, SCHEDULER_CAPACITY, + node_layer::ZkSyncNodeLayerRecursiveCircuit, ZkSyncRecursionLayerStorageType, + ZkSyncRecursionProof, ZkSyncRecursiveLayerCircuit, RECURSION_ARITY, SCHEDULER_CAPACITY, }, }, recursion_layer_proof_config, zk_evm, @@ -91,10 +86,92 @@ pub fn get_basic_circuits( >, > { let path = format!("{}/witness_artifacts.json", get_base_path()); - let test_artifact = read_witness_artifact(&path).context("read_withess_artifact()")?; - let (base_layer_circuit, _, _, _) = get_circuits(test_artifact, cycle_limit, geometry); - Ok(base_layer_circuit - .into_flattened_set() + let mut test_artifact = read_witness_artifact(&path).context("read_withess_artifact()")?; + + let mut storage_impl = InMemoryStorage::new(); + let mut tree = ZKSyncTestingTree::empty(); + + test_artifact.entry_point_address = + *zk_evm::zkevm_opcode_defs::system_params::BOOTLOADER_FORMAL_ADDRESS; + + let predeployed_contracts = test_artifact + .predeployed_contracts + .clone() + .into_iter() + .chain(Some(( + test_artifact.entry_point_address, + test_artifact.entry_point_code.clone(), + ))) + .collect::>(); + save_predeployed_contracts(&mut storage_impl, &mut tree, &predeployed_contracts); + + let used_bytecodes = HashMap::from_iter( + test_artifact + .predeployed_contracts + .values() + .map(|bytecode| { + ( + bytecode_to_code_hash(bytecode).unwrap().into(), + bytecode.clone(), + ) + }) + .chain( + Some(test_artifact.default_account_code.clone()).map(|bytecode| { + ( + bytecode_to_code_hash(&bytecode).unwrap().into(), + bytecode.clone(), + ) + }), + ), + ); + + let previous_enumeration_index = tree.next_enumeration_index(); + let previous_root = tree.root(); + // simulate content hash + + let mut hasher = Keccak256::new(); + hasher.update(previous_enumeration_index.to_be_bytes()); + hasher.update(previous_root); + hasher.update(0u64.to_be_bytes()); // porter shard + hasher.update([0u8; 32]); // porter shard + + let mut previous_data_hash = [0u8; 32]; + previous_data_hash[..].copy_from_slice(hasher.finalize().as_slice()); + + let previous_aux_hash = [0u8; 32]; + let previous_meta_hash = [0u8; 32]; + + let mut hasher = Keccak256::new(); + hasher.update(previous_data_hash); + hasher.update(previous_meta_hash); + hasher.update(previous_aux_hash); + + let mut previous_content_hash = [0u8; 32]; + previous_content_hash[..].copy_from_slice(hasher.finalize().as_slice()); + + let default_account_codehash = + bytecode_to_code_hash(&test_artifact.default_account_code).unwrap(); + let default_account_codehash = U256::from_big_endian(&default_account_codehash); + + let mut base_layer_circuits = vec![]; + let _ = run( + Address::zero(), + test_artifact.entry_point_address, + test_artifact.entry_point_code, + vec![], + false, + default_account_codehash, + used_bytecodes, + vec![], + cycle_limit, + geometry, + storage_impl, + &mut tree, + |circuit| base_layer_circuits.push(circuit), + |_, _, _| {}, + ); + + Ok(base_layer_circuits .into_iter() .dedup_by(|a, b| a.numeric_circuit_type() == b.numeric_circuit_type()) .collect()) @@ -193,6 +270,9 @@ pub fn get_scheduler_circuit() -> anyhow::Result { witness: scheduler_witness, config, transcript_params: (), + eip4844_proof_config: None, + eip4844_vk: None, + eip4844_vk_fixed_parameters: None, _marker: std::marker::PhantomData, }; Ok(ZkSyncRecursiveLayerCircuit::SchedulerCircuit( @@ -239,115 +319,3 @@ pub fn get_leaf_vk_params( } Ok(leaf_vk_commits) } - -#[allow(clippy::type_complexity)] -fn get_circuits( - mut test_artifact: TestArtifact, - cycle_limit: usize, - geometry: GeometryConfig, -) -> ( - BlockBasicCircuits, - BlockBasicCircuitsPublicInputs, - BlockBasicCircuitsPublicCompactFormsWitnesses, - SchedulerCircuitInstanceWitness< - GoldilocksField, - CircuitGoldilocksPoseidon2Sponge, - GoldilocksExt2, - >, -) { - let round_function = ZkSyncDefaultRoundFunction::default(); - - let mut storage_impl = InMemoryStorage::new(); - let mut tree = ZKSyncTestingTree::empty(); - - test_artifact.entry_point_address = - *zk_evm::zkevm_opcode_defs::system_params::BOOTLOADER_FORMAL_ADDRESS; - - let predeployed_contracts = test_artifact - .predeployed_contracts - .clone() - .into_iter() - .chain(Some(( - test_artifact.entry_point_address, - test_artifact.entry_point_code.clone(), - ))) - .collect::>(); - save_predeployed_contracts(&mut storage_impl, &mut tree, &predeployed_contracts); - - let used_bytecodes = HashMap::from_iter( - test_artifact - .predeployed_contracts - .values() - .map(|bytecode| { - ( - bytecode_to_code_hash(bytecode).unwrap().into(), - bytecode.clone(), - ) - }) - .chain( - Some(test_artifact.default_account_code.clone()).map(|bytecode| { - ( - bytecode_to_code_hash(&bytecode).unwrap().into(), - bytecode.clone(), - ) - }), - ), - ); - - let previous_enumeration_index = tree.next_enumeration_index(); - let previous_root = tree.root(); - // simualate content hash - - let mut hasher = Keccak256::new(); - hasher.update(previous_enumeration_index.to_be_bytes()); - hasher.update(previous_root); - hasher.update(0u64.to_be_bytes()); // porter shard - hasher.update([0u8; 32]); // porter shard - - let mut previous_data_hash = [0u8; 32]; - previous_data_hash[..].copy_from_slice(hasher.finalize().as_slice()); - - let previous_aux_hash = [0u8; 32]; - let previous_meta_hash = [0u8; 32]; - - let mut hasher = Keccak256::new(); - hasher.update(previous_data_hash); - hasher.update(previous_meta_hash); - hasher.update(previous_aux_hash); - - let mut previous_content_hash = [0u8; 32]; - previous_content_hash[..].copy_from_slice(hasher.finalize().as_slice()); - - let default_account_codehash = - bytecode_to_code_hash(&test_artifact.default_account_code).unwrap(); - let default_account_codehash = U256::from_big_endian(&default_account_codehash); - - let ( - basic_block_circuits, - basic_block_circuits_inputs, - closed_form_inputs, - scheduler_partial_input, - _, - ) = run( - Address::zero(), - test_artifact.entry_point_address, - test_artifact.entry_point_code, - vec![], - false, - default_account_codehash, - used_bytecodes, - vec![], - cycle_limit, - round_function, - geometry, - storage_impl, - &mut tree, - ); - - ( - basic_block_circuits, - basic_block_circuits_inputs, - closed_form_inputs, - scheduler_partial_input, - ) -} diff --git a/core/lib/prover_utils/src/vk_commitment_helper.rs b/prover/vk_setup_data_generator_server_fri/src/vk_commitment_helper.rs similarity index 100% rename from core/lib/prover_utils/src/vk_commitment_helper.rs rename to prover/vk_setup_data_generator_server_fri/src/vk_commitment_helper.rs diff --git a/prover/vk_setup_data_generator_server_fri/src/vk_generator.rs b/prover/vk_setup_data_generator_server_fri/src/vk_generator.rs index 2b633bc6d08d..ced67af82e62 100644 --- a/prover/vk_setup_data_generator_server_fri/src/vk_generator.rs +++ b/prover/vk_setup_data_generator_server_fri/src/vk_generator.rs @@ -14,7 +14,7 @@ use zksync_prover_fri_types::{ }, ProverServiceDataKey, }; -use zksync_types::proofs::AggregationRound; +use zksync_types::basic_fri_types::AggregationRound; use zksync_vk_setup_data_server_fri::{ get_round_for_recursive_circuit_type, save_base_layer_vk, save_finalization_hints, save_recursive_layer_vk, diff --git a/prover/witness_generator/Cargo.toml b/prover/witness_generator/Cargo.toml index 9d8b10d73fa2..515f0b0dd14f 100644 --- a/prover/witness_generator/Cargo.toml +++ b/prover/witness_generator/Cargo.toml @@ -15,6 +15,7 @@ vise = { git = "https://github.com/matter-labs/vise.git", version = "0.1.0", rev zksync_dal = { path = "../../core/lib/dal" } zksync_config = { path = "../../core/lib/config" } +zksync_prover_interface = { path = "../../core/lib/prover_interface" } zksync_env_config = { path = "../../core/lib/env_config" } zksync_system_constants = { path = "../../core/lib/constants" } prometheus_exporter = { path = "../../core/lib/prometheus_exporter" } @@ -26,15 +27,14 @@ zksync_types = { path = "../../core/lib/types" } zksync_state = { path = "../../core/lib/state" } zksync_utils = { path = "../../core/lib/utils" } vk_setup_data_generator_server_fri = { path = "../vk_setup_data_generator_server_fri" } -zksync_prover_utils = { path = "../../core/lib/prover_utils" } zksync_prover_fri_types = { path = "../prover_fri_types" } zksync_prover_fri_utils = { path = "../prover_fri_utils" } -zkevm_test_harness = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.0" } -circuit_definitions = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.0", features = [ +zkevm_test_harness = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.1" } +circuit_definitions = { git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.1", features = [ "log_tracing", ] } -zk_evm = { git = "https://github.com/matter-labs/era-zk_evm.git", branch = "v1.4.0" } +zk_evm = { git = "https://github.com/matter-labs/era-zk_evm.git", branch = "v1.4.1" } anyhow = "1.0" tracing = "0.1" diff --git a/prover/witness_generator/src/basic_circuits.rs b/prover/witness_generator/src/basic_circuits.rs index b883c4bb35aa..6d7d15b78613 100644 --- a/prover/witness_generator/src/basic_circuits.rs +++ b/prover/witness_generator/src/basic_circuits.rs @@ -7,24 +7,20 @@ use std::{ use anyhow::Context as _; use async_trait::async_trait; +use circuit_definitions::{ + circuit_definitions::base_layer::ZkSyncBaseLayerStorage, + encodings::recursion_request::RecursionQueueSimulator, + zkevm_circuits::fsm_input_output::ClosedFormInputCompactFormWitness, +}; use multivm::vm_latest::{ constants::MAX_CYCLES_FOR_TX, HistoryDisabled, StorageOracle as VmStorageOracle, }; use rand::Rng; use serde::{Deserialize, Serialize}; -use zkevm_test_harness::{ - geometry_config::get_geometry_config, - toolset::GeometryConfig, - witness::full_block_artifact::{ - BlockBasicCircuits, BlockBasicCircuitsPublicCompactFormsWitnesses, - BlockBasicCircuitsPublicInputs, - }, -}; +use zkevm_test_harness::{geometry_config::get_geometry_config, toolset::GeometryConfig}; use zksync_config::configs::FriWitnessGeneratorConfig; use zksync_dal::{fri_witness_generator_dal::FriWitnessJobStatus, ConnectionPool}; -use zksync_object_store::{ - Bucket, ClosedFormInputKey, ObjectStore, ObjectStoreFactory, StoredObject, -}; +use zksync_object_store::{Bucket, ObjectStore, ObjectStoreFactory, StoredObject}; use zksync_prover_fri_types::{ circuit_definitions::{ boojum::{ @@ -34,17 +30,18 @@ use zksync_prover_fri_types::{ zkevm_circuits::scheduler::{ block_header::BlockAuxilaryOutputWitness, input::SchedulerCircuitInstanceWitness, }, - ZkSyncDefaultRoundFunction, }, - get_current_pod_name, AuxOutputWitnessWrapper, + get_current_pod_name, + keys::ClosedFormInputKey, + AuxOutputWitnessWrapper, }; use zksync_prover_fri_utils::get_recursive_layer_circuit_id_for_base_layer; +use zksync_prover_interface::inputs::{BasicCircuitWitnessGeneratorInput, PrepareBasicCircuitsJob}; use zksync_queued_job_processor::JobProcessor; use zksync_state::{PostgresStorage, StorageView}; use zksync_types::{ - proofs::{AggregationRound, BasicCircuitWitnessGeneratorInput, PrepareBasicCircuitsJob}, - protocol_version::FriProtocolVersionId, - Address, L1BatchNumber, BOOTLOADER_ADDRESS, H256, U256, + basic_fri_types::AggregationRound, protocol_version::FriProtocolVersionId, Address, + L1BatchNumber, ProtocolVersionId, BOOTLOADER_ADDRESS, H256, U256, }; use zksync_utils::{bytes_to_chunks, h256_to_u256, u256_to_h256}; @@ -53,16 +50,14 @@ use crate::{ precalculated_merkle_paths_provider::PrecalculatedMerklePathsProvider, storage_oracle::StorageOracle, utils::{ - expand_bootloader_contents, save_base_prover_input_artifacts, ClosedFormInputWrapper, + expand_bootloader_contents, save_circuit, ClosedFormInputWrapper, SchedulerPartialInputWrapper, }, }; pub struct BasicCircuitArtifacts { - basic_circuits: BlockBasicCircuits, - basic_circuits_inputs: BlockBasicCircuitsPublicInputs, - per_circuit_closed_form_inputs: BlockBasicCircuitsPublicCompactFormsWitnesses, - #[allow(dead_code)] + circuit_urls: Vec<(u8, String)>, + queue_urls: Vec<(u8, String, usize)>, scheduler_witness: SchedulerCircuitInstanceWitness< GoldilocksField, CircuitGoldilocksPoseidon2Sponge, @@ -88,7 +83,7 @@ pub struct BasicWitnessGeneratorJob { pub struct BasicWitnessGenerator { config: Arc, object_store: Arc, - public_blob_store: Option>, + public_blob_store: Option>, connection_pool: ConnectionPool, prover_connection_pool: ConnectionPool, protocol_versions: Vec, @@ -98,14 +93,14 @@ impl BasicWitnessGenerator { pub async fn new( config: FriWitnessGeneratorConfig, store_factory: &ObjectStoreFactory, - public_blob_store: Option>, + public_blob_store: Option>, connection_pool: ConnectionPool, prover_connection_pool: ConnectionPool, protocol_versions: Vec, ) -> Self { Self { config: Arc::new(config), - object_store: store_factory.create_store().await.into(), + object_store: store_factory.create_store().await, public_blob_store, connection_pool, prover_connection_pool, @@ -257,9 +252,10 @@ impl JobProcessor for BasicWitnessGenerator { None => Ok(()), Some(artifacts) => { let blob_started_at = Instant::now(); - let blob_urls = save_artifacts( + let scheduler_witness_url = save_scheduler_artifacts( job_id, - artifacts, + artifacts.scheduler_witness, + artifacts.aux_output_witness, &*self.object_store, self.public_blob_store.as_deref(), self.config.shall_save_to_public_bucket, @@ -269,7 +265,17 @@ impl JobProcessor for BasicWitnessGenerator { WITNESS_GENERATOR_METRICS.blob_save_time[&AggregationRound::BasicCircuits.into()] .observe(blob_started_at.elapsed()); - update_database(&self.prover_connection_pool, started_at, job_id, blob_urls).await; + update_database( + &self.prover_connection_pool, + started_at, + job_id, + BlobUrls { + circuit_ids_and_urls: artifacts.circuit_urls, + closed_form_inputs_and_urls: artifacts.queue_urls, + scheduler_witness_url, + }, + ) + .await; Ok(()) } } @@ -304,16 +310,16 @@ async fn process_basic_circuits_job( ) -> BasicCircuitArtifacts { let witness_gen_input = build_basic_circuits_witness_generator_input(&connection_pool, job, block_number).await; - let ( - basic_circuits, - basic_circuits_inputs, - per_circuit_closed_form_inputs, - scheduler_witness, - aux_output_witness, - ) = generate_witness(object_store, config, connection_pool, witness_gen_input).await; + let (circuit_urls, queue_urls, scheduler_witness, aux_output_witness) = generate_witness( + block_number, + object_store, + config, + connection_pool, + witness_gen_input, + ) + .await; WITNESS_GENERATOR_METRICS.witness_generation_time[&AggregationRound::BasicCircuits.into()] .observe(started_at.elapsed()); - tracing::info!( "Witness generation for block {} is complete in {:?}", block_number.0, @@ -321,9 +327,8 @@ async fn process_basic_circuits_job( ); BasicCircuitArtifacts { - basic_circuits, - basic_circuits_inputs, - per_circuit_closed_form_inputs, + circuit_urls, + queue_urls, scheduler_witness, aux_output_witness, } @@ -374,44 +379,6 @@ async fn get_artifacts( BasicWitnessGeneratorJob { block_number, job } } -async fn save_artifacts( - block_number: L1BatchNumber, - artifacts: BasicCircuitArtifacts, - object_store: &dyn ObjectStore, - public_object_store: Option<&dyn ObjectStore>, - shall_save_to_public_bucket: bool, -) -> BlobUrls { - let circuit_ids_and_urls = save_base_prover_input_artifacts( - block_number, - artifacts.basic_circuits, - object_store, - AggregationRound::BasicCircuits, - ) - .await; - let closed_form_inputs_and_urls = save_leaf_aggregation_artifacts( - block_number, - artifacts.basic_circuits_inputs, - artifacts.per_circuit_closed_form_inputs, - object_store, - ) - .await; - let scheduler_witness_url = save_scheduler_artifacts( - block_number, - artifacts.scheduler_witness, - artifacts.aux_output_witness, - object_store, - public_object_store, - shall_save_to_public_bucket, - ) - .await; - - BlobUrls { - circuit_ids_and_urls, - closed_form_inputs_and_urls, - scheduler_witness_url, - } -} - async fn save_scheduler_artifacts( block_number: L1BatchNumber, scheduler_partial_input: SchedulerCircuitInstanceWitness< @@ -440,28 +407,25 @@ async fn save_scheduler_artifacts( object_store.put(block_number, &wrapper).await.unwrap() } -async fn save_leaf_aggregation_artifacts( +async fn save_recursion_queue( block_number: L1BatchNumber, - basic_circuits_inputs: BlockBasicCircuitsPublicInputs, - per_circuit_closed_form_inputs: BlockBasicCircuitsPublicCompactFormsWitnesses, + circuit_id: u8, + recursion_queue_simulator: RecursionQueueSimulator, + closed_form_inputs: &[ClosedFormInputCompactFormWitness], object_store: &dyn ObjectStore, -) -> Vec<(u8, String, usize)> { - let round_function = ZkSyncDefaultRoundFunction::default(); - let queues = basic_circuits_inputs - .into_recursion_queues(per_circuit_closed_form_inputs, &round_function); - let mut circuit_id_urls_with_count = Vec::with_capacity(queues.len()); - for (circuit_id_ref, recursion_queue_simulator, inputs) in queues { - let circuit_id = circuit_id_ref as u8; - let key = ClosedFormInputKey { - block_number, - circuit_id, - }; - let basic_circuit_count = inputs.len(); - let wrapper = ClosedFormInputWrapper(inputs, recursion_queue_simulator); - let blob_url = object_store.put(key, &wrapper).await.unwrap(); - circuit_id_urls_with_count.push((circuit_id, blob_url, basic_circuit_count)) - } - circuit_id_urls_with_count +) -> (u8, String, usize) { + let key = ClosedFormInputKey { + block_number, + circuit_id, + }; + let basic_circuit_count = closed_form_inputs.len(); + let closed_form_inputs = closed_form_inputs + .iter() + .map(|x| ZkSyncBaseLayerStorage::from_inner(circuit_id, x.clone())) + .collect(); + let wrapper = ClosedFormInputWrapper(closed_form_inputs, recursion_queue_simulator); + let blob_url = object_store.put(key, &wrapper).await.unwrap(); + (circuit_id, blob_url, basic_circuit_count) } // If making changes to this method, consider moving this logic to the DAL layer and make @@ -508,14 +472,14 @@ async fn build_basic_circuits_witness_generator_input( } async fn generate_witness( + block_number: L1BatchNumber, object_store: &dyn ObjectStore, config: Arc, connection_pool: ConnectionPool, input: BasicCircuitWitnessGeneratorInput, ) -> ( - BlockBasicCircuits, - BlockBasicCircuitsPublicInputs, - BlockBasicCircuitsPublicCompactFormsWitnesses, + Vec<(u8, String)>, + Vec<(u8, String, usize)>, SchedulerCircuitInstanceWitness< GoldilocksField, CircuitGoldilocksPoseidon2Sponge, @@ -531,6 +495,10 @@ async fn generate_witness( .unwrap() .unwrap(); + let protocol_version = header + .protocol_version + .unwrap_or(ProtocolVersionId::last_potentially_undefined()); + let previous_batch_with_metadata = connection .blocks_dal() .get_l1_batch_metadata(zksync_types::L1BatchNumber( @@ -552,13 +520,14 @@ async fn generate_witness( .await .expect("Default aa bytecode should exist"); let account_bytecode = bytes_to_chunks(&account_bytecode_bytes); - let bootloader_contents = expand_bootloader_contents(&input.initial_heap_content); + let bootloader_contents = + expand_bootloader_contents(&input.initial_heap_content, protocol_version); let account_code_hash = h256_to_u256(header.base_system_contracts_hashes.default_aa); let hashes: HashSet = input .used_bytecodes_hashes .iter() - // SMA-1555: remove this hack once updated to the latest version of zkevm_test_harness + // SMA-1555: remove this hack once updated to the latest version of `zkevm_test_harness` .filter(|&&hash| hash != h256_to_u256(header.base_system_contracts_hashes.bootloader)) .map(|hash| u256_to_h256(*hash)) .collect(); @@ -631,13 +600,10 @@ async fn generate_witness( // The following part is CPU-heavy, so we move it to a separate thread. let rt_handle = tokio::runtime::Handle::current(); - let ( - basic_circuits, - basic_circuits_public_inputs, - basic_circuits_public_compact_witness, - mut scheduler_witness, - block_aux_witness, - ) = tokio::task::spawn_blocking(move || { + let (circuit_sender, mut circuit_receiver) = tokio::sync::mpsc::channel(1); + let (queue_sender, mut queue_receiver) = tokio::sync::mpsc::channel(1); + + let make_circuits = tokio::task::spawn_blocking(move || { let connection = rt_handle .block_on(connection_pool.access_storage()) .unwrap(); @@ -649,7 +615,7 @@ async fn generate_witness( VmStorageOracle::new(storage_view.clone()); let storage_oracle = StorageOracle::new(vm_storage_oracle, storage_refunds); - zkevm_test_harness::external_calls::run_with_fixed_params( + let (scheduler_witness, block_witness) = zkevm_test_harness::external_calls::run( Address::zero(), BOOTLOADER_ADDRESS, bootloader_code, @@ -662,10 +628,37 @@ async fn generate_witness( geometry_config, storage_oracle, &mut tree, - ) - }) - .await - .unwrap(); + |circuit| { + circuit_sender.blocking_send(circuit).unwrap(); + }, + |a, b, c| queue_sender.blocking_send((a as u8, b, c)).unwrap(), + ); + (scheduler_witness, block_witness) + }); + + let mut circuit_urls = vec![]; + let mut recursion_urls = vec![]; + + let save_circuits = async { + loop { + tokio::select! { + Some(circuit) = circuit_receiver.recv() => { + circuit_urls.push( + save_circuit(block_number, circuit, circuit_urls.len(), object_store).await, + ); + } + Some((circuit_id, queue, inputs)) = queue_receiver.recv() =>recursion_urls.push( + save_recursion_queue(block_number, circuit_id, queue, &inputs, object_store) + .await, + ), + else => break, + }; + } + }; + + let (witnesses, ()) = tokio::join!(make_circuits, save_circuits); + + let (mut scheduler_witness, block_aux_witness) = witnesses.unwrap(); scheduler_witness.previous_block_meta_hash = previous_batch_with_metadata.metadata.meta_parameters_hash.0; @@ -673,9 +666,8 @@ async fn generate_witness( previous_batch_with_metadata.metadata.aux_data_hash.0; ( - basic_circuits, - basic_circuits_public_inputs, - basic_circuits_public_compact_witness, + circuit_urls, + recursion_urls, scheduler_witness, block_aux_witness, ) diff --git a/prover/witness_generator/src/leaf_aggregation.rs b/prover/witness_generator/src/leaf_aggregation.rs index f190aeb21645..dd2b5805e42d 100644 --- a/prover/witness_generator/src/leaf_aggregation.rs +++ b/prover/witness_generator/src/leaf_aggregation.rs @@ -1,4 +1,4 @@ -use std::time::Instant; +use std::{sync::Arc, time::Instant}; use anyhow::Context as _; use async_trait::async_trait; @@ -6,8 +6,8 @@ use zkevm_test_harness::witness::recursive_aggregation::{ compute_leaf_params, create_leaf_witnesses, }; use zksync_config::configs::FriWitnessGeneratorConfig; -use zksync_dal::ConnectionPool; -use zksync_object_store::{ClosedFormInputKey, ObjectStore, ObjectStoreFactory}; +use zksync_dal::{fri_prover_dal::types::LeafAggregationJobMetadata, ConnectionPool}; +use zksync_object_store::{ObjectStore, ObjectStoreFactory}; use zksync_prover_fri_types::{ circuit_definitions::{ boojum::field::goldilocks::GoldilocksField, @@ -21,14 +21,14 @@ use zksync_prover_fri_types::{ encodings::recursion_request::RecursionQueueSimulator, zkevm_circuits::recursion::leaf_layer::input::RecursionLeafParametersWitness, }, - get_current_pod_name, FriProofWrapper, + get_current_pod_name, + keys::ClosedFormInputKey, + FriProofWrapper, }; use zksync_prover_fri_utils::get_recursive_layer_circuit_id_for_base_layer; use zksync_queued_job_processor::JobProcessor; use zksync_types::{ - proofs::{AggregationRound, LeafAggregationJobMetadata}, - protocol_version::FriProtocolVersionId, - L1BatchNumber, + basic_fri_types::AggregationRound, protocol_version::FriProtocolVersionId, L1BatchNumber, }; use zksync_vk_setup_data_server_fri::{ get_base_layer_vk_for_circuit_type, get_recursive_layer_vk_for_circuit_type, @@ -72,7 +72,7 @@ pub struct LeafAggregationWitnessGeneratorJob { #[derive(Debug)] pub struct LeafAggregationWitnessGenerator { config: FriWitnessGeneratorConfig, - object_store: Box, + object_store: Arc, prover_connection_pool: ConnectionPool, protocol_versions: Vec, } diff --git a/prover/witness_generator/src/main.rs b/prover/witness_generator/src/main.rs index 3b3b8d460339..7e92397dd1c3 100644 --- a/prover/witness_generator/src/main.rs +++ b/prover/witness_generator/src/main.rs @@ -3,6 +3,7 @@ use std::time::Instant; use anyhow::{anyhow, Context as _}; +use futures::{channel::mpsc, executor::block_on, SinkExt}; use prometheus_exporter::PrometheusExporterConfig; use structopt::StructOpt; use tokio::sync::watch; @@ -13,9 +14,8 @@ use zksync_config::{ use zksync_dal::ConnectionPool; use zksync_env_config::{object_store::ProverObjectStoreConfig, FromEnv}; use zksync_object_store::ObjectStoreFactory; -use zksync_prover_utils::get_stop_signal_receiver; use zksync_queued_job_processor::JobProcessor; -use zksync_types::{proofs::AggregationRound, web3::futures::StreamExt}; +use zksync_types::{basic_fri_types::AggregationRound, web3::futures::StreamExt}; use zksync_utils::wait_for_tasks::wait_for_tasks; use zksync_vk_setup_data_server_fri::commitment_utils::get_cached_commitments; @@ -110,8 +110,8 @@ async fn main() -> anyhow::Result<()> { .protocol_version_for(&vk_commitments) .await; - // If batch_size is none, it means that the job is 'looping forever' (this is the usual setup in local network). - // At the same time, we're reading the protocol_version only once at startup - so if there is no protocol version + // If `batch_size` is none, it means that the job is 'looping forever' (this is the usual setup in local network). + // At the same time, we're reading the `protocol_version` only once at startup - so if there is no protocol version // read (this is often due to the fact, that the gateway was started too late, and it didn't put the updated protocol // versions into the database) - then the job will simply 'hang forever' and not pick any tasks. if opt.batch_size.is_none() && protocol_versions.is_empty() { @@ -157,7 +157,7 @@ async fn main() -> anyhow::Result<()> { prometheus_config.push_interval(), ) } else { - // u16 cast is safe since i is in range [0, 4) + // `u16` cast is safe since i is in range [0, 4) PrometheusExporterConfig::pull(prometheus_config.listener_port + i as u16) }; let prometheus_task = prometheus_config.run(stop_receiver.clone()); @@ -229,7 +229,11 @@ async fn main() -> anyhow::Result<()> { SERVER_METRICS.init_latency[&(*round).into()].set(started_at.elapsed()); } - let mut stop_signal_receiver = get_stop_signal_receiver(); + let (mut stop_signal_sender, mut stop_signal_receiver) = mpsc::channel(256); + ctrlc::set_handler(move || { + block_on(stop_signal_sender.send(true)).expect("Ctrl+C signal send"); + }) + .expect("Error setting Ctrl+C handler"); let graceful_shutdown = None::>; let tasks_allowed_to_finish = true; tokio::select! { diff --git a/prover/witness_generator/src/node_aggregation.rs b/prover/witness_generator/src/node_aggregation.rs index be9e5d0d6225..3c46ed98d50e 100644 --- a/prover/witness_generator/src/node_aggregation.rs +++ b/prover/witness_generator/src/node_aggregation.rs @@ -1,4 +1,4 @@ -use std::time::Instant; +use std::{sync::Arc, time::Instant}; use anyhow::Context as _; use async_trait::async_trait; @@ -6,8 +6,8 @@ use zkevm_test_harness::witness::recursive_aggregation::{ compute_node_vk_commitment, create_node_witnesses, }; use zksync_config::configs::FriWitnessGeneratorConfig; -use zksync_dal::ConnectionPool; -use zksync_object_store::{AggregationsKey, ObjectStore, ObjectStoreFactory}; +use zksync_dal::{fri_prover_dal::types::NodeAggregationJobMetadata, ConnectionPool}; +use zksync_object_store::{ObjectStore, ObjectStoreFactory}; use zksync_prover_fri_types::{ circuit_definitions::{ boojum::field::goldilocks::GoldilocksField, @@ -18,13 +18,13 @@ use zksync_prover_fri_types::{ encodings::recursion_request::RecursionQueueSimulator, zkevm_circuits::recursion::leaf_layer::input::RecursionLeafParametersWitness, }, - get_current_pod_name, FriProofWrapper, + get_current_pod_name, + keys::AggregationsKey, + FriProofWrapper, }; use zksync_queued_job_processor::JobProcessor; use zksync_types::{ - proofs::{AggregationRound, NodeAggregationJobMetadata}, - protocol_version::FriProtocolVersionId, - L1BatchNumber, + basic_fri_types::AggregationRound, protocol_version::FriProtocolVersionId, L1BatchNumber, }; use zksync_vk_setup_data_server_fri::{ get_recursive_layer_vk_for_circuit_type, utils::get_leaf_vk_params, @@ -74,7 +74,7 @@ pub struct NodeAggregationWitnessGeneratorJob { #[derive(Debug)] pub struct NodeAggregationWitnessGenerator { config: FriWitnessGeneratorConfig, - object_store: Box, + object_store: Arc, prover_connection_pool: ConnectionPool, protocol_versions: Vec, } diff --git a/prover/witness_generator/src/precalculated_merkle_paths_provider.rs b/prover/witness_generator/src/precalculated_merkle_paths_provider.rs index 89f5ca408aab..2cfadc93fc6a 100644 --- a/prover/witness_generator/src/precalculated_merkle_paths_provider.rs +++ b/prover/witness_generator/src/precalculated_merkle_paths_provider.rs @@ -3,7 +3,7 @@ use zk_evm::blake2::Blake2s256; use zkevm_test_harness::witness::tree::{ BinaryHasher, BinarySparseStorageTree, EnumeratedBinaryLeaf, LeafQuery, ZkSyncStorageLeaf, }; -use zksync_types::proofs::{PrepareBasicCircuitsJob, StorageLogMetadata}; +use zksync_prover_interface::inputs::{PrepareBasicCircuitsJob, StorageLogMetadata}; #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct PrecalculatedMerklePathsProvider { @@ -137,7 +137,7 @@ impl BinarySparseStorageTree<256, 32, 32, 8, 32, Blake2s256, ZkSyncStorageLeaf> "insert_leaf enumeration index mismatch", ); - // reset is_get_leaf_invoked for the next get/insert invocation + // reset `is_get_leaf_invoked` for the next get/insert invocation self.is_get_leaf_invoked = false; // if this insert was in fact the very first insert, it should bump the `next_enumeration_index` @@ -219,7 +219,7 @@ impl BinarySparseStorageTree<256, 32, 32, 8, 32, Blake2s256, ZkSyncStorageLeaf> root: &[u8; 32], query: &LeafQuery<256, 32, 32, 32, ZkSyncStorageLeaf>, ) -> bool { - //copied from zkevm_test_harness/src/witness/tree/mod.rs with minor changes + //copied from `zkevm_test_harness/src/witness/tree/mod.rs` with minor changes tracing::trace!( "invoked verify_inclusion. Index: {:?}, root: {:?})", query.index, diff --git a/prover/witness_generator/src/scheduler.rs b/prover/witness_generator/src/scheduler.rs index 921ba68f4024..68e48f832890 100644 --- a/prover/witness_generator/src/scheduler.rs +++ b/prover/witness_generator/src/scheduler.rs @@ -1,10 +1,10 @@ -use std::{convert::TryInto, time::Instant}; +use std::{convert::TryInto, sync::Arc, time::Instant}; use anyhow::Context as _; use async_trait::async_trait; use zksync_config::configs::FriWitnessGeneratorConfig; use zksync_dal::ConnectionPool; -use zksync_object_store::{FriCircuitKey, ObjectStore, ObjectStoreFactory}; +use zksync_object_store::{ObjectStore, ObjectStoreFactory}; use zksync_prover_fri_types::{ circuit_definitions::{ boojum::{ @@ -18,11 +18,13 @@ use zksync_prover_fri_types::{ recursion_layer_proof_config, zkevm_circuits::scheduler::{input::SchedulerCircuitInstanceWitness, SchedulerConfig}, }, - get_current_pod_name, CircuitWrapper, FriProofWrapper, + get_current_pod_name, + keys::FriCircuitKey, + CircuitWrapper, FriProofWrapper, }; use zksync_queued_job_processor::JobProcessor; use zksync_types::{ - proofs::AggregationRound, protocol_version::FriProtocolVersionId, L1BatchNumber, + basic_fri_types::AggregationRound, protocol_version::FriProtocolVersionId, L1BatchNumber, }; use zksync_vk_setup_data_server_fri::{ get_recursive_layer_vk_for_circuit_type, utils::get_leaf_vk_params, @@ -51,7 +53,7 @@ pub struct SchedulerWitnessGeneratorJob { #[derive(Debug)] pub struct SchedulerWitnessGenerator { config: FriWitnessGeneratorConfig, - object_store: Box, + object_store: Arc, prover_connection_pool: ConnectionPool, protocol_versions: Vec, } @@ -91,6 +93,9 @@ impl SchedulerWitnessGenerator { witness: job.scheduler_witness, config, transcript_params: (), + eip4844_proof_config: None, + eip4844_vk: None, + eip4844_vk_fixed_parameters: None, _marker: std::marker::PhantomData, }; WITNESS_GENERATOR_METRICS.witness_generation_time[&AggregationRound::Scheduler.into()] diff --git a/prover/witness_generator/src/storage_oracle.rs b/prover/witness_generator/src/storage_oracle.rs index 6771a0252132..4ead5a3c781e 100644 --- a/prover/witness_generator/src/storage_oracle.rs +++ b/prover/witness_generator/src/storage_oracle.rs @@ -1,7 +1,5 @@ -use zksync_types::{ - zkevm_test_harness::zk_evm::abstractions::{RefundType, RefundedAmounts, Storage}, - LogQuery, Timestamp, -}; +use zk_evm::aux_structures::{LogQuery, Timestamp}; +use zkevm_test_harness::zk_evm::abstractions::{RefundType, RefundedAmounts, Storage}; #[derive(Debug)] pub struct StorageOracle { diff --git a/prover/witness_generator/src/tests.rs b/prover/witness_generator/src/tests.rs index 7fd95a7c7d89..e167c82aba9e 100644 --- a/prover/witness_generator/src/tests.rs +++ b/prover/witness_generator/src/tests.rs @@ -2,10 +2,8 @@ use std::iter; use const_decoder::Decoder::Hex; use zkevm_test_harness::witness::tree::{BinarySparseStorageTree, ZkSyncStorageLeaf}; -use zksync_types::{ - proofs::{PrepareBasicCircuitsJob, StorageLogMetadata}, - U256, -}; +use zksync_prover_interface::inputs::{PrepareBasicCircuitsJob, StorageLogMetadata}; +use zksync_types::U256; use super::precalculated_merkle_paths_provider::PrecalculatedMerklePathsProvider; diff --git a/prover/witness_generator/src/utils.rs b/prover/witness_generator/src/utils.rs index 6efa333a8190..17e6533344a9 100644 --- a/prover/witness_generator/src/utils.rs +++ b/prover/witness_generator/src/utils.rs @@ -1,10 +1,10 @@ -use zkevm_test_harness::{ - boojum::field::goldilocks::GoldilocksField, witness::full_block_artifact::BlockBasicCircuits, -}; -use zksync_object_store::{ - serialize_using_bincode, AggregationsKey, Bucket, ClosedFormInputKey, FriCircuitKey, - ObjectStore, StoredObject, +use circuit_definitions::{ + aux_definitions::witness_oracle::VmWitnessOracle, + circuit_definitions::base_layer::ZkSyncBaseLayerCircuit, }; +use multivm::utils::get_used_bootloader_memory_bytes; +use zkevm_test_harness::boojum::field::goldilocks::GoldilocksField; +use zksync_object_store::{serialize_using_bincode, Bucket, ObjectStore, StoredObject}; use zksync_prover_fri_types::{ circuit_definitions::{ boojum::{ @@ -19,13 +19,18 @@ use zksync_prover_fri_types::{ zkevm_circuits::scheduler::input::SchedulerCircuitInstanceWitness, ZkSyncDefaultRoundFunction, }, + keys::{AggregationsKey, ClosedFormInputKey, FriCircuitKey}, CircuitWrapper, FriProofWrapper, }; -use zksync_system_constants::USED_BOOTLOADER_MEMORY_BYTES; -use zksync_types::{proofs::AggregationRound, L1BatchNumber, U256}; +use zksync_types::{basic_fri_types::AggregationRound, L1BatchNumber, ProtocolVersionId, U256}; + +pub fn expand_bootloader_contents( + packed: &[(usize, U256)], + protocol_version: ProtocolVersionId, +) -> Vec { + let full_length = get_used_bootloader_memory_bytes(protocol_version.into()); -pub fn expand_bootloader_contents(packed: &[(usize, U256)]) -> Vec { - let mut result = vec![0u8; USED_BOOTLOADER_MEMORY_BYTES]; + let mut result = vec![0u8; full_length]; for (offset, value) in packed { value.to_big_endian(&mut result[(offset * 32)..(offset + 1) * 32]); @@ -100,30 +105,29 @@ impl StoredObject for SchedulerPartialInputWrapper { serialize_using_bincode!(); } -pub async fn save_base_prover_input_artifacts( +pub async fn save_circuit( block_number: L1BatchNumber, - circuits: BlockBasicCircuits, + circuit: ZkSyncBaseLayerCircuit< + GoldilocksField, + VmWitnessOracle, + ZkSyncDefaultRoundFunction, + >, + sequence_number: usize, object_store: &dyn ObjectStore, - aggregation_round: AggregationRound, -) -> Vec<(u8, String)> { - let circuits = circuits.into_flattened_set(); - let mut ids_and_urls = Vec::with_capacity(circuits.len()); - for (sequence_number, circuit) in circuits.into_iter().enumerate() { - let circuit_id = circuit.numeric_circuit_type(); - let circuit_key = FriCircuitKey { - block_number, - sequence_number, - circuit_id, - aggregation_round, - depth: 0, - }; - let blob_url = object_store - .put(circuit_key, &CircuitWrapper::Base(circuit)) - .await - .unwrap(); - ids_and_urls.push((circuit_id, blob_url)); - } - ids_and_urls +) -> (u8, String) { + let circuit_id = circuit.numeric_circuit_type(); + let circuit_key = FriCircuitKey { + block_number, + sequence_number, + circuit_id, + aggregation_round: AggregationRound::BasicCircuits, + depth: 0, + }; + let blob_url = object_store + .put(circuit_key, &CircuitWrapper::Base(circuit)) + .await + .unwrap(); + (circuit_id, blob_url) } pub async fn save_recursive_layer_prover_input_artifacts( diff --git a/prover/witness_generator/tests/basic_test.rs b/prover/witness_generator/tests/basic_test.rs index 16cce19929da..446ee71c9226 100644 --- a/prover/witness_generator/tests/basic_test.rs +++ b/prover/witness_generator/tests/basic_test.rs @@ -2,14 +2,15 @@ use std::time::Instant; use serde::Serialize; use zksync_config::ObjectStoreConfig; +use zksync_dal::fri_prover_dal::types::{LeafAggregationJobMetadata, NodeAggregationJobMetadata}; use zksync_env_config::FromEnv; -use zksync_object_store::{AggregationsKey, FriCircuitKey, ObjectStoreFactory}; -use zksync_prover_fri_types::CircuitWrapper; -use zksync_prover_fri_utils::get_recursive_layer_circuit_id_for_base_layer; -use zksync_types::{ - proofs::{AggregationRound, LeafAggregationJobMetadata, NodeAggregationJobMetadata}, - L1BatchNumber, +use zksync_object_store::ObjectStoreFactory; +use zksync_prover_fri_types::{ + keys::{AggregationsKey, FriCircuitKey}, + CircuitWrapper, }; +use zksync_prover_fri_utils::get_recursive_layer_circuit_id_for_base_layer; +use zksync_types::{basic_fri_types::AggregationRound, L1BatchNumber}; use zksync_witness_generator::{ leaf_aggregation::{prepare_leaf_aggregation_job, LeafAggregationWitnessGenerator}, node_aggregation, diff --git a/prover/witness_vector_generator/Cargo.toml b/prover/witness_vector_generator/Cargo.toml index 3f5a6ac55d9e..523514af207f 100644 --- a/prover/witness_vector_generator/Cargo.toml +++ b/prover/witness_vector_generator/Cargo.toml @@ -17,7 +17,6 @@ zksync_prover_fri_utils = { path = "../prover_fri_utils" } zksync_utils = { path = "../../core/lib/utils" } prometheus_exporter = { path = "../../core/lib/prometheus_exporter" } zksync_prover_fri_types = { path = "../prover_fri_types" } -zksync_prover_utils = { path = "../../core/lib/prover_utils" } zksync_queued_job_processor = { path = "../../core/lib/queued_job_processor" } vk_setup_data_generator_server_fri = { path = "../vk_setup_data_generator_server_fri" } vlog = { path = "../../core/lib/vlog" } diff --git a/prover/witness_vector_generator/src/generator.rs b/prover/witness_vector_generator/src/generator.rs index 5dfb693af8f8..cbc2da1f5f39 100644 --- a/prover/witness_vector_generator/src/generator.rs +++ b/prover/witness_vector_generator/src/generator.rs @@ -1,10 +1,14 @@ -use std::time::{Duration, Instant}; +use std::{ + net::SocketAddr, + sync::Arc, + time::{Duration, Instant}, +}; use anyhow::Context as _; use async_trait::async_trait; use tokio::{task::JoinHandle, time::sleep}; use zksync_config::configs::FriWitnessVectorGeneratorConfig; -use zksync_dal::ConnectionPool; +use zksync_dal::{fri_prover_dal::types::GpuProverInstanceStatus, ConnectionPool}; use zksync_object_store::ObjectStore; use zksync_prover_fri_types::{ circuit_definitions::boojum::field::goldilocks::GoldilocksField, CircuitWrapper, ProverJob, @@ -14,17 +18,13 @@ use zksync_prover_fri_utils::{ fetch_next_circuit, get_numeric_circuit_id, socket_utils::send_assembly, }; use zksync_queued_job_processor::JobProcessor; -use zksync_types::{ - basic_fri_types::CircuitIdRoundTuple, - proofs::{GpuProverInstanceStatus, SocketAddress}, - protocol_version::L1VerifierConfig, -}; +use zksync_types::{basic_fri_types::CircuitIdRoundTuple, protocol_version::L1VerifierConfig}; use zksync_vk_setup_data_server_fri::get_finalization_hints; use crate::metrics::METRICS; pub struct WitnessVectorGenerator { - blob_store: Box, + blob_store: Arc, pool: ConnectionPool, circuit_ids_for_round_to_be_proven: Vec, zone: String, @@ -35,7 +35,7 @@ pub struct WitnessVectorGenerator { impl WitnessVectorGenerator { pub fn new( - blob_store: Box, + blob_store: Arc, prover_connection_pool: ConnectionPool, circuit_ids_for_round_to_be_proven: Vec, zone: String, @@ -152,6 +152,7 @@ impl JobProcessor for WitnessVectorGenerator { .await; if let Some(address) = prover { + let address = SocketAddr::from(address); tracing::info!( "Found prover after {:?}. Sending witness vector job...", now.elapsed() @@ -213,7 +214,7 @@ impl JobProcessor for WitnessVectorGenerator { async fn handle_send_result( result: &Result<(Duration, u64), String>, job_id: u32, - address: &SocketAddress, + address: &SocketAddr, pool: &ConnectionPool, zone: String, ) { @@ -242,12 +243,16 @@ async fn handle_send_result( reason: {err}" ); - // mark prover instance in gpu_prover_queue dead + // mark prover instance in `gpu_prover_queue` dead pool.access_storage() .await .unwrap() .fri_gpu_prover_queue_dal() - .update_prover_instance_status(address.clone(), GpuProverInstanceStatus::Dead, zone) + .update_prover_instance_status( + (*address).into(), + GpuProverInstanceStatus::Dead, + zone, + ) .await; // mark the job as failed diff --git a/prover/witness_vector_generator/src/main.rs b/prover/witness_vector_generator/src/main.rs index 79faa17c39cc..773a71fe46c6 100644 --- a/prover/witness_vector_generator/src/main.rs +++ b/prover/witness_vector_generator/src/main.rs @@ -6,13 +6,12 @@ use structopt::StructOpt; use tokio::sync::{oneshot, watch}; use zksync_config::configs::{ fri_prover_group::FriProverGroupConfig, FriProverConfig, FriWitnessVectorGeneratorConfig, - PostgresConfig, ProverGroupConfig, + PostgresConfig, }; use zksync_dal::ConnectionPool; use zksync_env_config::{object_store::ProverObjectStoreConfig, FromEnv}; use zksync_object_store::ObjectStoreFactory; -use zksync_prover_fri_utils::get_all_circuit_id_round_tuples_for; -use zksync_prover_utils::region_fetcher::get_zone; +use zksync_prover_fri_utils::{get_all_circuit_id_round_tuples_for, region_fetcher::get_zone}; use zksync_queued_job_processor::JobProcessor; use zksync_utils::wait_for_tasks::wait_for_tasks; use zksync_vk_setup_data_server_fri::commitment_utils::get_cached_commitments; @@ -28,7 +27,7 @@ mod metrics; about = "Tool for generating witness vectors for circuits" )] struct Opt { - /// Number of times witness_vector_generator should be run. + /// Number of times `witness_vector_generator` should be run. #[structopt(short = "n", long = "n_iterations")] number_of_iterations: Option, } @@ -73,11 +72,10 @@ async fn main() -> anyhow::Result<()> { .unwrap_or_default(); let circuit_ids_for_round_to_be_proven = get_all_circuit_id_round_tuples_for(circuit_ids_for_round_to_be_proven); - let prover_group_config = - ProverGroupConfig::from_env().context("ProverGroupConfig::from_env()")?; - let zone = get_zone(&prover_group_config).await.context("get_zone()")?; - let vk_commitments = get_cached_commitments(); let fri_prover_config = FriProverConfig::from_env().context("FriProverConfig::from_env()")?; + let zone_url = &fri_prover_config.zone_read_url; + let zone = get_zone(zone_url).await.context("get_zone()")?; + let vk_commitments = get_cached_commitments(); let witness_vector_generator = WitnessVectorGenerator::new( blob_store, pool, diff --git a/prover/witness_vector_generator/tests/basic_test.rs b/prover/witness_vector_generator/tests/basic_test.rs index 648b1ee4d9e6..54898cf94d5d 100644 --- a/prover/witness_vector_generator/tests/basic_test.rs +++ b/prover/witness_vector_generator/tests/basic_test.rs @@ -1,7 +1,7 @@ use std::fs; use zksync_prover_fri_types::{CircuitWrapper, ProverJob, ProverServiceDataKey}; -use zksync_types::{proofs::AggregationRound, L1BatchNumber}; +use zksync_types::{basic_fri_types::AggregationRound, L1BatchNumber}; use zksync_witness_vector_generator::generator::WitnessVectorGenerator; #[test] diff --git a/sdk/zksync-rs/README.md b/sdk/zksync-rs/README.md index f4b6444d71e6..209e7fa4104e 100644 --- a/sdk/zksync-rs/README.md +++ b/sdk/zksync-rs/README.md @@ -1,4 +1,4 @@ # Rust SDK for zkSync -This SDK is currently under construction and is only used for internal needs. A public version of the SDK would be +This SDK is currently under construction and is only used for internal needs. A public version of the SDK will be announced later. diff --git a/sdk/zksync-rs/src/abi/update-abi.sh b/sdk/zksync-rs/src/abi/update-abi.sh index 89c9172d1752..ad1ec3f79be1 100755 --- a/sdk/zksync-rs/src/abi/update-abi.sh +++ b/sdk/zksync-rs/src/abi/update-abi.sh @@ -7,4 +7,4 @@ cat $ZKSYNC_HOME/contracts/l1-contracts/artifacts/cache/solpp-generated-contract # Default L1 bridge cat $ZKSYNC_HOME/contracts/l1-contracts/artifacts/cache/solpp-generated-contracts/bridge/interfaces/IL1Bridge.sol/IL1Bridge.json | jq '{ abi: .abi}' > L1Bridge.json # Paymaster interface -cat $ZKSYNC_HOME/contracts/l2-contracts/artifacts-zk/cache-zk/solpp-generated-contracts/interfaces/IPaymasterFlow.sol/IPaymasterFlow.json | jq '{ abi: .abi}' > IPaymasterFlow.json +cat $ZKSYNC_HOME/contracts/l2-contracts/artifacts-zk/contracts-preprocessed/interfaces/IPaymasterFlow.sol/IPaymasterFlow.json | jq '{ abi: .abi}' > IPaymasterFlow.json diff --git a/sdk/zksync-rs/src/ethereum/mod.rs b/sdk/zksync-rs/src/ethereum/mod.rs index ac91e3589831..26b76017ed83 100644 --- a/sdk/zksync-rs/src/ethereum/mod.rs +++ b/sdk/zksync-rs/src/ethereum/mod.rs @@ -7,7 +7,7 @@ use std::{ use serde_json::{Map, Value}; use zksync_eth_client::{ - clients::http::SigningClient, types::Error, BoundEthInterface, EthInterface, + clients::SigningClient, BoundEthInterface, CallFunctionArgs, Error, EthInterface, }; use zksync_eth_signer::EthereumSigner; use zksync_types::{ @@ -15,7 +15,10 @@ use zksync_types::{ l1::L1Tx, network::Network, web3::{ - contract::{tokens::Tokenize, Options}, + contract::{ + tokens::{Detokenize, Tokenize}, + Options, + }, ethabi, transports::Http, types::{TransactionReceipt, H160, H256, U256}, @@ -36,7 +39,7 @@ const ZKSYNC_INTERFACE: &str = include_str!("../abi/IZkSync.json"); const L1_DEFAULT_BRIDGE_INTERFACE: &str = include_str!("../abi/IL1Bridge.json"); const RAW_ERC20_DEPOSIT_GAS_LIMIT: &str = include_str!("DepositERC20GasLimit.json"); -// The gasPerPubdata to be used in L1->L2 requests. It may be almost any number, but here we 800 +// The `gasPerPubdata` to be used in L1->L2 requests. It may be almost any number, but here we 800 // as an optimal one. In the future, it will be estimated. const L1_TO_L2_GAS_PER_PUBDATA: u32 = 800; @@ -69,7 +72,7 @@ pub struct EthereumProvider { polling_interval: Duration, } -// TODO (SMA-1623): create a way to pass `Options` (e.g. nonce, gas_limit, priority_fee_per_gas) +// TODO (SMA-1623): create a way to pass `Options` (e.g. `nonce`, `gas_limit`, `priority_fee_per_gas`) // into methods that perform L1 transactions. The unit is wei. pub const DEFAULT_PRIORITY_FEE: u64 = 2_000_000_000; @@ -146,20 +149,14 @@ impl EthereumProvider { address: Address, token_address: Address, ) -> Result { + let args = CallFunctionArgs::new("balanceOf", address) + .for_contract(token_address, self.erc20_abi.clone()); let res = self .eth_client - .call_contract_function( - "balanceOf", - address, - None, - Options::default(), - None, - token_address, - self.erc20_abi.clone(), - ) + .call_contract_function(args) .await .map_err(|err| ClientError::NetworkError(err.to_string()))?; - Ok(res) + U256::from_tokens(res).map_err(|err| ClientError::MalformedResponse(err.to_string())) } /// Returns the pending nonce for the Ethereum account. @@ -186,20 +183,14 @@ impl EthereumProvider { bridge: Option
, ) -> Result { let bridge = bridge.unwrap_or(self.default_bridges.l1_erc20_default_bridge); - let l2_token_address = self + let args = CallFunctionArgs::new("l2TokenAddress", l1_token_address) + .for_contract(bridge, self.l1_bridge_abi.clone()); + let res = self .eth_client - .call_contract_function( - "l2TokenAddress", - l1_token_address, - None, - Options::default(), - None, - bridge, - self.l1_bridge_abi.clone(), - ) + .call_contract_function(args) .await .map_err(|err| ClientError::NetworkError(err.to_string()))?; - Ok(l2_token_address) + Address::from_tokens(res).map_err(|err| ClientError::MalformedResponse(err.to_string())) } /// Checks whether ERC20 of a certain token deposit with limit is approved for account. @@ -372,15 +363,12 @@ impl EthereumProvider { } else { self.eth_client.get_gas_price("zksync-rs").await? }; - self.eth_client - .call_main_contract_function( - "l2TransactionBaseCost", - (gas_price, gas_limit, gas_per_pubdata_byte), - None, - Default::default(), - None, - ) - .await + let args = CallFunctionArgs::new( + "l2TransactionBaseCost", + (gas_price, gas_limit, gas_per_pubdata_byte), + ); + let res = self.eth_client.call_main_contract_function(args).await?; + Ok(U256::from_tokens(res)?) } #[allow(clippy::too_many_arguments)] @@ -420,7 +408,8 @@ impl EthereumProvider { L1_TO_L2_GAS_PER_PUBDATA, factory_deps, refund_recipient, - ), + ) + .into_tokens(), ); let tx = self @@ -483,7 +472,7 @@ impl EthereumProvider { let mut options = eth_options.unwrap_or_default(); - // If the user has already provided max_fee_per_gas or gas_price, we will use + // If the user has already provided `max_fee_per_gas` or `gas_price`, we will use // it to calculate the base cost for the transaction let gas_price = if let Some(max_fee_per_gas) = options.max_fee_per_gas { max_fee_per_gas diff --git a/sdk/zksync-rs/src/utils.rs b/sdk/zksync-rs/src/utils.rs index 5137dbca6db1..6decb062f08b 100644 --- a/sdk/zksync-rs/src/utils.rs +++ b/sdk/zksync-rs/src/utils.rs @@ -55,16 +55,19 @@ pub fn get_approval_based_paymaster_input( } } +/// Returns the approval based paymaster input to be used for estimation of transactions. +/// Note, that the `min_allowance` will be approved to paymaster contract during estimation and so for +/// instance "low" values like zero could lead to underestimation of the transaction (because the cost per +/// write depends on the size of the value). +/// +/// This is a chicken-and-egg problem, because we need to know the cost of the transaction to estimate it, so in order to provide +/// the most correct estimate possible it is recommended to set as realistic `min_allowance` as possible. pub fn get_approval_based_paymaster_input_for_estimation( paymaster: Address, token_address: Address, + min_allowance: U256, ) -> PaymasterParams { - get_approval_based_paymaster_input( - paymaster, - token_address, - Default::default(), - Default::default(), - ) + get_approval_based_paymaster_input(paymaster, token_address, min_allowance, Default::default()) } pub fn get_general_paymaster_input(paymaster: Address, inner_input: Vec) -> PaymasterParams { diff --git a/sdk/zksync-rs/tests/unit.rs b/sdk/zksync-rs/tests/unit.rs index 033acb75e7d7..1bd238d9e926 100644 --- a/sdk/zksync-rs/tests/unit.rs +++ b/sdk/zksync-rs/tests/unit.rs @@ -338,7 +338,7 @@ // eth_signature, // .. // })) => eth_signature.serialize_packed(), -// _ => panic!("No ChangePubKey ethereum siganture"), +// _ => panic!("No ChangePubKey ethereum signature"), // }; // assert_eq!(ð_signature[..], expected_eth_signature.as_slice()); // } diff --git a/yarn.lock b/yarn.lock index 4616e4d6be3a..055bf45e23b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -368,6 +368,348 @@ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== +"@cspell/cspell-bundled-dicts@8.3.2": + version "8.3.2" + resolved "https://registry.yarnpkg.com/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-8.3.2.tgz#649ed168a72cb49a7d83f3840ab6933a8beba68d" + integrity sha512-3ubOgz1/MDixJbq//0rQ2omB3cSdhVJDviERZeiREGz4HOq84aaK1Fqbw5SjNZHvhpoq+AYXm6kJbIAH8YhKgg== + dependencies: + "@cspell/dict-ada" "^4.0.2" + "@cspell/dict-aws" "^4.0.1" + "@cspell/dict-bash" "^4.1.3" + "@cspell/dict-companies" "^3.0.29" + "@cspell/dict-cpp" "^5.0.10" + "@cspell/dict-cryptocurrencies" "^5.0.0" + "@cspell/dict-csharp" "^4.0.2" + "@cspell/dict-css" "^4.0.12" + "@cspell/dict-dart" "^2.0.3" + "@cspell/dict-django" "^4.1.0" + "@cspell/dict-docker" "^1.1.7" + "@cspell/dict-dotnet" "^5.0.0" + "@cspell/dict-elixir" "^4.0.3" + "@cspell/dict-en-common-misspellings" "^2.0.0" + "@cspell/dict-en-gb" "1.1.33" + "@cspell/dict-en_us" "^4.3.13" + "@cspell/dict-filetypes" "^3.0.3" + "@cspell/dict-fonts" "^4.0.0" + "@cspell/dict-fsharp" "^1.0.1" + "@cspell/dict-fullstack" "^3.1.5" + "@cspell/dict-gaming-terms" "^1.0.4" + "@cspell/dict-git" "^3.0.0" + "@cspell/dict-golang" "^6.0.5" + "@cspell/dict-haskell" "^4.0.1" + "@cspell/dict-html" "^4.0.5" + "@cspell/dict-html-symbol-entities" "^4.0.0" + "@cspell/dict-java" "^5.0.6" + "@cspell/dict-k8s" "^1.0.2" + "@cspell/dict-latex" "^4.0.0" + "@cspell/dict-lorem-ipsum" "^4.0.0" + "@cspell/dict-lua" "^4.0.3" + "@cspell/dict-makefile" "^1.0.0" + "@cspell/dict-node" "^4.0.3" + "@cspell/dict-npm" "^5.0.14" + "@cspell/dict-php" "^4.0.5" + "@cspell/dict-powershell" "^5.0.3" + "@cspell/dict-public-licenses" "^2.0.5" + "@cspell/dict-python" "^4.1.11" + "@cspell/dict-r" "^2.0.1" + "@cspell/dict-ruby" "^5.0.2" + "@cspell/dict-rust" "^4.0.1" + "@cspell/dict-scala" "^5.0.0" + "@cspell/dict-software-terms" "^3.3.15" + "@cspell/dict-sql" "^2.1.3" + "@cspell/dict-svelte" "^1.0.2" + "@cspell/dict-swift" "^2.0.1" + "@cspell/dict-typescript" "^3.1.2" + "@cspell/dict-vue" "^3.0.0" + +"@cspell/cspell-json-reporter@8.3.2": + version "8.3.2" + resolved "https://registry.yarnpkg.com/@cspell/cspell-json-reporter/-/cspell-json-reporter-8.3.2.tgz#314f7b7deb465a7b94b03405c3498d9b96d410ab" + integrity sha512-gHSz4jXMJPcxx+lOGfXhHuoyenAWQ8PVA/atHFrWYKo1LzKTbpkEkrsDnlX8QNJubc3EMH63Uy+lOIaFDVyHiQ== + dependencies: + "@cspell/cspell-types" "8.3.2" + +"@cspell/cspell-pipe@8.3.2": + version "8.3.2" + resolved "https://registry.yarnpkg.com/@cspell/cspell-pipe/-/cspell-pipe-8.3.2.tgz#72b986c6c03ed9894d5ddafdcb435973336216b9" + integrity sha512-GZmDwvQGOjQi3IjD4k9xXeVTDANczksOsgVKb3v2QZk9mR4Qj8c6Uarjd4AgSiIhu/wBliJfzr5rWFJu4X2VfQ== + +"@cspell/cspell-resolver@8.3.2": + version "8.3.2" + resolved "https://registry.yarnpkg.com/@cspell/cspell-resolver/-/cspell-resolver-8.3.2.tgz#e4a981ed8fc2029804d8fa5847e47934a26c5c86" + integrity sha512-w2Tmb95bzdEz9L4W5qvsP5raZbyEzKL7N2ksU/+yh8NEJcTuExmAl/nMnb3aIk7m2b+kPHnMOcJuwfUMLmyv4A== + dependencies: + global-directory "^4.0.1" + +"@cspell/cspell-service-bus@8.3.2": + version "8.3.2" + resolved "https://registry.yarnpkg.com/@cspell/cspell-service-bus/-/cspell-service-bus-8.3.2.tgz#b1c6620232c22c0a7c8b68051e524963285f4768" + integrity sha512-skTHNyVi74//W/O+f4IauDhm6twA9S2whkylonsIzPxEl4Pn3y2ZEMXNki/MWUwZfDIzKKSxlcREH61g7zCvhg== + +"@cspell/cspell-types@8.3.2": + version "8.3.2" + resolved "https://registry.yarnpkg.com/@cspell/cspell-types/-/cspell-types-8.3.2.tgz#35a6d0f1a4c7c2a8a5275bcd41dacf85618f44c3" + integrity sha512-qS/gWd9ItOrN6ZX5pwC9lJjnBoyiAyhxYq0GUXuV892LQvwrBmECGk6KhsA1lPW7JJS7o57YTAS1jmXnmXMEpg== + +"@cspell/dict-ada@^4.0.2": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@cspell/dict-ada/-/dict-ada-4.0.2.tgz#8da2216660aeb831a0d9055399a364a01db5805a" + integrity sha512-0kENOWQeHjUlfyId/aCM/mKXtkEgV0Zu2RhUXCBr4hHo9F9vph+Uu8Ww2b0i5a4ZixoIkudGA+eJvyxrG1jUpA== + +"@cspell/dict-aws@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@cspell/dict-aws/-/dict-aws-4.0.1.tgz#a0e758531ae81792b928a3f406618296291a658a" + integrity sha512-NXO+kTPQGqaaJKa4kO92NAXoqS+i99dQzf3/L1BxxWVSBS3/k1f3uhmqIh7Crb/n22W793lOm0D9x952BFga3Q== + +"@cspell/dict-bash@^4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-bash/-/dict-bash-4.1.3.tgz#25fba40825ac10083676ab2c777e471c3f71b36e" + integrity sha512-tOdI3QVJDbQSwPjUkOiQFhYcu2eedmX/PtEpVWg0aFps/r6AyjUQINtTgpqMYnYuq8O1QUIQqnpx21aovcgZCw== + +"@cspell/dict-companies@^3.0.29": + version "3.0.29" + resolved "https://registry.yarnpkg.com/@cspell/dict-companies/-/dict-companies-3.0.29.tgz#0c102c852a9b1c879cd926c0870e2cfbaf1cd176" + integrity sha512-F/8XnkqjU7jmSDAcD3LSSX+WxCVUWPssqlO4lzGMIK3MNIUt+d48eSIt3pFAIB/Z9y0ojoLHUtWX9HJ1ZtGrXQ== + +"@cspell/dict-cpp@^5.0.10": + version "5.0.10" + resolved "https://registry.yarnpkg.com/@cspell/dict-cpp/-/dict-cpp-5.0.10.tgz#08c3eb438b631dd3f0fc04f5a6d4b6cab87c8d9b" + integrity sha512-WCRuDrkFdpmeIR6uXQYKU9loMQKNFS4bUhtHdv5fu4qVyJSh3k/kgmtTm1h1BDTj8EwPRc/RGxS+9Z3b2mnabA== + +"@cspell/dict-cryptocurrencies@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-5.0.0.tgz#19fbc7bdbec76ce64daf7d53a6d0f3cfff7d0038" + integrity sha512-Z4ARIw5+bvmShL+4ZrhDzGhnc9znaAGHOEMaB/GURdS/jdoreEDY34wdN0NtdLHDO5KO7GduZnZyqGdRoiSmYA== + +"@cspell/dict-csharp@^4.0.2": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@cspell/dict-csharp/-/dict-csharp-4.0.2.tgz#e55659dbe594e744d86b1baf0f3397fe57b1e283" + integrity sha512-1JMofhLK+4p4KairF75D3A924m5ERMgd1GvzhwK2geuYgd2ZKuGW72gvXpIV7aGf52E3Uu1kDXxxGAiZ5uVG7g== + +"@cspell/dict-css@^4.0.12": + version "4.0.12" + resolved "https://registry.yarnpkg.com/@cspell/dict-css/-/dict-css-4.0.12.tgz#59abf3512ae729835c933c38f64a3d8a5f09ce3d" + integrity sha512-vGBgPM92MkHQF5/2jsWcnaahOZ+C6OE/fPvd5ScBP72oFY9tn5GLuomcyO0z8vWCr2e0nUSX1OGimPtcQAlvSw== + +"@cspell/dict-dart@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-dart/-/dict-dart-2.0.3.tgz#75e7ffe47d5889c2c831af35acdd92ebdbd4cf12" + integrity sha512-cLkwo1KT5CJY5N5RJVHks2genFkNCl/WLfj+0fFjqNR+tk3tBI1LY7ldr9piCtSFSm4x9pO1x6IV3kRUY1lLiw== + +"@cspell/dict-data-science@^1.0.11": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@cspell/dict-data-science/-/dict-data-science-1.0.11.tgz#4eabba75c21d27253c1114b4fbbade0ead739ffc" + integrity sha512-TaHAZRVe0Zlcc3C23StZqqbzC0NrodRwoSAc8dis+5qLeLLnOCtagYQeROQvDlcDg3X/VVEO9Whh4W/z4PAmYQ== + +"@cspell/dict-django@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@cspell/dict-django/-/dict-django-4.1.0.tgz#2d4b765daf3c83e733ef3e06887ea34403a4de7a" + integrity sha512-bKJ4gPyrf+1c78Z0Oc4trEB9MuhcB+Yg+uTTWsvhY6O2ncFYbB/LbEZfqhfmmuK/XJJixXfI1laF2zicyf+l0w== + +"@cspell/dict-docker@^1.1.7": + version "1.1.7" + resolved "https://registry.yarnpkg.com/@cspell/dict-docker/-/dict-docker-1.1.7.tgz#bcf933283fbdfef19c71a642e7e8c38baf9014f2" + integrity sha512-XlXHAr822euV36GGsl2J1CkBIVg3fZ6879ZOg5dxTIssuhUOCiV2BuzKZmt6aIFmcdPmR14+9i9Xq+3zuxeX0A== + +"@cspell/dict-dotnet@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@cspell/dict-dotnet/-/dict-dotnet-5.0.0.tgz#13690aafe14b240ad17a30225ac1ec29a5a6a510" + integrity sha512-EOwGd533v47aP5QYV8GlSSKkmM9Eq8P3G/eBzSpH3Nl2+IneDOYOBLEUraHuiCtnOkNsz0xtZHArYhAB2bHWAw== + +"@cspell/dict-elixir@^4.0.3": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-elixir/-/dict-elixir-4.0.3.tgz#57c25843e46cf3463f97da72d9ef8e37c818296f" + integrity sha512-g+uKLWvOp9IEZvrIvBPTr/oaO6619uH/wyqypqvwpmnmpjcfi8+/hqZH8YNKt15oviK8k4CkINIqNhyndG9d9Q== + +"@cspell/dict-en-common-misspellings@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@cspell/dict-en-common-misspellings/-/dict-en-common-misspellings-2.0.0.tgz#708f424d75dc65237a6fcb8d253bc1e7ab641380" + integrity sha512-NOg8dlv37/YqLkCfBs5OXeJm/Wcfb/CzeOmOZJ2ZXRuxwsNuolb4TREUce0yAXRqMhawahY5TSDRJJBgKjBOdw== + +"@cspell/dict-en-gb@1.1.33": + version "1.1.33" + resolved "https://registry.yarnpkg.com/@cspell/dict-en-gb/-/dict-en-gb-1.1.33.tgz#7f1fd90fc364a5cb77111b5438fc9fcf9cc6da0e" + integrity sha512-tKSSUf9BJEV+GJQAYGw5e+ouhEe2ZXE620S7BLKe3ZmpnjlNG9JqlnaBhkIMxKnNFkLY2BP/EARzw31AZnOv4g== + +"@cspell/dict-en_us@^4.3.13": + version "4.3.13" + resolved "https://registry.yarnpkg.com/@cspell/dict-en_us/-/dict-en_us-4.3.13.tgz#4176be1e1510ac696a0fa33d9773aaffbf83a50d" + integrity sha512-T6lHiGCjloGNE0d8CogF+efJZPCAP8zdzn+KnlI0Bmjaz5nvG2LTX7CXl1zkOl1nYYev0FuIk9WJ9YPVRjcFbQ== + +"@cspell/dict-filetypes@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-filetypes/-/dict-filetypes-3.0.3.tgz#ab0723ca2f4d3d5674e9c9745efc9f144e49c905" + integrity sha512-J9UP+qwwBLfOQ8Qg9tAsKtSY/WWmjj21uj6zXTI9hRLD1eG1uUOLcfVovAmtmVqUWziPSKMr87F6SXI3xmJXgw== + +"@cspell/dict-fonts@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@cspell/dict-fonts/-/dict-fonts-4.0.0.tgz#9bc8beb2a7b068b4fdb45cb994b36fd184316327" + integrity sha512-t9V4GeN/m517UZn63kZPUYP3OQg5f0OBLSd3Md5CU3eH1IFogSvTzHHnz4Wqqbv8NNRiBZ3HfdY/pqREZ6br3Q== + +"@cspell/dict-fsharp@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@cspell/dict-fsharp/-/dict-fsharp-1.0.1.tgz#d62c699550a39174f182f23c8c1330a795ab5f53" + integrity sha512-23xyPcD+j+NnqOjRHgW3IU7Li912SX9wmeefcY0QxukbAxJ/vAN4rBpjSwwYZeQPAn3fxdfdNZs03fg+UM+4yQ== + +"@cspell/dict-fullstack@^3.1.5": + version "3.1.5" + resolved "https://registry.yarnpkg.com/@cspell/dict-fullstack/-/dict-fullstack-3.1.5.tgz#35d18678161f214575cc613dd95564e05422a19c" + integrity sha512-6ppvo1dkXUZ3fbYn/wwzERxCa76RtDDl5Afzv2lijLoijGGUw5yYdLBKJnx8PJBGNLh829X352ftE7BElG4leA== + +"@cspell/dict-gaming-terms@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@cspell/dict-gaming-terms/-/dict-gaming-terms-1.0.4.tgz#b67d89d014d865da6cb40de4269d4c162a00658e" + integrity sha512-hbDduNXlk4AOY0wFxcDMWBPpm34rpqJBeqaySeoUH70eKxpxm+dvjpoRLJgyu0TmymEICCQSl6lAHTHSDiWKZg== + +"@cspell/dict-git@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@cspell/dict-git/-/dict-git-3.0.0.tgz#c275af86041a2b59a7facce37525e2af05653b95" + integrity sha512-simGS/lIiXbEaqJu9E2VPoYW1OTC2xrwPPXNXFMa2uo/50av56qOuaxDrZ5eH1LidFXwoc8HROCHYeKoNrDLSw== + +"@cspell/dict-golang@^6.0.5": + version "6.0.5" + resolved "https://registry.yarnpkg.com/@cspell/dict-golang/-/dict-golang-6.0.5.tgz#4dd2e2fda419730a21fb77ade3b90241ad4a5bcc" + integrity sha512-w4mEqGz4/wV+BBljLxduFNkMrd3rstBNDXmoX5kD4UTzIb4Sy0QybWCtg2iVT+R0KWiRRA56QKOvBsgXiddksA== + +"@cspell/dict-haskell@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@cspell/dict-haskell/-/dict-haskell-4.0.1.tgz#e9fca7c452411ff11926e23ffed2b50bb9b95e47" + integrity sha512-uRrl65mGrOmwT7NxspB4xKXFUenNC7IikmpRZW8Uzqbqcu7ZRCUfstuVH7T1rmjRgRkjcIjE4PC11luDou4wEQ== + +"@cspell/dict-html-symbol-entities@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-4.0.0.tgz#4d86ac18a4a11fdb61dfb6f5929acd768a52564f" + integrity sha512-HGRu+48ErJjoweR5IbcixxETRewrBb0uxQBd6xFGcxbEYCX8CnQFTAmKI5xNaIt2PKaZiJH3ijodGSqbKdsxhw== + +"@cspell/dict-html@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@cspell/dict-html/-/dict-html-4.0.5.tgz#03a5182148d80e6c25f71339dbb2b7c5b9894ef8" + integrity sha512-p0brEnRybzSSWi8sGbuVEf7jSTDmXPx7XhQUb5bgG6b54uj+Z0Qf0V2n8b/LWwIPJNd1GygaO9l8k3HTCy1h4w== + +"@cspell/dict-java@^5.0.6": + version "5.0.6" + resolved "https://registry.yarnpkg.com/@cspell/dict-java/-/dict-java-5.0.6.tgz#2462d6fc15f79ec15eb88ecf875b6ad2a7bf7a6a" + integrity sha512-kdE4AHHHrixyZ5p6zyms1SLoYpaJarPxrz8Tveo6gddszBVVwIUZ+JkQE1bWNLK740GWzIXdkznpUfw1hP9nXw== + +"@cspell/dict-k8s@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@cspell/dict-k8s/-/dict-k8s-1.0.2.tgz#b19e66f4ac8a4264c0f3981ac6e23e88a60f1c91" + integrity sha512-tLT7gZpNPnGa+IIFvK9SP1LrSpPpJ94a/DulzAPOb1Q2UBFwdpFd82UWhio0RNShduvKG/WiMZf/wGl98pn+VQ== + +"@cspell/dict-latex@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@cspell/dict-latex/-/dict-latex-4.0.0.tgz#85054903db834ea867174795d162e2a8f0e9c51e" + integrity sha512-LPY4y6D5oI7D3d+5JMJHK/wxYTQa2lJMSNxps2JtuF8hbAnBQb3igoWEjEbIbRRH1XBM0X8dQqemnjQNCiAtxQ== + +"@cspell/dict-lorem-ipsum@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-4.0.0.tgz#2793a5dbfde474a546b0caecc40c38fdf076306e" + integrity sha512-1l3yjfNvMzZPibW8A7mQU4kTozwVZVw0AvFEdy+NcqtbxH+TvbSkNMqROOFWrkD2PjnKG0+Ea0tHI2Pi6Gchnw== + +"@cspell/dict-lua@^4.0.3": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-lua/-/dict-lua-4.0.3.tgz#2d23c8f7e74b4e62000678d80e7d1ebb10b003e0" + integrity sha512-lDHKjsrrbqPaea13+G9s0rtXjMO06gPXPYRjRYawbNmo4E/e3XFfVzeci3OQDQNDmf2cPOwt9Ef5lu2lDmwfJg== + +"@cspell/dict-makefile@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@cspell/dict-makefile/-/dict-makefile-1.0.0.tgz#5afb2910873ebbc01ab8d9c38661c4c93d0e5a40" + integrity sha512-3W9tHPcSbJa6s0bcqWo6VisEDTSN5zOtDbnPabF7rbyjRpNo0uHXHRJQF8gAbFzoTzBBhgkTmrfSiuyQm7vBUQ== + +"@cspell/dict-node@^4.0.3": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-node/-/dict-node-4.0.3.tgz#5ae0222d72871e82978049f8e11ea627ca42fca3" + integrity sha512-sFlUNI5kOogy49KtPg8SMQYirDGIAoKBO3+cDLIwD4MLdsWy1q0upc7pzGht3mrjuyMiPRUV14Bb0rkVLrxOhg== + +"@cspell/dict-npm@^5.0.14": + version "5.0.14" + resolved "https://registry.yarnpkg.com/@cspell/dict-npm/-/dict-npm-5.0.14.tgz#1ca3d305390f393bbfa75f41c4db0fd590ce1a9c" + integrity sha512-k0kC7/W2qG5YII+SW6s+JtvKrkZg651vizi5dv/5G2HmJaeLNgDqBVeeDk/uV+ntBorM66XG4BPMjSxoaIlC5w== + +"@cspell/dict-php@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@cspell/dict-php/-/dict-php-4.0.5.tgz#fa16350d907180a42f16d5e4666e61a97ae9b8b3" + integrity sha512-9r8ao7Z/mH9Z8pSB7yLtyvcCJWw+/MnQpj7xGVYzIV7V2ZWDRjXZAMgteHMJ37m8oYz64q5d4tiipD300QSetQ== + +"@cspell/dict-powershell@^5.0.3": + version "5.0.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-powershell/-/dict-powershell-5.0.3.tgz#7bceb4e7db39f87479a6d2af3a033ce26796ae49" + integrity sha512-lEdzrcyau6mgzu1ie98GjOEegwVHvoaWtzQnm1ie4DyZgMr+N6D0Iyj1lzvtmt0snvsDFa5F2bsYzf3IMKcpcA== + +"@cspell/dict-public-licenses@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.5.tgz#86948b29bd36184943955eaa80bf594488c4dd8a" + integrity sha512-91HK4dSRri/HqzAypHgduRMarJAleOX5NugoI8SjDLPzWYkwZ1ftuCXSk+fy8DLc3wK7iOaFcZAvbjmnLhVs4A== + +"@cspell/dict-python@^4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@cspell/dict-python/-/dict-python-4.1.11.tgz#4e339def01bf468b32d459c46ecb6894970b7eb8" + integrity sha512-XG+v3PumfzUW38huSbfT15Vqt3ihNb462ulfXifpQllPok5OWynhszCLCRQjQReV+dgz784ST4ggRxW452/kVg== + dependencies: + "@cspell/dict-data-science" "^1.0.11" + +"@cspell/dict-r@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@cspell/dict-r/-/dict-r-2.0.1.tgz#73474fb7cce45deb9094ebf61083fbf5913f440a" + integrity sha512-KCmKaeYMLm2Ip79mlYPc8p+B2uzwBp4KMkzeLd5E6jUlCL93Y5Nvq68wV5fRLDRTf7N1LvofkVFWfDcednFOgA== + +"@cspell/dict-ruby@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@cspell/dict-ruby/-/dict-ruby-5.0.2.tgz#cf1a71380c633dec0857143d3270cb503b10679a" + integrity sha512-cIh8KTjpldzFzKGgrqUX4bFyav5lC52hXDKo4LbRuMVncs3zg4hcSf4HtURY+f2AfEZzN6ZKzXafQpThq3dl2g== + +"@cspell/dict-rust@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@cspell/dict-rust/-/dict-rust-4.0.1.tgz#ef0b88cb3a45265824e2c9ce31b0baa4e1050351" + integrity sha512-xJSSzHDK2z6lSVaOmMxl3PTOtfoffaxMo7fTcbZUF+SCJzfKbO6vnN9TCGX2sx1RHFDz66Js6goz6SAZQdOwaw== + +"@cspell/dict-scala@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@cspell/dict-scala/-/dict-scala-5.0.0.tgz#b64365ad559110a36d44ccd90edf7151ea648022" + integrity sha512-ph0twaRoV+ylui022clEO1dZ35QbeEQaKTaV2sPOsdwIokABPIiK09oWwGK9qg7jRGQwVaRPEq0Vp+IG1GpqSQ== + +"@cspell/dict-software-terms@^3.3.15": + version "3.3.16" + resolved "https://registry.yarnpkg.com/@cspell/dict-software-terms/-/dict-software-terms-3.3.16.tgz#c088501687e6a19625800cc612dae8aebaf0f086" + integrity sha512-ixorEP80LGxAU+ODVSn/CYIDjV0XAlZ2VrBu7CT+PwUFJ7h8o3JX1ywKB4qnt0hHru3JjWFtBoBThmZdrXnREQ== + +"@cspell/dict-sql@^2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-sql/-/dict-sql-2.1.3.tgz#8d9666a82e35b310d0be4064032c0d891fbd2702" + integrity sha512-SEyTNKJrjqD6PAzZ9WpdSu6P7wgdNtGV2RV8Kpuw1x6bV+YsSptuClYG+JSdRExBTE6LwIe1bTklejUp3ZP8TQ== + +"@cspell/dict-svelte@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@cspell/dict-svelte/-/dict-svelte-1.0.2.tgz#0c866b08a7a6b33bbc1a3bdbe6a1b484ca15cdaa" + integrity sha512-rPJmnn/GsDs0btNvrRBciOhngKV98yZ9SHmg8qI6HLS8hZKvcXc0LMsf9LLuMK1TmS2+WQFAan6qeqg6bBxL2Q== + +"@cspell/dict-swift@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@cspell/dict-swift/-/dict-swift-2.0.1.tgz#06ec86e52e9630c441d3c19605657457e33d7bb6" + integrity sha512-gxrCMUOndOk7xZFmXNtkCEeroZRnS2VbeaIPiymGRHj5H+qfTAzAKxtv7jJbVA3YYvEzWcVE2oKDP4wcbhIERw== + +"@cspell/dict-typescript@^3.1.2": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@cspell/dict-typescript/-/dict-typescript-3.1.2.tgz#14d05f54db2984feaa24ea133b583d19c04cc104" + integrity sha512-lcNOYWjLUvDZdLa0UMNd/LwfVdxhE9rKA+agZBGjL3lTA3uNvH7IUqSJM/IXhJoBpLLMVEOk8v1N9xi+vDuCdA== + +"@cspell/dict-vue@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@cspell/dict-vue/-/dict-vue-3.0.0.tgz#68ccb432ad93fcb0fd665352d075ae9a64ea9250" + integrity sha512-niiEMPWPV9IeRBRzZ0TBZmNnkK3olkOPYxC1Ny2AX4TGlYRajcW0WUtoSHmvvjZNfWLSg2L6ruiBeuPSbjnG6A== + +"@cspell/dynamic-import@8.3.2": + version "8.3.2" + resolved "https://registry.yarnpkg.com/@cspell/dynamic-import/-/dynamic-import-8.3.2.tgz#96fea6b1139164449a8ef92530de670d4c2fb36e" + integrity sha512-4t0xM5luA3yQhar2xWvYK4wQSDB2r0u8XkpzzJqd57MnJXd7uIAxI0awGUrDXukadRaCo0tDIlMUBemH48SNVg== + dependencies: + import-meta-resolve "^4.0.0" + +"@cspell/strong-weak-map@8.3.2": + version "8.3.2" + resolved "https://registry.yarnpkg.com/@cspell/strong-weak-map/-/strong-weak-map-8.3.2.tgz#5a9490e042bbc472089817b50cf51262dfedef65" + integrity sha512-Mte/2000ap278kRYOUhiGWI7MNr1+A7WSWJmlcdP4CAH5SO20sZI3/cyZLjJJEyapdhK5vaP1L5J9sUcVDHd3A== + "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" @@ -375,22 +717,6 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" -"@ensdomains/ens@^0.4.4": - version "0.4.5" - resolved "https://registry.yarnpkg.com/@ensdomains/ens/-/ens-0.4.5.tgz#e0aebc005afdc066447c6e22feb4eda89a5edbfc" - integrity sha512-JSvpj1iNMFjK6K+uVl4unqMoa9rf5jopb8cya5UGBWz23Nw8hSNT7efgUx4BTlAPAgpNlEioUfeTyQ6J9ZvTVw== - dependencies: - bluebird "^3.5.2" - eth-ens-namehash "^2.0.8" - solc "^0.4.20" - testrpc "0.0.1" - web3-utils "^1.0.0-beta.31" - -"@ensdomains/resolver@^0.2.4": - version "0.2.4" - resolved "https://registry.yarnpkg.com/@ensdomains/resolver/-/resolver-0.2.4.tgz#c10fe28bf5efbf49bff4666d909aed0265efbc89" - integrity sha512-bvaTH34PMCbv6anRa9I/0zjLJgY4EuznbEMgbV77JBCQ9KNC46rzi0avuxpOfu+xDjPEtSFGqVEOr5GlUSGudA== - "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -438,64 +764,120 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.55.0.tgz#b721d52060f369aa259cf97392403cb9ce892ec6" integrity sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA== -"@ethereum-waffle/chai@^3.4.4": - version "3.4.4" - resolved "https://registry.yarnpkg.com/@ethereum-waffle/chai/-/chai-3.4.4.tgz#16c4cc877df31b035d6d92486dfdf983df9138ff" - integrity sha512-/K8czydBtXXkcM9X6q29EqEkc5dN3oYenyH2a9hF7rGAApAJUpH8QBtojxOY/xQ2up5W332jqgxwp0yPiYug1g== +"@ethereum-waffle/chai@4.0.10": + version "4.0.10" + resolved "https://registry.yarnpkg.com/@ethereum-waffle/chai/-/chai-4.0.10.tgz#6f600a40b6fdaed331eba42b8625ff23f3a0e59a" + integrity sha512-X5RepE7Dn8KQLFO7HHAAe+KeGaX/by14hn90wePGBhzL54tq4Y8JscZFu+/LCwCl6TnkAAy5ebiMoqJ37sFtWw== dependencies: - "@ethereum-waffle/provider" "^3.4.4" - ethers "^5.5.2" + "@ethereum-waffle/provider" "4.0.5" + debug "^4.3.4" + json-bigint "^1.0.0" -"@ethereum-waffle/compiler@^3.4.4": - version "3.4.4" - resolved "https://registry.yarnpkg.com/@ethereum-waffle/compiler/-/compiler-3.4.4.tgz#d568ee0f6029e68b5c645506079fbf67d0dfcf19" - integrity sha512-RUK3axJ8IkD5xpWjWoJgyHclOeEzDLQFga6gKpeGxiS/zBu+HB0W2FvsrrLalTFIaPw/CGYACRBSIxqiCqwqTQ== +"@ethereum-waffle/compiler@4.0.3": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@ethereum-waffle/compiler/-/compiler-4.0.3.tgz#069e2df24b879b8a7b78857bad6f8bf6ebc8a5b1" + integrity sha512-5x5U52tSvEVJS6dpCeXXKvRKyf8GICDwiTwUvGD3/WD+DpvgvaoHOL82XqpTSUHgV3bBq6ma5/8gKUJUIAnJCw== dependencies: "@resolver-engine/imports" "^0.3.3" "@resolver-engine/imports-fs" "^0.3.3" - "@typechain/ethers-v5" "^2.0.0" + "@typechain/ethers-v5" "^10.0.0" "@types/mkdirp" "^0.5.2" - "@types/node-fetch" "^2.5.5" - ethers "^5.0.1" + "@types/node-fetch" "^2.6.1" mkdirp "^0.5.1" - node-fetch "^2.6.1" - solc "^0.6.3" - ts-generator "^0.1.1" - typechain "^3.0.0" + node-fetch "^2.6.7" + +"@ethereum-waffle/ens@4.0.3": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@ethereum-waffle/ens/-/ens-4.0.3.tgz#4a46ac926414f3c83b4e8cc2562c8e2aee06377a" + integrity sha512-PVLcdnTbaTfCrfSOrvtlA9Fih73EeDvFS28JQnT5M5P4JMplqmchhcZB1yg/fCtx4cvgHlZXa0+rOCAk2Jk0Jw== + +"@ethereum-waffle/mock-contract@4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@ethereum-waffle/mock-contract/-/mock-contract-4.0.4.tgz#f13fea29922d87a4d2e7c4fc8fe72ea04d2c13de" + integrity sha512-LwEj5SIuEe9/gnrXgtqIkWbk2g15imM/qcJcxpLyAkOj981tQxXmtV4XmQMZsdedEsZ/D/rbUAOtZbgwqgUwQA== -"@ethereum-waffle/ens@^3.4.4": - version "3.4.4" - resolved "https://registry.yarnpkg.com/@ethereum-waffle/ens/-/ens-3.4.4.tgz#db97ea2c9decbb70b9205d53de2ccbd6f3182ba1" - integrity sha512-0m4NdwWxliy3heBYva1Wr4WbJKLnwXizmy5FfSSr5PMbjI7SIGCdCB59U7/ZzY773/hY3bLnzLwvG5mggVjJWg== +"@ethereum-waffle/provider@4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@ethereum-waffle/provider/-/provider-4.0.5.tgz#8a65dbf0263f4162c9209608205dee1c960e716b" + integrity sha512-40uzfyzcrPh+Gbdzv89JJTMBlZwzya1YLDyim8mVbEqYLP5VRYWoGp0JMyaizgV3hMoUFRqJKVmIUw4v7r3hYw== dependencies: - "@ensdomains/ens" "^0.4.4" - "@ensdomains/resolver" "^0.2.4" - ethers "^5.5.2" + "@ethereum-waffle/ens" "4.0.3" + "@ganache/ethereum-options" "0.1.4" + debug "^4.3.4" + ganache "7.4.3" -"@ethereum-waffle/mock-contract@^3.4.4": - version "3.4.4" - resolved "https://registry.yarnpkg.com/@ethereum-waffle/mock-contract/-/mock-contract-3.4.4.tgz#fc6ffa18813546f4950a69f5892d4dd54b2c685a" - integrity sha512-Mp0iB2YNWYGUV+VMl5tjPsaXKbKo8MDH9wSJ702l9EBjdxFf/vBvnMBAC1Fub1lLtmD0JHtp1pq+mWzg/xlLnA== +"@ethereumjs/block@^3.5.0", "@ethereumjs/block@^3.6.0", "@ethereumjs/block@^3.6.2": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@ethereumjs/block/-/block-3.6.3.tgz#d96cbd7af38b92ebb3424223dbf773f5ccd27f84" + integrity sha512-CegDeryc2DVKnDkg5COQrE0bJfw/p0v3GBk2W5/Dj5dOVfEmb50Ux0GLnSPypooLnfqjwFaorGuT9FokWB3GRg== dependencies: - "@ethersproject/abi" "^5.5.0" - ethers "^5.5.2" + "@ethereumjs/common" "^2.6.5" + "@ethereumjs/tx" "^3.5.2" + ethereumjs-util "^7.1.5" + merkle-patricia-tree "^4.2.4" + +"@ethereumjs/blockchain@^5.5.0": + version "5.5.3" + resolved "https://registry.yarnpkg.com/@ethereumjs/blockchain/-/blockchain-5.5.3.tgz#aa49a6a04789da6b66b5bcbb0d0b98efc369f640" + integrity sha512-bi0wuNJ1gw4ByNCV56H0Z4Q7D+SxUbwyG12Wxzbvqc89PXLRNR20LBcSUZRKpN0+YCPo6m0XZL/JLio3B52LTw== + dependencies: + "@ethereumjs/block" "^3.6.2" + "@ethereumjs/common" "^2.6.4" + "@ethereumjs/ethash" "^1.1.0" + debug "^4.3.3" + ethereumjs-util "^7.1.5" + level-mem "^5.0.1" + lru-cache "^5.1.1" + semaphore-async-await "^1.5.1" + +"@ethereumjs/common@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.6.0.tgz#feb96fb154da41ee2cc2c5df667621a440f36348" + integrity sha512-Cq2qS0FTu6O2VU1sgg+WyU9Ps0M6j/BEMHN+hRaECXCV/r0aI78u4N6p52QW/BDVhwWZpCdrvG8X7NJdzlpNUA== + dependencies: + crc-32 "^1.2.0" + ethereumjs-util "^7.1.3" + +"@ethereumjs/common@^2.6.0", "@ethereumjs/common@^2.6.4", "@ethereumjs/common@^2.6.5": + version "2.6.5" + resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.6.5.tgz#0a75a22a046272579d91919cb12d84f2756e8d30" + integrity sha512-lRyVQOeCDaIVtgfbowla32pzeDv2Obr8oR8Put5RdUBNRGr1VGPGQNGP6elWIpgK3YdpzqTOh4GyUGOureVeeA== + dependencies: + crc-32 "^1.2.0" + ethereumjs-util "^7.1.5" -"@ethereum-waffle/provider@^3.4.4": - version "3.4.4" - resolved "https://registry.yarnpkg.com/@ethereum-waffle/provider/-/provider-3.4.4.tgz#398fc1f7eb91cc2df7d011272eacba8af0c7fffb" - integrity sha512-GK8oKJAM8+PKy2nK08yDgl4A80mFuI8zBkE0C9GqTRYQqvuxIyXoLmJ5NZU9lIwyWVv5/KsoA11BgAv2jXE82g== +"@ethereumjs/ethash@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/ethash/-/ethash-1.1.0.tgz#7c5918ffcaa9cb9c1dc7d12f77ef038c11fb83fb" + integrity sha512-/U7UOKW6BzpA+Vt+kISAoeDie1vAvY4Zy2KF5JJb+So7+1yKmJeJEHOGSnQIj330e9Zyl3L5Nae6VZyh2TJnAA== dependencies: - "@ethereum-waffle/ens" "^3.4.4" - ethers "^5.5.2" - ganache-core "^2.13.2" - patch-package "^6.2.2" - postinstall-postinstall "^2.1.0" + "@ethereumjs/block" "^3.5.0" + "@types/levelup" "^4.3.0" + buffer-xor "^2.0.1" + ethereumjs-util "^7.1.1" + miller-rabin "^4.0.0" "@ethereumjs/rlp@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@ethereumjs/rlp/-/rlp-4.0.1.tgz#626fabfd9081baab3d0a3074b0c7ecaf674aaa41" integrity sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw== +"@ethereumjs/tx@3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.4.0.tgz#7eb1947eefa55eb9cf05b3ca116fb7a3dbd0bce7" + integrity sha512-WWUwg1PdjHKZZxPPo274ZuPsJCWV3SqATrEKQP1n2DrVYVP1aZIYpo/mFaA0BDoE0tIQmBeimRCEA0Lgil+yYw== + dependencies: + "@ethereumjs/common" "^2.6.0" + ethereumjs-util "^7.1.3" + +"@ethereumjs/tx@^3.4.0", "@ethereumjs/tx@^3.5.2": + version "3.5.2" + resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.5.2.tgz#197b9b6299582ad84f9527ca961466fce2296c1c" + integrity sha512-gQDNJWKrSDGu2w7w0PzVXVBNMzb7wwdDOmOqczmhNjqFxFuIbhVJDwiGEnxFNC2/b8ifcZzY7MLcluizohRzNw== + dependencies: + "@ethereumjs/common" "^2.6.4" + ethereumjs-util "^7.1.5" + "@ethereumjs/util@^8.1.0": version "8.1.0" resolved "https://registry.yarnpkg.com/@ethereumjs/util/-/util-8.1.0.tgz#299df97fb6b034e0577ce9f94c7d9d1004409ed4" @@ -505,20 +887,23 @@ ethereum-cryptography "^2.0.0" micro-ftch "^0.3.1" -"@ethersproject/abi@5.0.0-beta.153": - version "5.0.0-beta.153" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.0.0-beta.153.tgz#43a37172b33794e4562999f6e2d555b7599a8eee" - integrity sha512-aXweZ1Z7vMNzJdLpR1CZUAIgnwjrZeUSvN9syCwlBaEBUFJmFY+HHnfuTI5vIhVs/mRkfJVrbEyl51JZQqyjAg== - dependencies: - "@ethersproject/address" ">=5.0.0-beta.128" - "@ethersproject/bignumber" ">=5.0.0-beta.130" - "@ethersproject/bytes" ">=5.0.0-beta.129" - "@ethersproject/constants" ">=5.0.0-beta.128" - "@ethersproject/hash" ">=5.0.0-beta.128" - "@ethersproject/keccak256" ">=5.0.0-beta.127" - "@ethersproject/logger" ">=5.0.0-beta.129" - "@ethersproject/properties" ">=5.0.0-beta.131" - "@ethersproject/strings" ">=5.0.0-beta.130" +"@ethereumjs/vm@5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/vm/-/vm-5.6.0.tgz#e0ca62af07de820143674c30b776b86c1983a464" + integrity sha512-J2m/OgjjiGdWF2P9bj/4LnZQ1zRoZhY8mRNVw/N3tXliGI8ai1sI1mlDPkLpeUUM4vq54gH6n0ZlSpz8U/qlYQ== + dependencies: + "@ethereumjs/block" "^3.6.0" + "@ethereumjs/blockchain" "^5.5.0" + "@ethereumjs/common" "^2.6.0" + "@ethereumjs/tx" "^3.4.0" + async-eventemitter "^0.2.4" + core-js-pure "^3.0.1" + debug "^2.2.0" + ethereumjs-util "^7.1.3" + functional-red-black-tree "^1.0.1" + mcl-wasm "^0.7.1" + merkle-patricia-tree "^4.2.2" + rustbn.js "~0.2.0" "@ethersproject/abi@5.5.0": version "5.5.0" @@ -609,7 +994,7 @@ "@ethersproject/logger" "^5.5.0" "@ethersproject/rlp" "^5.5.0" -"@ethersproject/address@5.7.0", "@ethersproject/address@>=5.0.0-beta.128", "@ethersproject/address@^5.0.2", "@ethersproject/address@^5.5.0", "@ethersproject/address@^5.7.0": +"@ethersproject/address@5.7.0", "@ethersproject/address@^5.0.2", "@ethersproject/address@^5.5.0", "@ethersproject/address@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== @@ -659,7 +1044,7 @@ "@ethersproject/logger" "^5.5.0" bn.js "^4.11.9" -"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@>=5.0.0-beta.130", "@ethersproject/bignumber@^5.5.0", "@ethersproject/bignumber@^5.7.0": +"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@^5.5.0", "@ethersproject/bignumber@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== @@ -675,7 +1060,7 @@ dependencies: "@ethersproject/logger" "^5.5.0" -"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@>=5.0.0-beta.129", "@ethersproject/bytes@^5.5.0", "@ethersproject/bytes@^5.7.0": +"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@^5.5.0", "@ethersproject/bytes@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== @@ -689,7 +1074,7 @@ dependencies: "@ethersproject/bignumber" "^5.5.0" -"@ethersproject/constants@5.7.0", "@ethersproject/constants@>=5.0.0-beta.128", "@ethersproject/constants@^5.5.0", "@ethersproject/constants@^5.7.0": +"@ethersproject/constants@5.7.0", "@ethersproject/constants@^5.5.0", "@ethersproject/constants@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== @@ -742,7 +1127,7 @@ "@ethersproject/properties" "^5.5.0" "@ethersproject/strings" "^5.5.0" -"@ethersproject/hash@5.7.0", "@ethersproject/hash@>=5.0.0-beta.128", "@ethersproject/hash@^5.5.0", "@ethersproject/hash@^5.7.0": +"@ethersproject/hash@5.7.0", "@ethersproject/hash@^5.5.0", "@ethersproject/hash@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== @@ -839,7 +1224,7 @@ "@ethersproject/bytes" "^5.5.0" js-sha3 "0.8.0" -"@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@>=5.0.0-beta.127", "@ethersproject/keccak256@^5.5.0", "@ethersproject/keccak256@^5.7.0": +"@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@^5.5.0", "@ethersproject/keccak256@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== @@ -852,7 +1237,7 @@ resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.5.0.tgz#0c2caebeff98e10aefa5aef27d7441c7fd18cf5d" integrity sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg== -"@ethersproject/logger@5.7.0", "@ethersproject/logger@>=5.0.0-beta.129", "@ethersproject/logger@^5.5.0", "@ethersproject/logger@^5.7.0": +"@ethersproject/logger@5.7.0", "@ethersproject/logger@^5.5.0", "@ethersproject/logger@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== @@ -894,7 +1279,7 @@ dependencies: "@ethersproject/logger" "^5.5.0" -"@ethersproject/properties@5.7.0", "@ethersproject/properties@>=5.0.0-beta.131", "@ethersproject/properties@^5.5.0", "@ethersproject/properties@^5.7.0": +"@ethersproject/properties@5.7.0", "@ethersproject/properties@^5.5.0", "@ethersproject/properties@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== @@ -1059,7 +1444,7 @@ "@ethersproject/constants" "^5.5.0" "@ethersproject/logger" "^5.5.0" -"@ethersproject/strings@5.7.0", "@ethersproject/strings@>=5.0.0-beta.130", "@ethersproject/strings@^5.5.0", "@ethersproject/strings@^5.7.0": +"@ethersproject/strings@5.7.0", "@ethersproject/strings@^5.5.0", "@ethersproject/strings@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== @@ -1083,7 +1468,7 @@ "@ethersproject/rlp" "^5.5.0" "@ethersproject/signing-key" "^5.5.0" -"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.0.0-beta.135", "@ethersproject/transactions@^5.5.0", "@ethersproject/transactions@^5.7.0": +"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.5.0", "@ethersproject/transactions@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== @@ -1207,6 +1592,68 @@ resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.0.0.tgz#f22824caff3ae506b18207bad4126dbc6ccdb6b8" integrity sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ== +"@ganache/ethereum-address@0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@ganache/ethereum-address/-/ethereum-address-0.1.4.tgz#0e6d66f4a24f64bf687cb3ff7358fb85b9d9005e" + integrity sha512-sTkU0M9z2nZUzDeHRzzGlW724xhMLXo2LeX1hixbnjHWY1Zg1hkqORywVfl+g5uOO8ht8T0v+34IxNxAhmWlbw== + dependencies: + "@ganache/utils" "0.1.4" + +"@ganache/ethereum-options@0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@ganache/ethereum-options/-/ethereum-options-0.1.4.tgz#6a559abb44225e2b8741a8f78a19a46714a71cd6" + integrity sha512-i4l46taoK2yC41FPkcoDlEVoqHS52wcbHPqJtYETRWqpOaoj9hAg/EJIHLb1t6Nhva2CdTO84bG+qlzlTxjAHw== + dependencies: + "@ganache/ethereum-address" "0.1.4" + "@ganache/ethereum-utils" "0.1.4" + "@ganache/options" "0.1.4" + "@ganache/utils" "0.1.4" + bip39 "3.0.4" + seedrandom "3.0.5" + +"@ganache/ethereum-utils@0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@ganache/ethereum-utils/-/ethereum-utils-0.1.4.tgz#fae4b5b9e642e751ff1fa0cd7316c92996317257" + integrity sha512-FKXF3zcdDrIoCqovJmHLKZLrJ43234Em2sde/3urUT/10gSgnwlpFmrv2LUMAmSbX3lgZhW/aSs8krGhDevDAg== + dependencies: + "@ethereumjs/common" "2.6.0" + "@ethereumjs/tx" "3.4.0" + "@ethereumjs/vm" "5.6.0" + "@ganache/ethereum-address" "0.1.4" + "@ganache/rlp" "0.1.4" + "@ganache/utils" "0.1.4" + emittery "0.10.0" + ethereumjs-abi "0.6.8" + ethereumjs-util "7.1.3" + +"@ganache/options@0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@ganache/options/-/options-0.1.4.tgz#325b07e6de85094667aaaaf3d653e32404a04b78" + integrity sha512-zAe/craqNuPz512XQY33MOAG6Si1Xp0hCvfzkBfj2qkuPcbJCq6W/eQ5MB6SbXHrICsHrZOaelyqjuhSEmjXRw== + dependencies: + "@ganache/utils" "0.1.4" + bip39 "3.0.4" + seedrandom "3.0.5" + +"@ganache/rlp@0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@ganache/rlp/-/rlp-0.1.4.tgz#f4043afda83e1a14a4f80607b103daf166a9b374" + integrity sha512-Do3D1H6JmhikB+6rHviGqkrNywou/liVeFiKIpOBLynIpvZhRCgn3SEDxyy/JovcaozTo/BynHumfs5R085MFQ== + dependencies: + "@ganache/utils" "0.1.4" + rlp "2.2.6" + +"@ganache/utils@0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@ganache/utils/-/utils-0.1.4.tgz#25d60d7689e3dda6a8a7ad70e3646f07c2c39a1f" + integrity sha512-oatUueU3XuXbUbUlkyxeLLH3LzFZ4y5aSkNbx6tjSIhVTPeh+AuBKYt4eQ73FFcTB3nj/gZoslgAh5CN7O369w== + dependencies: + emittery "0.10.0" + keccak "3.0.1" + seedrandom "3.0.5" + optionalDependencies: + "@trufflesuite/bigint-buffer" "1.1.9" + "@humanwhocodes/config-array@^0.11.13": version "0.11.13" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297" @@ -1245,6 +1692,18 @@ resolved "https://registry.yarnpkg.com/@iarna/toml/-/toml-2.2.5.tgz#b32366c89b43c6f8cefbdefac778b9c828e3ba8c" integrity sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg== +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -1493,20 +1952,6 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@ljharb/resumer@~0.0.1": - version "0.0.1" - resolved "https://registry.yarnpkg.com/@ljharb/resumer/-/resumer-0.0.1.tgz#8a940a9192dd31f6a1df17564bbd26dc6ad3e68d" - integrity sha512-skQiAOrCfO7vRTq53cxznMpks7wS1va95UCidALlOVWqvBAzwPVErwizDwoMqNVMEn1mDq0utxZd02eIrvF1lw== - dependencies: - "@ljharb/through" "^2.3.9" - -"@ljharb/through@^2.3.9", "@ljharb/through@~2.3.9": - version "2.3.11" - resolved "https://registry.yarnpkg.com/@ljharb/through/-/through-2.3.11.tgz#783600ff12c06f21a76cc26e33abd0b1595092f9" - integrity sha512-ccfcIDlogiXNq5KcbAwbaO7lMh3Tm1i3khMPYpxlK8hH/W53zN81KM9coerRLOnTGu3nfXIniAmQbRI9OxbC0w== - dependencies: - call-bind "^1.0.2" - "@matterlabs/eslint-config-typescript@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@matterlabs/eslint-config-typescript/-/eslint-config-typescript-1.1.2.tgz#a9be4e56aedf298800f247c5049fc412f8b301a7" @@ -1535,6 +1980,16 @@ chalk "4.1.2" ts-morph "^19.0.0" +"@matterlabs/hardhat-zksync-node@^0.0.1-beta.7": + version "0.0.1" + resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-node/-/hardhat-zksync-node-0.0.1.tgz#d44bda3c0069b149e2a67c9697eb81166b169ea6" + integrity sha512-rMabl+I813lzXINqTq5OvujQ30wsfO9mTLMPDXuYzEEhEzvnXlaVxuqynKBXrgXAxjmr+G79rqvcWgeKygtwBA== + dependencies: + "@matterlabs/hardhat-zksync-solc" "^1.0.5" + axios "^1.4.0" + chalk "4.1.2" + fs-extra "^11.1.1" + "@matterlabs/hardhat-zksync-solc@0.4.1": version "0.4.1" resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-solc/-/hardhat-zksync-solc-0.4.1.tgz#e8e67d947098d7bb8925f968544d34e522af5a9c" @@ -1567,6 +2022,18 @@ chalk "4.1.2" dockerode "^3.3.4" +"@matterlabs/hardhat-zksync-solc@^1.0.5": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-solc/-/hardhat-zksync-solc-1.0.6.tgz#7ef8438e6bb15244691600e2afa77aaff7dff9f0" + integrity sha512-0icYSufXba/Bbb7v2iXuZJ+IbYsiNpR4Wy6UizHnGuFw3OMHgh+saebQphuaN9yyRL2UPGZbPkQFHWBLZj5/xQ== + dependencies: + "@nomiclabs/hardhat-docker" "^2.0.0" + chalk "4.1.2" + dockerode "^4.0.0" + fs-extra "^11.1.1" + proper-lockfile "^4.1.2" + semver "^7.5.1" + "@matterlabs/hardhat-zksync-verify@^0.2.0": version "0.2.2" resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-verify/-/hardhat-zksync-verify-0.2.2.tgz#daa34bc4404096ed0f44461ee366c1cb0e5a4f2f" @@ -2075,31 +2542,26 @@ resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-waffle/-/hardhat-waffle-2.0.6.tgz#d11cb063a5f61a77806053e54009c40ddee49a54" integrity sha512-+Wz0hwmJGSI17B+BhU/qFRZ1l6/xMW82QGXE/Gi+WTmwgJrQefuBs1lIf7hzQ1hLk6hpkvb/zwcNkpVKRYTQYg== -"@openzeppelin/contracts-upgradeable@4.6.0": - version "4.6.0" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.6.0.tgz#1bf55f230f008554d4c6fe25eb165b85112108b0" - integrity sha512-5OnVuO4HlkjSCJO165a4i2Pu1zQGzMs//o54LPrwUgxvEO2P3ax1QuaSI0cEHHTveA77guS0PnNugpR2JMsPfA== - -"@openzeppelin/contracts-upgradeable@4.8.0": - version "4.8.0" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.8.0.tgz#26688982f46969018e3ed3199e72a07c8d114275" - integrity sha512-5GeFgqMiDlqGT8EdORadp1ntGF0qzWZLmEY7Wbp/yVhN7/B3NNzCxujuI77ktlyG81N3CUZP8cZe3ZAQ/cW10w== - -"@openzeppelin/contracts@4.6.0": - version "4.6.0" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.6.0.tgz#c91cf64bc27f573836dba4122758b4743418c1b3" - integrity sha512-8vi4d50NNya/bQqCmaVzvHNmwHvS0OBKb7HNtuNwEE3scXWrP31fKQoGxNMT+KbzmrNZzatE3QK5p2gFONI/hg== +"@openzeppelin/contracts-upgradeable@4.9.5": + version "4.9.5" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.9.5.tgz#572b5da102fc9be1d73f34968e0ca56765969812" + integrity sha512-f7L1//4sLlflAN7fVzJLoRedrf5Na3Oal5PZfIq55NFcVZ90EpV1q5xOvL4lFvg3MNICSDr2hH0JUBxwlxcoPg== -"@openzeppelin/contracts@4.8.0": - version "4.8.0" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.8.0.tgz#6854c37df205dd2c056bdfa1b853f5d732109109" - integrity sha512-AGuwhRRL+NaKx73WKRNzeCxOCOCxpaqF+kp8TJ89QzAipSwZy/NoflkWaL9bywXFRhIzXt8j38sfF7KBKCPWLw== +"@openzeppelin/contracts@4.9.5": + version "4.9.5" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.5.tgz#1eed23d4844c861a1835b5d33507c1017fa98de8" + integrity sha512-ZK+W5mVhRppff9BE6YdR8CC52C8zAvsVAiWhEtQ5+oNxFE6h1WdeWo+FJSF8KKvtxxVYZ7MTP/5KoVpAU3aSWg== "@openzeppelin/contracts@^4.8.0": version "4.9.3" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.3.tgz#00d7a8cf35a475b160b3f0293a6403c511099364" integrity sha512-He3LieZ1pP2TNt5JbkPA4PNT9WC3gOTOlDcFGJW4Le4QKqwmiNJCRt44APfxMxvq7OugU/cqYuPcSBzOw38DAg== +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + "@pkgr/utils@^2.4.2": version "2.4.2" resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.4.2.tgz#9e638bbe9a6a6f165580dc943f138fd3309a2cbc" @@ -2314,16 +2776,6 @@ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== -"@sindresorhus/is@^0.14.0": - version "0.14.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" - integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== - -"@sindresorhus/is@^4.0.0": - version "4.6.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" - integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== - "@sinonjs/commons@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.0.tgz#beb434fe875d965265e04722ccfc21df7f755d72" @@ -2359,19 +2811,19 @@ dependencies: antlr4ts "^0.5.0-alpha.4" -"@szmarczak/http-timer@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" - integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== +"@trufflesuite/bigint-buffer@1.1.10": + version "1.1.10" + resolved "https://registry.yarnpkg.com/@trufflesuite/bigint-buffer/-/bigint-buffer-1.1.10.tgz#a1d9ca22d3cad1a138b78baaf15543637a3e1692" + integrity sha512-pYIQC5EcMmID74t26GCC67946mgTJFiLXOT/BYozgrd4UEY2JHEGLhWi9cMiQCt5BSqFEvKkCHNnoj82SRjiEw== dependencies: - defer-to-connect "^1.0.1" + node-gyp-build "4.4.0" -"@szmarczak/http-timer@^4.0.5": - version "4.0.6" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" - integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== +"@trufflesuite/bigint-buffer@1.1.9": + version "1.1.9" + resolved "https://registry.yarnpkg.com/@trufflesuite/bigint-buffer/-/bigint-buffer-1.1.9.tgz#e2604d76e1e4747b74376d68f1312f9944d0d75d" + integrity sha512-bdM5cEGCOhDSwminryHJbRmXc1x7dPKg6Pqns3qyTwFlxsqUgxE29lsERS3PlIW1HTjoIGMUqsk1zQQwST1Yxw== dependencies: - defer-to-connect "^2.0.0" + node-gyp-build "4.3.0" "@ts-morph/common@~0.20.0": version "0.20.0" @@ -2403,6 +2855,14 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== +"@typechain/ethers-v5@^10.0.0": + version "10.2.1" + resolved "https://registry.yarnpkg.com/@typechain/ethers-v5/-/ethers-v5-10.2.1.tgz#50241e6957683281ecfa03fb5a6724d8a3ce2391" + integrity sha512-n3tQmCZjRE6IU4h6lqUGiQ1j866n5MTCBJreNEHHVWXa2u9GJTaeYyU1/k+1qLutkyw+sS6VAN+AbeiTqsxd/A== + dependencies: + lodash "^4.17.15" + ts-essentials "^7.0.1" + "@typechain/ethers-v5@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@typechain/ethers-v5/-/ethers-v5-2.0.0.tgz#cd3ca1590240d587ca301f4c029b67bfccd08810" @@ -2410,6 +2870,11 @@ dependencies: ethers "^5.0.2" +"@types/abstract-leveldown@*": + version "7.2.5" + resolved "https://registry.yarnpkg.com/@types/abstract-leveldown/-/abstract-leveldown-7.2.5.tgz#db2cf364c159fb1f12be6cd3549f56387eaf8d73" + integrity sha512-/2B0nQF4UdupuxeKTJA2+Rj1D+uDemo6P4kMwKCpbfpnzeVaWSELTsAw4Lxn3VJD6APtRrZOCuYo+4nHUQfTfg== + "@types/argparse@^1.0.36": version "1.0.38" resolved "https://registry.yarnpkg.com/@types/argparse/-/argparse-1.0.38.tgz#a81fd8606d481f873a3800c6ebae4f1d768a56a9" @@ -2448,7 +2913,7 @@ dependencies: "@babel/types" "^7.20.7" -"@types/bn.js@^4.11.3", "@types/bn.js@^4.11.5": +"@types/bn.js@^4.11.3": version "4.11.6" resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== @@ -2462,16 +2927,6 @@ dependencies: "@types/node" "*" -"@types/cacheable-request@^6.0.1": - version "6.0.3" - resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" - integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw== - dependencies: - "@types/http-cache-semantics" "*" - "@types/keyv" "^3.1.4" - "@types/node" "*" - "@types/responselike" "^1.0.0" - "@types/chai-as-promised@^7.1.3", "@types/chai-as-promised@^7.1.4": version "7.1.8" resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz#f2b3d82d53c59626b5d6bbc087667ccb4b677fe9" @@ -2523,11 +2978,6 @@ dependencies: "@types/node" "*" -"@types/http-cache-semantics@*": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4" - integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA== - "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.6" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" @@ -2565,11 +3015,18 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== -"@types/keyv@^3.1.4": - version "3.1.4" - resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" - integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== +"@types/level-errors@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/level-errors/-/level-errors-3.0.2.tgz#f33ec813c50780b547463da9ad8acac89ee457d9" + integrity sha512-gyZHbcQ2X5hNXf/9KS2qGEmgDe9EN2WDM3rJ5Ele467C0nA1sLhtmv1bZiPMDYfAYCfPWft0uQIaTvXbASSTRA== + +"@types/levelup@^4.3.0": + version "4.3.3" + resolved "https://registry.yarnpkg.com/@types/levelup/-/levelup-4.3.3.tgz#4dc2b77db079b1cf855562ad52321aa4241b8ef4" + integrity sha512-K+OTIjJcZHVlZQN1HmU64VtrC0jC3dXWQozuEIR9zVvltIk90zaGPM2AgT+fIkChpzHhFE3YnvFLCbLtzAmexA== dependencies: + "@types/abstract-leveldown" "*" + "@types/level-errors" "*" "@types/node" "*" "@types/lodash@^4.14.199": @@ -2577,7 +3034,7 @@ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.202.tgz#f09dbd2fb082d507178b2f2a5c7e74bd72ff98f8" integrity sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ== -"@types/lru-cache@^5.1.0": +"@types/lru-cache@5.1.1", "@types/lru-cache@^5.1.0": version "5.1.1" resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-5.1.1.tgz#c48c2e27b65d2a153b19bfc1a317e30872e01eef" integrity sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw== @@ -2611,14 +3068,6 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.2.3.tgz#bbeb55fbc73f28ea6de601fbfa4613f58d785323" integrity sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw== -"@types/node-fetch@^2.5.5": - version "2.6.9" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.9.tgz#15f529d247f1ede1824f7e7acdaa192d5f28071e" - integrity sha512-bQVlnMLFJ2d35DkPNjEPmd9ueO/rh5EiaZt2bhqiSarPjZIuIV6bPQVqcrEyvNo+AfTrRGVazle1tl597w3gfA== - dependencies: - "@types/node" "*" - form-data "^4.0.0" - "@types/node-fetch@^2.5.7": version "2.6.7" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.7.tgz#a1abe2ce24228b58ad97f99480fdcf9bbc6ab16d" @@ -2627,6 +3076,14 @@ "@types/node" "*" form-data "^4.0.0" +"@types/node-fetch@^2.6.1": + version "2.6.10" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.10.tgz#ff5c1ceacab782f2b7ce69957d38c1c27b0dc469" + integrity sha512-PPpPK6F9ALFTn59Ka3BaL+qGuipRfxNE8qVgkp0bVixeiR2c2/L+IVOiBdu9JhhT22sWnQEp6YyHGI2b2+CMcA== + dependencies: + "@types/node" "*" + form-data "^4.0.0" + "@types/node@*": version "20.8.10" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.10.tgz#a5448b895c753ae929c26ce85cab557c6d4a365e" @@ -2634,6 +3091,11 @@ dependencies: undici-types "~5.26.4" +"@types/node@11.11.6": + version "11.11.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.6.tgz#df929d1bb2eee5afdda598a41930fe50b43eaa6a" + integrity sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ== + "@types/node@>=13.7.0": version "20.10.4" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.4.tgz#b246fd84d55d5b1b71bf51f964bd514409347198" @@ -2646,11 +3108,6 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== -"@types/node@^12.12.6": - version "12.20.55" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" - integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== - "@types/node@^14.14.5", "@types/node@^14.6.1": version "14.18.63" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.63.tgz#1788fa8da838dbb5f9ea994b834278205db6ca2b" @@ -2707,13 +3164,6 @@ dependencies: "@types/node" "*" -"@types/responselike@^1.0.0": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50" - integrity sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw== - dependencies: - "@types/node" "*" - "@types/secp256k1@^4.0.1": version "4.0.5" resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.5.tgz#14b1766b4fbc198b0af5599d9fd21c89056633ce" @@ -2721,6 +3171,11 @@ dependencies: "@types/node" "*" +"@types/seedrandom@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/seedrandom/-/seedrandom-3.0.1.tgz#1254750a4fec4aff2ebec088ccd0bb02e91fedb4" + integrity sha512-giB9gzDeiCeloIXDgzFBCgjj1k4WxcDrZtGl6h1IqmUPlxF+Nx8Ve+96QCyDZ/HseB/uvDsKbpib9hU5cU53pw== + "@types/semver@^7.5.0": version "7.5.4" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.4.tgz#0a41252ad431c473158b22f9bfb9a63df7541cff" @@ -2923,11 +3378,6 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== -"@yarnpkg/lockfile@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" - integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== - JSONStream@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.2.tgz#c102371b6ec3a7cf3b847ca00c20bb0fce4c6dea" @@ -2966,42 +3416,40 @@ abstract-level@^1.0.0, abstract-level@^1.0.2, abstract-level@^1.0.3: module-error "^1.0.1" queue-microtask "^1.2.3" -abstract-leveldown@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-3.0.0.tgz#5cb89f958a44f526779d740d1440e743e0c30a57" - integrity sha512-KUWx9UWGQD12zsmLNj64/pndaz4iJh/Pj7nopgkfDG6RlCcbMZvT6+9l7dchK4idog2Is8VdC/PvNbFuFmalIQ== - dependencies: - xtend "~4.0.0" - -abstract-leveldown@^2.4.1, abstract-leveldown@~2.7.1: - version "2.7.2" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.7.2.tgz#87a44d7ebebc341d59665204834c8b7e0932cc93" - integrity sha512-+OVvxH2rHVEhWLdbudP6p0+dNMXu8JA1CbhP19T8paTYAcX7oJ4OVjT+ZUVpv7mITxXHqDMej+GdqXBmXkw09w== +abstract-leveldown@^6.2.1: + version "6.3.0" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.3.0.tgz#d25221d1e6612f820c35963ba4bd739928f6026a" + integrity sha512-TU5nlYgta8YrBMNpc9FwQzRbiXsj49gsALsXadbGHt9CROPzX5fB0rWDR5mtdpOOKa5XqRFpbj1QroPAoPzVjQ== dependencies: + buffer "^5.5.0" + immediate "^3.2.3" + level-concat-iterator "~2.0.0" + level-supports "~1.0.0" xtend "~4.0.0" -abstract-leveldown@^5.0.0, abstract-leveldown@~5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-5.0.0.tgz#f7128e1f86ccabf7d2893077ce5d06d798e386c6" - integrity sha512-5mU5P1gXtsMIXg65/rsYGsi93+MlogXZ9FA8JnwKurHQg64bfXwGYVdVdijNTVNOlAsuIiOwHdvFFD5JqCJQ7A== +abstract-leveldown@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz#08d19d4e26fb5be426f7a57004851b39e1795a2e" + integrity sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ== dependencies: - xtend "~4.0.0" + buffer "^6.0.3" + catering "^2.0.0" + is-buffer "^2.0.5" + level-concat-iterator "^3.0.0" + level-supports "^2.0.1" + queue-microtask "^1.2.3" -abstract-leveldown@~2.6.0: - version "2.6.3" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.6.3.tgz#1c5e8c6a5ef965ae8c35dfb3a8770c476b82c4b8" - integrity sha512-2++wDf/DYqkPR3o5tbfdhF96EfMApo1GpPfzOsR/ZYXdkSmELlvOOEAl9iKkRsktMPHdGjO4rtkBpf2I7TiTeA== +abstract-leveldown@~6.2.1: + version "6.2.3" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz#036543d87e3710f2528e47040bc3261b77a9a8eb" + integrity sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ== dependencies: + buffer "^5.5.0" + immediate "^3.2.3" + level-concat-iterator "~2.0.0" + level-supports "~1.0.0" xtend "~4.0.0" -accepts@~1.3.8: - version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" - acorn-jsx@^5.3.1, acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -3037,11 +3485,6 @@ aes-js@3.0.0: resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== -aes-js@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a" - integrity sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ== - agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -3104,11 +3547,6 @@ ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: dependencies: type-fest "^0.21.3" -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== - ansi-regex@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" @@ -3124,10 +3562,10 @@ ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA== +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== ansi-styles@^3.2.1: version "3.2.1" @@ -3148,6 +3586,11 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + antlr4@^4.11.0: version "4.13.1" resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.13.1.tgz#1e0a1830a08faeb86217cb2e6c34716004e4253d" @@ -3193,21 +3636,6 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA== - -arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q== - array-back@^1.0.3, array-back@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/array-back/-/array-back-1.0.4.tgz#644ba7f095f7ffcf7c43b5f0dc39d3c1f03c063b" @@ -3222,6 +3650,16 @@ array-back@^2.0.0: dependencies: typical "^2.6.1" +array-back@^3.0.1, array-back@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0" + integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q== + +array-back@^4.0.1, array-back@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-4.0.2.tgz#8004e999a6274586beeb27342168652fdb89fa1e" + integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg== + array-buffer-byte-length@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" @@ -3230,11 +3668,6 @@ array-buffer-byte-length@^1.0.0: call-bind "^1.0.2" is-array-buffer "^3.0.1" -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== - array-includes@^3.1.7: version "3.1.7" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" @@ -3246,6 +3679,11 @@ array-includes@^3.1.7: get-intrinsic "^1.2.1" is-string "^1.0.7" +array-timsort@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-timsort/-/array-timsort-1.0.3.tgz#3c9e4199e54fb2b9c3fe5976396a21614ef0d926" + integrity sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ== + array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" @@ -3256,11 +3694,6 @@ array-uniq@1.0.3: resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ== - array.prototype.findlastindex@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz#b37598438f97b579166940814e2c0493a4f50207" @@ -3292,17 +3725,6 @@ array.prototype.flatmap@^1.3.2: es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -array.prototype.reduce@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/array.prototype.reduce/-/array.prototype.reduce-1.0.6.tgz#63149931808c5fc1e1354814923d92d45f7d96d5" - integrity sha512-UW+Mz8LG/sPSU8jRDCjVr6J/ZKAGpHfwrZ6kWTG5qCxIEiXdVshqGnu5vEZA8S1y6X4aCSbQZ0/EEsfvEvBiSg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-array-method-boxes-properly "^1.0.0" - is-string "^1.0.7" - arraybuffer.prototype.slice@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz#98bd561953e3e74bb34938e77647179dfe6e9f12" @@ -3321,16 +3743,6 @@ asap@~2.0.6: resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== -asn1.js@^5.2.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" - integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - safer-buffer "^2.1.0" - asn1@^0.2.6, asn1@~0.2.3: version "0.2.6" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" @@ -3348,11 +3760,6 @@ assertion-error@^1.1.0: resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw== - ast-parents@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/ast-parents/-/ast-parents-0.0.1.tgz#508fd0f05d0c48775d9eccda2e174423261e8dd3" @@ -3363,52 +3770,35 @@ astral-regex@^2.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== -async-eventemitter@^0.2.2: +async-eventemitter@^0.2.4: version "0.2.4" resolved "https://registry.yarnpkg.com/async-eventemitter/-/async-eventemitter-0.2.4.tgz#f5e7c8ca7d3e46aab9ec40a292baf686a0bafaca" integrity sha512-pd20BwL7Yt1zwDFy+8MX8F1+WCT8aQeKj0kQnTrH9WaeRETlRamVhD0JtRPmrV4GfOJ2F9CvdQkZeZhnh2TuHw== dependencies: async "^2.4.0" -async-limiter@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== - -async@1.x, async@^1.4.2: +async@1.x: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" integrity sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w== -async@2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381" - integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg== - dependencies: - lodash "^4.17.11" - -async@^2.0.1, async@^2.1.2, async@^2.4.0, async@^2.5.0, async@^2.6.1: +async@^2.4.0: version "2.6.4" resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== dependencies: lodash "^4.17.14" +async@^3.2.4: + version "3.2.5" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66" + integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -at-least-node@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" - integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== - -atob@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - available-typed-arrays@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" @@ -3440,40 +3830,6 @@ axios@^1.4.0, axios@^1.5.1: form-data "^4.0.0" proxy-from-env "^1.1.0" -babel-code-frame@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - integrity sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g== - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - -babel-core@^6.0.14, babel-core@^6.26.0: - version "6.26.3" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" - integrity sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA== - dependencies: - babel-code-frame "^6.26.0" - babel-generator "^6.26.0" - babel-helpers "^6.24.1" - babel-messages "^6.23.0" - babel-register "^6.26.0" - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - convert-source-map "^1.5.1" - debug "^2.6.9" - json5 "^0.5.1" - lodash "^4.17.4" - minimatch "^3.0.4" - path-is-absolute "^1.0.1" - private "^0.1.8" - slash "^1.0.0" - source-map "^0.5.7" - babel-eslint@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" @@ -3486,133 +3842,6 @@ babel-eslint@^10.1.0: eslint-visitor-keys "^1.0.0" resolve "^1.12.0" -babel-generator@^6.26.0: - version "6.26.1" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" - integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA== - dependencies: - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - detect-indent "^4.0.0" - jsesc "^1.3.0" - lodash "^4.17.4" - source-map "^0.5.7" - trim-right "^1.0.1" - -babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" - integrity sha512-gCtfYORSG1fUMX4kKraymq607FWgMWg+j42IFPc18kFQEsmtaibP4UrqsXt8FlEJle25HUd4tsoDR7H2wDhe9Q== - dependencies: - babel-helper-explode-assignable-expression "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-call-delegate@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" - integrity sha512-RL8n2NiEj+kKztlrVJM9JT1cXzzAdvWFh76xh/H1I4nKwunzE4INBXn8ieCZ+wh4zWszZk7NBS1s/8HR5jDkzQ== - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-define-map@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" - integrity sha512-bHkmjcC9lM1kmZcVpA5t2om2nzT/xiZpo6TJq7UlZ3wqKfzia4veeXbIhKvJXAMzhhEBd3cR1IElL5AenWEUpA== - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-explode-assignable-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" - integrity sha512-qe5csbhbvq6ccry9G7tkXbzNtcDiH4r51rrPUbwwoTzZ18AqxWYRZT6AOmxrpxKnQBW0pYlBI/8vh73Z//78nQ== - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-function-name@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" - integrity sha512-Oo6+e2iX+o9eVvJ9Y5eKL5iryeRdsIkwRYheCuhYdVHsdEQysbc2z2QkqCLIYnNxkT5Ss3ggrHdXiDI7Dhrn4Q== - dependencies: - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-get-function-arity@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" - integrity sha512-WfgKFX6swFB1jS2vo+DwivRN4NB8XUdM3ij0Y1gnC21y1tdBoe6xjVnd7NSI6alv+gZXCtJqvrTeMW3fR/c0ng== - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-hoist-variables@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" - integrity sha512-zAYl3tqerLItvG5cKYw7f1SpvIxS9zi7ohyGHaI9cgDUjAT6YcY9jIEH5CstetP5wHIVSceXwNS7Z5BpJg+rOw== - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-optimise-call-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" - integrity sha512-Op9IhEaxhbRT8MDXx2iNuMgciu2V8lDvYCNQbDGjdBNCjaMvyLf4wl4A3b8IgndCyQF8TwfgsQ8T3VD8aX1/pA== - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-regex@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" - integrity sha512-VlPiWmqmGJp0x0oK27Out1D+71nVVCTSdlbhIVoaBAj2lUgrNjBCRR9+llO4lTSb2O4r7PJg+RobRkhBrf6ofg== - dependencies: - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-remap-async-to-generator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" - integrity sha512-RYqaPD0mQyQIFRu7Ho5wE2yvA/5jxqCIj/Lv4BXNq23mHYu/vxikOy2JueLiBxQknwapwrJeNCesvY0ZcfnlHg== - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-replace-supers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" - integrity sha512-sLI+u7sXJh6+ToqDr57Bv973kCepItDhMou0xCP2YPVmR1jkHSCY+p1no8xErbV1Siz5QE8qKT1WIwybSWlqjw== - dependencies: - babel-helper-optimise-call-expression "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helpers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" - integrity sha512-n7pFrqQm44TCYvrCDb0MqabAF+JUBq+ijBvNMUxpkLjJaAu32faIexewMumrH5KLLJ1HDyT0PTEqRyAe/GwwuQ== - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-jest@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" @@ -3626,20 +3855,6 @@ babel-jest@^29.7.0: graceful-fs "^4.2.9" slash "^3.0.0" -babel-messages@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" - integrity sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w== - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-check-es2015-constants@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" - integrity sha512-B1M5KBP29248dViEo1owyY32lk1ZSH2DaNNrXLGt8lyjjHm7pBqAdQ7VKUPR6EEDO323+OvT3MQXbCin8ooWdA== - dependencies: - babel-runtime "^6.22.0" - babel-plugin-istanbul@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" @@ -3661,244 +3876,6 @@ babel-plugin-jest-hoist@^29.6.3: "@types/babel__core" "^7.1.14" "@types/babel__traverse" "^7.0.6" -babel-plugin-syntax-async-functions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" - integrity sha512-4Zp4unmHgw30A1eWI5EpACji2qMocisdXhAftfhXoSV9j0Tvj6nRFE3tOmRY912E0FMRm/L5xWE7MGVT2FoLnw== - -babel-plugin-syntax-exponentiation-operator@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" - integrity sha512-Z/flU+T9ta0aIEKl1tGEmN/pZiI1uXmCiGFRegKacQfEJzp7iNsKloZmyJlQr+75FCJtiFfGIK03SiCvCt9cPQ== - -babel-plugin-syntax-trailing-function-commas@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" - integrity sha512-Gx9CH3Q/3GKbhs07Bszw5fPTlU+ygrOGfAhEt7W2JICwufpC4SuO0mG0+4NykPBSYPMJhqvVlDBU17qB1D+hMQ== - -babel-plugin-transform-async-to-generator@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" - integrity sha512-7BgYJujNCg0Ti3x0c/DL3tStvnKS6ktIYOmo9wginv/dfZOrbSZ+qG4IRRHMBOzZ5Awb1skTiAsQXg/+IWkZYw== - dependencies: - babel-helper-remap-async-to-generator "^6.24.1" - babel-plugin-syntax-async-functions "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-arrow-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" - integrity sha512-PCqwwzODXW7JMrzu+yZIaYbPQSKjDTAsNNlK2l5Gg9g4rz2VzLnZsStvp/3c46GfXpwkyufb3NCyG9+50FF1Vg== - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" - integrity sha512-2+ujAT2UMBzYFm7tidUsYh+ZoIutxJ3pN9IYrF1/H6dCKtECfhmB8UkHVpyxDwkj0CYbQG35ykoz925TUnBc3A== - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-block-scoping@^6.23.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" - integrity sha512-YiN6sFAQ5lML8JjCmr7uerS5Yc/EMbgg9G8ZNmk2E3nYX4ckHR01wrkeeMijEf5WHNK5TW0Sl0Uu3pv3EdOJWw== - dependencies: - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-plugin-transform-es2015-classes@^6.23.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" - integrity sha512-5Dy7ZbRinGrNtmWpquZKZ3EGY8sDgIVB4CU8Om8q8tnMLrD/m94cKglVcHps0BCTdZ0TJeeAWOq2TK9MIY6cag== - dependencies: - babel-helper-define-map "^6.24.1" - babel-helper-function-name "^6.24.1" - babel-helper-optimise-call-expression "^6.24.1" - babel-helper-replace-supers "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-computed-properties@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" - integrity sha512-C/uAv4ktFP/Hmh01gMTvYvICrKze0XVX9f2PdIXuriCSvUmV9j+u+BB9f5fJK3+878yMK6dkdcq+Ymr9mrcLzw== - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-destructuring@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" - integrity sha512-aNv/GDAW0j/f4Uy1OEPZn1mqD+Nfy9viFGBfQ5bZyT35YqOiqx7/tXdyfZkJ1sC21NyEsBdfDY6PYmLHF4r5iA== - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-duplicate-keys@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" - integrity sha512-ossocTuPOssfxO2h+Z3/Ea1Vo1wWx31Uqy9vIiJusOP4TbF7tPs9U0sJ9pX9OJPf4lXRGj5+6Gkl/HHKiAP5ug== - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-for-of@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" - integrity sha512-DLuRwoygCoXx+YfxHLkVx5/NpeSbVwfoTeBykpJK7JhYWlL/O8hgAK/reforUnZDlxasOrVPPJVI/guE3dCwkw== - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-function-name@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" - integrity sha512-iFp5KIcorf11iBqu/y/a7DK3MN5di3pNCzto61FqCNnUX4qeBwcV1SLqe10oXNnCaxBUImX3SckX2/o1nsrTcg== - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" - integrity sha512-tjFl0cwMPpDYyoqYA9li1/7mGFit39XiNX5DKC/uCNjBctMxyL1/PT/l4rSlbvBG1pOKI88STRdUsWXB3/Q9hQ== - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" - integrity sha512-LnIIdGWIKdw7zwckqx+eGjcS8/cl8D74A3BpJbGjKTFFNJSMrjN4bIh22HY1AlkUbeLG6X6OZj56BDvWD+OeFA== - dependencies: - babel-plugin-transform-es2015-modules-commonjs "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: - version "6.26.2" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" - integrity sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q== - dependencies: - babel-plugin-transform-strict-mode "^6.24.1" - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-types "^6.26.0" - -babel-plugin-transform-es2015-modules-systemjs@^6.23.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" - integrity sha512-ONFIPsq8y4bls5PPsAWYXH/21Hqv64TBxdje0FvU3MhIV6QM2j5YS7KvAzg/nTIVLot2D2fmFQrFWCbgHlFEjg== - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-modules-umd@^6.23.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" - integrity sha512-LpVbiT9CLsuAIp3IG0tfbVo81QIhn6pE8xBJ7XSeCtFlMltuar5VuBV6y6Q45tpui9QWcy5i0vLQfCfrnF7Kiw== - dependencies: - babel-plugin-transform-es2015-modules-amd "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-object-super@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" - integrity sha512-8G5hpZMecb53vpD3mjs64NhI1au24TAmokQ4B+TBFBjN9cVoGoOvotdrMMRmHvVZUEvqGUPWL514woru1ChZMA== - dependencies: - babel-helper-replace-supers "^6.24.1" - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-parameters@^6.23.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" - integrity sha512-8HxlW+BB5HqniD+nLkQ4xSAVq3bR/pcYW9IigY+2y0dI+Y7INFeTbfAQr+63T3E4UDsZGjyb+l9txUnABWxlOQ== - dependencies: - babel-helper-call-delegate "^6.24.1" - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-shorthand-properties@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" - integrity sha512-mDdocSfUVm1/7Jw/FIRNw9vPrBQNePy6wZJlR8HAUBLybNp1w/6lr6zZ2pjMShee65t/ybR5pT8ulkLzD1xwiw== - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-spread@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" - integrity sha512-3Ghhi26r4l3d0Js933E5+IhHwk0A1yiutj9gwvzmFbVV0sPMYk2lekhOufHBswX7NCoSeF4Xrl3sCIuSIa+zOg== - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-sticky-regex@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" - integrity sha512-CYP359ADryTo3pCsH0oxRo/0yn6UsEZLqYohHmvLQdfS9xkf+MbCzE3/Kolw9OYIY4ZMilH25z/5CbQbwDD+lQ== - dependencies: - babel-helper-regex "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-template-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" - integrity sha512-x8b9W0ngnKzDMHimVtTfn5ryimars1ByTqsfBDwAqLibmuuQY6pgBQi5z1ErIsUOWBdw1bW9FSz5RZUojM4apg== - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-typeof-symbol@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" - integrity sha512-fz6J2Sf4gYN6gWgRZaoFXmq93X+Li/8vf+fb0sGDVtdeWvxC9y5/bTD7bvfWMEq6zetGEHpWjtzRGSugt5kNqw== - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-unicode-regex@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" - integrity sha512-v61Dbbihf5XxnYjtBN04B/JBvsScY37R1cZT5r9permN1cp+b70DY3Ib3fIkgn1DI9U3tGgBJZVD8p/mE/4JbQ== - dependencies: - babel-helper-regex "^6.24.1" - babel-runtime "^6.22.0" - regexpu-core "^2.0.0" - -babel-plugin-transform-exponentiation-operator@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" - integrity sha512-LzXDmbMkklvNhprr20//RStKVcT8Cu+SQtX18eMHLhjHf2yFzwtQ0S2f0jQ+89rokoNdmwoSqYzAhq86FxlLSQ== - dependencies: - babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" - babel-plugin-syntax-exponentiation-operator "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-regenerator@^6.22.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" - integrity sha512-LS+dBkUGlNR15/5WHKe/8Neawx663qttS6AGqoOUhICc9d1KciBvtrQSuc0PI+CxQ2Q/S1aKuJ+u64GtLdcEZg== - dependencies: - regenerator-transform "^0.10.0" - -babel-plugin-transform-strict-mode@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" - integrity sha512-j3KtSpjyLSJxNoCDrhwiJad8kw0gJ9REGj8/CqL0HeRyLnvUNYV9zcqluL6QJSXh3nfsLEmSLvwRfGzrgR96Pw== - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - babel-preset-current-node-syntax@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" @@ -3917,42 +3894,6 @@ babel-preset-current-node-syntax@^1.0.0: "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-top-level-await" "^7.8.3" -babel-preset-env@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a" - integrity sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg== - dependencies: - babel-plugin-check-es2015-constants "^6.22.0" - babel-plugin-syntax-trailing-function-commas "^6.22.0" - babel-plugin-transform-async-to-generator "^6.22.0" - babel-plugin-transform-es2015-arrow-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoping "^6.23.0" - babel-plugin-transform-es2015-classes "^6.23.0" - babel-plugin-transform-es2015-computed-properties "^6.22.0" - babel-plugin-transform-es2015-destructuring "^6.23.0" - babel-plugin-transform-es2015-duplicate-keys "^6.22.0" - babel-plugin-transform-es2015-for-of "^6.23.0" - babel-plugin-transform-es2015-function-name "^6.22.0" - babel-plugin-transform-es2015-literals "^6.22.0" - babel-plugin-transform-es2015-modules-amd "^6.22.0" - babel-plugin-transform-es2015-modules-commonjs "^6.23.0" - babel-plugin-transform-es2015-modules-systemjs "^6.23.0" - babel-plugin-transform-es2015-modules-umd "^6.23.0" - babel-plugin-transform-es2015-object-super "^6.22.0" - babel-plugin-transform-es2015-parameters "^6.23.0" - babel-plugin-transform-es2015-shorthand-properties "^6.22.0" - babel-plugin-transform-es2015-spread "^6.22.0" - babel-plugin-transform-es2015-sticky-regex "^6.22.0" - babel-plugin-transform-es2015-template-literals "^6.22.0" - babel-plugin-transform-es2015-typeof-symbol "^6.23.0" - babel-plugin-transform-es2015-unicode-regex "^6.22.0" - babel-plugin-transform-exponentiation-operator "^6.22.0" - babel-plugin-transform-regenerator "^6.22.0" - browserslist "^3.2.6" - invariant "^2.2.2" - semver "^5.3.0" - babel-preset-jest@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" @@ -3961,20 +3902,7 @@ babel-preset-jest@^29.6.3: babel-plugin-jest-hoist "^29.6.3" babel-preset-current-node-syntax "^1.0.0" -babel-register@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" - integrity sha512-veliHlHX06wjaeY8xNITbveXSiI+ASFnOqvne/LaIJIqOWi2Ogmj91KOugEz/hoh/fwMhXNBJPCv8Xaz5CyM4A== - dependencies: - babel-core "^6.26.0" - babel-runtime "^6.26.0" - core-js "^2.5.0" - home-or-tmp "^2.0.0" - lodash "^4.17.4" - mkdirp "^0.5.1" - source-map-support "^0.4.15" - -babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: +babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" integrity sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g== @@ -3982,68 +3910,12 @@ babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: core-js "^2.4.0" regenerator-runtime "^0.11.0" -babel-template@^6.24.1, babel-template@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" - integrity sha512-PCOcLFW7/eazGUKIoqH97sO9A2UYMahsn/yRQ7uOk37iutwjq7ODtcTNF+iFDSHNfkctqsLRjLP7URnOx0T1fg== - dependencies: - babel-runtime "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - lodash "^4.17.4" - -babel-traverse@^6.24.1, babel-traverse@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" - integrity sha512-iSxeXx7apsjCHe9c7n8VtRXGzI2Bk1rBSOJgCCjfyXb6v1aCqE1KSEpq/8SXuVN8Ka/Rh1WDTF0MDzkvTA4MIA== - dependencies: - babel-code-frame "^6.26.0" - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - debug "^2.6.8" - globals "^9.18.0" - invariant "^2.2.2" - lodash "^4.17.4" - -babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" - integrity sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g== - dependencies: - babel-runtime "^6.26.0" - esutils "^2.0.2" - lodash "^4.17.4" - to-fast-properties "^1.0.3" - -babelify@^7.3.0: - version "7.3.0" - resolved "https://registry.yarnpkg.com/babelify/-/babelify-7.3.0.tgz#aa56aede7067fd7bd549666ee16dc285087e88e5" - integrity sha512-vID8Fz6pPN5pJMdlUnNFSfrlcx5MUule4k9aKs/zbZPyXxMTcRrB0M4Tarw22L8afr8eYSWxDPYCob3TdrqtlA== - dependencies: - babel-core "^6.0.14" - object-assign "^4.0.0" - -babylon@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" - integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== - -backoff@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/backoff/-/backoff-2.5.0.tgz#f616eda9d3e4b66b8ca7fca79f695722c5f8e26f" - integrity sha512-wC5ihrnUXmR2douXmXLCe5O3zg3GKIyvRi/hi58a/XyRxVI+3/yM0PYueQOZXPXQ9pxBislYkw+sF9b7C/RuMA== - dependencies: - precond "0.2" - balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base-x@^3.0.2, base-x@^3.0.8: +base-x@^3.0.2: version "3.0.9" resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== @@ -4055,19 +3927,6 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - bcrypt-pbkdf@^1.0.0, bcrypt-pbkdf@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" @@ -4100,16 +3959,15 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -bip39@2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/bip39/-/bip39-2.5.0.tgz#51cbd5179460504a63ea3c000db3f787ca051235" - integrity sha512-xwIx/8JKoT2+IPJpFEfXoWdYwP7UVAoUxxLNfGCfVowaJE7yg1Y5B1BVPqlUNsBq5/nGwmFkwRJ8xDW4sX8OdA== +bip39@3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/bip39/-/bip39-3.0.4.tgz#5b11fed966840b5e1b8539f0f54ab6392969b2a0" + integrity sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw== dependencies: + "@types/node" "11.11.6" create-hash "^1.1.0" pbkdf2 "^3.0.9" randombytes "^2.0.1" - safe-buffer "^5.0.1" - unorm "^1.3.3" bl@^1.0.0: version "1.2.3" @@ -4133,11 +3991,6 @@ blakejs@^1.1.0: resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== -bluebird@^3.5.0, bluebird@^3.5.2: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - bn-str-256@^1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/bn-str-256/-/bn-str-256-1.9.1.tgz#898cebee70a3edc3968f97b4cebbc4771025aa82" @@ -4151,51 +4004,20 @@ bn.js@4.11.6: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" integrity sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA== -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.10.0, bn.js@^4.11.0, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.11.9, bn.js@^4.8.0: +bn.js@^4.0.0, bn.js@^4.11.0, bn.js@^4.11.1, bn.js@^4.11.8, bn.js@^4.11.9: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== -bn.js@^5.0.0, bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: +bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== -body-parser@1.20.1: - version "1.20.1" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" - integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== - dependencies: - bytes "3.1.2" - content-type "~1.0.4" - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - http-errors "2.0.0" - iconv-lite "0.4.24" - on-finished "2.4.1" - qs "6.11.0" - raw-body "2.5.1" - type-is "~1.6.18" - unpipe "1.0.0" - -body-parser@^1.16.0: - version "1.20.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" - integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== - dependencies: - bytes "3.1.2" - content-type "~1.0.5" - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - http-errors "2.0.0" - iconv-lite "0.4.24" - on-finished "2.4.1" - qs "6.11.0" - raw-body "2.5.2" - type-is "~1.6.18" - unpipe "1.0.0" +boolbase@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== bplist-parser@^0.2.0: version "0.2.0" @@ -4219,22 +4041,6 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -4262,7 +4068,7 @@ browser-stdout@1.3.1: resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== -browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.2.0: +browserify-aes@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== @@ -4274,56 +4080,6 @@ browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.2.0: inherits "^2.0.1" safe-buffer "^5.0.1" -browserify-cipher@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -browserify-rsa@^4.0.0, browserify-rsa@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" - integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== - dependencies: - bn.js "^5.0.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.2.2" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.2.tgz#e78d4b69816d6e3dd1c747e64e9947f9ad79bc7e" - integrity sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg== - dependencies: - bn.js "^5.2.1" - browserify-rsa "^4.1.0" - create-hash "^1.2.0" - create-hmac "^1.1.7" - elliptic "^6.5.4" - inherits "^2.0.4" - parse-asn1 "^5.1.6" - readable-stream "^3.6.2" - safe-buffer "^5.2.1" - -browserslist@^3.2.6: - version "3.2.8" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" - integrity sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ== - dependencies: - caniuse-lite "^1.0.30000844" - electron-to-chromium "^1.3.47" - browserslist@^4.21.9: version "4.22.1" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.1.tgz#ba91958d1a59b87dab6fed8dfbcb3da5e2e9c619" @@ -4397,11 +4153,6 @@ buffer-reverse@^1.0.1: resolved "https://registry.yarnpkg.com/buffer-reverse/-/buffer-reverse-1.0.1.tgz#49283c8efa6f901bc01fa3304d06027971ae2f60" integrity sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg== -buffer-to-arraybuffer@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz#6064a40fa76eb43c723aba9ef8f6e1216d10511a" - integrity sha512-3dthu5CYiVB1DEJp61FtApNnNndTckcqe4pFcLdvHtrpG+kcyekCJKg4MRiDcFW7A6AODnXB9U4dwQiCW5kzJQ== - buffer-writer@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" @@ -4419,7 +4170,7 @@ buffer-xor@^2.0.1: dependencies: safe-buffer "^5.1.1" -buffer@^5.0.5, buffer@^5.2.1, buffer@^5.5.0, buffer@^5.6.0: +buffer@^5.5.0, buffer@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== @@ -4435,10 +4186,10 @@ buffer@^6.0.3: base64-js "^1.3.1" ieee754 "^1.2.1" -bufferutil@^4.0.1: - version "4.0.8" - resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.8.tgz#1de6a71092d65d7766c4d8a522b261a6e787e8ea" - integrity sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw== +bufferutil@4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.5.tgz#da9ea8166911cc276bf677b8aed2d02d31f59028" + integrity sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A== dependencies: node-gyp-build "^4.3.0" @@ -4459,76 +4210,7 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -bytewise-core@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/bytewise-core/-/bytewise-core-1.2.3.tgz#3fb410c7e91558eb1ab22a82834577aa6bd61d42" - integrity sha512-nZD//kc78OOxeYtRlVk8/zXqTB4gf/nlguL1ggWA8FuchMyOxcyHR4QPQZMUmA7czC+YnaBrPUCubqAWe50DaA== - dependencies: - typewise-core "^1.2" - -bytewise@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/bytewise/-/bytewise-1.1.0.tgz#1d13cbff717ae7158094aa881b35d081b387253e" - integrity sha512-rHuuseJ9iQ0na6UDhnrRVDh8YnWVlU6xM3VH6q/+yHDeUH2zIhUzP+2/h3LIrhLDBtTqzWpE3p3tP/boefskKQ== - dependencies: - bytewise-core "^1.2.2" - typewise "^1.0.3" - -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - -cacheable-lookup@^5.0.3: - version "5.0.4" - resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" - integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== - -cacheable-request@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" - integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^3.0.0" - lowercase-keys "^2.0.0" - normalize-url "^4.1.0" - responselike "^1.0.2" - -cacheable-request@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817" - integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg== - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^4.0.0" - lowercase-keys "^2.0.0" - normalize-url "^6.0.1" - responselike "^2.0.0" - -cachedown@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/cachedown/-/cachedown-1.0.0.tgz#d43f036e4510696b31246d7db31ebf0f7ac32d15" - integrity sha512-t+yVk82vQWCJF3PsWHMld+jhhjkkWjcAzz8NbFx1iULOXWl8Tm/FdM4smZNVw3MRr0X+lVTx9PKzvEn4Ng19RQ== - dependencies: - abstract-leveldown "^2.4.1" - lru-cache "^3.2.0" - -call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5, call-bind@~1.0.2: +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== @@ -4537,16 +4219,11 @@ call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5, call-bin get-intrinsic "^1.2.1" set-function-length "^1.1.1" -callsites@^3.0.0: +callsites@^3.0.0, callsites@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camelcase@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" - integrity sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg== - camelcase@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" @@ -4557,11 +4234,6 @@ camelcase@^6.0.0, camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30000844: - version "1.0.30001570" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001570.tgz#b4e5c1fa786f733ab78fc70f592df6b3f23244ca" - integrity sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw== - caniuse-lite@^1.0.30001541: version "1.0.30001558" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001558.tgz#d2c6e21fdbfe83817f70feab902421a19b7983ee" @@ -4577,7 +4249,7 @@ caseless@^0.12.0, caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== -catering@^2.1.0, catering@^2.1.1: +catering@^2.0.0, catering@^2.1.0, catering@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== @@ -4596,6 +4268,19 @@ chai-as-promised@^7.1.1: dependencies: check-error "^1.0.2" +chai@^4.3.10: + version "4.4.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.4.0.tgz#f9ac79f26726a867ac9d90a9b382120479d5f55b" + integrity sha512-x9cHNq1uvkCdU+5xTkNh5WtgD4e4yDFCsp9jVc7N7qVeKeftv3gO/ZrviX5d+3ZfxdYnZXZYujjRInu1RogU6A== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" + pathval "^1.1.1" + type-detect "^4.0.8" + chai@^4.3.4: version "4.3.10" resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.10.tgz#d784cec635e3b7e2ffb66446a63b4e33bd390384" @@ -4609,6 +4294,13 @@ chai@^4.3.4: pathval "^1.1.1" type-detect "^4.0.8" +chalk-template@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/chalk-template/-/chalk-template-1.1.0.tgz#ffc55db6dd745e9394b85327c8ac8466edb7a7b1" + integrity sha512-T2VJbcDuZQ0Tb2EWwSotMPJjgpy1/tGee1BTpUNsGZ/qgNjV2t7Mvu+d4600U564nbLesN1x2dPL+xii174Ekg== + dependencies: + chalk "^5.2.0" + chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -4617,17 +4309,6 @@ chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A== - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -4637,6 +4318,11 @@ chalk@^2.4.1, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^5.2.0, chalk@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -4659,12 +4345,30 @@ check-error@^1.0.2, check-error@^1.0.3: dependencies: get-func-name "^2.0.2" -checkpoint-store@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/checkpoint-store/-/checkpoint-store-1.1.0.tgz#04e4cb516b91433893581e6d4601a78e9552ea06" - integrity sha512-J/NdY2WvIx654cc6LWSq/IYFFCUf75fFTgwzFnmbqyORH4MwgiQCgswLLKBGzmsyTI5V7i5bp/So6sMbDWhedg== - dependencies: - functional-red-black-tree "^1.0.1" +cheerio-select@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-2.1.0.tgz#4d8673286b8126ca2a8e42740d5e3c4884ae21b4" + integrity sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g== + dependencies: + boolbase "^1.0.0" + css-select "^5.1.0" + css-what "^6.1.0" + domelementtype "^2.3.0" + domhandler "^5.0.3" + domutils "^3.0.1" + +cheerio@^1.0.0-rc.10: + version "1.0.0-rc.12" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.12.tgz#788bf7466506b1c6bf5fae51d24a2c4d62e47683" + integrity sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q== + dependencies: + cheerio-select "^2.1.0" + dom-serializer "^2.0.0" + domhandler "^5.0.3" + domutils "^3.0.1" + htmlparser2 "^8.0.1" + parse5 "^7.0.0" + parse5-htmlparser2-tree-adapter "^7.0.0" chokidar@3.5.3, chokidar@^3.4.0: version "3.5.3" @@ -4681,7 +4385,7 @@ chokidar@3.5.3, chokidar@^3.4.0: optionalDependencies: fsevents "~2.3.2" -chownr@^1.0.1, chownr@^1.1.1, chownr@^1.1.4: +chownr@^1.0.1, chownr@^1.1.1: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== @@ -4696,17 +4400,6 @@ ci-info@^3.2.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== -cids@^0.7.1: - version "0.7.5" - resolved "https://registry.yarnpkg.com/cids/-/cids-0.7.5.tgz#60a08138a99bfb69b6be4ceb63bfef7a396b28b2" - integrity sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA== - dependencies: - buffer "^5.5.0" - class-is "^1.1.0" - multibase "~0.6.0" - multicodec "^1.0.0" - multihashes "~0.4.15" - cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -4720,21 +4413,6 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== -class-is@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825" - integrity sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw== - -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - classic-level@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/classic-level/-/classic-level-1.3.0.tgz#5e36680e01dc6b271775c093f2150844c5edd5c8" @@ -4751,6 +4429,14 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== +clear-module@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/clear-module/-/clear-module-4.1.2.tgz#5a58a5c9f8dccf363545ad7284cad3c887352a80" + integrity sha512-LWAxzHqdHsAZlPlEyJ2Poz6AIs384mPeqLVCru2p0BrP9G/kVGuhNyZYClLO6cXlnuJjzC8xtsJIuMjKqLXoAw== + dependencies: + parent-module "^2.0.0" + resolve-from "^5.0.0" + cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" @@ -4782,15 +4468,6 @@ cli-width@^2.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== -cliui@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" - integrity sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w== - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi "^2.0.0" - cliui@^7.0.2: version "7.0.4" resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" @@ -4809,18 +4486,6 @@ cliui@^8.0.1: strip-ansi "^6.0.1" wrap-ansi "^7.0.0" -clone-response@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3" - integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA== - dependencies: - mimic-response "^1.0.0" - -clone@2.1.2, clone@^2.0.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" - integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== - co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -4831,24 +4496,11 @@ code-block-writer@^12.0.0: resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-12.0.0.tgz#4dd58946eb4234105aff7f0035977b2afdc2a770" integrity sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w== -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA== - collect-v8-coverage@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw== - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - collections@^5.1.12: version "5.1.13" resolved "https://registry.yarnpkg.com/collections/-/collections-5.1.13.tgz#eee204a93b67473c8e74e00e934a997cc2817585" @@ -4906,16 +4558,41 @@ command-line-args@^4.0.7: find-replace "^1.0.3" typical "^2.6.1" +command-line-args@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.1.tgz#c44c32e437a57d7c51157696893c5909e9cec42e" + integrity sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg== + dependencies: + array-back "^3.1.0" + find-replace "^3.0.0" + lodash.camelcase "^4.3.0" + typical "^4.0.0" + +command-line-usage@^6.1.0: + version "6.1.3" + resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-6.1.3.tgz#428fa5acde6a838779dfa30e44686f4b6761d957" + integrity sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw== + dependencies: + array-back "^4.0.2" + chalk "^2.4.2" + table-layout "^1.0.2" + typical "^5.2.0" + commander@3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow== -commander@^10.0.0: +commander@^10.0.0, commander@^10.0.1: version "10.0.1" resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== +commander@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906" + integrity sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ== + commander@^2.19.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -4931,6 +4608,11 @@ commander@^8.1.0, commander@^8.3.0: resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== +commander@^9.4.1: + version "9.5.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" + integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== + commander@~2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" @@ -4943,17 +4625,23 @@ commander@~9.4.1: resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.1.tgz#d1dd8f2ce6faf93147295c0df13c7c21141cfbdd" integrity sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw== -component-emitter@^1.2.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.1.tgz#ef1d5796f7d93f135ee6fb684340b26403c97d17" - integrity sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ== +comment-json@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/comment-json/-/comment-json-4.2.3.tgz#50b487ebbf43abe44431f575ebda07d30d015365" + integrity sha512-SsxdiOf064DWoZLH799Ata6u7iV658A11PlWtZATDlXPpKGJnbJZ5Z24ybixAi+LUUqJ/GKowAejtC5GFUG7Tw== + dependencies: + array-timsort "^1.0.3" + core-util-is "^1.0.3" + esprima "^4.0.1" + has-own-prop "^2.0.0" + repeat-string "^1.6.1" concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -concat-stream@^1.5.1, concat-stream@^1.6.0, concat-stream@^1.6.2, concat-stream@~1.6.2: +concat-stream@^1.6.0, concat-stream@^1.6.2, concat-stream@~1.6.2: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== @@ -4963,68 +4651,33 @@ concat-stream@^1.5.1, concat-stream@^1.6.0, concat-stream@^1.6.2, concat-stream@ readable-stream "^2.2.2" typedarray "^0.0.6" -content-disposition@0.5.4: - version "0.5.4" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" - integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== - dependencies: - safe-buffer "5.2.1" - -content-hash@^2.5.2: - version "2.5.2" - resolved "https://registry.yarnpkg.com/content-hash/-/content-hash-2.5.2.tgz#bbc2655e7c21f14fd3bfc7b7d4bfe6e454c9e211" - integrity sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw== +configstore@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-6.0.0.tgz#49eca2ebc80983f77e09394a1a56e0aca8235566" + integrity sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA== dependencies: - cids "^0.7.1" - multicodec "^0.5.5" - multihashes "^0.4.15" - -content-type@~1.0.4, content-type@~1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" - integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== - -convert-source-map@^1.5.1: - version "1.9.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" - integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== + dot-prop "^6.0.1" + graceful-fs "^4.2.6" + unique-string "^3.0.0" + write-file-atomic "^3.0.3" + xdg-basedir "^5.0.1" convert-source-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== - -cookie@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" - integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== - cookie@^0.4.1: version "0.4.2" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== -cookiejar@^2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b" - integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw== - -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== - core-js-pure@^3.0.1: version "3.34.0" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.34.0.tgz#981e462500708664c91b827a75b011f04a8134a0" integrity sha512-pmhivkYXkymswFfbXsANmBAewXx86UBfmagP+w0wkK06kLsLlTK5oQmsURPivzMkIBQiYq2cjamcZExIwlFQIg== -core-js@^2.4.0, core-js@^2.5.0: +core-js@^2.4.0: version "2.6.12" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== @@ -5034,19 +4687,11 @@ core-util-is@1.0.2: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== -core-util-is@~1.0.0: +core-util-is@^1.0.3, core-util-is@~1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== -cors@^2.8.1: - version "2.8.5" - resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" - integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== - dependencies: - object-assign "^4" - vary "^1" - cosmiconfig@^8.0.0: version "8.3.6" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3" @@ -5070,14 +4715,6 @@ crc-32@^1.2.0: resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== -create-ecdh@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" - integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== - dependencies: - bn.js "^4.1.0" - elliptic "^6.5.3" - create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" @@ -5089,7 +4726,7 @@ create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: ripemd160 "^2.0.1" sha.js "^2.4.0" -create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: +create-hmac@^1.1.4, create-hmac@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== @@ -5119,14 +4756,6 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-fetch@^2.1.0, cross-fetch@^2.1.1: - version "2.2.6" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-2.2.6.tgz#2ef0bb39a24ac034787965c457368a28730e220a" - integrity sha512-9JZz+vXCmfKUZ68zAptS7k4Nu8e2qcibe7WVZYps7sAgk5R8GYTc+T1WR0v1rlP9HxgARmOX1UTIJZFytajpNA== - dependencies: - node-fetch "^2.6.7" - whatwg-fetch "^2.0.4" - cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -5138,7 +4767,7 @@ cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -5152,35 +4781,143 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3: resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== -crypto-browserify@3.12.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== +crypto-js@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" + integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== + +crypto-random-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-4.0.0.tgz#5a3cc53d7dd86183df5da0312816ceeeb5bb1fc2" + integrity sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA== dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" + type-fest "^1.0.1" -crypto-js@^3.1.9-1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.3.0.tgz#846dd1cce2f68aacfa156c8578f926a609b7976b" - integrity sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q== +cspell-config-lib@8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/cspell-config-lib/-/cspell-config-lib-8.3.2.tgz#050a6d782072a810cb6655efe11c08c80ae7636b" + integrity sha512-Wc98XhBNLwDxnxCzMtgRJALI9a69cu3C5Gf1rGjNTKSFo9JYiQmju0Ur3z25Pkx9Sa86f+2IjvNCf33rUDSoBQ== + dependencies: + "@cspell/cspell-types" "8.3.2" + comment-json "^4.2.3" + yaml "^2.3.4" -d@1, d@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" - integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== +cspell-dictionary@8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/cspell-dictionary/-/cspell-dictionary-8.3.2.tgz#6627a94501811a143f3b638e0e77f7262335dbd4" + integrity sha512-xyK95hO2BMPFxIo8zBwGml8035qOxSBdga1BMhwW/p2wDrQP8S4Cdm/54//tCDmKn6uRkFQvyOfWGaX2l8WMEg== + dependencies: + "@cspell/cspell-pipe" "8.3.2" + "@cspell/cspell-types" "8.3.2" + cspell-trie-lib "8.3.2" + fast-equals "^5.0.1" + gensequence "^6.0.0" + +cspell-gitignore@8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/cspell-gitignore/-/cspell-gitignore-8.3.2.tgz#5cf244be494bf87257ca8715ac88b0849dd5fef3" + integrity sha512-3Qc9P5BVvl/cg//s2s+zIMGKcoH5v7oOtRgwn4UQry8yiyo19h0tiTKkSR574FMhF5NtcShTnwIwPSIXVBPFHA== + dependencies: + cspell-glob "8.3.2" + find-up-simple "^1.0.0" + +cspell-glob@8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/cspell-glob/-/cspell-glob-8.3.2.tgz#4c208e4ddd5604d2871df534a3054c7a3fdc9998" + integrity sha512-KtIFxE+3l5dGEofND4/CdZffXP8XN1+XGQKxJ96lIzWsc01mkotfhxTkla6mgvfH039t7BsY/SWv0460KyGslQ== + dependencies: + micromatch "^4.0.5" + +cspell-grammar@8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/cspell-grammar/-/cspell-grammar-8.3.2.tgz#69d7980c036c206745d5d417d32c95edaaff6107" + integrity sha512-tYCkOmRzJe1a6/R+8QGSwG7TwTgznLPqsHtepKzLmnS4YX54VXjKRI9zMARxXDzUVfyCSVdW5MyiY/0WTNoy+A== dependencies: - es5-ext "^0.10.50" - type "^1.0.1" + "@cspell/cspell-pipe" "8.3.2" + "@cspell/cspell-types" "8.3.2" + +cspell-io@8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/cspell-io/-/cspell-io-8.3.2.tgz#8ddd865fa9a1391852e3288789f5b2a6613239bd" + integrity sha512-WYpKsyBCQP0SY4gXnhW5fPuxcYchKYKG1PIXVV3ezFU4muSgW6GuLNbGuSfwv/8YNXRgFSN0e3hYH0rdBK2Aow== + dependencies: + "@cspell/cspell-service-bus" "8.3.2" + +cspell-lib@8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/cspell-lib/-/cspell-lib-8.3.2.tgz#8225f8d3a20596bda4b9689a2ad958f7831f5a7d" + integrity sha512-wTvdaev/TyGB/ln6CVD1QbVs2D7/+QiajQ67S7yj1suLHM6YcNQQb/5sPAM8VPtj0E7PgwgPXf3bq18OtPvnFg== + dependencies: + "@cspell/cspell-bundled-dicts" "8.3.2" + "@cspell/cspell-pipe" "8.3.2" + "@cspell/cspell-resolver" "8.3.2" + "@cspell/cspell-types" "8.3.2" + "@cspell/dynamic-import" "8.3.2" + "@cspell/strong-weak-map" "8.3.2" + clear-module "^4.1.2" + comment-json "^4.2.3" + configstore "^6.0.0" + cspell-config-lib "8.3.2" + cspell-dictionary "8.3.2" + cspell-glob "8.3.2" + cspell-grammar "8.3.2" + cspell-io "8.3.2" + cspell-trie-lib "8.3.2" + fast-equals "^5.0.1" + gensequence "^6.0.0" + import-fresh "^3.3.0" + resolve-from "^5.0.0" + vscode-languageserver-textdocument "^1.0.11" + vscode-uri "^3.0.8" + +cspell-trie-lib@8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/cspell-trie-lib/-/cspell-trie-lib-8.3.2.tgz#e1e8c9926f41a094bec7f0af85b931be06019fe7" + integrity sha512-8qh2FqzkLMwzlTlvO/5Z+89fhi30rrfekocpight/BmqKbE2XFJQD7wS2ml24e7q/rdHJLXVpJbY/V5mByucCA== + dependencies: + "@cspell/cspell-pipe" "8.3.2" + "@cspell/cspell-types" "8.3.2" + gensequence "^6.0.0" + +cspell@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/cspell/-/cspell-8.3.2.tgz#56e7e919d87d38016b4c34b8c8ee745404c230a7" + integrity sha512-V8Ub3RO/a5lwSsltW/ib3Z3G/sczKtSpBBN1JChzbSCfEgaY2mJY8JW0BpkSV+Ug6uJitpXNOOaxa3Xr489i7g== + dependencies: + "@cspell/cspell-json-reporter" "8.3.2" + "@cspell/cspell-pipe" "8.3.2" + "@cspell/cspell-types" "8.3.2" + "@cspell/dynamic-import" "8.3.2" + chalk "^5.3.0" + chalk-template "^1.1.0" + commander "^11.1.0" + cspell-gitignore "8.3.2" + cspell-glob "8.3.2" + cspell-io "8.3.2" + cspell-lib "8.3.2" + fast-glob "^3.3.2" + fast-json-stable-stringify "^2.1.0" + file-entry-cache "^8.0.0" + get-stdin "^9.0.0" + semver "^7.5.4" + strip-ansi "^7.1.0" + vscode-uri "^3.0.8" + +css-select@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.1.0.tgz#b8ebd6554c3637ccc76688804ad3f6a6fdaea8a6" + integrity sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg== + dependencies: + boolbase "^1.0.0" + css-what "^6.1.0" + domhandler "^5.0.2" + domutils "^3.0.1" + nth-check "^2.0.1" + +css-what@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" + integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== dashdash@^1.12.0: version "1.14.1" @@ -5194,20 +4931,6 @@ death@^1.1.0: resolved "https://registry.yarnpkg.com/death/-/death-1.1.0.tgz#01aa9c401edd92750514470b8266390c66c67318" integrity sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w== -debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - debug@4, debug@4.3.4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" @@ -5222,6 +4945,13 @@ debug@4.3.3: dependencies: ms "2.1.2" +debug@^2.2.0: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + debug@^3.1.0, debug@^3.2.6, debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -5229,11 +4959,6 @@ debug@^3.1.0, debug@^3.2.6, debug@^3.2.7: dependencies: ms "^2.1.1" -decamelize@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== - decamelize@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" @@ -5244,25 +4969,6 @@ decimal.js-light@^2.5.0: resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz#134fd32508f19e208f4fb2f8dac0d2626a867934" integrity sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg== -decode-uri-component@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" - integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== - -decompress-response@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" - integrity sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA== - dependencies: - mimic-response "^1.0.0" - -decompress-response@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" - integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== - dependencies: - mimic-response "^3.1.0" - dedent@^1.0.0: version "1.5.1" resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" @@ -5275,19 +4981,7 @@ deep-eql@^4.0.1, deep-eql@^4.1.3: dependencies: type-detect "^4.0.0" -deep-equal@~1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.2.tgz#78a561b7830eef3134c7f6f3a3d6af272a678761" - integrity sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg== - dependencies: - is-arguments "^1.1.1" - is-date-object "^1.0.5" - is-regex "^1.1.4" - object-is "^1.1.5" - object-keys "^1.1.1" - regexp.prototype.flags "^1.5.1" - -deep-extend@^0.6.0: +deep-extend@^0.6.0, deep-extend@~0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== @@ -5325,29 +5019,12 @@ default-browser@^4.0.0: execa "^7.1.1" titleize "^3.0.0" -defer-to-connect@^1.0.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" - integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== - -defer-to-connect@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" - integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== - -deferred-leveldown@~1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-1.2.2.tgz#3acd2e0b75d1669924bc0a4b642851131173e1eb" - integrity sha512-uukrWD2bguRtXilKt6cAWKyoXrTSMo5m7crUdLfWQmu8kIm88w3QZoUL+6nhpfKVmhHANER6Re3sKoNoZ3IKMA== - dependencies: - abstract-leveldown "~2.6.0" - -deferred-leveldown@~4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-4.0.2.tgz#0b0570087827bf480a23494b398f04c128c19a20" - integrity sha512-5fMC8ek8alH16QiV0lTCis610D1Zt1+LA4MS4d63JgS32lrCjTFDUFz2ao09/j2I4Bqb5jL4FZYwu7Jz0XO1ww== +deferred-leveldown@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz#27a997ad95408b61161aa69bd489b86c71b78058" + integrity sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw== dependencies: - abstract-leveldown "~5.0.0" + abstract-leveldown "~6.2.1" inherits "^2.0.3" define-data-property@^1.0.1, define-data-property@^1.1.1: @@ -5373,33 +5050,6 @@ define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: has-property-descriptors "^1.0.0" object-keys "^1.1.1" -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA== - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA== - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - -defined@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.1.tgz#c0b9db27bfaffd95d6f61399419b893df0f91ebf" - integrity sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q== - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -5410,26 +5060,6 @@ depd@2.0.0: resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== -des.js@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.1.0.tgz#1d37f5766f3bbff4ee9638e871a8768c173b81da" - integrity sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg== - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -destroy@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" - integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== - -detect-indent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" - integrity sha512-BDKtmHlOzwI7iRuEkhzsnPoi5ypEhWAJB5RvHWe1kMr06js3uK5B3734i3ui5Yd+wOJV1cpE4JnivPD283GU/A== - dependencies: - repeating "^2.0.0" - detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" @@ -5458,15 +5088,6 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== -diffie-hellman@^5.0.0: - version "5.0.3" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - difflib@^0.2.4: version "0.2.4" resolved "https://registry.yarnpkg.com/difflib/-/difflib-0.2.4.tgz#b5e30361a6db023176d562892db85940a718f47e" @@ -5506,6 +5127,16 @@ docker-modem@^3.0.0: split-ca "^1.0.1" ssh2 "^1.11.0" +docker-modem@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/docker-modem/-/docker-modem-5.0.2.tgz#d119282d85679a8e7bc788e620093f1348658b5d" + integrity sha512-1Nwtxsk3D6CMj7ovGxSj/r3cEw2EVcT4AsAOdKngDVn2mENnRdq5tIgwpjecgdEtPhd7U5Ww39FNzxo8k++ESw== + dependencies: + debug "^4.1.1" + readable-stream "^3.5.0" + split-ca "^1.0.1" + ssh2 "^1.11.0" + dockerode@^2.5.8: version "2.5.8" resolved "https://registry.yarnpkg.com/dockerode/-/dockerode-2.5.8.tgz#1b661e36e1e4f860e25f56e0deabe9f87f1d0acc" @@ -5524,6 +5155,15 @@ dockerode@^3.3.4: docker-modem "^3.0.0" tar-fs "~2.0.1" +dockerode@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/dockerode/-/dockerode-4.0.1.tgz#c1d4dad585c14f091a34aed394c63fb67e986c30" + integrity sha512-2TGh2Sb/r4X9xVVjtcfDoxIYLYdBI3cFCK1OApLfDW+iNdGWAdHq8wJU/CGqueOTYF1JBflUSFVPy2gw8NAJoA== + dependencies: + "@balena/dockerignore" "^1.0.2" + docker-modem "^5.0.2" + tar-fs "~2.0.1" + doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" @@ -5538,10 +5178,42 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -dom-walk@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" - integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== +dom-serializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" + integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + entities "^4.2.0" + +domelementtype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== + +domhandler@^5.0.2, domhandler@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" + integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== + dependencies: + domelementtype "^2.3.0" + +domutils@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e" + integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA== + dependencies: + dom-serializer "^2.0.0" + domelementtype "^2.3.0" + domhandler "^5.0.3" + +dot-prop@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083" + integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA== + dependencies: + is-obj "^2.0.0" dotenv@^16.0.3: version "16.3.1" @@ -5553,17 +5225,10 @@ dotenv@^8.2.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== -dotignore@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/dotignore/-/dotignore-0.1.2.tgz#f942f2200d28c3a76fbdd6f0ee9f3257c8a2e905" - integrity sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw== - dependencies: - minimatch "^3.0.4" - -duplexer3@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.5.tgz#0b5e4d7bad5de8901ea4440624c8e1d20099217e" - integrity sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA== +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== ecc-jsbn@~0.1.1: version "0.1.2" @@ -5580,22 +5245,12 @@ ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer "^5.0.1" -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== - -electron-to-chromium@^1.3.47: - version "1.4.611" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.611.tgz#92d3a8f03110fbf5f99b054da97825f994fa480a" - integrity sha512-ZtRpDxrjHapOwxtv+nuth5ByB8clyn8crVynmRNGO3wG3LOp8RTcyZDqwaI6Ng6y8FCK2hVZmJoqwCskKbNMaw== - electron-to-chromium@^1.4.535: version "1.4.569" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.569.tgz#1298b67727187ffbaac005a7425490d157f3ad03" integrity sha512-LsrJjZ0IbVy12ApW3gpYpcmHS3iRxH4bkKOW98y1/D+3cvDUWGcbzbsFinfUS8knpcZk/PG/2p/RnkMCYN7PVg== -elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.2, elliptic@^6.5.3, elliptic@^6.5.4: +elliptic@6.5.4, elliptic@^6.5.2, elliptic@^6.5.4: version "6.5.4" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== @@ -5608,6 +5263,11 @@ elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.2, elliptic@^6.5.3, elliptic@^6.5 minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" +emittery@0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.0.tgz#bb373c660a9d421bb44706ec4967ed50c02a8026" + integrity sha512-AGvFfs+d0JKCJQ4o01ASQLGPmSCxgfU9RFXvzPvZdjKK8oscynksuJhWrSTSw7j7Ep/sZct5b5ZhYCi8S/t0HQ== + emittery@^0.13.1: version "0.13.1" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" @@ -5623,28 +5283,20 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== -encoding-down@5.0.4, encoding-down@~5.0.0: - version "5.0.4" - resolved "https://registry.yarnpkg.com/encoding-down/-/encoding-down-5.0.4.tgz#1e477da8e9e9d0f7c8293d320044f8b2cd8e9614" - integrity sha512-8CIZLDcSKxgzT+zX8ZVfgNbu8Md2wq/iqa1Y7zyVR18QBEAc0Nmzuvj/N5ykSKpfGzjM8qxbaFntLPwnVoUhZw== +encoding-down@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/encoding-down/-/encoding-down-6.3.0.tgz#b1c4eb0e1728c146ecaef8e32963c549e76d082b" + integrity sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw== dependencies: - abstract-leveldown "^5.0.0" + abstract-leveldown "^6.2.1" inherits "^2.0.3" level-codec "^9.0.0" level-errors "^2.0.0" - xtend "^4.0.1" - -encoding@^0.1.11: - version "0.1.13" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" - integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== - dependencies: - iconv-lite "^0.6.2" end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" @@ -5669,6 +5321,11 @@ enquirer@^2.3.0, enquirer@^2.3.5: ansi-colors "^4.1.1" strip-ansi "^6.0.1" +entities@^4.2.0, entities@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + entities@~2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f" @@ -5691,7 +5348,7 @@ errno@~0.1.1: dependencies: prr "~1.0.1" -error-ex@^1.2.0, error-ex@^1.3.1: +error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== @@ -5743,11 +5400,6 @@ es-abstract@^1.22.1: unbox-primitive "^1.0.2" which-typed-array "^1.1.13" -es-array-method-boxes-properly@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" - integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== - es-set-tostringtag@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9" @@ -5773,53 +5425,22 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -es5-ext@^0.10.35, es5-ext@^0.10.50: - version "0.10.62" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5" - integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA== - dependencies: - es6-iterator "^2.0.3" - es6-symbol "^3.1.3" - next-tick "^1.1.0" - -es6-iterator@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g== - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - es6-promisify@^6.0.0: version "6.1.1" resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.1.1.tgz#46837651b7b06bf6fff893d03f29393668d01621" integrity sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg== -es6-symbol@^3.1.1, es6-symbol@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" - integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== - dependencies: - d "^1.0.1" - ext "^1.1.2" - escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== - escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== @@ -6057,7 +5678,7 @@ esprima@2.7.x, esprima@^2.7.1: resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" integrity sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A== -esprima@^4.0.0: +esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== @@ -6096,32 +5717,6 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== - -eth-block-tracker@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-3.0.1.tgz#95cd5e763c7293e0b1b2790a2a39ac2ac188a5e1" - integrity sha512-WUVxWLuhMmsfenfZvFO5sbl1qFY2IqUlw/FPVmjjdElpqLsZtSG+wPe9Dz7W/sB6e80HgFKknOmKk2eNlznHug== - dependencies: - eth-query "^2.1.0" - ethereumjs-tx "^1.3.3" - ethereumjs-util "^5.1.3" - ethjs-util "^0.1.3" - json-rpc-engine "^3.6.0" - pify "^2.3.0" - tape "^4.6.3" - -eth-ens-namehash@2.0.8, eth-ens-namehash@^2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz#229ac46eca86d52e0c991e7cb2aef83ff0f68bcf" - integrity sha512-VWEI1+KJfz4Km//dadyvBBoBeSQ0MHTXPvr8UIXiLW6IanxvAV+DmlZAijZwAyggqGUfwQBeHf7tc9wzc1piSw== - dependencies: - idna-uts46-hx "^2.3.1" - js-sha3 "^0.5.7" - eth-gas-reporter@^0.2.25: version "0.2.27" resolved "https://registry.yarnpkg.com/eth-gas-reporter/-/eth-gas-reporter-0.2.27.tgz#928de8548a674ed64c7ba0bf5795e63079150d4e" @@ -6141,110 +5736,6 @@ eth-gas-reporter@^0.2.25: sha1 "^1.1.1" sync-request "^6.0.0" -eth-json-rpc-infura@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/eth-json-rpc-infura/-/eth-json-rpc-infura-3.2.1.tgz#26702a821067862b72d979c016fd611502c6057f" - integrity sha512-W7zR4DZvyTn23Bxc0EWsq4XGDdD63+XPUCEhV2zQvQGavDVC4ZpFDK4k99qN7bd7/fjj37+rxmuBOBeIqCA5Mw== - dependencies: - cross-fetch "^2.1.1" - eth-json-rpc-middleware "^1.5.0" - json-rpc-engine "^3.4.0" - json-rpc-error "^2.0.0" - -eth-json-rpc-middleware@^1.5.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz#5c9d4c28f745ccb01630f0300ba945f4bef9593f" - integrity sha512-tDVCTlrUvdqHKqivYMjtFZsdD7TtpNLBCfKAcOpaVs7orBMS/A8HWro6dIzNtTZIR05FAbJ3bioFOnZpuCew9Q== - dependencies: - async "^2.5.0" - eth-query "^2.1.2" - eth-tx-summary "^3.1.2" - ethereumjs-block "^1.6.0" - ethereumjs-tx "^1.3.3" - ethereumjs-util "^5.1.2" - ethereumjs-vm "^2.1.0" - fetch-ponyfill "^4.0.0" - json-rpc-engine "^3.6.0" - json-rpc-error "^2.0.0" - json-stable-stringify "^1.0.1" - promise-to-callback "^1.0.0" - tape "^4.6.3" - -eth-lib@0.2.8: - version "0.2.8" - resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.8.tgz#b194058bef4b220ad12ea497431d6cb6aa0623c8" - integrity sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw== - dependencies: - bn.js "^4.11.6" - elliptic "^6.4.0" - xhr-request-promise "^0.1.2" - -eth-lib@^0.1.26: - version "0.1.29" - resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.1.29.tgz#0c11f5060d42da9f931eab6199084734f4dbd1d9" - integrity sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ== - dependencies: - bn.js "^4.11.6" - elliptic "^6.4.0" - nano-json-stream-parser "^0.1.2" - servify "^0.1.12" - ws "^3.0.0" - xhr-request-promise "^0.1.2" - -eth-query@^2.0.2, eth-query@^2.1.0, eth-query@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/eth-query/-/eth-query-2.1.2.tgz#d6741d9000106b51510c72db92d6365456a6da5e" - integrity sha512-srES0ZcvwkR/wd5OQBRA1bIJMww1skfGS0s8wlwK3/oNP4+wnds60krvu5R1QbpRQjMmpG5OMIWro5s7gvDPsA== - dependencies: - json-rpc-random-id "^1.0.0" - xtend "^4.0.1" - -eth-sig-util@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eth-sig-util/-/eth-sig-util-3.0.0.tgz#75133b3d7c20a5731af0690c385e184ab942b97e" - integrity sha512-4eFkMOhpGbTxBQ3AMzVf0haUX2uTur7DpWiHzWyTURa28BVJJtOkcb9Ok5TV0YvEPG61DODPW7ZUATbJTslioQ== - dependencies: - buffer "^5.2.1" - elliptic "^6.4.0" - ethereumjs-abi "0.6.5" - ethereumjs-util "^5.1.1" - tweetnacl "^1.0.0" - tweetnacl-util "^0.15.0" - -eth-sig-util@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/eth-sig-util/-/eth-sig-util-1.4.2.tgz#8d958202c7edbaae839707fba6f09ff327606210" - integrity sha512-iNZ576iTOGcfllftB73cPB5AN+XUQAT/T8xzsILsghXC1o8gJUqe3RHlcDqagu+biFpYQ61KQrZZJza8eRSYqw== - dependencies: - ethereumjs-abi "git+https://github.com/ethereumjs/ethereumjs-abi.git" - ethereumjs-util "^5.1.1" - -eth-tx-summary@^3.1.2: - version "3.2.4" - resolved "https://registry.yarnpkg.com/eth-tx-summary/-/eth-tx-summary-3.2.4.tgz#e10eb95eb57cdfe549bf29f97f1e4f1db679035c" - integrity sha512-NtlDnaVZah146Rm8HMRUNMgIwG/ED4jiqk0TME9zFheMl1jOp6jL1m0NKGjJwehXQ6ZKCPr16MTr+qspKpEXNg== - dependencies: - async "^2.1.2" - clone "^2.0.0" - concat-stream "^1.5.1" - end-of-stream "^1.1.0" - eth-query "^2.0.2" - ethereumjs-block "^1.4.1" - ethereumjs-tx "^1.1.1" - ethereumjs-util "^5.0.1" - ethereumjs-vm "^2.6.0" - through2 "^2.0.3" - -ethashjs@~0.0.7: - version "0.0.8" - resolved "https://registry.yarnpkg.com/ethashjs/-/ethashjs-0.0.8.tgz#227442f1bdee409a548fb04136e24c874f3aa6f9" - integrity sha512-/MSbf/r2/Ld8o0l15AymjOTlPqpN8Cr4ByUEA9GtR4x0yAh3TdtDzEg29zMjXCNPI7u6E5fOQdj/Cf9Tc7oVNw== - dependencies: - async "^2.1.2" - buffer-xor "^2.0.1" - ethereumjs-util "^7.0.2" - miller-rabin "^4.0.0" - ethereum-bloom-filters@^1.0.6: version "1.0.10" resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz#3ca07f4aed698e75bd134584850260246a5fed8a" @@ -6252,16 +5743,6 @@ ethereum-bloom-filters@^1.0.6: dependencies: js-sha3 "^0.8.0" -ethereum-common@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.2.0.tgz#13bf966131cce1eeade62a1b434249bb4cb120ca" - integrity sha512-XOnAR/3rntJgbCdGhqdaLIxDLWKLmsZOGhHdBKadEr6gEnJLH52k93Ou+TUdFaPN3hJc3isBZBal3U/XZ15abA== - -ethereum-common@^0.0.18: - version "0.0.18" - resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.0.18.tgz#2fdc3576f232903358976eb39da783213ff9523f" - integrity sha512-EoltVQTRNg2Uy4o84qpa2aXymXDJhxm7eos/ACOg0DG4baAbMjhbdAEsx9GeE8sC3XCxnYvrrzZDH8D8MtA2iQ== - ethereum-cryptography@0.1.3, ethereum-cryptography@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191" @@ -6303,24 +5784,17 @@ ethereum-cryptography@^2.0.0, ethereum-cryptography@^2.1.2: "@scure/bip32" "1.3.1" "@scure/bip39" "1.2.1" -ethereum-waffle@^3.0.0: - version "3.4.4" - resolved "https://registry.yarnpkg.com/ethereum-waffle/-/ethereum-waffle-3.4.4.tgz#1378b72040697857b7f5e8f473ca8f97a37b5840" - integrity sha512-PA9+jCjw4WC3Oc5ocSMBj5sXvueWQeAbvCA+hUlb6oFgwwKyq5ka3bWQ7QZcjzIX+TdFkxP4IbFmoY2D8Dkj9Q== - dependencies: - "@ethereum-waffle/chai" "^3.4.4" - "@ethereum-waffle/compiler" "^3.4.4" - "@ethereum-waffle/mock-contract" "^3.4.4" - "@ethereum-waffle/provider" "^3.4.4" - ethers "^5.0.1" - -ethereumjs-abi@0.6.5: - version "0.6.5" - resolved "https://registry.yarnpkg.com/ethereumjs-abi/-/ethereumjs-abi-0.6.5.tgz#5a637ef16ab43473fa72a29ad90871405b3f5241" - integrity sha512-rCjJZ/AE96c/AAZc6O3kaog4FhOsAViaysBxqJNy2+LHP0ttH0zkZ7nXdVHOAyt6lFwLO0nlCwWszysG/ao1+g== +ethereum-waffle@^4.0.10: + version "4.0.10" + resolved "https://registry.yarnpkg.com/ethereum-waffle/-/ethereum-waffle-4.0.10.tgz#f1ef1564c0155236f1a66c6eae362a5d67c9f64c" + integrity sha512-iw9z1otq7qNkGDNcMoeNeLIATF9yKl1M8AIeu42ElfNBplq0e+5PeasQmm8ybY/elkZ1XyRO0JBQxQdVRb8bqQ== dependencies: - bn.js "^4.10.0" - ethereumjs-util "^4.3.0" + "@ethereum-waffle/chai" "4.0.10" + "@ethereum-waffle/compiler" "4.0.3" + "@ethereum-waffle/mock-contract" "4.0.4" + "@ethereum-waffle/provider" "4.0.5" + solc "0.8.15" + typechain "^8.0.0" ethereumjs-abi@0.6.8, ethereumjs-abi@^0.6.8: version "0.6.8" @@ -6330,96 +5804,18 @@ ethereumjs-abi@0.6.8, ethereumjs-abi@^0.6.8: bn.js "^4.11.8" ethereumjs-util "^6.0.0" -"ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git": - version "0.6.8" - resolved "git+https://github.com/ethereumjs/ethereumjs-abi.git#ee3994657fa7a427238e6ba92a84d0b529bbcde0" - dependencies: - bn.js "^4.11.8" - ethereumjs-util "^6.0.0" - -ethereumjs-account@3.0.0, ethereumjs-account@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ethereumjs-account/-/ethereumjs-account-3.0.0.tgz#728f060c8e0c6e87f1e987f751d3da25422570a9" - integrity sha512-WP6BdscjiiPkQfF9PVfMcwx/rDvfZTjFKY0Uwc09zSQr9JfIVH87dYIJu0gNhBhpmovV4yq295fdllS925fnBA== +ethereumjs-util@7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.3.tgz#b55d7b64dde3e3e45749e4c41288238edec32d23" + integrity sha512-y+82tEbyASO0K0X1/SRhbJJoAlfcvq8JbrG4a5cjrOks7HS/36efU/0j2flxCPOUM++HFahk33kr/ZxyC4vNuw== dependencies: - ethereumjs-util "^6.0.0" - rlp "^2.2.1" - safe-buffer "^5.1.1" - -ethereumjs-account@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/ethereumjs-account/-/ethereumjs-account-2.0.5.tgz#eeafc62de544cb07b0ee44b10f572c9c49e00a84" - integrity sha512-bgDojnXGjhMwo6eXQC0bY6UK2liSFUSMwwylOmQvZbSl/D7NXQ3+vrGO46ZeOgjGfxXmgIeVNDIiHw7fNZM4VA== - dependencies: - ethereumjs-util "^5.0.0" - rlp "^2.0.0" - safe-buffer "^5.1.1" - -ethereumjs-block@2.2.2, ethereumjs-block@^2.2.2, ethereumjs-block@~2.2.0, ethereumjs-block@~2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-2.2.2.tgz#c7654be7e22df489fda206139ecd63e2e9c04965" - integrity sha512-2p49ifhek3h2zeg/+da6XpdFR3GlqY3BIEiqxGF8j9aSRIgkb7M1Ky+yULBKJOu8PAZxfhsYA+HxUk2aCQp3vg== - dependencies: - async "^2.0.1" - ethereumjs-common "^1.5.0" - ethereumjs-tx "^2.1.1" - ethereumjs-util "^5.0.0" - merkle-patricia-tree "^2.1.2" - -ethereumjs-block@^1.2.2, ethereumjs-block@^1.4.1, ethereumjs-block@^1.6.0: - version "1.7.1" - resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz#78b88e6cc56de29a6b4884ee75379b6860333c3f" - integrity sha512-B+sSdtqm78fmKkBq78/QLKJbu/4Ts4P2KFISdgcuZUPDm9x+N7qgBPIIFUGbaakQh8bzuquiRVbdmvPKqbILRg== - dependencies: - async "^2.0.1" - ethereum-common "0.2.0" - ethereumjs-tx "^1.2.2" - ethereumjs-util "^5.0.0" - merkle-patricia-tree "^2.1.2" - -ethereumjs-blockchain@^4.0.3: - version "4.0.4" - resolved "https://registry.yarnpkg.com/ethereumjs-blockchain/-/ethereumjs-blockchain-4.0.4.tgz#30f2228dc35f6dcf94423692a6902604ae34960f" - integrity sha512-zCxaRMUOzzjvX78DTGiKjA+4h2/sF0OYL1QuPux0DHpyq8XiNoF5GYHtb++GUxVlMsMfZV7AVyzbtgcRdIcEPQ== - dependencies: - async "^2.6.1" - ethashjs "~0.0.7" - ethereumjs-block "~2.2.2" - ethereumjs-common "^1.5.0" - ethereumjs-util "^6.1.0" - flow-stoplight "^1.0.0" - level-mem "^3.0.1" - lru-cache "^5.1.1" - rlp "^2.2.2" - semaphore "^1.1.0" - -ethereumjs-common@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-1.5.0.tgz#d3e82fc7c47c0cef95047f431a99485abc9bb1cd" - integrity sha512-SZOjgK1356hIY7MRj3/ma5qtfr/4B5BL+G4rP/XSMYr2z1H5el4RX5GReYCKmQmYI/nSBmRnwrZ17IfHuG0viQ== - -ethereumjs-common@^1.1.0, ethereumjs-common@^1.3.2, ethereumjs-common@^1.5.0: - version "1.5.2" - resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-1.5.2.tgz#2065dbe9214e850f2e955a80e650cb6999066979" - integrity sha512-hTfZjwGX52GS2jcVO6E2sx4YuFnf0Fhp5ylo4pEPhEffNln7vS59Hr5sLnp3/QCazFLluuBZ+FZ6J5HTp0EqCA== - -ethereumjs-tx@2.1.2, ethereumjs-tx@^2.1.1, ethereumjs-tx@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz#5dfe7688bf177b45c9a23f86cf9104d47ea35fed" - integrity sha512-zZEK1onCeiORb0wyCXUvg94Ve5It/K6GD1K+26KfFKodiBiS6d9lfCXlUKGBBdQ+bv7Day+JK0tj1K+BeNFRAw== - dependencies: - ethereumjs-common "^1.5.0" - ethereumjs-util "^6.0.0" - -ethereumjs-tx@^1.1.1, ethereumjs-tx@^1.2.0, ethereumjs-tx@^1.2.2, ethereumjs-tx@^1.3.3: - version "1.3.7" - resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz#88323a2d875b10549b8347e09f4862b546f3d89a" - integrity sha512-wvLMxzt1RPhAQ9Yi3/HKZTn0FZYpnsmQdbKYfUUpi4j1SEIcbkd9tndVjcPrufY3V7j2IebOpC00Zp2P/Ay2kA== - dependencies: - ethereum-common "^0.0.18" - ethereumjs-util "^5.0.0" + "@types/bn.js" "^5.1.0" + bn.js "^5.1.2" + create-hash "^1.1.2" + ethereum-cryptography "^0.1.3" + rlp "^2.2.4" -ethereumjs-util@6.2.1, ethereumjs-util@^6.0.0, ethereumjs-util@^6.1.0, ethereumjs-util@^6.2.0, ethereumjs-util@^6.2.1: +ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz#fcb4e4dd5ceacb9d2305426ab1a5cd93e3163b69" integrity sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw== @@ -6432,95 +5828,18 @@ ethereumjs-util@6.2.1, ethereumjs-util@^6.0.0, ethereumjs-util@^6.1.0, ethereumj ethjs-util "0.1.6" rlp "^2.2.3" -ethereumjs-util@^4.3.0: - version "4.5.1" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-4.5.1.tgz#f4bf9b3b515a484e3cc8781d61d9d980f7c83bd0" - integrity sha512-WrckOZ7uBnei4+AKimpuF1B3Fv25OmoRgmYCpGsP7u8PFxXAmAgiJSYT2kRWnt6fVIlKaQlZvuwXp7PIrmn3/w== - dependencies: - bn.js "^4.8.0" - create-hash "^1.1.2" - elliptic "^6.5.2" - ethereum-cryptography "^0.1.3" - rlp "^2.0.0" - -ethereumjs-util@^5.0.0, ethereumjs-util@^5.0.1, ethereumjs-util@^5.1.1, ethereumjs-util@^5.1.2, ethereumjs-util@^5.1.3, ethereumjs-util@^5.1.5, ethereumjs-util@^5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz#a833f0e5fca7e5b361384dc76301a721f537bf65" - integrity sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ== - dependencies: - bn.js "^4.11.0" - create-hash "^1.1.2" - elliptic "^6.5.2" - ethereum-cryptography "^0.1.3" - ethjs-util "^0.1.3" - rlp "^2.0.0" - safe-buffer "^5.1.1" - -ethereumjs-util@^7.0.2: +ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.3, ethereumjs-util@^7.1.4, ethereumjs-util@^7.1.5: version "7.1.5" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== dependencies: - "@types/bn.js" "^5.1.0" - bn.js "^5.1.2" - create-hash "^1.1.2" - ethereum-cryptography "^0.1.3" - rlp "^2.2.4" - -ethereumjs-vm@4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/ethereumjs-vm/-/ethereumjs-vm-4.2.0.tgz#e885e861424e373dbc556278f7259ff3fca5edab" - integrity sha512-X6qqZbsY33p5FTuZqCnQ4+lo957iUJMM6Mpa6bL4UW0dxM6WmDSHuI4j/zOp1E2TDKImBGCJA9QPfc08PaNubA== - dependencies: - async "^2.1.2" - async-eventemitter "^0.2.2" - core-js-pure "^3.0.1" - ethereumjs-account "^3.0.0" - ethereumjs-block "^2.2.2" - ethereumjs-blockchain "^4.0.3" - ethereumjs-common "^1.5.0" - ethereumjs-tx "^2.1.2" - ethereumjs-util "^6.2.0" - fake-merkle-patricia-tree "^1.0.1" - functional-red-black-tree "^1.0.1" - merkle-patricia-tree "^2.3.2" - rustbn.js "~0.2.0" - safe-buffer "^5.1.1" - util.promisify "^1.0.0" - -ethereumjs-vm@^2.1.0, ethereumjs-vm@^2.3.4, ethereumjs-vm@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/ethereumjs-vm/-/ethereumjs-vm-2.6.0.tgz#76243ed8de031b408793ac33907fb3407fe400c6" - integrity sha512-r/XIUik/ynGbxS3y+mvGnbOKnuLo40V5Mj1J25+HEO63aWYREIqvWeRO/hnROlMBE5WoniQmPmhiaN0ctiHaXw== - dependencies: - async "^2.1.2" - async-eventemitter "^0.2.2" - ethereumjs-account "^2.0.3" - ethereumjs-block "~2.2.0" - ethereumjs-common "^1.1.0" - ethereumjs-util "^6.0.0" - fake-merkle-patricia-tree "^1.0.1" - functional-red-black-tree "^1.0.1" - merkle-patricia-tree "^2.3.2" - rustbn.js "~0.2.0" - safe-buffer "^5.1.1" - -ethereumjs-wallet@0.6.5: - version "0.6.5" - resolved "https://registry.yarnpkg.com/ethereumjs-wallet/-/ethereumjs-wallet-0.6.5.tgz#685e9091645cee230ad125c007658833991ed474" - integrity sha512-MDwjwB9VQVnpp/Dc1XzA6J1a3wgHQ4hSvA1uWNatdpOrtCbPVuQSKSyRnjLvS0a+KKMw2pvQ9Ybqpb3+eW8oNA== - dependencies: - aes-js "^3.1.1" - bs58check "^2.1.2" + "@types/bn.js" "^5.1.0" + bn.js "^5.1.2" + create-hash "^1.1.2" ethereum-cryptography "^0.1.3" - ethereumjs-util "^6.0.0" - randombytes "^2.0.6" - safe-buffer "^5.1.2" - scryptsy "^1.2.1" - utf8 "^3.0.0" - uuid "^3.3.2" + rlp "^2.2.4" -ethers@^5.0.1, ethers@^5.0.2, ethers@^5.5.2, ethers@^5.7.0, ethers@^5.7.1, ethers@^5.7.2, ethers@~5.7.0: +ethers@^5.0.2, ethers@^5.7.0, ethers@^5.7.1, ethers@^5.7.2, ethers@~5.7.0: version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== @@ -6683,7 +6002,7 @@ ethjs-util@0.1.3: is-hex-prefixed "1.0.0" strip-hex-prefix "1.0.0" -ethjs-util@0.1.6, ethjs-util@^0.1.3, ethjs-util@^0.1.6: +ethjs-util@0.1.6, ethjs-util@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w== @@ -6712,17 +6031,7 @@ event-target-shim@^5.0.0: resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== -eventemitter3@4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" - integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ== - -events@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: +evp_bytestokey@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== @@ -6765,19 +6074,6 @@ exit@^0.1.2: resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA== - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - expect@^29.0.0, expect@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" @@ -6789,65 +6085,6 @@ expect@^29.0.0, expect@^29.7.0: jest-message-util "^29.7.0" jest-util "^29.7.0" -express@^4.14.0: - version "4.18.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" - integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== - dependencies: - accepts "~1.3.8" - array-flatten "1.1.1" - body-parser "1.20.1" - content-disposition "0.5.4" - content-type "~1.0.4" - cookie "0.5.0" - cookie-signature "1.0.6" - debug "2.6.9" - depd "2.0.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "1.2.0" - fresh "0.5.2" - http-errors "2.0.0" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "2.4.1" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.7" - qs "6.11.0" - range-parser "~1.2.1" - safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" - setprototypeof "1.2.0" - statuses "2.0.1" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - -ext@^1.1.2: - version "1.7.0" - resolved "https://registry.yarnpkg.com/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f" - integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw== - dependencies: - type "^2.7.2" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug== - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q== - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" @@ -6862,20 +6099,6 @@ external-editor@^3.0.3: iconv-lite "^0.4.24" tmp "^0.0.33" -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" @@ -6886,13 +6109,6 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== -fake-merkle-patricia-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fake-merkle-patricia-tree/-/fake-merkle-patricia-tree-1.0.1.tgz#4b8c3acfb520afadf9860b1f14cd8ce3402cddd3" - integrity sha512-Tgq37lkc9pUIgIKw5uitNUKcgcYL3R6JvXtKQbOf/ZSavXbidsksgp/pAY6p//uhw0I4yoMsvTSovvVIsk/qxA== - dependencies: - checkpoint-store "^1.1.0" - fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -6903,7 +6119,12 @@ fast-diff@^1.1.2, fast-diff@^1.2.0: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== -fast-glob@^3.0.3, fast-glob@^3.3.0, fast-glob@^3.3.1: +fast-equals@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-5.0.1.tgz#a4eefe3c5d1c0d021aeed0bc10ba5e0c12ee405d" + integrity sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ== + +fast-glob@^3.0.3, fast-glob@^3.3.0, fast-glob@^3.3.1, fast-glob@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== @@ -6949,13 +6170,6 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" -fetch-ponyfill@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz#ae3ce5f732c645eab87e4ae8793414709b239893" - integrity sha512-knK9sGskIg2T7OnYLdZ2hZXn0CtDrAIBxYQLpmEf0BqfdWnwmM1weccUl5+4EdA44tzNSFAuxITPbXtPehUB3g== - dependencies: - node-fetch "~1.7.1" - figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -6970,15 +6184,12 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ== +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" + flat-cache "^4.0.0" fill-range@^7.0.1: version "7.0.1" @@ -6987,19 +6198,6 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -finalhandler@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" - integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "2.4.1" - parseurl "~1.3.3" - statuses "2.0.1" - unpipe "~1.0.0" - find-replace@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-1.0.3.tgz#b88e7364d2d9c959559f388c66670d6130441fa0" @@ -7008,6 +6206,18 @@ find-replace@^1.0.3: array-back "^1.0.4" test-value "^2.1.0" +find-replace@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38" + integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ== + dependencies: + array-back "^3.0.1" + +find-up-simple@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/find-up-simple/-/find-up-simple-1.0.0.tgz#21d035fde9fdbd56c8f4d2f63f32fd93a1cfc368" + integrity sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw== + find-up@5.0.0, find-up@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" @@ -7016,14 +6226,6 @@ find-up@5.0.0, find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - integrity sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA== - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" @@ -7039,21 +6241,6 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" -find-yarn-workspace-root@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-1.2.1.tgz#40eb8e6e7c2502ddfaa2577c176f221422f860db" - integrity sha512-dVtfb0WuQG+8Ag2uWkbG79hOUzEsRrhBzgfn86g2sJPkzmcpGdghbNTfUKGTxymFrY/tLIodDzLoW9nOJ4FY8Q== - dependencies: - fs-extra "^4.0.3" - micromatch "^3.1.4" - -find-yarn-workspace-root@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" - integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== - dependencies: - micromatch "^4.0.2" - flat-cache@^3.0.4: version "3.1.1" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.1.1.tgz#a02a15fdec25a8f844ff7cc658f03dd99eb4609b" @@ -7063,6 +6250,15 @@ flat-cache@^3.0.4: keyv "^4.5.3" rimraf "^3.0.2" +flat-cache@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.0.tgz#d12437636f83bb8a12b8f300c36fd1614e1c7224" + integrity sha512-EryKbCE/wxpxKniQlyas6PY1I9vwtF3uCBweX+N8KYTCn3Y12RTGtQAJ/bd5pl7kxUAc8v/R3Ake/N17OZiFqA== + dependencies: + flatted "^3.2.9" + keyv "^4.5.4" + rimraf "^5.0.5" + flat@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" @@ -7073,27 +6269,25 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== -flow-stoplight@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/flow-stoplight/-/flow-stoplight-1.0.0.tgz#4a292c5bcff8b39fa6cc0cb1a853d86f27eeff7b" - integrity sha512-rDjbZUKpN8OYhB0IE/vY/I8UWO/602IIJEU/76Tv4LvYnwHCk0BCsvz4eRr9n+FQcri7L5cyaXOo0+/Kh4HisA== - follow-redirects@^1.12.1, follow-redirects@^1.14.0, follow-redirects@^1.15.0: version "1.15.3" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a" integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q== -for-each@^0.3.3, for-each@~0.3.3: +for-each@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== dependencies: is-callable "^1.1.3" -for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ== +foreground-child@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" + integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" forever-agent@~0.6.1: version "0.6.1" @@ -7127,11 +6321,6 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" -forwarded@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" - integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== - fp-ts@1.19.3: version "1.19.3" resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.19.3.tgz#261a60d1088fbff01f91256f91d21d0caaaaa96f" @@ -7142,18 +6331,6 @@ fp-ts@^1.0.0: resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.19.5.tgz#3da865e585dfa1fdfd51785417357ac50afc520a" integrity sha512-wDNqTimnzs8QqpldiId9OavWK2NptormjXnRJTQecNjzwfyp6P/8s/zG8e4h3ja3oqkKaY72UlTjQYt/1yXf9A== -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA== - dependencies: - map-cache "^0.2.2" - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== - fs-constants@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" @@ -7179,15 +6356,6 @@ fs-extra@^11.1.1: jsonfile "^6.0.1" universalify "^2.0.0" -fs-extra@^4.0.2, fs-extra@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" - integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs-extra@^7.0.0, fs-extra@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" @@ -7206,23 +6374,6 @@ fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@^9.0.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" - integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== - dependencies: - at-least-node "^1.0.0" - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs-minipass@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" - integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== - dependencies: - minipass "^2.6.0" - fs-readdir-recursive@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" @@ -7268,53 +6419,33 @@ functions-have-names@^1.2.3: resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== -ganache-core@^2.13.2: - version "2.13.2" - resolved "https://registry.yarnpkg.com/ganache-core/-/ganache-core-2.13.2.tgz#27e6fc5417c10e6e76e2e646671869d7665814a3" - integrity sha512-tIF5cR+ANQz0+3pHWxHjIwHqFXcVo0Mb+kcsNhglNFALcYo49aQpnS9dqHartqPfMFjiHh/qFoD3mYK0d/qGgw== - dependencies: - abstract-leveldown "3.0.0" - async "2.6.2" - bip39 "2.5.0" - cachedown "1.0.0" - clone "2.1.2" - debug "3.2.6" - encoding-down "5.0.4" - eth-sig-util "3.0.0" - ethereumjs-abi "0.6.8" - ethereumjs-account "3.0.0" - ethereumjs-block "2.2.2" - ethereumjs-common "1.5.0" - ethereumjs-tx "2.1.2" - ethereumjs-util "6.2.1" - ethereumjs-vm "4.2.0" - heap "0.2.6" - keccak "3.0.1" - level-sublevel "6.6.4" - levelup "3.1.1" - lodash "4.17.20" - lru-cache "5.1.1" - merkle-patricia-tree "3.0.0" - patch-package "6.2.2" - seedrandom "3.0.1" - source-map-support "0.5.12" - tmp "0.1.0" - web3-provider-engine "14.2.1" - websocket "1.0.32" +ganache@7.4.3: + version "7.4.3" + resolved "https://registry.yarnpkg.com/ganache/-/ganache-7.4.3.tgz#e995f1250697264efbb34d4241c374a2b0271415" + integrity sha512-RpEDUiCkqbouyE7+NMXG26ynZ+7sGiODU84Kz+FVoXUnQ4qQM4M8wif3Y4qUCt+D/eM1RVeGq0my62FPD6Y1KA== + dependencies: + "@trufflesuite/bigint-buffer" "1.1.10" + "@types/bn.js" "^5.1.0" + "@types/lru-cache" "5.1.1" + "@types/seedrandom" "3.0.1" + emittery "0.10.0" + keccak "3.0.2" + leveldown "6.1.0" + secp256k1 "4.0.3" optionalDependencies: - ethereumjs-wallet "0.6.5" - web3 "1.2.11" + bufferutil "4.0.5" + utf-8-validate "5.0.7" + +gensequence@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/gensequence/-/gensequence-6.0.0.tgz#ae46a0f89ebd7cc334e45cfb8f1c99a65248694e" + integrity sha512-8WwuywE9pokJRAcg2QFR/plk3cVPebSUqRPzpGQh3WQ0wIiHAw+HyOQj5IuHyUTQBHpBKFoB2JUMu9zT3vJ16Q== gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== -get-caller-file@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" - integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== - get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" @@ -7350,29 +6481,15 @@ get-stdin@=8.0.0: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== -get-stdin@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" - integrity sha512-jZV7n6jGE3Gt7fgSTJoz91Ak5MuTLwMwkoYdjxuJ/AmjIsE1UC03y/IWkZCQGEvVNS9qoRNwy5BCqxImv0FVeA== - -get-stdin@~9.0.0: +get-stdin@^9.0.0, get-stdin@~9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-9.0.0.tgz#3983ff82e03d56f1b2ea0d3e60325f39d703a575" integrity sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA== -get-stream@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - -get-stream@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" - integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== - dependencies: - pump "^3.0.0" +get-stdin@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" + integrity sha512-jZV7n6jGE3Gt7fgSTJoz91Ak5MuTLwMwkoYdjxuJ/AmjIsE1UC03y/IWkZCQGEvVNS9qoRNwy5BCqxImv0FVeA== get-stream@^6.0.0, get-stream@^6.0.1: version "6.0.1" @@ -7394,11 +6511,6 @@ get-tsconfig@^4.5.0: dependencies: resolve-pkg-maps "^1.0.0" -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA== - getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" @@ -7428,6 +6540,18 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" +glob@7.1.7, glob@~7.1.2: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + glob@7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" @@ -7440,6 +6564,17 @@ glob@7.2.0: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^10.3.7: + version "10.3.10" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" + integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.3.5" + minimatch "^9.0.1" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry "^1.10.1" + glob@^5.0.15: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" @@ -7451,7 +6586,7 @@ glob@^5.0.15: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.2.3: +glob@^7.0.0, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -7474,18 +6609,6 @@ glob@^8.0.3: minimatch "^5.0.1" once "^1.3.0" -glob@~7.1.2: - version "7.1.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - glob@~8.0.3: version "8.0.3" resolved "https://registry.yarnpkg.com/glob/-/glob-8.0.3.tgz#415c6eb2deed9e502c68fa44a272e6da6eeca42e" @@ -7497,6 +6620,13 @@ glob@~8.0.3: minimatch "^5.0.1" once "^1.3.0" +global-directory@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/global-directory/-/global-directory-4.0.1.tgz#4d7ac7cfd2cb73f304c53b8810891748df5e361e" + integrity sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q== + dependencies: + ini "4.1.1" + global-modules@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" @@ -7513,14 +6643,6 @@ global-prefix@^3.0.0: kind-of "^6.0.2" which "^1.3.1" -global@~4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" - integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== - dependencies: - min-document "^2.19.0" - process "^0.11.10" - globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" @@ -7540,11 +6662,6 @@ globals@^13.6.0, globals@^13.9.0: dependencies: type-fest "^0.20.2" -globals@^9.18.0: - version "9.18.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" - integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== - globalthis@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" @@ -7585,41 +6702,7 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -got@9.6.0: - version "9.6.0" - resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" - integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== - dependencies: - "@sindresorhus/is" "^0.14.0" - "@szmarczak/http-timer" "^1.1.2" - cacheable-request "^6.0.0" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^4.1.0" - lowercase-keys "^1.0.1" - mimic-response "^1.0.1" - p-cancelable "^1.0.0" - to-readable-stream "^1.0.0" - url-parse-lax "^3.0.0" - -got@^11.8.5: - version "11.8.6" - resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" - integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== - dependencies: - "@sindresorhus/is" "^4.0.0" - "@szmarczak/http-timer" "^4.0.5" - "@types/cacheable-request" "^6.0.1" - "@types/responselike" "^1.0.0" - cacheable-lookup "^5.0.3" - cacheable-request "^7.0.2" - decompress-response "^6.0.0" - http2-wrapper "^1.0.0-beta.5.2" - lowercase-keys "^2.0.0" - p-cancelable "^2.0.0" - responselike "^2.0.0" - -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9: +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -7796,13 +6879,6 @@ hardhat@^2.18.3: uuid "^8.3.2" ws "^7.4.6" -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg== - dependencies: - ansi-regex "^2.0.0" - has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" @@ -7823,6 +6899,11 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-own-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-own-prop/-/has-own-prop-2.0.0.tgz#f0f95d58f65804f5d218db32563bb85b8e0417af" + integrity sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ== + has-property-descriptors@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340" @@ -7847,42 +6928,6 @@ has-tostringtag@^1.0.0: dependencies: has-symbols "^1.0.2" -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q== - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw== - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ== - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ== - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -has@~1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.4.tgz#2eb2860e000011dae4f1406a86fe80e530fb2ec6" - integrity sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ== - hash-base@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" @@ -7912,11 +6957,6 @@ he@1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== -heap@0.2.6: - version "0.2.6" - resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac" - integrity sha512-MzzWcnfB1e4EG2vHi3dXHoBupmuXNZzx6pY6HldVS55JKKBoq3xOyzfSaZRkJp37HIhEYC78knabHff3zc4dQQ== - "heap@>= 0.2.0": version "0.2.7" resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.7.tgz#1e6adf711d3f27ce35a81fe3b7bd576c2260a8fc" @@ -7931,14 +6971,6 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -home-or-tmp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" - integrity sha512-ycURW7oUxE2sNiPVw1HVEFsW+ecOpJ5zaj7eC0RlwhibhRBod20muUN8qu/gzx956YrLolVvs1MTXwKgC2rVEg== - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.1" - hosted-git-info@^2.1.4, hosted-git-info@^2.6.0: version "2.8.9" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" @@ -7949,6 +6981,23 @@ html-escaper@^2.0.0: resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== +html-link-extractor@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/html-link-extractor/-/html-link-extractor-1.0.5.tgz#a4be345cb13b8c3352d82b28c8b124bb7bf5dd6f" + integrity sha512-ADd49pudM157uWHwHQPUSX4ssMsvR/yHIswOR5CUfBdK9g9ZYGMhVSE6KZVHJ6kCkR0gH4htsfzU6zECDNVwyw== + dependencies: + cheerio "^1.0.0-rc.10" + +htmlparser2@^8.0.1: + version "8.0.2" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.2.tgz#f002151705b383e62433b5cf466f5b716edaec21" + integrity sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.3" + domutils "^3.0.1" + entities "^4.4.0" + http-basic@^8.1.1: version "8.1.3" resolved "https://registry.yarnpkg.com/http-basic/-/http-basic-8.1.3.tgz#a7cabee7526869b9b710136970805b1004261bbf" @@ -7959,11 +7008,6 @@ http-basic@^8.1.1: http-response-object "^3.0.1" parse-cache-control "^1.0.1" -http-cache-semantics@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" - integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== - http-errors@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" @@ -7975,11 +7019,6 @@ http-errors@2.0.0: statuses "2.0.1" toidentifier "1.0.1" -http-https@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" - integrity sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg== - http-response-object@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/http-response-object/-/http-response-object-3.0.2.tgz#7f435bb210454e4360d074ef1f989d5ea8aa9810" @@ -7996,14 +7035,6 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" -http2-wrapper@^1.0.0-beta.5.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" - integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg== - dependencies: - quick-lru "^5.1.1" - resolve-alpn "^1.0.0" - https-proxy-agent@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" @@ -8029,20 +7060,13 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@^0.6.2: +iconv-lite@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -idna-uts46-hx@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz#a1dc5c4df37eee522bf66d969cc980e00e8711f9" - integrity sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA== - dependencies: - punycode "2.1.0" - ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" @@ -8099,6 +7123,11 @@ import-local@^3.0.2: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" +import-meta-resolve@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-4.0.0.tgz#0b1195915689f60ab00f830af0f15cc841e8919e" + integrity sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA== + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -8117,7 +7146,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -8127,6 +7156,11 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== +ini@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.1.tgz#d95b3d843b1e906e56d6747d5447904ff50ce7a1" + integrity sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g== + ini@^1.3.5, ini@~1.3.0: version "1.3.8" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" @@ -8170,18 +7204,6 @@ interpret@^1.0.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== -invariant@^2.2.2: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -invert-kv@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - integrity sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ== - io-ts@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-1.10.4.tgz#cd5401b138de88e4f920adbcb7026e2d1967e6e2" @@ -8189,25 +7211,10 @@ io-ts@1.10.4: dependencies: fp-ts "^1.0.0" -ipaddr.js@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - -is-accessor-descriptor@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz#3223b10628354644b86260db29b3e693f5ceedd4" - integrity sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA== - dependencies: - hasown "^2.0.0" - -is-arguments@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" +is-absolute-url@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-4.0.1.tgz#16e4d487d4fded05cfe0685e53ec86804a5e94dc" + integrity sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A== is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: version "3.0.2" @@ -8245,11 +7252,6 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - is-buffer@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" @@ -8260,13 +7262,6 @@ is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-ci@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" - integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== - dependencies: - ci-info "^2.0.0" - is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.13.1: version "2.13.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" @@ -8274,36 +7269,13 @@ is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.13.1: dependencies: hasown "^2.0.0" -is-data-descriptor@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz#2109164426166d32ea38c405c1e0945d9e6a4eeb" - integrity sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw== - dependencies: - hasown "^2.0.0" - -is-date-object@^1.0.1, is-date-object@^1.0.5: +is-date-object@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== dependencies: has-tostringtag "^1.0.0" -is-descriptor@^0.1.0: - version "0.1.7" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.7.tgz#2727eb61fd789dcd5bdf0ed4569f551d2fe3be33" - integrity sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg== - dependencies: - is-accessor-descriptor "^1.0.1" - is-data-descriptor "^1.0.1" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.3.tgz#92d27cb3cd311c4977a4db47df457234a13cb306" - integrity sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw== - dependencies: - is-accessor-descriptor "^1.0.1" - is-data-descriptor "^1.0.1" - is-docker@^2.0.0: version "2.2.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" @@ -8314,40 +7286,16 @@ is-docker@^3.0.0: resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200" integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ== -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw== - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== -is-finite@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" - integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== - is-fn@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fn/-/is-fn-1.0.0.tgz#9543d5de7bcf5b08a22ec8a20bae6e286d510d8c" integrity sha512-XoFPJQmsAShb3jEQRfzf2rqXavq7fIqF/jOekp308JlThqrODnMpweVSGilKTCXELfLhltGP2AGgbQGVP8F1dg== -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw== - dependencies: - number-is-nan "^1.0.0" - is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" @@ -8358,11 +7306,6 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-function@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" - integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ== - is-generator-fn@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" @@ -8399,18 +7342,16 @@ is-number-object@^1.0.4: dependencies: has-tostringtag "^1.0.0" -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg== - dependencies: - kind-of "^3.0.2" - is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + is-path-inside@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" @@ -8421,14 +7362,7 @@ is-plain-obj@^2.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== -is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-regex@^1.1.4, is-regex@~1.1.4: +is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== @@ -8436,6 +7370,13 @@ is-regex@^1.1.4, is-regex@~1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-relative-url@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-relative-url/-/is-relative-url-4.0.0.tgz#4d8371999ff6033b76e4d9972fb5bf496fddfa97" + integrity sha512-PkzoL1qKAYXNFct5IKdKRH/iBQou/oCC85QhXj6WKtUQBliZ4Yfd3Zk27RHu9KQG8r6zgvAA2AQKC9p+rqTszg== + dependencies: + is-absolute-url "^4.0.1" + is-shared-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" @@ -8443,11 +7384,6 @@ is-shared-array-buffer@^1.0.2: dependencies: call-bind "^1.0.2" -is-stream@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== - is-stream@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" @@ -8494,11 +7430,6 @@ is-url@^1.2.4: resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww== -is-utf8@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - integrity sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q== - is-weakref@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" @@ -8506,12 +7437,7 @@ is-weakref@^1.0.2: dependencies: call-bind "^1.0.2" -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - -is-wsl@^2.1.1, is-wsl@^2.2.0: +is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== @@ -8523,33 +7449,28 @@ isarray@0.0.1: resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== -isarray@1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== - isarray@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isemail@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/isemail/-/isemail-3.2.0.tgz#59310a021931a9fb06bbb51e155ce0b3f236832c" + integrity sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg== + dependencies: + punycode "2.x.x" + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA== - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== - isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -8608,6 +7529,15 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" +jackspeak@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" + integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + jest-changed-files@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" @@ -8981,21 +7911,11 @@ js-sha3@0.8.0, js-sha3@^0.8.0: resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== -js-sha3@^0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" - integrity sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g== - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: +js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - integrity sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg== - js-yaml@3.x, js-yaml@^3.13.1: version "3.14.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" @@ -9024,25 +7944,17 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== -jsesc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" - integrity sha512-Mke0DA0QjUWuJlhsE0ZPPhYiJkRap642SmI/4ztCFaUs6V2AiH1sfecc+57NgaryfAA2VR3v6O+CSjC1jZJKOA== - jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== - -json-buffer@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" - integrity sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ== +json-bigint@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-bigint/-/json-bigint-1.0.0.tgz#ae547823ac0cad8398667f8cd9ef4730f5b01ff1" + integrity sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ== + dependencies: + bignumber.js "^9.0.0" json-buffer@3.0.1: version "3.0.1" @@ -9059,30 +7971,6 @@ json-parse-even-better-errors@^2.3.0: resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== -json-rpc-engine@^3.4.0, json-rpc-engine@^3.6.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-3.8.0.tgz#9d4ff447241792e1d0a232f6ef927302bb0c62a9" - integrity sha512-6QNcvm2gFuuK4TKU1uwfH0Qd/cOSb9c1lls0gbnIhciktIUQJwz6NQNAW4B1KiGPenv7IKu97V222Yo1bNhGuA== - dependencies: - async "^2.0.1" - babel-preset-env "^1.7.0" - babelify "^7.3.0" - json-rpc-error "^2.0.0" - promise-to-callback "^1.0.0" - safe-event-emitter "^1.0.1" - -json-rpc-error@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/json-rpc-error/-/json-rpc-error-2.0.0.tgz#a7af9c202838b5e905c7250e547f1aff77258a02" - integrity sha512-EwUeWP+KgAZ/xqFpaP6YDAXMtCJi+o/QQpCQFIYyxr01AdADi2y413eM8hSqJcoQym9WMePAJWoaODEJufC4Ug== - dependencies: - inherits "^2.0.1" - -json-rpc-random-id@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-rpc-random-id/-/json-rpc-random-id-1.0.1.tgz#ba49d96aded1444dbb8da3d203748acbbcdec8c8" - integrity sha512-RJ9YYNCkhVDBuP4zN5BBtYAzEl03yq/jIIsyif0JY9qyJuQQZNeDK7anAPKKlyEtLSj2s8h6hNh2F8zO5q7ScA== - json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -9103,26 +7991,11 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -json-stable-stringify@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.1.0.tgz#43d39c7c8da34bfaf785a61a56808b0def9f747d" - integrity sha512-zfA+5SuwYN2VWqN1/5HZaDzQKLJHaBVMZIIM+wuYjdptkaQsqzDdqjqf+lZZJUuJq1aanHiY8LhH8LmH+qBYJA== - dependencies: - call-bind "^1.0.5" - isarray "^2.0.5" - jsonify "^0.0.1" - object-keys "^1.1.1" - json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== -json5@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - integrity sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw== - json5@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" @@ -9168,11 +8041,6 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -jsonify@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978" - integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg== - jsonparse@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" @@ -9234,6 +8102,15 @@ keccak@3.0.1: node-addon-api "^2.0.0" node-gyp-build "^4.2.0" +keccak@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.2.tgz#4c2c6e8c54e04f2670ee49fa734eb9da152206e0" + integrity sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ== + dependencies: + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + readable-stream "^3.6.0" + keccak@^3.0.0, keccak@^3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.4.tgz#edc09b89e633c0549da444432ecf062ffadee86d" @@ -9243,46 +8120,18 @@ keccak@^3.0.0, keccak@^3.0.2: node-gyp-build "^4.2.0" readable-stream "^3.6.0" -keyv@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" - integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== - dependencies: - json-buffer "3.0.0" - -keyv@^4.0.0, keyv@^4.5.3: +keyv@^4.5.3, keyv@^4.5.4: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== dependencies: json-buffer "3.0.1" -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw== - dependencies: - is-buffer "^1.1.5" - kind-of@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== -klaw-sync@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" - integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== - dependencies: - graceful-fs "^4.1.11" - klaw@^1.0.0: version "1.3.1" resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" @@ -9307,13 +8156,6 @@ kleur@^3.0.3: dependencies: dotenv "^16.0.3" -lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - integrity sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw== - dependencies: - invert-kv "^1.0.0" - level-codec@^9.0.0: version "9.0.2" resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-9.0.2.tgz#fd60df8c64786a80d44e63423096ffead63d8cbc" @@ -9321,17 +8163,17 @@ level-codec@^9.0.0: dependencies: buffer "^5.6.0" -level-codec@~7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-7.0.1.tgz#341f22f907ce0f16763f24bddd681e395a0fb8a7" - integrity sha512-Ua/R9B9r3RasXdRmOtd+t9TCOEIIlts+TN/7XTT2unhDaL6sJn83S3rUyljbr6lVtw49N3/yA0HHjpV6Kzb2aQ== - -level-errors@^1.0.3: - version "1.1.2" - resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.1.2.tgz#4399c2f3d3ab87d0625f7e3676e2d807deff404d" - integrity sha512-Sw/IJwWbPKF5Ai4Wz60B52yj0zYeqzObLh8k1Tk88jVmD51cJSKWSYpRyhVIvFzZdvsPqlH5wfhp/yxdsaQH4w== +level-concat-iterator@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz#5235b1f744bc34847ed65a50548aa88d22e881cf" + integrity sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ== dependencies: - errno "~0.1.1" + catering "^2.1.0" + +level-concat-iterator@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz#1d1009cf108340252cb38c51f9727311193e6263" + integrity sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw== level-errors@^2.0.0, level-errors@~2.0.0: version "2.0.1" @@ -9340,85 +8182,48 @@ level-errors@^2.0.0, level-errors@~2.0.0: dependencies: errno "~0.1.1" -level-errors@~1.0.3: - version "1.0.5" - resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.0.5.tgz#83dbfb12f0b8a2516bdc9a31c4876038e227b859" - integrity sha512-/cLUpQduF6bNrWuAC4pwtUKA5t669pCsCi2XbmojG2tFeOr9j6ShtdDCtFFQO1DRt+EVZhx9gPzP9G2bUaG4ig== - dependencies: - errno "~0.1.1" - -level-iterator-stream@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-2.0.3.tgz#ccfff7c046dcf47955ae9a86f46dfa06a31688b4" - integrity sha512-I6Heg70nfF+e5Y3/qfthJFexhRw/Gi3bIymCoXAlijZdAcLaPuWSJs3KXyTYf23ID6g0o2QF62Yh+grOXY3Rig== - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.5" - xtend "^4.0.0" - -level-iterator-stream@~1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz#e43b78b1a8143e6fa97a4f485eb8ea530352f2ed" - integrity sha512-1qua0RHNtr4nrZBgYlpV0qHHeHpcRRWTxEZJ8xsemoHAXNL5tbooh4tPEEqIqsbWCAJBmUmkwYK/sW5OrFjWWw== - dependencies: - inherits "^2.0.1" - level-errors "^1.0.3" - readable-stream "^1.0.33" - xtend "^4.0.0" - -level-iterator-stream@~3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-3.0.1.tgz#2c98a4f8820d87cdacab3132506815419077c730" - integrity sha512-nEIQvxEED9yRThxvOrq8Aqziy4EGzrxSZK+QzEFAVuJvQ8glfyZ96GB6BoI4sBbLfjMXm2w4vu3Tkcm9obcY0g== - dependencies: - inherits "^2.0.1" - readable-stream "^2.3.6" - xtend "^4.0.0" - -level-mem@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/level-mem/-/level-mem-3.0.1.tgz#7ce8cf256eac40f716eb6489654726247f5a89e5" - integrity sha512-LbtfK9+3Ug1UmvvhR2DqLqXiPW1OJ5jEh0a3m9ZgAipiwpSxGj/qaVVy54RG5vAQN1nCuXqjvprCuKSCxcJHBg== +level-iterator-stream@~4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-4.0.2.tgz#7ceba69b713b0d7e22fcc0d1f128ccdc8a24f79c" + integrity sha512-ZSthfEqzGSOMWoUGhTXdX9jv26d32XJuHz/5YnuHZzH6wldfWMOVwI9TBtKcya4BKTyTt3XVA0A3cF3q5CY30Q== dependencies: - level-packager "~4.0.0" - memdown "~3.0.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + xtend "^4.0.2" -level-packager@~4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/level-packager/-/level-packager-4.0.1.tgz#7e7d3016af005be0869bc5fa8de93d2a7f56ffe6" - integrity sha512-svCRKfYLn9/4CoFfi+d8krOtrp6RoX8+xm0Na5cgXMqSyRru0AnDYdLl+YI8u1FyS6gGZ94ILLZDE5dh2but3Q== +level-mem@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/level-mem/-/level-mem-5.0.1.tgz#c345126b74f5b8aa376dc77d36813a177ef8251d" + integrity sha512-qd+qUJHXsGSFoHTziptAKXoLX87QjR7v2KMbqncDXPxQuCdsQlzmyX+gwrEHhlzn08vkf8TyipYyMmiC6Gobzg== dependencies: - encoding-down "~5.0.0" - levelup "^3.0.0" + level-packager "^5.0.3" + memdown "^5.0.0" -level-post@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/level-post/-/level-post-1.0.7.tgz#19ccca9441a7cc527879a0635000f06d5e8f27d0" - integrity sha512-PWYqG4Q00asOrLhX7BejSajByB4EmG2GaKHfj3h5UmmZ2duciXLPGYWIjBzLECFWUGOZWlm5B20h/n3Gs3HKew== +level-packager@^5.0.3: + version "5.1.1" + resolved "https://registry.yarnpkg.com/level-packager/-/level-packager-5.1.1.tgz#323ec842d6babe7336f70299c14df2e329c18939" + integrity sha512-HMwMaQPlTC1IlcwT3+swhqf/NUO+ZhXVz6TY1zZIIZlIR0YSn8GtAAWmIvKjNY16ZkEg/JcpAuQskxsXqC0yOQ== dependencies: - ltgt "^2.1.2" + encoding-down "^6.3.0" + levelup "^4.3.2" -level-sublevel@6.6.4: - version "6.6.4" - resolved "https://registry.yarnpkg.com/level-sublevel/-/level-sublevel-6.6.4.tgz#f7844ae893919cd9d69ae19d7159499afd5352ba" - integrity sha512-pcCrTUOiO48+Kp6F1+UAzF/OtWqLcQVTVF39HLdZ3RO8XBoXt+XVPKZO1vVr1aUoxHZA9OtD2e1v7G+3S5KFDA== - dependencies: - bytewise "~1.1.0" - level-codec "^9.0.0" - level-errors "^2.0.0" - level-iterator-stream "^2.0.3" - ltgt "~2.1.1" - pull-defer "^0.2.2" - pull-level "^2.0.3" - pull-stream "^3.6.8" - typewiselite "~1.0.0" - xtend "~4.0.0" +level-supports@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-2.1.0.tgz#9af908d853597ecd592293b2fad124375be79c5f" + integrity sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA== level-supports@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-4.0.1.tgz#431546f9d81f10ff0fea0e74533a0e875c08c66a" integrity sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA== +level-supports@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-1.0.1.tgz#2f530a596834c7301622521988e2c36bb77d122d" + integrity sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg== + dependencies: + xtend "^4.0.2" + level-transcoder@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/level-transcoder/-/level-transcoder-1.0.1.tgz#f8cef5990c4f1283d4c86d949e73631b0bc8ba9c" @@ -9427,21 +8232,13 @@ level-transcoder@^1.0.1: buffer "^6.0.3" module-error "^1.0.1" -level-ws@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-0.0.0.tgz#372e512177924a00424b0b43aef2bb42496d228b" - integrity sha512-XUTaO/+Db51Uiyp/t7fCMGVFOTdtLS/NIACxE/GHsij15mKzxksZifKVjlXDF41JMUP/oM1Oc4YNGdKnc3dVLw== - dependencies: - readable-stream "~1.0.15" - xtend "~2.1.1" - -level-ws@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-1.0.0.tgz#19a22d2d4ac57b18cc7c6ecc4bd23d899d8f603b" - integrity sha512-RXEfCmkd6WWFlArh3X8ONvQPm8jNpfA0s/36M4QzLqrLEIt1iJE9WBHLZ5vZJK6haMjJPJGJCQWfjMNnRcq/9Q== +level-ws@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-2.0.0.tgz#207a07bcd0164a0ec5d62c304b4615c54436d339" + integrity sha512-1iv7VXx0G9ec1isqQZ7y5LmoZo/ewAsyDHNA8EFDW5hqH2Kqovm33nSFkSdnLLAK+I5FlT+lo5Cw9itGe+CpQA== dependencies: inherits "^2.0.3" - readable-stream "^2.2.8" + readable-stream "^3.1.0" xtend "^4.0.1" level@^8.0.0: @@ -9452,27 +8249,24 @@ level@^8.0.0: browser-level "^1.0.1" classic-level "^1.2.0" -levelup@3.1.1, levelup@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/levelup/-/levelup-3.1.1.tgz#c2c0b3be2b4dc316647c53b42e2f559e232d2189" - integrity sha512-9N10xRkUU4dShSRRFTBdNaBxofz+PGaIZO962ckboJZiNmLuhVT6FZ6ZKAsICKfUBO76ySaYU6fJWX/jnj3Lcg== +leveldown@6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-6.1.0.tgz#7ab1297706f70c657d1a72b31b40323aa612b9ee" + integrity sha512-8C7oJDT44JXxh04aSSsfcMI8YiaGRhOFI9/pMEL7nWJLVsWajDPTRxsSHTM2WcTVY5nXM+SuRHzPPi0GbnDX+w== dependencies: - deferred-leveldown "~4.0.0" - level-errors "~2.0.0" - level-iterator-stream "~3.0.0" - xtend "~4.0.0" + abstract-leveldown "^7.2.0" + napi-macros "~2.0.0" + node-gyp-build "^4.3.0" -levelup@^1.2.1: - version "1.3.9" - resolved "https://registry.yarnpkg.com/levelup/-/levelup-1.3.9.tgz#2dbcae845b2bb2b6bea84df334c475533bbd82ab" - integrity sha512-VVGHfKIlmw8w1XqpGOAGwq6sZm2WwWLmlDcULkKWQXEA5EopA8OBNJ2Ck2v6bdk8HeEZSbCSEgzXadyQFm76sQ== +levelup@^4.3.2: + version "4.4.0" + resolved "https://registry.yarnpkg.com/levelup/-/levelup-4.4.0.tgz#f89da3a228c38deb49c48f88a70fb71f01cafed6" + integrity sha512-94++VFO3qN95cM/d6eBXvd894oJE0w3cInq9USsyQzzoJxmiYzPAocNcuGCPGGjoXqDVJcr3C1jzt1TSjyaiLQ== dependencies: - deferred-leveldown "~1.2.1" - level-codec "~7.0.0" - level-errors "~1.0.3" - level-iterator-stream "~1.3.0" - prr "~1.0.1" - semver "~5.4.1" + deferred-leveldown "~5.3.0" + level-errors "~2.0.0" + level-iterator-stream "~4.0.0" + level-supports "~1.0.0" xtend "~4.0.0" leven@^3.1.0: @@ -9501,6 +8295,16 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +link-check@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/link-check/-/link-check-5.2.0.tgz#595a339d305900bed8c1302f4342a29c366bf478" + integrity sha512-xRbhYLaGDw7eRDTibTAcl6fXtmUQ13vkezQiTqshHHdGueQeumgxxmQMIOmJYsh2p8BF08t8thhDQ++EAOOq3w== + dependencies: + is-relative-url "^4.0.0" + isemail "^3.2.0" + ms "^2.1.3" + needle "^3.1.0" + linkify-it@^3.0.1: version "3.0.3" resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.3.tgz#a98baf44ce45a550efb4d49c769d07524cc2fa2e" @@ -9515,17 +8319,6 @@ linkify-it@^4.0.1: dependencies: uc.micro "^1.0.1" -load-json-file@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - integrity sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A== - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - pinkie-promise "^2.0.0" - strip-bom "^2.0.0" - load-json-file@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" @@ -9558,10 +8351,10 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -lodash.assign@^4.0.3, lodash.assign@^4.0.6: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" - integrity sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw== +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== lodash.clonedeep@^4.5.0: version "4.5.0" @@ -9633,12 +8426,7 @@ lodash.truncate@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== -lodash@4.17.20: - version "4.17.20" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" - integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== - -lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.21, lodash@^4.17.4: +lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -9656,23 +8444,6 @@ long@^5.0.0: resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== -looper@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/looper/-/looper-2.0.0.tgz#66cd0c774af3d4fedac53794f742db56da8f09ec" - integrity sha512-6DzMHJcjbQX/UPHc1rRCBfKlLwDkvuGZ715cIR36wSdYqWXFT35uLXq5P/2orl3tz+t+VOVPxw4yPinQlUDGDQ== - -looper@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/looper/-/looper-3.0.0.tgz#2efa54c3b1cbaba9b94aee2e5914b0be57fbb749" - integrity sha512-LJ9wplN/uSn72oJRsXTx+snxPet5c8XiZmOKCm906NVYu+ag6SB6vUcnJcWxgnl2NfbIyeobAn7Bwv6xRj2XJg== - -loose-envify@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - loupe@^2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" @@ -9680,30 +8451,13 @@ loupe@^2.3.6: dependencies: get-func-name "^2.0.1" -lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" - integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== - -lowercase-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" - integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== - -lru-cache@5.1.1, lru-cache@^5.1.1: +lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== dependencies: yallist "^3.0.2" -lru-cache@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-3.2.0.tgz#71789b3b7f5399bec8565dda38aa30d2a097efee" - integrity sha512-91gyOKTc2k66UG6kHiH4h3S2eltcPwE1STVfMYC/NG+nZwf8IIuiamfmpGZjpbbxzSyEJaLC0tNSmhjlQUTJow== - dependencies: - pseudomap "^1.0.1" - lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -9711,21 +8465,21 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +"lru-cache@^9.1.1 || ^10.0.0": + version "10.1.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.1.0.tgz#2098d41c2dc56500e6c88584aa656c84de7d0484" + integrity sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag== + lru_map@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" integrity sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ== -ltgt@^2.1.2, ltgt@~2.2.0: +ltgt@~2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" integrity sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA== -ltgt@~2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.1.3.tgz#10851a06d9964b971178441c23c9e52698eece34" - integrity sha512-5VjHC5GsENtIi5rbJd+feEpDKhfr7j0odoUR2Uh978g+2p93nd5o34cTjQWohXsPsCZeqoDnIqEf88mPCe0Pfw== - make-dir@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" @@ -9745,18 +8499,6 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg== - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w== - dependencies: - object-visit "^1.0.0" - markdown-it@11.0.0: version "11.0.0" resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-11.0.0.tgz#dbfc30363e43d756ebc52c38586b91b90046b876" @@ -9779,6 +8521,28 @@ markdown-it@13.0.1: mdurl "^1.0.1" uc.micro "^1.0.5" +markdown-link-check@^3.11.2: + version "3.11.2" + resolved "https://registry.yarnpkg.com/markdown-link-check/-/markdown-link-check-3.11.2.tgz#303a8a03d4a34c42ef3158e0b245bced26b5d904" + integrity sha512-zave+vI4AMeLp0FlUllAwGbNytSKsS3R2Zgtf3ufVT892Z/L6Ro9osZwE9PNA7s0IkJ4onnuHqatpsaCiAShJw== + dependencies: + async "^3.2.4" + chalk "^5.2.0" + commander "^10.0.1" + link-check "^5.2.0" + lodash "^4.17.21" + markdown-link-extractor "^3.1.0" + needle "^3.2.0" + progress "^2.0.3" + +markdown-link-extractor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/markdown-link-extractor/-/markdown-link-extractor-3.1.0.tgz#0d5a703630d791a9e2017449e1a9b294f2d2b676" + integrity sha512-r0NEbP1dsM+IqB62Ru9TXLP/HDaTdBNIeylYXumuBi6Xv4ufjE1/g3TnslYL8VNqNcGAGbMptQFHrrdfoZ/Sug== + dependencies: + html-link-extractor "^1.0.5" + marked "^4.1.0" + markdown-table@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-1.1.3.tgz#9fcb69bcfdb8717bfd0398c6ec2d93036ef8de60" @@ -9838,6 +8602,11 @@ markdownlint@~0.27.0: dependencies: markdown-it "13.0.1" +marked@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.3.0.tgz#796362821b019f734054582038b116481b456cf3" + integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A== + mcl-wasm@^0.7.1: version "0.7.9" resolved "https://registry.yarnpkg.com/mcl-wasm/-/mcl-wasm-0.7.9.tgz#c1588ce90042a8700c3b60e40efb339fc07ab87f" @@ -9857,34 +8626,17 @@ mdurl@^1.0.1: resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g== -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== - -memdown@^1.0.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/memdown/-/memdown-1.4.1.tgz#b4e4e192174664ffbae41361aa500f3119efe215" - integrity sha512-iVrGHZB8i4OQfM155xx8akvG9FIj+ht14DX5CQkCTG4EHzZ3d3sgckIf/Lm9ivZalEsFuEVnWv2B2WZvbrro2w== - dependencies: - abstract-leveldown "~2.7.1" - functional-red-black-tree "^1.0.1" - immediate "^3.2.3" - inherits "~2.0.1" - ltgt "~2.2.0" - safe-buffer "~5.1.1" - -memdown@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/memdown/-/memdown-3.0.0.tgz#93aca055d743b20efc37492e9e399784f2958309" - integrity sha512-tbV02LfZMWLcHcq4tw++NuqMO+FZX8tNJEiD2aNRm48ZZusVg5N8NART+dmBkepJVye986oixErf7jfXboMGMA== +memdown@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/memdown/-/memdown-5.1.0.tgz#608e91a9f10f37f5b5fe767667a8674129a833cb" + integrity sha512-B3J+UizMRAlEArDjWHTMmadet+UKwHd3UjMgGBkZcKAxAYVPS9o0Yeiha4qvz7iGiL2Sb3igUft6p7nbFWctpw== dependencies: - abstract-leveldown "~5.0.0" + abstract-leveldown "~6.2.1" functional-red-black-tree "~1.0.1" immediate "~3.2.3" inherits "~2.0.1" ltgt "~2.2.0" - safe-buffer "~5.1.1" + safe-buffer "~5.2.0" memory-level@^1.0.0: version "1.0.0" @@ -9900,11 +8652,6 @@ memorystream@^0.3.1: resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" integrity sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw== -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== - merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -9915,74 +8662,35 @@ merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -merkle-patricia-tree@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-3.0.0.tgz#448d85415565df72febc33ca362b8b614f5a58f8" - integrity sha512-soRaMuNf/ILmw3KWbybaCjhx86EYeBbD8ph0edQCTed0JN/rxDt1EBN52Ajre3VyGo+91f8+/rfPIRQnnGMqmQ== - dependencies: - async "^2.6.1" - ethereumjs-util "^5.2.0" - level-mem "^3.0.1" - level-ws "^1.0.0" - readable-stream "^3.0.6" - rlp "^2.0.0" - semaphore ">=1.0.1" - -merkle-patricia-tree@^2.1.2, merkle-patricia-tree@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-2.3.2.tgz#982ca1b5a0fde00eed2f6aeed1f9152860b8208a" - integrity sha512-81PW5m8oz/pz3GvsAwbauj7Y00rqm81Tzad77tHBwU7pIAtN+TJnMSOJhxBKflSVYhptMMb9RskhqHqrSm1V+g== - dependencies: - async "^1.4.2" - ethereumjs-util "^5.0.0" - level-ws "0.0.0" - levelup "^1.2.1" - memdown "^1.0.0" - readable-stream "^2.0.0" - rlp "^2.0.0" - semaphore ">=1.0.1" - -merkletreejs@^0.2.32: - version "0.2.32" - resolved "https://registry.yarnpkg.com/merkletreejs/-/merkletreejs-0.2.32.tgz#cf1c0760e2904e4a1cc269108d6009459fd06223" - integrity sha512-TostQBiwYRIwSE5++jGmacu3ODcKAgqb0Y/pnIohXS7sWxh1gCkSptbmF1a43faehRDpcHf7J/kv0Ml2D/zblQ== +merkle-patricia-tree@^4.2.2, merkle-patricia-tree@^4.2.4: + version "4.2.4" + resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-4.2.4.tgz#ff988d045e2bf3dfa2239f7fabe2d59618d57413" + integrity sha512-eHbf/BG6eGNsqqfbLED9rIqbsF4+sykEaBn6OLNs71tjclbMcMOk1tEPmJKcNcNCLkvbpY/lwyOlizWsqPNo8w== + dependencies: + "@types/levelup" "^4.3.0" + ethereumjs-util "^7.1.4" + level-mem "^5.0.1" + level-ws "^2.0.0" + readable-stream "^3.6.0" + semaphore-async-await "^1.5.1" + +merkletreejs@^0.3.11: + version "0.3.11" + resolved "https://registry.yarnpkg.com/merkletreejs/-/merkletreejs-0.3.11.tgz#e0de05c3ca1fd368de05a12cb8efb954ef6fc04f" + integrity sha512-LJKTl4iVNTndhL+3Uz/tfkjD0klIWsHlUzgtuNnNrsf7bAlXR30m+xYB7lHr5Z/l6e/yAIsr26Dabx6Buo4VGQ== dependencies: bignumber.js "^9.0.1" buffer-reverse "^1.0.1" - crypto-js "^3.1.9-1" + crypto-js "^4.2.0" treeify "^1.1.0" web3-utils "^1.3.4" -methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== - micro-ftch@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/micro-ftch/-/micro-ftch-0.3.1.tgz#6cb83388de4c1f279a034fb0cf96dfc050853c5f" integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== -micromatch@^3.1.4: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -micromatch@^4.0.2, micromatch@^4.0.4: +micromatch@^4.0.4, micromatch@^4.0.5: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== @@ -10003,18 +8711,13 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@^2.1.12, mime-types@~2.1.19: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" -mime@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" @@ -10030,23 +8733,6 @@ mimic-fn@^4.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== -mimic-response@^1.0.0, mimic-response@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" - integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== - -mimic-response@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" - integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== - -min-document@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" - integrity sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ== - dependencies: - dom-walk "^0.1.0" - minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -10092,6 +8778,13 @@ minimatch@^7.4.3: dependencies: brace-expansion "^2.0.1" +minimatch@^9.0.1: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + minimatch@~3.0.4: version "3.0.8" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.8.tgz#5e6a59bd11e2ab0de1cfb843eb2d82e546c321c1" @@ -10099,52 +8792,22 @@ minimatch@~3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.8, minimist@~1.2.5, minimist@~1.2.8: +minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.8, minimist@~1.2.5: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -minipass@^2.6.0, minipass@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" - integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - -minizlib@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" - integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== - dependencies: - minipass "^2.9.0" - -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": + version "7.0.4" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" + integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== mkdirp-classic@^0.5.2: version "0.5.3" resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== -mkdirp-promise@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz#e9b8f68e552c68a9c1713b84883f7a1dd039b8a1" - integrity sha512-Hepn5kb1lJPtVW84RFT40YG1OddBNTOVUZR2bzQUHc+Z03en8/3uX0+060JDhcEzyO08HmipsN9DcnFMxhIL9w== - dependencies: - mkdirp "*" - -mkdirp@*: - version "3.0.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" - integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== - -mkdirp@0.5.x, mkdirp@^0.5.1, mkdirp@^0.5.5: +mkdirp@0.5.x, mkdirp@^0.5.1: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== @@ -10230,23 +8893,6 @@ mocha@^9.0.2: yargs-parser "20.2.4" yargs-unparser "2.0.0" -mock-fs@^4.1.0: - version "4.14.0" - resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" - integrity sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw== - -mock-property@~1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/mock-property/-/mock-property-1.0.3.tgz#3e37c50a56609d548cabd56559fde3dd8767b10c" - integrity sha512-2emPTb1reeLLYwHxyVx993iYyCHEiRRO+y8NFXFPL5kl5q14sgTK76cXyEKkeKCHeRw35SfdkUJ10Q1KfHuiIQ== - dependencies: - define-data-property "^1.1.1" - functions-have-names "^1.2.3" - gopd "^1.0.1" - has-property-descriptors "^1.0.0" - hasown "^2.0.0" - isarray "^2.0.5" - module-error@^1.0.1, module-error@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" @@ -10267,51 +8913,11 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.1.1: +ms@2.1.3, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -multibase@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.7.0.tgz#1adfc1c50abe05eefeb5091ac0c2728d6b84581b" - integrity sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg== - dependencies: - base-x "^3.0.8" - buffer "^5.5.0" - -multibase@~0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.6.1.tgz#b76df6298536cc17b9f6a6db53ec88f85f8cc12b" - integrity sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw== - dependencies: - base-x "^3.0.8" - buffer "^5.5.0" - -multicodec@^0.5.5: - version "0.5.7" - resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-0.5.7.tgz#1fb3f9dd866a10a55d226e194abba2dcc1ee9ffd" - integrity sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA== - dependencies: - varint "^5.0.0" - -multicodec@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-1.0.4.tgz#46ac064657c40380c28367c90304d8ed175a714f" - integrity sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg== - dependencies: - buffer "^5.6.0" - varint "^5.0.0" - -multihashes@^0.4.15, multihashes@~0.4.15: - version "0.4.21" - resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-0.4.21.tgz#dc02d525579f334a7909ade8a122dabb58ccfcb5" - integrity sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw== - dependencies: - buffer "^5.5.0" - multibase "^0.7.0" - varint "^5.0.0" - mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" @@ -10331,11 +8937,6 @@ nan@^2.17.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.18.0.tgz#26a6faae7ffbeb293a39660e88a76b82e30b7554" integrity sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w== -nano-json-stream-parser@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f" - integrity sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew== - nanoid@3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" @@ -10346,28 +8947,16 @@ nanoid@3.3.3: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - napi-macros@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.2.2.tgz#817fef20c3e0e40a963fbf7b37d1600bd0201044" integrity sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g== +napi-macros@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" + integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -10383,21 +8972,19 @@ nearley@^2.20.1: railroad-diagrams "^1.0.0" randexp "0.4.6" -negotiator@0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== +needle@^3.1.0, needle@^3.2.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/needle/-/needle-3.3.1.tgz#63f75aec580c2e77e209f3f324e2cdf3d29bd049" + integrity sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q== + dependencies: + iconv-lite "^0.6.3" + sax "^1.2.4" neo-async@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -next-tick@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" - integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== - nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -10422,13 +9009,15 @@ node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7: dependencies: whatwg-url "^5.0.0" -node-fetch@~1.7.1: - version "1.7.3" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" - integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ== - dependencies: - encoding "^0.1.11" - is-stream "^1.0.1" +node-gyp-build@4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" + integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== + +node-gyp-build@4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.4.0.tgz#42e99687ce87ddeaf3a10b99dc06abc11021f3f4" + integrity sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ== node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: version "4.6.1" @@ -10472,16 +9061,6 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -normalize-url@^4.1.0: - version "4.5.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" - integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== - -normalize-url@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" - integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== - npm-run-all@^4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba" @@ -10511,10 +9090,12 @@ npm-run-path@^5.1.0: dependencies: path-key "^4.0.0" -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== +nth-check@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" + integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== + dependencies: + boolbase "^1.0.0" number-to-bn@1.7.0: version "1.7.0" @@ -10529,55 +9110,21 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@^4, object-assign@^4.0.0, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ== - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - object-inspect@^1.13.1, object-inspect@^1.9.0: version "1.13.1" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== -object-inspect@~1.12.3: - version "1.12.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" - integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== - -object-is@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" - integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object-keys@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" - integrity sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw== - -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA== - dependencies: - isobject "^3.0.0" - object.assign@^4.1.4: version "4.1.4" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" @@ -10597,17 +9144,6 @@ object.fromentries@^2.0.7: define-properties "^1.2.0" es-abstract "^1.22.1" -object.getownpropertydescriptors@^2.1.6: - version "2.1.7" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.7.tgz#7a466a356cd7da4ba8b9e94ff6d35c3eeab5d56a" - integrity sha512-PrJz0C2xJ58FNn11XV2lr4Jt5Gzl94qpy9Lu0JlfEj14z88sqbSBJCBEzdlNUCzY2gburhbrwOZ5BHCmuNUy0g== - dependencies: - array.prototype.reduce "^1.0.6" - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - safe-array-concat "^1.0.0" - object.groupby@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.1.tgz#d41d9f3c8d6c778d9cbac86b4ee9f5af103152ee" @@ -10618,13 +9154,6 @@ object.groupby@^1.0.1: es-abstract "^1.22.1" get-intrinsic "^1.2.1" -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ== - dependencies: - isobject "^3.0.1" - object.values@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" @@ -10639,25 +9168,11 @@ obliterator@^2.0.0: resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-2.0.4.tgz#fa650e019b2d075d745e44f1effeb13a2adbe816" integrity sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ== -oboe@2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.4.tgz#20c88cdb0c15371bb04119257d4fdd34b0aa49f6" - integrity sha512-ymBJ4xSC6GBXLT9Y7lirj+xbqBLa+jADGJldGEYG7u8sZbS9GyG+u1Xk9c5cbriKwSpCg41qUhPjvU5xOpvIyQ== - dependencies: - http-https "^1.0.0" - obuf@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== -on-finished@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - once@1.x, once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -10686,14 +9201,6 @@ onetime@^6.0.0: dependencies: mimic-fn "^4.0.0" -open@^7.4.2: - version "7.4.2" - resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" - integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== - dependencies: - is-docker "^2.0.0" - is-wsl "^2.1.1" - open@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/open/-/open-9.1.0.tgz#684934359c90ad25742f5a26151970ff8c6c80b6" @@ -10733,33 +9240,11 @@ ordinal@^1.0.3: resolved "https://registry.yarnpkg.com/ordinal/-/ordinal-1.0.3.tgz#1a3c7726a61728112f50944ad7c35c06ae3a0d4d" integrity sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ== -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - integrity sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ== - -os-locale@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" - integrity sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g== - dependencies: - lcid "^1.0.0" - -os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: +os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== -p-cancelable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" - integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== - -p-cancelable@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" - integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== - p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" @@ -10838,34 +9323,18 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-asn1@^5.0.0, parse-asn1@^5.1.6: - version "5.1.6" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" - integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== +parent-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-2.0.0.tgz#fa71f88ff1a50c27e15d8ff74e0e3a9523bf8708" + integrity sha512-uo0Z9JJeWzv8BG+tRcapBKNJ0dro9cLyczGzulS6EfeyAdeC9sbojtW6XwvYxJkEne9En+J2XEl4zyglVeIwFg== dependencies: - asn1.js "^5.2.0" - browserify-aes "^1.0.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - safe-buffer "^5.1.1" + callsites "^3.1.0" parse-cache-control@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/parse-cache-control/-/parse-cache-control-1.0.1.tgz#8eeab3e54fa56920fe16ba38f77fa21aacc2d74e" integrity sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg== -parse-headers@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.5.tgz#069793f9356a54008571eb7f9761153e6c770da9" - integrity sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA== - -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ== - dependencies: - error-ex "^1.2.0" - parse-json@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" @@ -10884,66 +9353,26 @@ parse-json@^5.2.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" -parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== - -patch-package@6.2.2: - version "6.2.2" - resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.2.2.tgz#71d170d650c65c26556f0d0fbbb48d92b6cc5f39" - integrity sha512-YqScVYkVcClUY0v8fF0kWOjDYopzIM8e3bj/RU1DPeEF14+dCGm6UeOYm4jvCyxqIEQ5/eJzmbWfDWnUleFNMg== +parse5-htmlparser2-tree-adapter@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz#23c2cc233bcf09bb7beba8b8a69d46b08c62c2f1" + integrity sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g== dependencies: - "@yarnpkg/lockfile" "^1.1.0" - chalk "^2.4.2" - cross-spawn "^6.0.5" - find-yarn-workspace-root "^1.2.1" - fs-extra "^7.0.1" - is-ci "^2.0.0" - klaw-sync "^6.0.0" - minimist "^1.2.0" - rimraf "^2.6.3" - semver "^5.6.0" - slash "^2.0.0" - tmp "^0.0.33" + domhandler "^5.0.2" + parse5 "^7.0.0" -patch-package@^6.2.2: - version "6.5.1" - resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.5.1.tgz#3e5d00c16997e6160291fee06a521c42ac99b621" - integrity sha512-I/4Zsalfhc6bphmJTlrLoOcAF87jcxko4q0qsv4bGcurbr8IskEOtdnt9iCmsQVGL1B+iUhSQqweyTLJfCF9rA== +parse5@^7.0.0: + version "7.1.2" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" + integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== dependencies: - "@yarnpkg/lockfile" "^1.1.0" - chalk "^4.1.2" - cross-spawn "^6.0.5" - find-yarn-workspace-root "^2.0.0" - fs-extra "^9.0.0" - is-ci "^2.0.0" - klaw-sync "^6.0.0" - minimist "^1.2.6" - open "^7.4.2" - rimraf "^2.6.3" - semver "^5.6.0" - slash "^2.0.0" - tmp "^0.0.33" - yaml "^1.10.2" + entities "^4.4.0" path-browserify@^1.0.0, path-browserify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== -path-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - integrity sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ== - dependencies: - pinkie-promise "^2.0.0" - path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -10954,7 +9383,7 @@ path-exists@^4.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== -path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: +path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== @@ -10979,19 +9408,13 @@ path-parse@^1.0.6, path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== - -path-type@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - integrity sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg== +path-scurry@^1.10.1: + version "1.10.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" + integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== dependencies: - graceful-fs "^4.1.2" - pify "^2.0.0" - pinkie-promise "^2.0.0" + lru-cache "^9.1.1 || ^10.0.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-type@^3.0.0: version "3.0.0" @@ -11023,7 +9446,7 @@ pathval@^1.1.1: resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== -pbkdf2@^3.0.17, pbkdf2@^3.0.3, pbkdf2@^3.0.9: +pbkdf2@^3.0.17, pbkdf2@^3.0.9: version "3.1.2" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== @@ -11130,11 +9553,6 @@ pidtree@^0.3.0: resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a" integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== -pify@^2.0.0, pify@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== - pify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" @@ -11145,18 +9563,6 @@ pify@^4.0.1: resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw== - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg== - pirates@^4.0.4: version "4.0.6" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" @@ -11174,11 +9580,6 @@ pluralize@^8.0.0: resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg== - postgres-array@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" @@ -11228,16 +9629,6 @@ postgres-range@^1.1.1: resolved "https://registry.yarnpkg.com/postgres-range/-/postgres-range-1.1.3.tgz#9ccd7b01ca2789eb3c2e0888b3184225fa859f76" integrity sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g== -postinstall-postinstall@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/postinstall-postinstall/-/postinstall-postinstall-2.1.0.tgz#4f7f77441ef539d1512c40bd04c71b06a4704ca3" - integrity sha512-7hQX6ZlZXIoRiWNrbMQaLzUUfH+sSx39u8EJ9HYuDc1kLo9IXKWjM5RSquZN1ad5GnH8CGFM78fsAAQi3OKEEQ== - -precond@0.2: - version "0.2.3" - resolved "https://registry.yarnpkg.com/precond/-/precond-0.2.3.tgz#aa9591bcaa24923f1e0f4849d240f47efc1075ac" - integrity sha512-QCYG84SgGyGzqJ/vlMsxeXd/pgL/I94ixdNFyh1PusWmTCyVfPJjZ1K1jvHtsbfnXQs2TSkEP2fR7QiMZAnKFQ== - prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -11248,11 +9639,6 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== -prepend-http@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" - integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA== - preprocess@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/preprocess/-/preprocess-3.2.0.tgz#36b3e2c52331fbc6fabb26d4fd5709304b7e3675" @@ -11288,7 +9674,7 @@ prettier-plugin-solidity@^1.1.3: semver "^7.5.4" solidity-comments-extractor "^0.0.7" -prettier@^2.1.2, prettier@^2.3.2, prettier@^2.8.3: +prettier@^2.1.2, prettier@^2.3.1, prettier@^2.3.2, prettier@^2.8.3: version "2.8.8" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== @@ -11307,22 +9693,17 @@ pretty-format@^29.0.0, pretty-format@^29.7.0: ansi-styles "^5.0.0" react-is "^18.0.0" -private@^0.1.6, private@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== - process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -process@^0.11.1, process@^0.11.10: +process@^0.11.1: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== -progress@^2.0.0: +progress@^2.0.0, progress@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== @@ -11377,14 +9758,6 @@ protobufjs@^7.2.5: "@types/node" ">=13.7.0" long "^5.0.0" -proxy-addr@~2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" - integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== - dependencies: - forwarded "0.2.0" - ipaddr.js "1.9.1" - proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -11395,76 +9768,11 @@ prr@~1.0.1: resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw== -pseudomap@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ== - psl@^1.1.28: version "1.9.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== -public-encrypt@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" - integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - safe-buffer "^5.1.2" - -pull-cat@^1.1.9: - version "1.1.11" - resolved "https://registry.yarnpkg.com/pull-cat/-/pull-cat-1.1.11.tgz#b642dd1255da376a706b6db4fa962f5fdb74c31b" - integrity sha512-i3w+xZ3DCtTVz8S62hBOuNLRHqVDsHMNZmgrZsjPnsxXUgbWtXEee84lo1XswE7W2a3WHyqsNuDJTjVLAQR8xg== - -pull-defer@^0.2.2: - version "0.2.3" - resolved "https://registry.yarnpkg.com/pull-defer/-/pull-defer-0.2.3.tgz#4ee09c6d9e227bede9938db80391c3dac489d113" - integrity sha512-/An3KE7mVjZCqNhZsr22k1Tx8MACnUnHZZNPSJ0S62td8JtYr/AiRG42Vz7Syu31SoTLUzVIe61jtT/pNdjVYA== - -pull-level@^2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pull-level/-/pull-level-2.0.4.tgz#4822e61757c10bdcc7cf4a03af04c92734c9afac" - integrity sha512-fW6pljDeUThpq5KXwKbRG3X7Ogk3vc75d5OQU/TvXXui65ykm+Bn+fiktg+MOx2jJ85cd+sheufPL+rw9QSVZg== - dependencies: - level-post "^1.0.7" - pull-cat "^1.1.9" - pull-live "^1.0.1" - pull-pushable "^2.0.0" - pull-stream "^3.4.0" - pull-window "^2.1.4" - stream-to-pull-stream "^1.7.1" - -pull-live@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/pull-live/-/pull-live-1.0.1.tgz#a4ecee01e330155e9124bbbcf4761f21b38f51f5" - integrity sha512-tkNz1QT5gId8aPhV5+dmwoIiA1nmfDOzJDlOOUpU5DNusj6neNd3EePybJ5+sITr2FwyCs/FVpx74YMCfc8YeA== - dependencies: - pull-cat "^1.1.9" - pull-stream "^3.4.0" - -pull-pushable@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/pull-pushable/-/pull-pushable-2.2.0.tgz#5f2f3aed47ad86919f01b12a2e99d6f1bd776581" - integrity sha512-M7dp95enQ2kaHvfCt2+DJfyzgCSpWVR2h2kWYnVsW6ZpxQBx5wOu0QWOvQPVoPnBLUZYitYP2y7HyHkLQNeGXg== - -pull-stream@^3.2.3, pull-stream@^3.4.0, pull-stream@^3.6.8: - version "3.7.0" - resolved "https://registry.yarnpkg.com/pull-stream/-/pull-stream-3.7.0.tgz#85de0e44ff38a4d2ad08cc43fc458e1922f9bf0b" - integrity sha512-Eco+/R004UaCK2qEDE8vGklcTG2OeZSVm1kTUQNrykEjDwcFXDZhygFDsW49DbXyJMEhHeRL3z5cRVqPAhXlIw== - -pull-window@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/pull-window/-/pull-window-2.1.4.tgz#fc3b86feebd1920c7ae297691e23f705f88552f0" - integrity sha512-cbDzN76BMlcGG46OImrgpkMf/VkCnupj8JhsrpBw3aWBM9ye345aYnqitmZCgauBkc0HbbRRn9hCnsa3k2FNUg== - dependencies: - looper "^2.0.0" - pump@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" @@ -11481,10 +9789,10 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" - integrity sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA== +punycode@2.x.x, punycode@^2.1.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== punycode@^1.4.1: version "1.4.1" @@ -11496,23 +9804,11 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== -punycode@^2.1.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" - integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== - pure-rand@^6.0.0: version "6.0.4" resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.4.tgz#50b737f6a925468679bff00ad20eade53f37d5c7" integrity sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA== -qs@6.11.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== - dependencies: - side-channel "^1.0.4" - qs@^6.11.2, qs@^6.4.0: version "6.11.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" @@ -11525,15 +9821,6 @@ qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== -query-string@^5.0.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" - integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== - dependencies: - decode-uri-component "^0.2.0" - object-assign "^4.1.0" - strict-uri-encode "^1.0.0" - querystring@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd" @@ -11544,11 +9831,6 @@ queue-microtask@^1.2.2, queue-microtask@^1.2.3: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -quick-lru@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" - integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== - railroad-diagrams@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e" @@ -11562,37 +9844,14 @@ randexp@0.4.6: discontinuous-range "1.0.0" ret "~0.1.10" -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.0.6, randombytes@^2.1.0: +randombytes@^2.0.1, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== dependencies: safe-buffer "^5.1.0" -randomfill@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - -range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -raw-body@2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" - integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== - dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.4.24" - unpipe "1.0.0" - -raw-body@2.5.2, raw-body@^2.4.1: +raw-body@^2.4.1: version "2.5.2" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== @@ -11617,23 +9876,6 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== -read-pkg-up@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - integrity sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A== - dependencies: - find-up "^1.0.0" - read-pkg "^1.0.0" - -read-pkg@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - integrity sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ== - dependencies: - load-json-file "^1.0.0" - normalize-package-data "^2.3.2" - path-type "^1.0.0" - read-pkg@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" @@ -11643,17 +9885,7 @@ read-pkg@^3.0.0: normalize-package-data "^2.3.2" path-type "^3.0.0" -readable-stream@^1.0.33: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.2.2, readable-stream@^2.2.8, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: +readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.5: version "2.3.8" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -11666,7 +9898,7 @@ readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.2.2, readable string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0, readable-stream@^3.6.2: +readable-stream@^3.1.0, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0: version "3.6.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== @@ -11675,7 +9907,7 @@ readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable string_decoder "^1.1.1" util-deprecate "^1.0.1" -readable-stream@~1.0.15, readable-stream@~1.0.26-4: +readable-stream@~1.0.26-4: version "1.0.34" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg== @@ -11706,33 +9938,16 @@ recursive-readdir@^2.2.2: dependencies: minimatch "^3.0.5" -regenerate@^1.2.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" - integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== +reduce-flatten@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27" + integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w== regenerator-runtime@^0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== -regenerator-transform@^0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" - integrity sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q== - dependencies: - babel-runtime "^6.18.0" - babel-types "^6.19.0" - private "^0.1.6" - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - regexp.prototype.flags@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" @@ -11747,44 +9962,11 @@ regexpp@^3.1.0: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== -regexpu-core@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" - integrity sha512-tJ9+S4oKjxY8IZ9jmjnp/mtytu1u3iyIQAfmI51IKWH6bFf7XR1ybtaO6j7INhZKXOTYADk7V5qxaqLkmNxiZQ== - dependencies: - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - -regjsgen@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" - integrity sha512-x+Y3yA24uF68m5GA+tBjbGYo64xXVJpbToBaWCoSNSc1hdk6dfctaRWrNFTVJZIIhL5GxW8zwjoixbnifnK59g== - -regjsparser@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" - integrity sha512-jlQ9gYLfk2p3V5Ag5fYhA7fv7OHzd1KUH0PRP46xc3TgwjwgROIW572AfYg/X9kaNq/LJnu6oJcFRXlIrGoTRw== - dependencies: - jsesc "~0.5.0" - -repeat-element@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" - integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== - repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - integrity sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A== - dependencies: - is-finite "^1.0.0" - req-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/req-cwd/-/req-cwd-2.0.0.tgz#d4082b4d44598036640fb73ddea01ed53db49ebc" @@ -11799,7 +9981,7 @@ req-from@^2.0.0: dependencies: resolve-from "^3.0.0" -request@^2.79.0, request@^2.85.0: +request@^2.85.0: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -11830,26 +10012,11 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== -require-from-string@^1.1.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-1.2.1.tgz#529c9ccef27380adfec9a2f965b649bbee636418" - integrity sha512-H7AkJWMobeskkttHyhTVtS0fxpFLjxhbfMa6Bk3wimP7sdPRGL3EyCg3sAQenFfAe+xQ+oAc85Nmtvq0ROM83Q== - require-from-string@^2.0.0, require-from-string@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== -require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - integrity sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug== - -resolve-alpn@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" - integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== - resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" @@ -11877,11 +10044,6 @@ resolve-pkg-maps@^1.0.0: resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg== - resolve.exports@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" @@ -11899,7 +10061,7 @@ resolve@1.17.0: dependencies: path-parse "^1.0.6" -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.20.0, resolve@^1.22.4, resolve@^1.8.1, resolve@~1.22.6: +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.20.0, resolve@^1.22.4, resolve@^1.8.1: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -11908,20 +10070,6 @@ resolve@^1.1.6, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.20.0, resolve@^1.22 path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -responselike@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" - integrity sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ== - dependencies: - lowercase-keys "^1.0.0" - -responselike@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc" - integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw== - dependencies: - lowercase-keys "^2.0.0" - restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" @@ -11945,7 +10093,7 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@^2.2.8, rimraf@^2.6.3: +rimraf@^2.2.8: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -11959,6 +10107,13 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" +rimraf@^5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.5.tgz#9be65d2d6e683447d2e9013da2bf451139a61ccf" + integrity sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A== + dependencies: + glob "^10.3.7" + ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" @@ -11967,7 +10122,14 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" -rlp@^2.0.0, rlp@^2.2.1, rlp@^2.2.2, rlp@^2.2.3, rlp@^2.2.4: +rlp@2.2.6: + version "2.2.6" + resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.6.tgz#c80ba6266ac7a483ef1e69e8e2f056656de2fb2c" + integrity sha512-HAfAmL6SDYNWPUOJNrM500x4Thn4PZsEy5pijPh40U9WfNk0z15hUYzO9xVIMAdIHdFtD8CBDHd75Td1g36Mjg== + dependencies: + bn.js "^4.11.1" + +rlp@^2.2.3, rlp@^2.2.4: version "2.2.7" resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.7.tgz#33f31c4afac81124ac4b283e2bd4d9720b30beaf" integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== @@ -12022,7 +10184,7 @@ rxjs@^6.4.0: dependencies: tslib "^1.9.0" -safe-array-concat@^1.0.0, safe-array-concat@^1.0.1: +safe-array-concat@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c" integrity sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q== @@ -12032,7 +10194,7 @@ safe-array-concat@^1.0.0, safe-array-concat@^1.0.1: has-symbols "^1.0.3" isarray "^2.0.5" -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -12042,13 +10204,6 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-event-emitter@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/safe-event-emitter/-/safe-event-emitter-1.0.1.tgz#5b692ef22329ed8f69fdce607e50ca734f6f20af" - integrity sha512-e1wFe99A91XYYxoQbcq2ZJUWurxEyP8vfz7A7vuUe1s95q8r5ebraVaA1BukYJcpM6V16ugWoD9vngi8Ccu5fg== - dependencies: - events "^3.0.0" - safe-regex-test@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" @@ -12058,18 +10213,16 @@ safe-regex-test@^1.0.0: get-intrinsic "^1.1.3" is-regex "^1.1.4" -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg== - dependencies: - ret "~0.1.10" - "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +sax@^1.2.4: + version "1.3.0" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0" + integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA== + sc-istanbul@^0.4.5: version "0.4.6" resolved "https://registry.yarnpkg.com/sc-istanbul/-/sc-istanbul-0.4.6.tgz#cf6784355ff2076f92d70d59047d71c13703e839" @@ -12090,19 +10243,12 @@ sc-istanbul@^0.4.5: which "^1.1.1" wordwrap "^1.0.0" -scrypt-js@3.0.1, scrypt-js@^3.0.0, scrypt-js@^3.0.1: +scrypt-js@3.0.1, scrypt-js@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== -scryptsy@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-1.2.1.tgz#a3225fa4b2524f802700761e2855bdf3b2d92163" - integrity sha512-aldIRgMozSJ/Gl6K6qmJZysRP82lz83Wb42vl4PWN8SaLFHIaOzLPc9nUUW2jQN88CuGm5q5HefJ9jZ3nWSmTw== - dependencies: - pbkdf2 "^3.0.3" - -secp256k1@^4.0.1: +secp256k1@4.0.3, secp256k1@^4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.3.tgz#c4559ecd1b8d3c1827ed2d1b94190d69ce267303" integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA== @@ -12111,17 +10257,17 @@ secp256k1@^4.0.1: node-addon-api "^2.0.0" node-gyp-build "^4.2.0" -seedrandom@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.1.tgz#eb3dde015bcf55df05a233514e5df44ef9dce083" - integrity sha512-1/02Y/rUeU1CJBAGLebiC5Lbo5FnB22gQbIFFYTLkwvp1xdABZJH1sn4ZT1MzXmPpzv+Rf/Lu2NcsLJiK4rcDg== +seedrandom@3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.5.tgz#54edc85c95222525b0c7a6f6b3543d8e0b3aa0a7" + integrity sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg== -semaphore@>=1.0.1, semaphore@^1.0.3, semaphore@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa" - integrity sha512-O4OZEaNtkMd/K0i6js9SL+gqy0ZCBMgUvlSqHKi4IBdjhe7wB8pwztUk1BbZ1fmrvpwFrPbHzqd2w5pTcJH6LA== +semaphore-async-await@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/semaphore-async-await/-/semaphore-async-await-1.5.1.tgz#857bef5e3644601ca4b9570b87e9df5ca12974fa" + integrity sha512-b/ptP11hETwYWpeilHXXQiV5UJNJl7ZWWooKRE5eBIYWoom6dZ0SluCIdCtKycsMtZgKWE01/qAw6jblw1YVhg== -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.6.0: version "5.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== @@ -12138,30 +10284,6 @@ semver@^7.2.1, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.5.1, semve dependencies: lru-cache "^6.0.0" -semver@~5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" - integrity sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg== - -send@0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== - dependencies: - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "2.0.0" - mime "1.6.0" - ms "2.1.3" - on-finished "2.4.1" - range-parser "~1.2.1" - statuses "2.0.1" - serialize-javascript@6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" @@ -12169,32 +10291,6 @@ serialize-javascript@6.0.0: dependencies: randombytes "^2.1.0" -serve-static@1.15.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.18.0" - -servify@^0.1.12: - version "0.1.12" - resolved "https://registry.yarnpkg.com/servify/-/servify-0.1.12.tgz#142ab7bee1f1d033b66d0707086085b17c06db95" - integrity sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw== - dependencies: - body-parser "^1.16.0" - cors "^2.8.1" - express "^4.14.0" - request "^2.79.0" - xhr "^2.3.3" - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== - set-function-length@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" @@ -12219,16 +10315,6 @@ set-immediate-shim@^1.0.1: resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" integrity sha512-Li5AOqrZWCVA2n5kryzEmqai6bKSIvpz5oUJHPVj6+dsbD3X1ixtsY5tEnsaNpH3pFAHmG8eIHUrtEtohrg+UQ== -set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" @@ -12307,35 +10393,16 @@ signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== -simple-concat@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" - integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== - -simple-get@^2.7.0: - version "2.8.2" - resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.2.tgz#5708fb0919d440657326cd5fe7d2599d07705019" - integrity sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw== - dependencies: - decompress-response "^3.3.0" - once "^1.3.1" - simple-concat "^1.0.0" +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== -slash@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - integrity sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg== - -slash@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" - integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== - slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -12350,36 +10417,6 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - solc@0.7.3: version "0.7.3" resolved "https://registry.yarnpkg.com/solc/-/solc-0.7.3.tgz#04646961bd867a744f63d2b4e3c0701ffdc7d78a" @@ -12395,10 +10432,10 @@ solc@0.7.3: semver "^5.5.0" tmp "0.0.33" -solc@0.8.17: - version "0.8.17" - resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.17.tgz#c748fec6a64bf029ec406aa9b37e75938d1115ae" - integrity sha512-Dtidk2XtTTmkB3IKdyeg6wLYopJnBVxdoykN8oP8VY3PQjN16BScYoUJTXFm2OP7P0hXNAqWiJNmmfuELtLf8g== +solc@0.8.15: + version "0.8.15" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.15.tgz#d274dca4d5a8b7d3c9295d4cbdc9291ee1c52152" + integrity sha512-Riv0GNHNk/SddN/JyEuFKwbcWcEeho15iyupTSHw5Np6WuXA5D8kEHbyzDHi6sqmvLzu2l+8b1YmL8Ytple+8w== dependencies: command-exists "^1.2.8" commander "^8.1.0" @@ -12408,28 +10445,16 @@ solc@0.8.17: semver "^5.5.0" tmp "0.0.33" -solc@^0.4.20: - version "0.4.26" - resolved "https://registry.yarnpkg.com/solc/-/solc-0.4.26.tgz#5390a62a99f40806b86258c737c1cf653cc35cb5" - integrity sha512-o+c6FpkiHd+HPjmjEVpQgH7fqZ14tJpXhho+/bQXlXbliLIS/xjXb42Vxh+qQY1WCSTMQ0+a5vR9vi0MfhU6mA== - dependencies: - fs-extra "^0.30.0" - memorystream "^0.3.1" - require-from-string "^1.1.0" - semver "^5.3.0" - yargs "^4.7.1" - -solc@^0.6.3: - version "0.6.12" - resolved "https://registry.yarnpkg.com/solc/-/solc-0.6.12.tgz#48ac854e0c729361b22a7483645077f58cba080e" - integrity sha512-Lm0Ql2G9Qc7yPP2Ba+WNmzw2jwsrd3u4PobHYlSOxaut3TtUbj9+5ZrT6f4DUpNPEoBaFUOEg9Op9C0mk7ge9g== +solc@0.8.17: + version "0.8.17" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.17.tgz#c748fec6a64bf029ec406aa9b37e75938d1115ae" + integrity sha512-Dtidk2XtTTmkB3IKdyeg6wLYopJnBVxdoykN8oP8VY3PQjN16BScYoUJTXFm2OP7P0hXNAqWiJNmmfuELtLf8g== dependencies: command-exists "^1.2.8" - commander "3.0.2" - fs-extra "^0.30.0" + commander "^8.1.0" + follow-redirects "^1.12.1" js-sha3 "0.8.0" memorystream "^0.3.1" - require-from-string "^2.0.0" semver "^5.5.0" tmp "0.0.33" @@ -12463,7 +10488,7 @@ solidity-comments-extractor@^0.0.7: resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz#99d8f1361438f84019795d928b931f4e5c39ca19" integrity sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw== -solidity-coverage@^0.8.2: +solidity-coverage@^0.8.5: version "0.8.5" resolved "https://registry.yarnpkg.com/solidity-coverage/-/solidity-coverage-0.8.5.tgz#64071c3a0c06a0cecf9a7776c35f49edc961e875" integrity sha512-6C6N6OV2O8FQA0FWA95FdzVH+L16HU94iFgg5wAFZ29UpLFkgNI/DRR2HotG1bC0F4gAc/OMs2BJI44Q/DYlKQ== @@ -12504,25 +10529,6 @@ solpp@^0.11.5: resolve "^1.10.0" semver "^5.6.0" -source-map-resolve@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" - integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - -source-map-support@0.5.12: - version "0.5.12" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" - integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - source-map-support@0.5.13: version "0.5.13" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" @@ -12531,13 +10537,6 @@ source-map-support@0.5.13: buffer-from "^1.0.0" source-map "^0.6.0" -source-map-support@^0.4.15: - version "0.4.18" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" - integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== - dependencies: - source-map "^0.5.6" - source-map-support@^0.5.13: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" @@ -12546,16 +10545,6 @@ source-map-support@^0.5.13: buffer-from "^1.0.0" source-map "^0.6.0" -source-map-url@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" - integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== - -source-map@^0.5.6, source-map@^0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== - source-map@^0.6.0, source-map@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -12599,13 +10588,6 @@ split-ca@^1.0.0, split-ca@^1.0.1: resolved "https://registry.yarnpkg.com/split-ca/-/split-ca-1.0.1.tgz#6c83aff3692fa61256e0cd197e05e9de157691a6" integrity sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ== -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - split2@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" @@ -12665,31 +10647,15 @@ stacktrace-parser@^0.1.10: dependencies: type-fest "^0.7.1" -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g== - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - statuses@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== -stream-to-pull-stream@^1.7.1: - version "1.7.3" - resolved "https://registry.yarnpkg.com/stream-to-pull-stream/-/stream-to-pull-stream-1.7.3.tgz#4161aa2d2eb9964de60bfa1af7feaf917e874ece" - integrity sha512-6sNyqJpr5dIOQdgNy/xcDWwDuzAsAwVzhzrWlAPAQ7Lkjx/rv0wgvxEyKwTq6FmNd5rjTrELt/CLmaSw7crMGg== - dependencies: - looper "^3.0.0" - pull-stream "^3.2.3" - -strict-uri-encode@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" - integrity sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ== +string-format@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-format/-/string-format-2.0.0.tgz#f2df2e7097440d3b65de31b6d40d54c96eaffb9b" + integrity sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA== string-length@^4.0.1: version "4.0.2" @@ -12699,14 +10665,14 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw== +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" @@ -12716,14 +10682,14 @@ string-width@^2.1.0, string-width@^2.1.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" string.prototype.padend@^3.0.0: version "3.1.5" @@ -12734,7 +10700,7 @@ string.prototype.padend@^3.0.0: define-properties "^1.2.0" es-abstract "^1.22.1" -string.prototype.trim@^1.2.8, string.prototype.trim@~1.2.8: +string.prototype.trim@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== @@ -12780,12 +10746,12 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: - ansi-regex "^2.0.0" + ansi-regex "^5.0.1" strip-ansi@^4.0.0: version "4.0.0" @@ -12801,19 +10767,12 @@ strip-ansi@^5.1.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-bom@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - integrity sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g== +strip-ansi@^7.0.1, strip-ansi@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== dependencies: - is-utf8 "^0.2.0" + ansi-regex "^6.0.1" strip-bom@^3.0.0: version "3.0.0" @@ -12859,11 +10818,6 @@ supports-color@8.1.1, supports-color@^8.0.0: dependencies: has-flag "^4.0.0" -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g== - supports-color@^3.1.0: version "3.2.3" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" @@ -12890,23 +10844,6 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -swarm-js@^0.1.40: - version "0.1.42" - resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.42.tgz#497995c62df6696f6e22372f457120e43e727979" - integrity sha512-BV7c/dVlA3R6ya1lMlSSNPLYrntt0LUq4YMgy3iwpCIc6rZnS5W2wUoctarZ5pXlpKtxDDf9hNziEkcfrxdhqQ== - dependencies: - bluebird "^3.5.0" - buffer "^5.0.5" - eth-lib "^0.1.26" - fs-extra "^4.0.2" - got "^11.8.5" - mime-types "^2.1.16" - mkdirp-promise "^5.0.1" - mock-fs "^4.1.0" - setimmediate "^1.0.5" - tar "^4.0.2" - xhr-request "^1.0.1" - sync-request@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/sync-request/-/sync-request-6.1.0.tgz#e96217565b5e50bbffe179868ba75532fb597e68" @@ -12936,12 +10873,23 @@ synckit@^0.8.5: dependencies: "@matterlabs/hardhat-zksync-deploy" "^0.6.5" "@nomiclabs/hardhat-solpp" "^2.0.1" - commander "^8.3.0" + commander "^9.4.1" ethers "^5.7.0" + fast-glob "^3.3.2" hardhat "^2.18.3" preprocess "^3.2.0" zksync-web3 "^0.14.3" +table-layout@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.2.tgz#c4038a1853b0136d63365a734b6931cf4fad4a04" + integrity sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A== + dependencies: + array-back "^4.0.1" + deep-extend "~0.6.0" + typical "^5.2.0" + wordwrapjs "^4.0.0" + table@^6.0.9, table@^6.8.0, table@^6.8.1: version "6.8.1" resolved "https://registry.yarnpkg.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf" @@ -12970,28 +10918,6 @@ tapable@^2.2.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== -tape@^4.6.3: - version "4.17.0" - resolved "https://registry.yarnpkg.com/tape/-/tape-4.17.0.tgz#de89f3671ddc5dad178d04c28dc6b0183f42268e" - integrity sha512-KCuXjYxCZ3ru40dmND+oCLsXyuA8hoseu2SS404Px5ouyS0A99v8X/mdiLqsR5MTAyamMBN7PRwt2Dv3+xGIxw== - dependencies: - "@ljharb/resumer" "~0.0.1" - "@ljharb/through" "~2.3.9" - call-bind "~1.0.2" - deep-equal "~1.1.1" - defined "~1.0.1" - dotignore "~0.1.2" - for-each "~0.3.3" - glob "~7.2.3" - has "~1.0.3" - inherits "~2.0.4" - is-regex "~1.1.4" - minimist "~1.2.8" - mock-property "~1.0.0" - object-inspect "~1.12.3" - resolve "~1.22.6" - string.prototype.trim "~1.2.8" - tar-fs@~1.16.3: version "1.16.3" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509" @@ -13036,19 +10962,6 @@ tar-stream@^2.0.0: inherits "^2.0.3" readable-stream "^3.1.1" -tar@^4.0.2: - version "4.4.19" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3" - integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA== - dependencies: - chownr "^1.1.4" - fs-minipass "^1.2.7" - minipass "^2.9.0" - minizlib "^1.3.3" - mkdirp "^0.5.5" - safe-buffer "^5.2.1" - yallist "^3.1.1" - template-file@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/template-file/-/template-file-6.0.1.tgz#ce4d1f48e56d637cc94bb97ec205e6e035bbb2a5" @@ -13076,11 +10989,6 @@ test-value@^2.1.0: array-back "^1.0.3" typical "^2.6.0" -testrpc@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/testrpc/-/testrpc-0.0.1.tgz#83e2195b1f5873aec7be1af8cbe6dcf39edb7aed" - integrity sha512-afH1hO+SQ/VPlmaLUFj2636QMeDvPCeQMc/9RBMW0IfjNe9gFD9Ra3ShqYkB7py0do1ZcCna/9acHyzTJ+GcNA== - text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -13117,24 +11025,11 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" -through2@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - "through@>=2.2.7 <3", through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== -timed-out@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" - integrity sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA== - titleize@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/titleize/-/titleize-3.0.0.tgz#71c12eb7fdd2558aa8a44b0be83b8a76694acd53" @@ -13147,13 +11042,6 @@ tmp@0.0.33, tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" -tmp@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.1.0.tgz#ee434a4e22543082e294ba6201dcc6eafefa2877" - integrity sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw== - dependencies: - rimraf "^2.6.3" - tmpl@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" @@ -13164,36 +11052,11 @@ to-buffer@^1.1.1: resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== -to-fast-properties@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" - integrity sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og== - to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg== - dependencies: - kind-of "^3.0.2" - -to-readable-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" - integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg== - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -13201,16 +11064,6 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - toidentifier@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" @@ -13234,26 +11087,26 @@ treeify@^1.1.0: resolved "https://registry.yarnpkg.com/treeify/-/treeify-1.1.0.tgz#4e31c6a463accd0943879f30667c4fdaff411bb8" integrity sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A== -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - integrity sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw== - ts-api-utils@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.3.tgz#f12c1c781d04427313dbac808f453f050e54a331" integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg== +ts-command-line-args@^2.2.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz#e64456b580d1d4f6d948824c274cf6fa5f45f7f0" + integrity sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw== + dependencies: + chalk "^4.1.0" + command-line-args "^5.1.1" + command-line-usage "^6.1.0" + string-format "^2.0.0" + ts-essentials@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-1.0.4.tgz#ce3b5dade5f5d97cf69889c11bf7d2da8555b15a" integrity sha512-q3N1xS4vZpRouhYHDPwO0bDW3EZ6SK9CrrDHxi/D6BPReSjpVgWIOpLS2o0gSBZm+7q/wyKp6RVM1AeeW7uyfQ== -ts-essentials@^6.0.3: - version "6.0.7" - resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-6.0.7.tgz#5f4880911b7581a873783740ce8b94da163d18a6" - integrity sha512-2E4HIIj4tQJlIHuATRHayv0EfMGK3ris/GRk1E3CFnsZzeNV+hUmelbaTZHLtXaZppM5oLhHRtO04gINC4Jusw== - ts-essentials@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-7.0.3.tgz#686fd155a02133eedcc5362dc8b5056cde3e5a38" @@ -13354,7 +11207,7 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" -tweetnacl-util@^0.15.0, tweetnacl-util@^0.15.1: +tweetnacl-util@^0.15.1: version "0.15.1" resolved "https://registry.yarnpkg.com/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz#b80fcdb5c97bcc508be18c44a4be50f022eea00b" integrity sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw== @@ -13364,7 +11217,7 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== -tweetnacl@^1.0.0, tweetnacl@^1.0.3: +tweetnacl@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== @@ -13403,49 +11256,39 @@ type-fest@^0.7.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== -type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -type@^1.0.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" - integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== - -type@^2.7.2: - version "2.7.2" - resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0" - integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw== +type-fest@^1.0.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1" + integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== -typechain@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/typechain/-/typechain-3.0.0.tgz#d5a47700831f238e43f7429b987b4bb54849b92e" - integrity sha512-ft4KVmiN3zH4JUFu2WJBrwfHeDf772Tt2d8bssDTo/YcckKW2D+OwFrHXRC6hJvO3mHjFQTihoMV6fJOi0Hngg== +typechain@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/typechain/-/typechain-4.0.3.tgz#e8fcd6c984676858c64eeeb155ea783a10b73779" + integrity sha512-tmoHQeXZWHxIdeLK+i6dU0CU0vOd9Cndr3jFTZIMzak5/YpFZ8XoiYpTZcngygGBqZo+Z1EUmttLbW9KkFZLgQ== dependencies: command-line-args "^4.0.7" debug "^4.1.1" fs-extra "^7.0.0" js-sha3 "^0.8.0" lodash "^4.17.15" - ts-essentials "^6.0.3" + ts-essentials "^7.0.1" ts-generator "^0.1.1" -typechain@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/typechain/-/typechain-4.0.3.tgz#e8fcd6c984676858c64eeeb155ea783a10b73779" - integrity sha512-tmoHQeXZWHxIdeLK+i6dU0CU0vOd9Cndr3jFTZIMzak5/YpFZ8XoiYpTZcngygGBqZo+Z1EUmttLbW9KkFZLgQ== +typechain@^8.0.0: + version "8.3.2" + resolved "https://registry.yarnpkg.com/typechain/-/typechain-8.3.2.tgz#1090dd8d9c57b6ef2aed3640a516bdbf01b00d73" + integrity sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q== dependencies: - command-line-args "^4.0.7" - debug "^4.1.1" + "@types/prettier" "^2.1.1" + debug "^4.3.1" fs-extra "^7.0.0" + glob "7.1.7" js-sha3 "^0.8.0" lodash "^4.17.15" + mkdirp "^1.0.4" + prettier "^2.3.1" + ts-command-line-args "^2.2.0" ts-essentials "^7.0.1" - ts-generator "^0.1.1" typed-array-buffer@^1.0.0: version "1.0.0" @@ -13508,28 +11351,21 @@ typescript@^5.2.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37" integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw== -typewise-core@^1.2, typewise-core@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/typewise-core/-/typewise-core-1.2.0.tgz#97eb91805c7f55d2f941748fa50d315d991ef195" - integrity sha512-2SCC/WLzj2SbUwzFOzqMCkz5amXLlxtJqDKTICqg30x+2DZxcfZN2MvQZmGfXWKNWaKK9pBPsvkcwv8bF/gxKg== - -typewise@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/typewise/-/typewise-1.0.3.tgz#1067936540af97937cc5dcf9922486e9fa284651" - integrity sha512-aXofE06xGhaQSPzt8hlTY+/YWQhm9P0jYUp1f2XtmW/3Bk0qzXcyFWAtPoo2uTGQj1ZwbDuSyuxicq+aDo8lCQ== - dependencies: - typewise-core "^1.2.0" - -typewiselite@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typewiselite/-/typewiselite-1.0.0.tgz#c8882fa1bb1092c06005a97f34ef5c8508e3664e" - integrity sha512-J9alhjVHupW3Wfz6qFRGgQw0N3gr8hOkw6zm7FZ6UR1Cse/oD9/JVok7DNE9TT9IbciDHX2Ex9+ksE6cRmtymw== - typical@^2.6.0, typical@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/typical/-/typical-2.6.1.tgz#5c080e5d661cbbe38259d2e70a3c7253e873881d" integrity sha512-ofhi8kjIje6npGozTip9Fr8iecmYfEbS06i0JnIg+rh51KakryWF4+jX8lLKZVhy6N+ID45WYSFCxPOdTWCzNg== +typical@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" + integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw== + +typical@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/typical/-/typical-5.2.0.tgz#4daaac4f2b5315460804f0acf6cb69c52bb93066" + integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg== + uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" @@ -13540,11 +11376,6 @@ uglify-js@^3.1.4: resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== -ultron@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" - integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== - unbox-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" @@ -13555,11 +11386,6 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" -underscore@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" - integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg== - undici-types@~5.26.4: version "5.26.5" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" @@ -13572,15 +11398,12 @@ undici@^5.14.0: dependencies: "@fastify/busboy" "^2.0.0" -union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== +unique-string@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-3.0.0.tgz#84a1c377aff5fd7a8bc6b55d8244b2bd90d75b9a" + integrity sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ== dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" + crypto-random-string "^4.0.0" universalify@^0.1.0: version "0.1.2" @@ -13592,24 +11415,11 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== -unorm@^1.3.3: - version "1.6.0" - resolved "https://registry.yarnpkg.com/unorm/-/unorm-1.6.0.tgz#029b289661fba714f1a9af439eb51d9b16c205af" - integrity sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA== - -unpipe@1.0.0, unpipe@~1.0.0: +unpipe@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ== - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - untildify@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.3.tgz#1e7b42b140bcfd922b22e70ca1265bfe3634c7c9" @@ -13635,23 +11445,6 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg== - -url-parse-lax@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" - integrity sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ== - dependencies: - prepend-http "^2.0.0" - -url-set-query@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/url-set-query/-/url-set-query-1.0.0.tgz#016e8cfd7c20ee05cafe7795e892bd0702faa339" - integrity sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg== - url@^0.11.0: version "0.11.3" resolved "https://registry.yarnpkg.com/url/-/url-0.11.3.tgz#6f495f4b935de40ce4a0a52faee8954244f3d3ad" @@ -13660,19 +11453,14 @@ url@^0.11.0: punycode "^1.4.1" qs "^6.11.2" -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - -utf-8-validate@^5.0.2: - version "5.0.10" - resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.10.tgz#d7d10ea39318171ca982718b6b96a8d2442571a2" - integrity sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ== +utf-8-validate@5.0.7: + version "5.0.7" + resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.7.tgz#c15a19a6af1f7ad9ec7ddc425747ca28c3644922" + integrity sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q== dependencies: node-gyp-build "^4.3.0" -utf8@3.0.0, utf8@^3.0.0: +utf8@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== @@ -13682,19 +11470,6 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -util.promisify@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.1.2.tgz#02b3dbadbb80071eee4c43aed58747afdfc516db" - integrity sha512-PBdZ03m1kBnQ5cjjO0ZvJMJS+QsbyIcFwi4hY4U76OQsCO9JrOYjbCFgIF76ccFg9xnJo7ZHPkqyj1GqmdS7MA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - for-each "^0.3.3" - has-proto "^1.0.1" - has-symbols "^1.0.3" - object.getownpropertydescriptors "^2.1.6" - safe-array-concat "^1.0.0" - util@^0.10.3: version "0.10.4" resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" @@ -13702,16 +11477,6 @@ util@^0.10.3: dependencies: inherits "2.0.3" -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== - -uuid@3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== - uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" @@ -13749,16 +11514,6 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" -varint@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.2.tgz#5b47f8a947eb668b848e034dcfa87d0ff8a7f7a4" - integrity sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow== - -vary@^1, vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== - verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" @@ -13768,6 +11523,16 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +vscode-languageserver-textdocument@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz#0822a000e7d4dc083312580d7575fe9e3ba2e2bf" + integrity sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA== + +vscode-uri@^3.0.8: + version "3.0.8" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.8.tgz#1770938d3e72588659a172d0fd4642780083ff9f" + integrity sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw== + walker@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" @@ -13780,259 +11545,7 @@ weak-map@~1.0.x: resolved "https://registry.yarnpkg.com/weak-map/-/weak-map-1.0.8.tgz#394c18a9e8262e790544ed8b55c6a4ddad1cb1a3" integrity sha512-lNR9aAefbGPpHO7AEnY0hCFjz1eTkWCXYvkTRrTHs9qv8zJp+SkVYpzfLIFXQQiG3tVvbNFQgVg2bQS8YGgxyw== -web3-bzz@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.11.tgz#41bc19a77444bd5365744596d778b811880f707f" - integrity sha512-XGpWUEElGypBjeFyUhTkiPXFbDVD6Nr/S5jznE3t8cWUA0FxRf1n3n/NuIZeb0H9RkN2Ctd/jNma/k8XGa3YKg== - dependencies: - "@types/node" "^12.12.6" - got "9.6.0" - swarm-js "^0.1.40" - underscore "1.9.1" - -web3-core-helpers@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.11.tgz#84c681ed0b942c0203f3b324a245a127e8c67a99" - integrity sha512-PEPoAoZd5ME7UfbnCZBdzIerpe74GEvlwT4AjOmHeCVZoIFk7EqvOZDejJHt+feJA6kMVTdd0xzRNN295UhC1A== - dependencies: - underscore "1.9.1" - web3-eth-iban "1.2.11" - web3-utils "1.2.11" - -web3-core-method@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.11.tgz#f880137d1507a0124912bf052534f168b8d8fbb6" - integrity sha512-ff0q76Cde94HAxLDZ6DbdmKniYCQVtvuaYh+rtOUMB6kssa5FX0q3vPmixi7NPooFnbKmmZCM6NvXg4IreTPIw== - dependencies: - "@ethersproject/transactions" "^5.0.0-beta.135" - underscore "1.9.1" - web3-core-helpers "1.2.11" - web3-core-promievent "1.2.11" - web3-core-subscriptions "1.2.11" - web3-utils "1.2.11" - -web3-core-promievent@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.11.tgz#51fe97ca0ddec2f99bf8c3306a7a8e4b094ea3cf" - integrity sha512-il4McoDa/Ox9Agh4kyfQ8Ak/9ABYpnF8poBLL33R/EnxLsJOGQG2nZhkJa3I067hocrPSjEdlPt/0bHXsln4qA== - dependencies: - eventemitter3 "4.0.4" - -web3-core-requestmanager@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.11.tgz#fe6eb603fbaee18530293a91f8cf26d8ae28c45a" - integrity sha512-oFhBtLfOiIbmfl6T6gYjjj9igOvtyxJ+fjS+byRxiwFJyJ5BQOz4/9/17gWR1Cq74paTlI7vDGxYfuvfE/mKvA== - dependencies: - underscore "1.9.1" - web3-core-helpers "1.2.11" - web3-providers-http "1.2.11" - web3-providers-ipc "1.2.11" - web3-providers-ws "1.2.11" - -web3-core-subscriptions@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.11.tgz#beca908fbfcb050c16f45f3f0f4c205e8505accd" - integrity sha512-qEF/OVqkCvQ7MPs1JylIZCZkin0aKK9lDxpAtQ1F8niEDGFqn7DT8E/vzbIa0GsOjL2fZjDhWJsaW+BSoAW1gg== - dependencies: - eventemitter3 "4.0.4" - underscore "1.9.1" - web3-core-helpers "1.2.11" - -web3-core@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.11.tgz#1043cacc1becb80638453cc5b2a14be9050288a7" - integrity sha512-CN7MEYOY5ryo5iVleIWRE3a3cZqVaLlIbIzDPsvQRUfzYnvzZQRZBm9Mq+ttDi2STOOzc1MKylspz/o3yq/LjQ== - dependencies: - "@types/bn.js" "^4.11.5" - "@types/node" "^12.12.6" - bignumber.js "^9.0.0" - web3-core-helpers "1.2.11" - web3-core-method "1.2.11" - web3-core-requestmanager "1.2.11" - web3-utils "1.2.11" - -web3-eth-abi@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.11.tgz#a887494e5d447c2926d557a3834edd66e17af9b0" - integrity sha512-PkRYc0+MjuLSgg03QVWqWlQivJqRwKItKtEpRUaxUAeLE7i/uU39gmzm2keHGcQXo3POXAbOnMqkDvOep89Crg== - dependencies: - "@ethersproject/abi" "5.0.0-beta.153" - underscore "1.9.1" - web3-utils "1.2.11" - -web3-eth-accounts@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.11.tgz#a9e3044da442d31903a7ce035a86d8fa33f90520" - integrity sha512-6FwPqEpCfKIh3nSSGeo3uBm2iFSnFJDfwL3oS9pyegRBXNsGRVpgiW63yhNzL0796StsvjHWwQnQHsZNxWAkGw== - dependencies: - crypto-browserify "3.12.0" - eth-lib "0.2.8" - ethereumjs-common "^1.3.2" - ethereumjs-tx "^2.1.1" - scrypt-js "^3.0.1" - underscore "1.9.1" - uuid "3.3.2" - web3-core "1.2.11" - web3-core-helpers "1.2.11" - web3-core-method "1.2.11" - web3-utils "1.2.11" - -web3-eth-contract@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.11.tgz#917065902bc27ce89da9a1da26e62ef663663b90" - integrity sha512-MzYuI/Rq2o6gn7vCGcnQgco63isPNK5lMAan2E51AJLknjSLnOxwNY3gM8BcKoy4Z+v5Dv00a03Xuk78JowFow== - dependencies: - "@types/bn.js" "^4.11.5" - underscore "1.9.1" - web3-core "1.2.11" - web3-core-helpers "1.2.11" - web3-core-method "1.2.11" - web3-core-promievent "1.2.11" - web3-core-subscriptions "1.2.11" - web3-eth-abi "1.2.11" - web3-utils "1.2.11" - -web3-eth-ens@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.11.tgz#26d4d7f16d6cbcfff918e39832b939edc3162532" - integrity sha512-dbW7dXP6HqT1EAPvnniZVnmw6TmQEKF6/1KgAxbo8iBBYrVTMDGFQUUnZ+C4VETGrwwaqtX4L9d/FrQhZ6SUiA== - dependencies: - content-hash "^2.5.2" - eth-ens-namehash "2.0.8" - underscore "1.9.1" - web3-core "1.2.11" - web3-core-helpers "1.2.11" - web3-core-promievent "1.2.11" - web3-eth-abi "1.2.11" - web3-eth-contract "1.2.11" - web3-utils "1.2.11" - -web3-eth-iban@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.11.tgz#f5f73298305bc7392e2f188bf38a7362b42144ef" - integrity sha512-ozuVlZ5jwFC2hJY4+fH9pIcuH1xP0HEFhtWsR69u9uDIANHLPQQtWYmdj7xQ3p2YT4bQLq/axKhZi7EZVetmxQ== - dependencies: - bn.js "^4.11.9" - web3-utils "1.2.11" - -web3-eth-personal@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.11.tgz#a38b3942a1d87a62070ce0622a941553c3d5aa70" - integrity sha512-42IzUtKq9iHZ8K9VN0vAI50iSU9tOA1V7XU2BhF/tb7We2iKBVdkley2fg26TxlOcKNEHm7o6HRtiiFsVK4Ifw== - dependencies: - "@types/node" "^12.12.6" - web3-core "1.2.11" - web3-core-helpers "1.2.11" - web3-core-method "1.2.11" - web3-net "1.2.11" - web3-utils "1.2.11" - -web3-eth@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.11.tgz#4c81fcb6285b8caf544058fba3ae802968fdc793" - integrity sha512-REvxW1wJ58AgHPcXPJOL49d1K/dPmuw4LjPLBPStOVkQjzDTVmJEIsiLwn2YeuNDd4pfakBwT8L3bz1G1/wVsQ== - dependencies: - underscore "1.9.1" - web3-core "1.2.11" - web3-core-helpers "1.2.11" - web3-core-method "1.2.11" - web3-core-subscriptions "1.2.11" - web3-eth-abi "1.2.11" - web3-eth-accounts "1.2.11" - web3-eth-contract "1.2.11" - web3-eth-ens "1.2.11" - web3-eth-iban "1.2.11" - web3-eth-personal "1.2.11" - web3-net "1.2.11" - web3-utils "1.2.11" - -web3-net@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.11.tgz#eda68ef25e5cdb64c96c39085cdb74669aabbe1b" - integrity sha512-sjrSDj0pTfZouR5BSTItCuZ5K/oZPVdVciPQ6981PPPIwJJkCMeVjD7I4zO3qDPCnBjBSbWvVnLdwqUBPtHxyg== - dependencies: - web3-core "1.2.11" - web3-core-method "1.2.11" - web3-utils "1.2.11" - -web3-provider-engine@14.2.1: - version "14.2.1" - resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-14.2.1.tgz#ef351578797bf170e08d529cb5b02f8751329b95" - integrity sha512-iSv31h2qXkr9vrL6UZDm4leZMc32SjWJFGOp/D92JXfcEboCqraZyuExDkpxKw8ziTufXieNM7LSXNHzszYdJw== - dependencies: - async "^2.5.0" - backoff "^2.5.0" - clone "^2.0.0" - cross-fetch "^2.1.0" - eth-block-tracker "^3.0.0" - eth-json-rpc-infura "^3.1.0" - eth-sig-util "^1.4.2" - ethereumjs-block "^1.2.2" - ethereumjs-tx "^1.2.0" - ethereumjs-util "^5.1.5" - ethereumjs-vm "^2.3.4" - json-rpc-error "^2.0.0" - json-stable-stringify "^1.0.1" - promise-to-callback "^1.0.0" - readable-stream "^2.2.9" - request "^2.85.0" - semaphore "^1.0.3" - ws "^5.1.1" - xhr "^2.2.0" - xtend "^4.0.1" - -web3-providers-http@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.11.tgz#1cd03442c61670572d40e4dcdf1faff8bd91e7c6" - integrity sha512-psh4hYGb1+ijWywfwpB2cvvOIMISlR44F/rJtYkRmQ5jMvG4FOCPlQJPiHQZo+2cc3HbktvvSJzIhkWQJdmvrA== - dependencies: - web3-core-helpers "1.2.11" - xhr2-cookies "1.1.0" - -web3-providers-ipc@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.11.tgz#d16d6c9be1be6e0b4f4536c4acc16b0f4f27ef21" - integrity sha512-yhc7Y/k8hBV/KlELxynWjJDzmgDEDjIjBzXK+e0rHBsYEhdCNdIH5Psa456c+l0qTEU2YzycF8VAjYpWfPnBpQ== - dependencies: - oboe "2.1.4" - underscore "1.9.1" - web3-core-helpers "1.2.11" - -web3-providers-ws@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.11.tgz#a1dfd6d9778d840561d9ec13dd453046451a96bb" - integrity sha512-ZxnjIY1Er8Ty+cE4migzr43zA/+72AF1myzsLaU5eVgdsfV7Jqx7Dix1hbevNZDKFlSoEyq/3j/jYalh3So1Zg== - dependencies: - eventemitter3 "4.0.4" - underscore "1.9.1" - web3-core-helpers "1.2.11" - websocket "^1.0.31" - -web3-shh@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.11.tgz#f5d086f9621c9a47e98d438010385b5f059fd88f" - integrity sha512-B3OrO3oG1L+bv3E1sTwCx66injW1A8hhwpknDUbV+sw3fehFazA06z9SGXUefuFI1kVs4q2vRi0n4oCcI4dZDg== - dependencies: - web3-core "1.2.11" - web3-core-method "1.2.11" - web3-core-subscriptions "1.2.11" - web3-net "1.2.11" - -web3-utils@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.11.tgz#af1942aead3fb166ae851a985bed8ef2c2d95a82" - integrity sha512-3Tq09izhD+ThqHEaWYX4VOT7dNPdZiO+c/1QMA0s5X2lDFKK/xHJb7cyTRRVzN2LvlHbR7baS1tmQhSua51TcQ== - dependencies: - bn.js "^4.11.9" - eth-lib "0.2.8" - ethereum-bloom-filters "^1.0.6" - ethjs-unit "0.1.6" - number-to-bn "1.7.0" - randombytes "^2.1.0" - underscore "1.9.1" - utf8 "3.0.0" - -web3-utils@^1.0.0-beta.31, web3-utils@^1.3.4, web3-utils@^1.3.6: +web3-utils@^1.3.4, web3-utils@^1.3.6: version "1.10.3" resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.10.3.tgz#f1db99c82549c7d9f8348f04ffe4e0188b449714" integrity sha512-OqcUrEE16fDBbGoQtZXWdavsPzbGIDc5v3VrRTZ0XrIpefC/viZ1ZU9bGEemazyS0catk/3rkOOxpzTfY+XsyQ== @@ -14046,53 +11559,11 @@ web3-utils@^1.0.0-beta.31, web3-utils@^1.3.4, web3-utils@^1.3.6: randombytes "^2.1.0" utf8 "3.0.0" -web3@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.11.tgz#50f458b2e8b11aa37302071c170ed61cff332975" - integrity sha512-mjQ8HeU41G6hgOYm1pmeH0mRAeNKJGnJEUzDMoerkpw7QUQT4exVREgF1MYPvL/z6vAshOXei25LE/t/Bxl8yQ== - dependencies: - web3-bzz "1.2.11" - web3-core "1.2.11" - web3-eth "1.2.11" - web3-eth-personal "1.2.11" - web3-net "1.2.11" - web3-shh "1.2.11" - web3-utils "1.2.11" - webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== -websocket@1.0.32: - version "1.0.32" - resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.32.tgz#1f16ddab3a21a2d929dec1687ab21cfdc6d3dbb1" - integrity sha512-i4yhcllSP4wrpoPMU2N0TQ/q0O94LRG/eUQjEAamRltjQ1oT1PFFKOG4i877OlJgCG8rw6LrrowJp+TYCEWF7Q== - dependencies: - bufferutil "^4.0.1" - debug "^2.2.0" - es5-ext "^0.10.50" - typedarray-to-buffer "^3.1.5" - utf-8-validate "^5.0.2" - yaeti "^0.0.6" - -websocket@^1.0.31: - version "1.0.34" - resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.34.tgz#2bdc2602c08bf2c82253b730655c0ef7dcab3111" - integrity sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ== - dependencies: - bufferutil "^4.0.1" - debug "^2.2.0" - es5-ext "^0.10.50" - typedarray-to-buffer "^3.1.5" - utf-8-validate "^5.0.2" - yaeti "^0.0.6" - -whatwg-fetch@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" - integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng== - whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" @@ -14112,11 +11583,6 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" -which-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" - integrity sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ== - which-typed-array@^1.1.11, which-typed-array@^1.1.13: version "1.1.13" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" @@ -14142,11 +11608,6 @@ which@^1.1.1, which@^1.2.9, which@^1.3.1: dependencies: isexe "^2.0.0" -window-size@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" - integrity sha512-UD7d8HFA2+PZsbKyaOCEy8gMh1oDtHgJh1LfgjQ4zVXmYjAT/kvz3PueITKuqDiIXQe7yzpPnxX3lNc+AhQMyw== - word-wrap@~1.2.3: version "1.2.5" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" @@ -14157,6 +11618,14 @@ wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== +wordwrapjs@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-4.0.1.tgz#d9790bccfb110a0fc7836b5ebce0937b37a8b98f" + integrity sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA== + dependencies: + reduce-flatten "^2.0.0" + typical "^5.2.0" + workerpool@6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b" @@ -14167,15 +11636,7 @@ workerpool@6.2.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw== - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - -wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -14184,11 +11645,30 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +write-file-atomic@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + write-file-atomic@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" @@ -14202,102 +11682,37 @@ ws@7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== -ws@^3.0.0: - version "3.3.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" - integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== - dependencies: - async-limiter "~1.0.0" - safe-buffer "~5.1.0" - ultron "~1.1.0" - -ws@^5.1.1: - version "5.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.3.tgz#05541053414921bc29c63bee14b8b0dd50b07b3d" - integrity sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA== - dependencies: - async-limiter "~1.0.0" - ws@^7.4.6: version "7.5.9" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== -xhr-request-promise@^0.1.2: - version "0.1.3" - resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz#2d5f4b16d8c6c893be97f1a62b0ed4cf3ca5f96c" - integrity sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg== - dependencies: - xhr-request "^1.1.0" - -xhr-request@^1.0.1, xhr-request@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/xhr-request/-/xhr-request-1.1.0.tgz#f4a7c1868b9f198723444d82dcae317643f2e2ed" - integrity sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA== - dependencies: - buffer-to-arraybuffer "^0.0.5" - object-assign "^4.1.1" - query-string "^5.0.1" - simple-get "^2.7.0" - timed-out "^4.0.1" - url-set-query "^1.0.0" - xhr "^2.0.4" - -xhr2-cookies@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz#7d77449d0999197f155cb73b23df72505ed89d48" - integrity sha512-hjXUA6q+jl/bd8ADHcVfFsSPIf+tyLIjuO9TwJC9WI6JP2zKcS7C+p56I9kCLLsaCiNT035iYvEUUzdEFj/8+g== - dependencies: - cookiejar "^2.1.1" +xdg-basedir@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-5.1.0.tgz#1efba19425e73be1bc6f2a6ceb52a3d2c884c0c9" + integrity sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ== xhr2@0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.3.tgz#cbfc4759a69b4a888e78cf4f20b051038757bd11" integrity sha512-6RmGK22QwC7yXB1CRwyLWuS2opPcKOlAu0ViAnyZjDlzrEmCKL4kLHkfvB8oMRWeztMsNoDGAjsMZY15w/4tTw== -xhr@^2.0.4, xhr@^2.2.0, xhr@^2.3.3: - version "2.6.0" - resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.6.0.tgz#b69d4395e792b4173d6b7df077f0fc5e4e2b249d" - integrity sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA== - dependencies: - global "~4.4.0" - is-function "^1.0.1" - parse-headers "^2.0.0" - xtend "^4.0.0" - xregexp@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-3.1.0.tgz#14d8461e0bdd38224bfee5039a0898fc42fcd336" integrity sha512-4Y1x6DyB8xRoxosooa6PlGWqmmSKatbzhrftZ7Purmm4B8R4qIEJG1A2hZsdz5DhmIqS0msC0I7KEq93GphEVg== -xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: +xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== -xtend@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" - integrity sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ== - dependencies: - object-keys "~0.4.0" - -y18n@^3.2.1: - version "3.2.2" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.2.tgz#85c901bd6470ce71fc4bb723ad209b70f7f28696" - integrity sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ== - y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yaeti@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" - integrity sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug== - -yallist@^3.0.0, yallist@^3.0.2, yallist@^3.1.1: +yallist@^3.0.2: version "3.1.1" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== @@ -14307,24 +11722,16 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@^1.10.2: - version "1.10.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +yaml@^2.3.4: + version "2.3.4" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2" + integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA== yargs-parser@20.2.4: version "20.2.4" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== -yargs-parser@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4" - integrity sha512-9pIKIJhnI5tonzG6OnCFlz/yln8xHYcGl+pn3xR0Vzff0vzN1PbNRaelgfgRUwZ3s4i3jvxT9WhmUGL4whnasA== - dependencies: - camelcase "^3.0.0" - lodash.assign "^4.0.6" - yargs-parser@^20.2.2: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" @@ -14371,26 +11778,6 @@ yargs@^17.3.1: y18n "^5.0.5" yargs-parser "^21.1.1" -yargs@^4.7.1: - version "4.8.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-4.8.1.tgz#c0c42924ca4aaa6b0e6da1739dfb216439f9ddc0" - integrity sha512-LqodLrnIDM3IFT+Hf/5sxBnEGECrfdC1uIbgZeJmESCSo4HoCAaKEus8MylXHAkdacGc0ye+Qa+dpkuom8uVYA== - dependencies: - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - lodash.assign "^4.0.3" - os-locale "^1.4.0" - read-pkg-up "^1.0.1" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^1.0.1" - which-module "^1.0.0" - window-size "^0.2.0" - y18n "^3.2.1" - yargs-parser "^2.4.1" - yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" @@ -14406,6 +11793,13 @@ yocto-queue@^1.0.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251" integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g== +zksync-ethers@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/zksync-ethers/-/zksync-ethers-5.0.0.tgz#2d0bb9a98ad1198957038f7669a50b10ef96bc3c" + integrity sha512-zPowwK/2wG3YqIlKNtRfzpMnHMnWSa5wFsfDrxKFgLjbA3VvuHl4mFCFUxMapsroGyG619+zt71HKM1jyNpSmQ== + dependencies: + ethers "~5.7.0" + zksync-web3@^0.14.3: version "0.14.4" resolved "https://registry.yarnpkg.com/zksync-web3/-/zksync-web3-0.14.4.tgz#0b70a7e1a9d45cc57c0971736079185746d46b1f"