Merge pull request #1534 from maticnetwork/v2.0.2-candidate

v2.0.2 release
This commit is contained in:
Manav Darji 2025-05-09 15:09:46 +05:30 committed by GitHub
commit 84fd09a04c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
401 changed files with 8930 additions and 3775 deletions

View file

@ -20,7 +20,7 @@ Heimdall client version: [e.g. v0.2.10] <!--Can be found by running the command
OS & Version: Windows / Linux / OSX OS & Version: Windows / Linux / OSX
Environment: Polygon Mainnet / Polygon Mumbai / Polygon Amoy / Devnet Environment: Polygon Mainnet / Polygon Amoy / Devnet
Type of node: Validator / Sentry / Archive Type of node: Validator / Sentry / Archive

View file

@ -1,26 +1,38 @@
defaultStake: 10000 devnetType: docker
defaultFee: 2000 defaultFee: 2000
defaultStake: 10000
borChainId: 15001 borChainId: 15001
heimdallChainId: heimdall-15001 heimdallChainId: heimdall-15001
contractsBranch: mardizzone/node-16
borDockerBuildContext: '../../bor'
heimdallDockerBuildContext: 'https://github.com/maticnetwork/heimdall.git#develop'
genesisContractsBranch: master genesisContractsBranch: master
sprintSize: contractsRepo: https://github.com/0xPolygon/pos-contracts.git
- '64' contractsBranch: anvil-pos
blockNumber:
- '0'
blockTime: blockTime:
- '2' - '2'
blockNumber:
- '0'
sprintSize:
- '64'
sprintSizeBlockNumber:
- '0'
numOfBorValidators: 3 numOfBorValidators: 3
numOfBorSentries: 0 numOfBorSentries: 0
numOfBorArchiveNodes: 0 numOfBorArchiveNodes: 0
devnetBorFlags: config,config,config
numOfErigonValidators: 0 numOfErigonValidators: 0
numOfErigonSentries: 0 numOfErigonSentries: 0
numOfErigonArchiveNodes: 0 numOfErigonArchiveNodes: 0
ethURL: http://ganache:9545
ethURL: http://anvil:9545
ethHostUser: ubuntu ethHostUser: ubuntu
devnetType: docker mnemonic: 'clock radar mass judge dismiss just intact mind resemble fringe diary casino'
borDockerBuildContext: "../../bor"
heimdallDockerBuildContext: "https://github.com/maticnetwork/heimdall.git#develop"
sprintSizeBlockNumber:
- '0'
devnetBorFlags: config,config,config

View file

@ -1,7 +1,7 @@
# Number of days of inactivity before an Issue is closed for lack of response # Number of days of inactivity before an Issue is closed for lack of response
daysUntilClose: 30 daysUntilClose: 30
# Label requiring a response # Label requiring a response
responseRequiredLabel: "need:more-information" responseRequiredLabel: 'need:more-information'
# Comment to post when closing an Issue for lack of response. Set to `false` to disable # Comment to post when closing an Issue for lack of response. Set to `false` to disable
closeComment: > closeComment: >
This issue has been automatically closed because there has been no response This issue has been automatically closed because there has been no response

View file

@ -39,7 +39,7 @@ In case this PR includes changes that must be applied only to a subset of nodes,
- [ ] I have added tests to CI - [ ] I have added tests to CI
- [ ] I have tested this code manually on local environment - [ ] I have tested this code manually on local environment
- [ ] I have tested this code manually on remote devnet using express-cli - [ ] I have tested this code manually on remote devnet using express-cli
- [ ] I have tested this code manually on mumbai/amoy - [ ] I have tested this code manually on amoy
- [ ] I have created new e2e tests into express-cli - [ ] I have created new e2e tests into express-cli
### Manual tests ### Manual tests

2
.github/stale.yml vendored
View file

@ -7,7 +7,7 @@ exemptLabels:
- pinned - pinned
- security - security
# Label to use when marking an issue as stale # Label to use when marking an issue as stale
staleLabel: "status:inactive" staleLabel: 'status:inactive'
# Comment to post when marking an issue as stale. Set to `false` to disable # Comment to post when marking an issue as stale. Set to `false` to disable
markComment: > markComment: >
This issue has been automatically marked as stale because it has not had This issue has been automatically marked as stale because it has not had

View file

@ -15,7 +15,7 @@ jobs:
permissions: permissions:
id-token: write id-token: write
contents: write contents: write
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
@ -29,7 +29,6 @@ jobs:
NUMERIC_VERSION=$( echo ${{ env.GIT_TAG }} | sed 's/[^0-9.]//g' ) NUMERIC_VERSION=$( echo ${{ env.GIT_TAG }} | sed 's/[^0-9.]//g' )
echo "VERSION=$NUMERIC_VERSION" >> $GITHUB_ENV echo "VERSION=$NUMERIC_VERSION" >> $GITHUB_ENV
- name: Making directory structure for yaml - name: Making directory structure for yaml
run: mkdir -p packaging/deb/bor/var/lib/bor run: mkdir -p packaging/deb/bor/var/lib/bor
- name: making directory structure for the systemd - name: making directory structure for the systemd
@ -391,14 +390,3 @@ jobs:
packaging/deb/bor-pbss-amoy-**.deb packaging/deb/bor-pbss-amoy-**.deb
packaging/deb/bor-amoy-**.deb.checksum packaging/deb/bor-amoy-**.deb.checksum
packaging/deb/bor-pbss-amoy-**.deb.checksum packaging/deb/bor-pbss-amoy-**.deb.checksum

View file

@ -2,12 +2,12 @@ name: CI
on: on:
push: push:
branches: branches:
- "master" - 'master'
- "qa" - 'qa'
- "develop" - 'develop'
pull_request: pull_request:
branches: branches:
- "**" - '**'
types: [opened, synchronize] types: [opened, synchronize]
concurrency: concurrency:
@ -16,11 +16,14 @@ concurrency:
jobs: jobs:
build: build:
name: Build
if: (github.event.action != 'closed' || github.event.pull_request.merged == true) if: (github.event.action != 'closed' || github.event.pull_request.merged == true)
strategy: strategy:
matrix: matrix:
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments os: [ubuntu-22.04] # List of OS: https://github.com/actions/virtual-environments
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: | - run: |
@ -51,7 +54,7 @@ jobs:
if: (github.event.action != 'closed' || github.event.pull_request.merged == true) if: (github.event.action != 'closed' || github.event.pull_request.merged == true)
strategy: strategy:
matrix: matrix:
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments os: [ubuntu-22.04] # List of OS: https://github.com/actions/virtual-environments
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -79,7 +82,7 @@ jobs:
if: (github.event.action != 'closed' || github.event.pull_request.merged == true) if: (github.event.action != 'closed' || github.event.pull_request.merged == true)
strategy: strategy:
matrix: matrix:
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments os: [ubuntu-22.04] # List of OS: https://github.com/actions/virtual-environments
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -107,12 +110,12 @@ jobs:
- name: Test - name: Test
run: make test run: make test
- uses: PaloAltoNetworks/upload-secure-artifact@main - uses: actions/upload-artifact@v4.4.0
with: with:
name: unitTest-coverage name: unitTest-coverage
path: cover.out path: cover.out
#- name: Data race tests # - name: Data race tests
# run: make test-race # run: make test-race
# # TODO: make it work # # TODO: make it work
@ -130,7 +133,7 @@ jobs:
if: (github.event.action != 'closed' || github.event.pull_request.merged == true) if: (github.event.action != 'closed' || github.event.pull_request.merged == true)
strategy: strategy:
matrix: matrix:
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments os: [ubuntu-22.04] # List of OS: https://github.com/actions/virtual-environments
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -158,7 +161,7 @@ jobs:
- name: test-integration - name: test-integration
run: make test-integration run: make test-integration
- uses: PaloAltoNetworks/upload-secure-artifact@main - uses: actions/upload-artifact@v4.4.0
with: with:
name: integrationTest-coverage name: integrationTest-coverage
path: cover.out path: cover.out
@ -167,7 +170,7 @@ jobs:
if: (github.event.action != 'closed' || github.event.pull_request.merged == true) if: (github.event.action != 'closed' || github.event.pull_request.merged == true)
strategy: strategy:
matrix: matrix:
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments os: [ubuntu-22.04] # List of OS: https://github.com/actions/virtual-environments
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
needs: [unit-tests, integration-tests] needs: [unit-tests, integration-tests]
steps: steps:
@ -182,7 +185,7 @@ jobs:
if: (github.event.action != 'closed' || github.event.pull_request.merged == true) if: (github.event.action != 'closed' || github.event.pull_request.merged == true)
strategy: strategy:
matrix: matrix:
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments os: [ubuntu-22.04] # List of OS: https://github.com/actions/virtual-environments
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -211,9 +214,7 @@ jobs:
sudo apt update sudo apt update
sudo apt install build-essential sudo apt install build-essential
curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
sudo snap install solc sudo apt install jq curl
sudo apt install python2 jq curl
sudo ln -sf /usr/bin/python2 /usr/bin/python
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
@ -225,6 +226,23 @@ jobs:
matic-cli/devnet/code/genesis-contracts/package-lock.json matic-cli/devnet/code/genesis-contracts/package-lock.json
matic-cli/devnet/code/genesis-contracts/matic-contracts/package-lock.json matic-cli/devnet/code/genesis-contracts/matic-contracts/package-lock.json
- name: Install solc-select
run: |
sudo apt update
sudo apt install python3 python3-pip -y
sudo ln -sf /usr/bin/python3 /usr/bin/python
pip install solc-select
- name: Install Solidity Version
run: |
solc-select install 0.5.17
solc-select install 0.6.12
solc-select use 0.5.17
solc --version
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
- name: Bootstrap devnet - name: Bootstrap devnet
run: | run: |
cd matic-cli cd matic-cli
@ -242,25 +260,28 @@ jobs:
- name: Run smoke tests - name: Run smoke tests
run: | run: |
echo "Funding ganache accounts..."
timeout 10m bash bor/integration-tests/fund_ganache_accounts.sh
echo "Deposit 100 matic for each account to bor network" echo "Deposit 100 matic for each account to bor network"
cd matic-cli/devnet/code/contracts cd matic-cli/devnet/devnet
npm run truffle exec scripts/deposit.js -- --network development $(jq -r .root.tokens.MaticToken contractAddresses.json) 100000000000000000000 SCRIPT_ADDRESS=$(jq -r '.[0].address' signer-dump.json)
cd - SCRIPT_PRIVATE_KEY=$(jq -r '.[0].priv_key' signer-dump.json)
cd ../code/pos-contracts
CONTRACT_ADDRESS=$(jq -r .root.tokens.MaticToken contractAddresses.json)
forge script scripts/matic-cli-scripts/Deposit.s.sol:MaticDeposit --rpc-url http://localhost:9545 --private-key $SCRIPT_PRIVATE_KEY --broadcast --sig "run(address,address,uint256)" $SCRIPT_ADDRESS $CONTRACT_ADDRESS 100000000000000000000
cd ../../../..
timeout 60m bash bor/integration-tests/smoke_test.sh timeout 60m bash bor/integration-tests/smoke_test.sh
- name: Resolve absolute path for logs - name: Run RPC Tests
id: pathfix
run: | run: |
echo "ABS_LOG_PATH=$(realpath matic-cli/devnet/logs)" >> $GITHUB_ENV echo "Starting RPC Tests..."
timeout 5m bash bor/integration-tests/rpc_test.sh
- name: Upload logs - name: Upload logs
if: always() if: always()
uses: PaloAltoNetworks/upload-secure-artifact@main uses: actions/upload-artifact@v4.4.0
with: with:
name: logs_${{ github.run_id }} name: logs_${{ github.run_id }}
path: ${{ env.ABS_LOG_PATH }} path: |
matic-cli/devnet/logs
- name: Package code and chain data - name: Package code and chain data
if: always() if: always()
@ -271,11 +292,11 @@ jobs:
mkdir -p ${{ github.run_id }}/matic-cli mkdir -p ${{ github.run_id }}/matic-cli
sudo mv bor ${{ github.run_id }} sudo mv bor ${{ github.run_id }}
sudo mv matic-cli/devnet ${{ github.run_id }}/matic-cli sudo mv matic-cli/devnet ${{ github.run_id }}/matic-cli
sudo tar --warning=no-file-changed --exclude='.git' -czf code.tar.gz ${{ github.run_id }} sudo tar czf code.tar.gz ${{ github.run_id }}
- name: Upload code and chain data - name: Upload code and chain data
if: always() if: always()
uses: PaloAltoNetworks/upload-secure-artifact@main uses: actions/upload-artifact@v4.4.0
with: with:
name: code_${{ github.run_id }} name: code_${{ github.run_id }}
path: code.tar.gz path: code.tar.gz

View file

@ -1,10 +1,10 @@
name: "CodeQL" name: 'CodeQL'
on: on:
push: push:
branches: [ "master", "develop" ] branches: ['master', 'develop']
pull_request: pull_request:
branches: [ "master", "develop" ] branches: ['master', 'develop']
schedule: schedule:
- cron: '0 0 * * *' - cron: '0 0 * * *'
@ -21,7 +21,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
language: [ 'go' ] language: ['go']
steps: steps:
- name: Checkout repository - name: Checkout repository
@ -43,4 +43,4 @@ jobs:
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2 uses: github/codeql-action/analyze@v2
with: with:
category: "/language:${{matrix.language}}" category: '/language:${{matrix.language}}'

View file

@ -1,5 +1,5 @@
name: Govuln name: Govuln
on: [ push, pull_request ] on: [push, pull_request]
jobs: jobs:
govulncheck: govulncheck:
@ -8,7 +8,7 @@ jobs:
steps: steps:
- uses: actions/setup-go@v5 - uses: actions/setup-go@v5
with: with:
go-version: "1.23.6" go-version: '1.23.6'
check-latest: true check-latest: true
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: technote-space/get-diff-action@v6 - uses: technote-space/get-diff-action@v6
@ -20,4 +20,4 @@ jobs:
Makefile Makefile
- name: govulncheck - name: govulncheck
run: make vulncheck run: make vulncheck
if: "env.GIT_DIFF != ''" if: env.GIT_DIFF != ''

View file

@ -15,7 +15,7 @@ jobs:
permissions: permissions:
id-token: write id-token: write
contents: write contents: write
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
@ -29,7 +29,6 @@ jobs:
NUMERIC_VERSION=$( echo ${{ env.GIT_TAG }} | sed 's/[^0-9.]//g' ) NUMERIC_VERSION=$( echo ${{ env.GIT_TAG }} | sed 's/[^0-9.]//g' )
echo "VERSION=$NUMERIC_VERSION" >> $GITHUB_ENV echo "VERSION=$NUMERIC_VERSION" >> $GITHUB_ENV
- name: Making directory structure for yaml - name: Making directory structure for yaml
run: mkdir -p packaging/deb/bor/var/lib/bor run: mkdir -p packaging/deb/bor/var/lib/bor
- name: making directory structure for the systemd - name: making directory structure for the systemd
@ -387,8 +386,6 @@ jobs:
NODE: archive NODE: archive
NETWORK: mainnet NETWORK: mainnet
############ Check and Upload ########################## ############ Check and Upload ##########################
- name: Confirming package built - name: Confirming package built
run: ls -ltr packaging/deb/ | grep bor run: ls -ltr packaging/deb/ | grep bor

View file

@ -15,7 +15,7 @@ jobs:
permissions: permissions:
id-token: write id-token: write
contents: write contents: write
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
@ -97,7 +97,6 @@ jobs:
echo "Maintainer: devops@polygon.technology" >> packaging/deb/bor/DEBIAN/control echo "Maintainer: devops@polygon.technology" >> packaging/deb/bor/DEBIAN/control
echo "Description: bor binary package" >> packaging/deb/bor/DEBIAN/control echo "Description: bor binary package" >> packaging/deb/bor/DEBIAN/control
- name: Creating package for binary for bor ${{ env.ARCH }} - name: Creating package for binary for bor ${{ env.ARCH }}
run: cp -rp packaging/deb/bor packaging/deb/bor-${{ env.GIT_TAG }}-${{ env.ARCH }} run: cp -rp packaging/deb/bor packaging/deb/bor-${{ env.GIT_TAG }}-${{ env.ARCH }}
env: env:

View file

@ -11,7 +11,6 @@ on:
jobs: jobs:
stale: stale:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
issues: write issues: write

8
.gitignore vendored
View file

@ -30,6 +30,14 @@ cover.out
/build/bin/ /build/bin/
/geth*.zip /geth*.zip
# used by the build/ci.go archive + upload tool
/geth*.tar.gz
/geth*.tar.gz.sig
/geth*.tar.gz.asc
/geth*.zip.sig
/geth*.zip.asc
# travis # travis
profile.tmp profile.tmp
profile.cov profile.cov

View file

@ -60,6 +60,10 @@ issues:
- path: crypto/bn256/ - path: crypto/bn256/
linters: linters:
- revive - revive
- path: cmd/utils/flags.go
text: "SA1019: cfg.TxLookupLimit is deprecated: use 'TransactionHistory' instead."
- path: cmd/utils/flags.go
text: "SA1019: ethconfig.Defaults.TxLookupLimit is deprecated: use 'TransactionHistory' instead."
- path: internal/build/pgp.go - path: internal/build/pgp.go
text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.' text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.'
- path: core/vm/contracts.go - path: core/vm/contracts.go

View file

@ -9,26 +9,13 @@ jobs:
- azure-osx - azure-osx
include: include:
# This builder only tests code linters on latest version of Go # This builder create and push the Docker images for all architectures
- stage: lint
os: linux
dist: bionic
go: 1.22.x
env:
- lint
git:
submodules: false # avoid cloning ethereum/tests
script:
- go run build/ci.go lint
# These builders create the Docker sub-images for multi-arch push and each
# will attempt to push the multi-arch image if they are the last builder
- stage: build - stage: build
if: type = push if: type = push
os: linux os: linux
arch: amd64 arch: amd64
dist: noble dist: focal
go: 1.22.x go: 1.23.x
env: env:
- docker - docker
services: services:
@ -38,24 +25,7 @@ jobs:
before_install: before_install:
- export DOCKER_CLI_EXPERIMENTAL=enabled - export DOCKER_CLI_EXPERIMENTAL=enabled
script: script:
- go run build/ci.go docker -image -manifest amd64,arm64 -upload ethereum/client-go - go run build/ci.go dockerx -platform "linux/amd64,linux/arm64" -upload ethereum/client-go
- stage: build
if: type = push
os: linux
arch: arm64
dist: noble
go: 1.22.x
env:
- docker
services:
- docker
git:
submodules: false # avoid cloning ethereum/tests
before_install:
- export DOCKER_CLI_EXPERIMENTAL=enabled
script:
- go run build/ci.go docker -image -manifest amd64,arm64 -upload ethereum/client-go
# This builder does the Ubuntu PPA upload # This builder does the Ubuntu PPA upload
- stage: build - stage: build
@ -85,9 +55,9 @@ jobs:
- stage: build - stage: build
if: type = push if: type = push
os: linux os: linux
dist: noble dist: focal
sudo: required sudo: required
go: 1.22.x go: 1.23.x
env: env:
- azure-linux - azure-linux
git: git:
@ -99,6 +69,7 @@ jobs:
# build 386 # build 386
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends install gcc-multilib - sudo -E apt-get -yq --no-install-suggests --no-install-recommends install gcc-multilib
- git status --porcelain
- go run build/ci.go install -dlgo -arch 386 - go run build/ci.go install -dlgo -arch 386
- go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds
@ -158,12 +129,13 @@ jobs:
if: type = push if: type = push
os: osx os: osx
osx_image: xcode14.2 osx_image: xcode14.2
go: 1.22.x go: 1.23.1 # See https://github.com/ethereum/go-ethereum/pull/30478
env: env:
- azure-osx - azure-osx
git: git:
submodules: false # avoid cloning ethereum/tests submodules: false # avoid cloning ethereum/tests
script: script:
- ln -sf /Users/travis/gopath/bin/go1.23.1 /usr/local/bin/go # Work around travis go-setup bug
- go run build/ci.go install -dlgo - go run build/ci.go install -dlgo
- go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds
- go run build/ci.go install -dlgo -arch arm64 - go run build/ci.go install -dlgo -arch arm64
@ -174,8 +146,8 @@ jobs:
if: type = push if: type = push
os: linux os: linux
arch: amd64 arch: amd64
dist: noble dist: focal
go: 1.22.x go: 1.23.x
script: script:
- travis_wait 45 go run build/ci.go test $TEST_PACKAGES - travis_wait 45 go run build/ci.go test $TEST_PACKAGES
@ -190,7 +162,7 @@ jobs:
- stage: build - stage: build
os: linux os: linux
dist: noble dist: focal
go: 1.22.x go: 1.22.x
script: script:
- travis_wait 45 go run build/ci.go test $TEST_PACKAGES - travis_wait 45 go run build/ci.go test $TEST_PACKAGES
@ -199,8 +171,8 @@ jobs:
- stage: build - stage: build
if: type = cron || (type = push && tag ~= /^v[0-9]/) if: type = cron || (type = push && tag ~= /^v[0-9]/)
os: linux os: linux
dist: noble dist: focal
go: 1.22.x go: 1.23.x
env: env:
- ubuntu-ppa - ubuntu-ppa
git: git:
@ -215,8 +187,8 @@ jobs:
- stage: build - stage: build
if: type = cron if: type = cron
os: linux os: linux
dist: noble dist: focal
go: 1.22.x go: 1.23.x
env: env:
- azure-purge - azure-purge
git: git:
@ -228,8 +200,8 @@ jobs:
- stage: build - stage: build
if: type = cron if: type = cron
os: linux os: linux
dist: noble dist: focal
go: 1.22.x go: 1.23.x
env: env:
- racetests - racetests
script: script:

View file

@ -1,5 +1,5 @@
# Build Geth in a stock Go builder container # Build Geth in a stock Go builder container
FROM golang:1.22.1-alpine as builder FROM golang:1.23-alpine AS builder
RUN apk add --no-cache make gcc musl-dev linux-headers git RUN apk add --no-cache make gcc musl-dev linux-headers git

View file

@ -90,7 +90,6 @@ lintci-deps:
vulncheck: vulncheck:
@go run golang.org/x/vuln/cmd/govulncheck@latest ./... @go run golang.org/x/vuln/cmd/govulncheck@latest ./...
goimports: goimports:
goimports -local "$(PACKAGE)" -w . goimports -local "$(PACKAGE)" -w .

View file

@ -1,9 +1,7 @@
# Bor Overview # Bor Overview
Bor is the Official Golang implementation of the Polygon PoS blockchain. It is a fork of [geth](https://github.com/ethereum/go-ethereum) and is EVM compatible (upto London fork). Bor is the official Golang implementation of the Polygon PoS blockchain. It is a fork of [geth](https://github.com/ethereum/go-ethereum) and is EVM compatible (upto London fork).
[![API Reference]( [![API Reference](https://pkg.go.dev/badge/github.com/maticnetwork/bor)](https://pkg.go.dev/github.com/maticnetwork/bor)
https://pkg.go.dev/badge/github.com/maticnetwork/bor
)](https://pkg.go.dev/github.com/maticnetwork/bor)
[![Go Report Card](https://goreportcard.com/badge/github.com/maticnetwork/bor)](https://goreportcard.com/report/github.com/maticnetwork/bor) [![Go Report Card](https://goreportcard.com/badge/github.com/maticnetwork/bor)](https://goreportcard.com/report/github.com/maticnetwork/bor)
![MIT License](https://img.shields.io/github/license/maticnetwork/bor) ![MIT License](https://img.shields.io/github/license/maticnetwork/bor)
[![Discord](https://img.shields.io/badge/discord-join%20chat-blue.svg)](https://discord.com/invite/0xpolygonrnd) [![Discord](https://img.shields.io/badge/discord-join%20chat-blue.svg)](https://discord.com/invite/0xpolygonrnd)
@ -13,15 +11,15 @@ https://pkg.go.dev/badge/github.com/maticnetwork/bor
The easiest way to get started with bor is to install the packages using the command below. Please take a look at the [releases](https://github.com/maticnetwork/bor/releases) section to find the latest stable version of bor. The easiest way to get started with bor is to install the packages using the command below. Please take a look at the [releases](https://github.com/maticnetwork/bor/releases) section to find the latest stable version of bor.
curl -L https://raw.githubusercontent.com/maticnetwork/install/main/bor.sh | bash -s -- v0.4.0 <network> <node_type> curl -L https://raw.githubusercontent.com/maticnetwork/install/main/bor.sh | bash -s -- v2.0.0 <network> <node_type>
The network accepts `mainnet`,`amoy` or `mumbai` and the node type accepts `validator` or `sentry` or `archive`. The installation script does the following things: The network accepts `mainnet`, or `amoy` and the node type accepts `validator` or `sentry` or `archive`. The installation script does the following things:
- Create a new user named `bor`. - Create a new user named `bor`.
- Install the bor binary at `/usr/bin/bor`. - Install the bor binary at `/usr/bin/bor`.
- Dump the suitable config file (based on the network and node type provided) at `/var/lib/bor` and use it as the home dir. - Dump the suitable config file (based on the network and node type provided) at `/var/lib/bor` and use it as the home dir.
- Create a systemd service named `bor` at `/lib/systemd/system/bor.service` which starts bor using the config file as `bor` user. - Create a systemd service named `bor` at `/lib/systemd/system/bor.service` which starts bor using the config file as `bor` user.
The releases supports both the networks i.e. Polygon Mainnet, Amoy and Mumbai (Testnet) unless explicitly specified. Before the stable release for mainnet, pre-releases will be available marked with `beta` tag for deploying on Mumbai/Amoy (testnet). On sufficient testing, stable release for mainnet will be announced with a forum post. The releases supports both the networks i.e. Polygon Mainnet, and Amoy (Testnet) unless explicitly specified. Before the stable release for mainnet, pre-releases will be available marked with `beta` tag for deploying on Amoy (testnet). On sufficient testing, stable release for mainnet will be announced with a forum post.
### Building from source ### Building from source

View file

@ -1326,3 +1326,10 @@ func TestUnpackRevert(t *testing.T) {
}) })
} }
} }
func TestInternalContractType(t *testing.T) {
jsonData := `[{"inputs":[{"components":[{"internalType":"uint256","name":"dailyLimit","type":"uint256"},{"internalType":"uint256","name":"txLimit","type":"uint256"},{"internalType":"uint256","name":"accountDailyLimit","type":"uint256"},{"internalType":"uint256","name":"minAmount","type":"uint256"},{"internalType":"bool","name":"onlyWhitelisted","type":"bool"}],"internalType":"struct IMessagePassingBridge.BridgeLimits","name":"bridgeLimits","type":"tuple"},{"components":[{"internalType":"uint256","name":"lastTransferReset","type":"uint256"},{"internalType":"uint256","name":"bridged24Hours","type":"uint256"}],"internalType":"struct IMessagePassingBridge.AccountLimit","name":"accountDailyLimit","type":"tuple"},{"components":[{"internalType":"uint256","name":"lastTransferReset","type":"uint256"},{"internalType":"uint256","name":"bridged24Hours","type":"uint256"}],"internalType":"struct IMessagePassingBridge.BridgeDailyLimit","name":"bridgeDailyLimit","type":"tuple"},{"internalType":"contract INameService","name":"nameService","type":"INameService"},{"internalType":"bool","name":"isClosed","type":"bool"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"canBridge","outputs":[{"internalType":"bool","name":"isWithinLimit","type":"bool"},{"internalType":"string","name":"error","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"normalizeFrom18ToTokenDecimals","outputs":[{"internalType":"uint256","name":"normalized","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"normalizeFromTokenTo18Decimals","outputs":[{"internalType":"uint256","name":"normalized","type":"uint256"}],"stateMutability":"pure","type":"function"}]`
if _, err := JSON(strings.NewReader(jsonData)); err != nil {
t.Fatal(err)
}
}

View file

@ -154,7 +154,7 @@ func (b *SimulatedBackend) rollback(parent *types.Block) {
blocks, _ := core.GenerateChain(b.config, parent, ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {}) blocks, _ := core.GenerateChain(b.config, parent, ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {})
b.pendingBlock = blocks[0] b.pendingBlock = blocks[0]
b.pendingState, _ = state.New(b.pendingBlock.Root(), b.blockchain.StateCache(), nil) b.pendingState, _ = state.New(b.pendingBlock.Root(), b.blockchain.StateCache())
} }
// Fork creates a side-chain that can be used to simulate reorgs. // Fork creates a side-chain that can be used to simulate reorgs.
@ -699,7 +699,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
GasTipCap: call.GasTipCap, GasTipCap: call.GasTipCap,
Data: call.Data, Data: call.Data,
AccessList: call.AccessList, AccessList: call.AccessList,
SkipAccountChecks: true, SkipNonceChecks: true,
} }
// Create a new environment which holds all relevant information // Create a new environment which holds all relevant information
@ -744,7 +744,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
return err return err
} }
b.pendingBlock = blocks[0] b.pendingBlock = blocks[0]
b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database(), nil) b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database())
b.pendingReceipts = receipts[0] b.pendingReceipts = receipts[0]
return nil return nil
} }
@ -867,7 +867,7 @@ func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error {
return err return err
} }
b.pendingBlock = blocks[0] b.pendingBlock = blocks[0]
b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database(), nil) b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database())
return nil return nil
} }

View file

@ -85,7 +85,9 @@ func TestWaitDeployed(t *testing.T) {
}() }()
// Send and mine the transaction. // Send and mine the transaction.
backend.SendTransaction(ctx, tx) if err := backend.SendTransaction(ctx, tx); err != nil {
t.Errorf("test %q: failed to send transaction: %v", name, err)
}
backend.Commit() backend.Commit()
select { select {
@ -122,7 +124,9 @@ func TestWaitDeployedCornerCases(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
backend.SendTransaction(ctx, tx) if err := backend.SendTransaction(ctx, tx); err != nil {
t.Errorf("failed to send transaction: %q", err)
}
backend.Commit() backend.Commit()
notContractCreation := errors.New("tx is not contract creation") notContractCreation := errors.New("tx is not contract creation")
if _, err := bind.WaitDeployed(ctx, backend, tx); err.Error() != notContractCreation.Error() { if _, err := bind.WaitDeployed(ctx, backend, tx); err.Error() != notContractCreation.Error() {
@ -140,6 +144,8 @@ func TestWaitDeployedCornerCases(t *testing.T) {
} }
}() }()
backend.SendTransaction(ctx, tx) if err := backend.SendTransaction(ctx, tx); err != nil {
t.Errorf("failed to send transaction: %q", err)
}
cancel() cancel()
} }

View file

@ -238,8 +238,13 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty
typ.T = FunctionTy typ.T = FunctionTy
typ.Size = 24 typ.Size = 24
default: default:
if strings.HasPrefix(internalType, "contract ") {
typ.Size = 20
typ.T = AddressTy
} else {
return Type{}, fmt.Errorf("unsupported arg type: %s", t) return Type{}, fmt.Errorf("unsupported arg type: %s", t)
} }
}
return return
} }

0
beacon/blsync/block_sync.go Executable file → Normal file
View file

View file

@ -70,7 +70,10 @@ func TestBlockSync(t *testing.T) {
t.Helper() t.Helper()
var expNumber, headNumber uint64 var expNumber, headNumber uint64
if expHead != nil { if expHead != nil {
p, _ := expHead.ExecutionPayload() p, err := expHead.ExecutionPayload()
if err != nil {
t.Fatalf("expHead.ExecutionPayload() failed: %v", err)
}
expNumber = p.NumberU64() expNumber = p.NumberU64()
} }
select { select {

View file

@ -56,32 +56,17 @@ var (
AddFork("DENEB", 132608, []byte{144, 0, 0, 115}), AddFork("DENEB", 132608, []byte{144, 0, 0, 115}),
Checkpoint: common.HexToHash("0x1005a6d9175e96bfbce4d35b80f468e9bff0b674e1e861d16e09e10005a58e81"), Checkpoint: common.HexToHash("0x1005a6d9175e96bfbce4d35b80f468e9bff0b674e1e861d16e09e10005a58e81"),
} }
GoerliConfig = lightClientConfig{
ChainConfig: (&types.ChainConfig{
GenesisValidatorsRoot: common.HexToHash("0x043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb"),
GenesisTime: 1614588812,
}).
AddFork("GENESIS", 0, []byte{0, 0, 16, 32}).
AddFork("ALTAIR", 36660, []byte{1, 0, 16, 32}).
AddFork("BELLATRIX", 112260, []byte{2, 0, 16, 32}).
AddFork("CAPELLA", 162304, []byte{3, 0, 16, 32}).
AddFork("DENEB", 231680, []byte{4, 0, 16, 32}),
Checkpoint: common.HexToHash("0x53a0f4f0a378e2c4ae0a9ee97407eb69d0d737d8d8cd0a5fb1093f42f7b81c49"),
}
) )
func makeChainConfig(ctx *cli.Context) lightClientConfig { func makeChainConfig(ctx *cli.Context) lightClientConfig {
var config lightClientConfig var config lightClientConfig
customConfig := ctx.IsSet(utils.BeaconConfigFlag.Name) customConfig := ctx.IsSet(utils.BeaconConfigFlag.Name)
utils.CheckExclusive(ctx, utils.MainnetFlag, utils.GoerliFlag, utils.SepoliaFlag, utils.BeaconConfigFlag) utils.CheckExclusive(ctx, utils.MainnetFlag, utils.SepoliaFlag, utils.BeaconConfigFlag)
switch { switch {
case ctx.Bool(utils.MainnetFlag.Name): case ctx.Bool(utils.MainnetFlag.Name):
config = MainnetConfig config = MainnetConfig
case ctx.Bool(utils.SepoliaFlag.Name): case ctx.Bool(utils.SepoliaFlag.Name):
config = SepoliaConfig config = SepoliaConfig
case ctx.Bool(utils.GoerliFlag.Name):
config = GoerliConfig
default: default:
if !customConfig { if !customConfig {
config = MainnetConfig config = MainnetConfig

View file

@ -34,6 +34,8 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
Withdrawals []*types.Withdrawal `json:"withdrawals"` Withdrawals []*types.Withdrawal `json:"withdrawals"`
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
Deposits types.Deposits `json:"depositRequests"`
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
} }
var enc ExecutableData var enc ExecutableData
@ -61,6 +63,8 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
enc.Withdrawals = e.Withdrawals enc.Withdrawals = e.Withdrawals
enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed) enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed)
enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas) enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas)
enc.Deposits = e.Deposits
enc.ExecutionWitness = e.ExecutionWitness
return json.Marshal(&enc) return json.Marshal(&enc)
} }
@ -84,6 +88,8 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
Withdrawals []*types.Withdrawal `json:"withdrawals"` Withdrawals []*types.Withdrawal `json:"withdrawals"`
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
Deposits *types.Deposits `json:"depositRequests"`
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
} }
var dec ExecutableData var dec ExecutableData
@ -187,5 +193,11 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
if dec.ExcessBlobGas != nil { if dec.ExcessBlobGas != nil {
e.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas) e.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas)
} }
if dec.Deposits != nil {
e.Deposits = *dec.Deposits
}
if dec.ExecutionWitness != nil {
e.ExecutionWitness = dec.ExecutionWitness
}
return nil return nil
} }

View file

@ -19,6 +19,7 @@ func (e ExecutionPayloadEnvelope) MarshalJSON() ([]byte, error) {
BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"` BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"`
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"` BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
Override bool `json:"shouldOverrideBuilder"` Override bool `json:"shouldOverrideBuilder"`
Witness *hexutil.Bytes `json:"witness"`
} }
var enc ExecutionPayloadEnvelope var enc ExecutionPayloadEnvelope
@ -26,6 +27,7 @@ func (e ExecutionPayloadEnvelope) MarshalJSON() ([]byte, error) {
enc.BlockValue = (*hexutil.Big)(e.BlockValue) enc.BlockValue = (*hexutil.Big)(e.BlockValue)
enc.BlobsBundle = e.BlobsBundle enc.BlobsBundle = e.BlobsBundle
enc.Override = e.Override enc.Override = e.Override
enc.Witness = e.Witness
return json.Marshal(&enc) return json.Marshal(&enc)
} }
@ -36,6 +38,7 @@ func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error {
BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"` BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"`
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"` BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
Override *bool `json:"shouldOverrideBuilder"` Override *bool `json:"shouldOverrideBuilder"`
Witness *hexutil.Bytes `json:"witness"`
} }
var dec ExecutionPayloadEnvelope var dec ExecutionPayloadEnvelope
@ -60,5 +63,8 @@ func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error {
if dec.Override != nil { if dec.Override != nil {
e.Override = *dec.Override e.Override = *dec.Override
} }
if dec.Witness != nil {
e.Witness = dec.Witness
}
return nil return nil
} }

View file

@ -76,6 +76,8 @@ type ExecutableData struct {
Withdrawals []*types.Withdrawal `json:"withdrawals"` Withdrawals []*types.Withdrawal `json:"withdrawals"`
BlobGasUsed *uint64 `json:"blobGasUsed"` BlobGasUsed *uint64 `json:"blobGasUsed"`
ExcessBlobGas *uint64 `json:"excessBlobGas"` ExcessBlobGas *uint64 `json:"excessBlobGas"`
Deposits types.Deposits `json:"depositRequests"`
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
} }
// JSON type overrides for executableData. // JSON type overrides for executableData.
@ -92,6 +94,14 @@ type executableDataMarshaling struct {
ExcessBlobGas *hexutil.Uint64 ExcessBlobGas *hexutil.Uint64
} }
// StatelessPayloadStatusV1 is the result of a stateless payload execution.
type StatelessPayloadStatusV1 struct {
Status string `json:"status"`
StateRoot common.Hash `json:"stateRoot"`
ReceiptsRoot common.Hash `json:"receiptsRoot"`
ValidationError *string `json:"validationError"`
}
//go:generate go run github.com/fjl/gencodec -type ExecutionPayloadEnvelope -field-override executionPayloadEnvelopeMarshaling -out gen_epe.go //go:generate go run github.com/fjl/gencodec -type ExecutionPayloadEnvelope -field-override executionPayloadEnvelopeMarshaling -out gen_epe.go
type ExecutionPayloadEnvelope struct { type ExecutionPayloadEnvelope struct {
@ -99,6 +109,7 @@ type ExecutionPayloadEnvelope struct {
BlockValue *big.Int `json:"blockValue" gencodec:"required"` BlockValue *big.Int `json:"blockValue" gencodec:"required"`
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"` BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
Override bool `json:"shouldOverrideBuilder"` Override bool `json:"shouldOverrideBuilder"`
Witness *hexutil.Bytes `json:"witness"`
} }
type BlobsBundleV1 struct { type BlobsBundleV1 struct {
@ -114,6 +125,7 @@ type executionPayloadEnvelopeMarshaling struct {
type PayloadStatusV1 struct { type PayloadStatusV1 struct {
Status string `json:"status"` Status string `json:"status"`
Witness *hexutil.Bytes `json:"witness"`
LatestValidHash *common.Hash `json:"latestValidHash"` LatestValidHash *common.Hash `json:"latestValidHash"`
ValidationError *string `json:"validationError"` ValidationError *string `json:"validationError"`
} }
@ -201,6 +213,20 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
// Withdrawals value will propagate through the returned block. Empty // Withdrawals value will propagate through the returned block. Empty
// Withdrawals value must be passed via non-nil, length 0 value in data. // Withdrawals value must be passed via non-nil, length 0 value in data.
func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (*types.Block, error) { func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (*types.Block, error) {
block, err := ExecutableDataToBlockNoHash(data, versionedHashes, beaconRoot)
if err != nil {
return nil, err
}
if block.Hash() != data.BlockHash {
return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", data.BlockHash, block.Hash())
}
return block, nil
}
// ExecutableDataToBlockNoHash is analogous to ExecutableDataToBlock, but is used
// for stateless execution, so it skips checking if the executable data hashes to
// the requested hash (stateless has to *compute* the root hash, it's not given).
func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (*types.Block, error) {
txs, err := decodeTransactions(data.Transactions) txs, err := decodeTransactions(data.Transactions)
if err != nil { if err != nil {
return nil, err return nil, err
@ -235,7 +261,19 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b
h := types.DeriveSha(types.Withdrawals(data.Withdrawals), trie.NewStackTrie(nil)) h := types.DeriveSha(types.Withdrawals(data.Withdrawals), trie.NewStackTrie(nil))
withdrawalsRoot = &h withdrawalsRoot = &h
} }
// Compute requestsHash if any requests are non-nil.
var (
requestsHash *common.Hash
requests types.Requests
)
if data.Deposits != nil {
requests = make(types.Requests, 0)
for _, d := range data.Deposits {
requests = append(requests, types.NewRequest(d))
}
h := types.DeriveSha(requests, trie.NewStackTrie(nil))
requestsHash = &h
}
header := &types.Header{ header := &types.Header{
ParentHash: data.ParentHash, ParentHash: data.ParentHash,
UncleHash: types.EmptyUncleHash, UncleHash: types.EmptyUncleHash,
@ -256,13 +294,12 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b
ExcessBlobGas: data.ExcessBlobGas, ExcessBlobGas: data.ExcessBlobGas,
BlobGasUsed: data.BlobGasUsed, BlobGasUsed: data.BlobGasUsed,
ParentBeaconRoot: beaconRoot, ParentBeaconRoot: beaconRoot,
RequestsHash: requestsHash,
} }
block := types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals}) return types.NewBlockWithHeader(header).
if block.Hash() != data.BlockHash { WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals, Requests: requests}).
return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", data.BlockHash, block.Hash()) WithWitness(data.ExecutionWitness),
} nil
return block, nil
} }
// BlockToExecutableData constructs the ExecutableData structure by filling the // BlockToExecutableData constructs the ExecutableData structure by filling the
@ -286,6 +323,7 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.
Withdrawals: block.Withdrawals(), Withdrawals: block.Withdrawals(),
BlobGasUsed: block.BlobGasUsed(), BlobGasUsed: block.BlobGasUsed(),
ExcessBlobGas: block.ExcessBlobGas(), ExcessBlobGas: block.ExcessBlobGas(),
ExecutionWitness: block.ExecutionWitness(),
} }
bundle := BlobsBundleV1{ bundle := BlobsBundleV1{
Commitments: make([]hexutil.Bytes, 0), Commitments: make([]hexutil.Bytes, 0),
@ -299,13 +337,30 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.
bundle.Proofs = append(bundle.Proofs, hexutil.Bytes(sidecar.Proofs[j][:])) bundle.Proofs = append(bundle.Proofs, hexutil.Bytes(sidecar.Proofs[j][:]))
} }
} }
setRequests(block.Requests(), data)
return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees, BlobsBundle: &bundle, Override: false} return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees, BlobsBundle: &bundle, Override: false}
} }
// ExecutionPayloadBodyV1 is used in the response to GetPayloadBodiesByHashV1 and GetPayloadBodiesByRangeV1 // setRequests differentiates the different request types and
type ExecutionPayloadBodyV1 struct { // assigns them to the associated fields in ExecutableData.
func setRequests(requests types.Requests, data *ExecutableData) {
if requests != nil {
// If requests is non-nil, it means deposits are available in block and we
// should return an empty slice instead of nil if there are no deposits.
data.Deposits = make(types.Deposits, 0)
}
for _, r := range requests {
if d, ok := r.Inner().(*types.Deposit); ok {
data.Deposits = append(data.Deposits, d)
}
}
}
// ExecutionPayloadBody is used in the response to GetPayloadBodiesByHash and GetPayloadBodiesByRange
type ExecutionPayloadBody struct {
TransactionData []hexutil.Bytes `json:"transactions"` TransactionData []hexutil.Bytes `json:"transactions"`
Withdrawals []*types.Withdrawal `json:"withdrawals"` Withdrawals []*types.Withdrawal `json:"withdrawals"`
Deposits types.Deposits `json:"depositRequests"`
} }
// Client identifiers to support ClientVersionV1. // Client identifiers to support ClientVersionV1.

0
beacon/light/api/api_server.go Executable file → Normal file
View file

49
beacon/light/api/light_api.go Executable file → Normal file
View file

@ -23,6 +23,8 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"net/url"
"strconv"
"sync" "sync"
"time" "time"
@ -120,8 +122,12 @@ func NewBeaconLightApi(url string, customHeaders map[string]string) *BeaconLight
} }
} }
func (api *BeaconLightApi) httpGet(path string) ([]byte, error) { func (api *BeaconLightApi) httpGet(path string, params url.Values) ([]byte, error) {
req, err := http.NewRequest("GET", api.url+path, nil) uri, err := api.buildURL(path, params)
if err != nil {
return nil, err
}
req, err := http.NewRequest("GET", uri, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -145,17 +151,16 @@ func (api *BeaconLightApi) httpGet(path string) ([]byte, error) {
} }
} }
func (api *BeaconLightApi) httpGetf(format string, params ...any) ([]byte, error) {
return api.httpGet(fmt.Sprintf(format, params...))
}
// GetBestUpdatesAndCommittees fetches and validates LightClientUpdate for given // GetBestUpdatesAndCommittees fetches and validates LightClientUpdate for given
// period and full serialized committee for the next period (committee root hash // period and full serialized committee for the next period (committee root hash
// equals update.NextSyncCommitteeRoot). // equals update.NextSyncCommitteeRoot).
// Note that the results are validated but the update signature should be verified // Note that the results are validated but the update signature should be verified
// by the caller as its validity depends on the update chain. // by the caller as its validity depends on the update chain.
func (api *BeaconLightApi) GetBestUpdatesAndCommittees(firstPeriod, count uint64) ([]*types.LightClientUpdate, []*types.SerializedSyncCommittee, error) { func (api *BeaconLightApi) GetBestUpdatesAndCommittees(firstPeriod, count uint64) ([]*types.LightClientUpdate, []*types.SerializedSyncCommittee, error) {
resp, err := api.httpGetf("/eth/v1/beacon/light_client/updates?start_period=%d&count=%d", firstPeriod, count) resp, err := api.httpGet("/eth/v1/beacon/light_client/updates", map[string][]string{
"start_period": {strconv.FormatUint(firstPeriod, 10)},
"count": {strconv.FormatUint(count, 10)},
})
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -192,7 +197,7 @@ func (api *BeaconLightApi) GetBestUpdatesAndCommittees(firstPeriod, count uint64
// See data structure definition here: // See data structure definition here:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate
func (api *BeaconLightApi) GetOptimisticUpdate() (types.OptimisticUpdate, error) { func (api *BeaconLightApi) GetOptimisticUpdate() (types.OptimisticUpdate, error) {
resp, err := api.httpGet("/eth/v1/beacon/light_client/optimistic_update") resp, err := api.httpGet("/eth/v1/beacon/light_client/optimistic_update", nil)
if err != nil { if err != nil {
return types.OptimisticUpdate{}, err return types.OptimisticUpdate{}, err
} }
@ -245,7 +250,7 @@ func decodeOptimisticUpdate(enc []byte) (types.OptimisticUpdate, error) {
// See data structure definition here: // See data structure definition here:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientfinalityupdate // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientfinalityupdate
func (api *BeaconLightApi) GetFinalityUpdate() (types.FinalityUpdate, error) { func (api *BeaconLightApi) GetFinalityUpdate() (types.FinalityUpdate, error) {
resp, err := api.httpGet("/eth/v1/beacon/light_client/finality_update") resp, err := api.httpGet("/eth/v1/beacon/light_client/finality_update", nil)
if err != nil { if err != nil {
return types.FinalityUpdate{}, err return types.FinalityUpdate{}, err
} }
@ -311,7 +316,7 @@ func (api *BeaconLightApi) GetHeader(blockRoot common.Hash) (types.Header, bool,
} else { } else {
blockId = blockRoot.Hex() blockId = blockRoot.Hex()
} }
resp, err := api.httpGetf("/eth/v1/beacon/headers/%s", blockId) resp, err := api.httpGet(fmt.Sprintf("/eth/v1/beacon/headers/%s", blockId), nil)
if err != nil { if err != nil {
return types.Header{}, false, false, err return types.Header{}, false, false, err
} }
@ -342,7 +347,7 @@ func (api *BeaconLightApi) GetHeader(blockRoot common.Hash) (types.Header, bool,
// GetCheckpointData fetches and validates bootstrap data belonging to the given checkpoint. // GetCheckpointData fetches and validates bootstrap data belonging to the given checkpoint.
func (api *BeaconLightApi) GetCheckpointData(checkpointHash common.Hash) (*types.BootstrapData, error) { func (api *BeaconLightApi) GetCheckpointData(checkpointHash common.Hash) (*types.BootstrapData, error) {
resp, err := api.httpGetf("/eth/v1/beacon/light_client/bootstrap/0x%x", checkpointHash[:]) resp, err := api.httpGet(fmt.Sprintf("/eth/v1/beacon/light_client/bootstrap/0x%x", checkpointHash[:]), nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -384,7 +389,7 @@ func (api *BeaconLightApi) GetCheckpointData(checkpointHash common.Hash) (*types
} }
func (api *BeaconLightApi) GetBeaconBlock(blockRoot common.Hash) (*types.BeaconBlock, error) { func (api *BeaconLightApi) GetBeaconBlock(blockRoot common.Hash) (*types.BeaconBlock, error) {
resp, err := api.httpGetf("/eth/v2/beacon/blocks/0x%x", blockRoot) resp, err := api.httpGet(fmt.Sprintf("/eth/v2/beacon/blocks/0x%x", blockRoot), nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -545,9 +550,13 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func()
// established. It can only return nil when the context is canceled. // established. It can only return nil when the context is canceled.
func (api *BeaconLightApi) startEventStream(ctx context.Context, listener *HeadEventListener) *eventsource.Stream { func (api *BeaconLightApi) startEventStream(ctx context.Context, listener *HeadEventListener) *eventsource.Stream {
for retry := true; retry; retry = ctxSleep(ctx, 5*time.Second) { for retry := true; retry; retry = ctxSleep(ctx, 5*time.Second) {
path := "/eth/v1/events?topics=head&topics=light_client_finality_update&topics=light_client_optimistic_update"
log.Trace("Sending event subscription request") log.Trace("Sending event subscription request")
req, err := http.NewRequestWithContext(ctx, "GET", api.url+path, nil) uri, err := api.buildURL("/eth/v1/events", map[string][]string{"topics": {"head", "light_client_finality_update", "light_client_optimistic_update"}})
if err != nil {
listener.OnError(fmt.Errorf("error creating event subscription URL: %v", err))
continue
}
req, err := http.NewRequestWithContext(ctx, "GET", uri, nil)
if err != nil { if err != nil {
listener.OnError(fmt.Errorf("error creating event subscription request: %v", err)) listener.OnError(fmt.Errorf("error creating event subscription request: %v", err))
continue continue
@ -576,3 +585,15 @@ func ctxSleep(ctx context.Context, timeout time.Duration) (ok bool) {
return false return false
} }
} }
func (api *BeaconLightApi) buildURL(path string, params url.Values) (string, error) {
uri, err := url.Parse(api.url)
if err != nil {
return "", err
}
uri = uri.JoinPath(path)
if params != nil {
uri.RawQuery = params.Encode()
}
return uri.String(), nil
}

View file

@ -269,7 +269,7 @@ func (s *Scheduler) addEvent(event Event) {
s.Trigger() s.Trigger()
} }
// filterEvent sorts each Event either as a request event or a server event, // filterEvents sorts each Event either as a request event or a server event,
// depending on its type. Request events are also sorted in a map based on the // depending on its type. Request events are also sorted in a map based on the
// module that originally initiated the request. It also ensures that no events // module that originally initiated the request. It also ensures that no events
// related to a server are returned before EvRegistered or after EvUnregistered. // related to a server are returned before EvRegistered or after EvUnregistered.

View file

@ -201,6 +201,34 @@ func TestUpdateSyncDifferentHeads(t *testing.T) {
chain.ExpNextSyncPeriod(t, 17) chain.ExpNextSyncPeriod(t, 17)
} }
func TestRangeLock(t *testing.T) {
r := make(rangeLock)
// Lock from 0 to 99.
r.lock(0, 100, 1)
for i := 0; i < 100; i++ {
if v, ok := r[uint64(i)]; v <= 0 || !ok {
t.Fatalf("integer space: %d not locked", i)
}
}
// Unlock from 0 to 99.
r.lock(0, 100, -1)
for i := 0; i < 100; i++ {
if v, ok := r[uint64(i)]; v > 0 || ok {
t.Fatalf("integer space: %d is locked", i)
}
}
// Lock from 0 to 99 then unlock from 10 to 59.
r.lock(0, 100, 1)
r.lock(10, 50, -1)
first, count := r.firstUnlocked(0, 100)
if first != 10 || count != 50 {
t.Fatalf("unexpected first: %d or count: %d", first, count)
}
}
func testRespUpdate(request requestWithID) request.Response { func testRespUpdate(request requestWithID) request.Response {
var resp RespUpdates var resp RespUpdates
if request.request == nil { if request.request == nil {

View file

@ -5,55 +5,56 @@
# https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/ # https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/
ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz
# version:golang 1.22.6 # version:golang 1.23.1
# https://go.dev/dl/ # https://go.dev/dl/
9e48d99d519882579917d8189c17e98c373ce25abaebb98772e2927088992a51 go1.22.6.src.tar.gz 6ee44e298379d146a5e5aa6b1c5b5d5f5d0a3365eabdd70741e6e21340ec3b0d go1.23.1.src.tar.gz
eeb0cc42120cbae6d3695dae2e5420fa0e93a5db957db139b55efdb879dd9856 go1.22.6.aix-ppc64.tar.gz f17f2791717c15728ec63213a014e244c35f9c8846fb29f5a1b63d0c0556f756 go1.23.1.aix-ppc64.tar.gz
b47ac340f0b072943fed1f558a26eb260cc23bd21b8af175582e9103141d465b go1.22.6.darwin-amd64.pkg dd9e772686ed908bcff94b6144322d4e2473a7dcd7c696b7e8b6d12f23c887fd go1.23.1.darwin-amd64.pkg
9c3c0124b01b5365f73a1489649f78f971ecf84844ad9ca58fde133096ddb61b go1.22.6.darwin-amd64.tar.gz 488d9e4ca3e3ed513ee4edd91bef3a2360c65fa6d6be59cf79640bf840130a58 go1.23.1.darwin-amd64.tar.gz
14d0355ec1c0eeb213a16efa8635fac1f16067ef78a8173abf9a8c7b805e551e go1.22.6.darwin-arm64.pkg be34b488157ec69d94e26e1554558219a2c90789bcb7e3686965a7f9c8cfcbe7 go1.23.1.darwin-arm64.pkg
ebac39fd44fc22feed1bb519af431c84c55776e39b30f4fd62930da9c0cfd1e3 go1.22.6.darwin-arm64.tar.gz e223795ca340e285a760a6446ce57a74500b30e57469a4109961d36184d3c05a go1.23.1.darwin-arm64.tar.gz
3695b10c722a4920c8a736284f8820c142e1e752f3a87f797a45c64366f7a173 go1.22.6.dragonfly-amd64.tar.gz 6af626176923a6ae6c5de6dc1c864f38365793c0e4ecd0d6eab847bdc23953e5 go1.23.1.dragonfly-amd64.tar.gz
a9b9570c80294a664d50b566d6bd1aa42465997d2d76a57936b32f55f5c69c63 go1.22.6.freebsd-386.tar.gz cc957c1a019702e6cdc2e257202d42799011ebc1968b6c3bcd6b1965952607d5 go1.23.1.freebsd-386.tar.gz
424a5618406800365fe3ad96a795fb55ce394bea3ff48eaf56d292bf7a916d1e go1.22.6.freebsd-amd64.tar.gz a7d57781c50bb80886a8f04066791956d45aa3eea0f83070c5268b6223afb2ff go1.23.1.freebsd-amd64.tar.gz
e0dce3a6dbe8e7e054d329dd4cb403935c63c0f7e22e693077aa60e12018b883 go1.22.6.freebsd-arm.tar.gz c7b09f3fef456048e596db9bea746eb66796aeb82885622b0388feee18f36a3e go1.23.1.freebsd-arm.tar.gz
34930b01f58889c71f7a78c51c6c3bd2ce289ac7862c76dab691303cfa935fd1 go1.22.6.freebsd-arm64.tar.gz b05cd6a77995a0c8439d88df124811c725fb78b942d0b6dd1643529d7ba62f1f go1.23.1.freebsd-arm64.tar.gz
4c9d630e55d4d600a5b4297e59620c3bdfe63a441981682b3638e2fdda228a44 go1.22.6.freebsd-riscv64.tar.gz 56236ae70be1613f2915943b94f53c96be5bffc0719314078facd778a89bc57e go1.23.1.freebsd-riscv64.tar.gz
9ed63feaf2ef56c56f1cf0d9d3fab4006efd22a38e2f1f5252e95c6ac09332f3 go1.22.6.illumos-amd64.tar.gz 8644c52df4e831202114fd67c9fcaf1f7233ad27bf945ac53fa7217cf1a0349f go1.23.1.illumos-amd64.tar.gz
9e680027b058beab10ce5938607660964b6d2c564bf50bdb01aa090dc5beda98 go1.22.6.linux-386.tar.gz cdee2f4e2efa001f7ee75c90f2efc310b63346cfbba7b549987e9139527c6b17 go1.23.1.linux-386.tar.gz
999805bed7d9039ec3da1a53bfbcafc13e367da52aa823cb60b68ba22d44c616 go1.22.6.linux-amd64.tar.gz 49bbb517cfa9eee677e1e7897f7cf9cfdbcf49e05f61984a2789136de359f9bd go1.23.1.linux-amd64.tar.gz
c15fa895341b8eaf7f219fada25c36a610eb042985dc1a912410c1c90098eaf2 go1.22.6.linux-arm64.tar.gz faec7f7f8ae53fda0f3d408f52182d942cc89ef5b7d3d9f23ff117437d4b2d2f go1.23.1.linux-arm64.tar.gz
b566484fe89a54c525dd1a4cbfec903c1f6e8f0b7b3dbaf94c79bc9145391083 go1.22.6.linux-armv6l.tar.gz 6c7832c7dcd8fb6d4eb308f672a725393403c74ee7be1aeccd8a443015df99de go1.23.1.linux-armv6l.tar.gz
1ee6e1896aea856142d2af7045cea118995b39404aa61afd12677d023d47ee69 go1.22.6.linux-loong64.tar.gz 649ce3856ddc808c00b14a46232eab0bf95e7911cdf497010b17d76656f5ca4e go1.23.1.linux-loong64.tar.gz
fdd0e1a3e178f9bc79adf6ff1e3de4554ce581b4c468fd6e113c43fbbbe1eec6 go1.22.6.linux-mips.tar.gz 201911048f234e5a0c51ec94b1a11d4e47062fee4398b1d2faa6c820dc026724 go1.23.1.linux-mips.tar.gz
d3e5a621fc5a07759e503a971af0b28ded6a7d6f5604ab511f51f930a18dd3e4 go1.22.6.linux-mips64.tar.gz 2bce3743df463915e45d2612f9476ffb03d0b3750b1cb3879347de08715b5fc6 go1.23.1.linux-mips64.tar.gz
01547606c5b5c1b0e5587b3afd65172860d2f4755e523785832905759ecce2d7 go1.22.6.linux-mips64le.tar.gz 54e301f266e33431b0703136e0bbd4cf02461b1ecedd37b7cbd90cb862a98e5f go1.23.1.linux-mips64le.tar.gz
2cd771416ae03c11240cfdb551d66ab9a941077664f3727b966f94386c23b0fa go1.22.6.linux-mipsle.tar.gz 8efd495e93d17408c0803595cdc3bf13cb28e0f957aeabd9cc18245fb8e64019 go1.23.1.linux-mipsle.tar.gz
6ef61d517777925e6bdb0321ea42d5f60acc20c1314dd902b9d0bfa3a5fd4fca go1.22.6.linux-ppc64.tar.gz 52bd68689095831ad9af7160844c23b28bb8d0acd268de7e300ff5f0662b7a07 go1.23.1.linux-ppc64.tar.gz
9d99fce3f6f72a76630fe91ec0884dfe3db828def4713368424900fa98bb2bd6 go1.22.6.linux-ppc64le.tar.gz 042888cae54b5fbfd9dd1e3b6bc4a5134879777fe6497fc4c62ec394b5ecf2da go1.23.1.linux-ppc64le.tar.gz
30be9c9b9cc4f044d4da9a33ee601ab7b3aff4246107d323a79e08888710754e go1.22.6.linux-riscv64.tar.gz 1a4a609f0391bea202d9095453cbfaf7368fa88a04c206bf9dd715a738664dc3 go1.23.1.linux-riscv64.tar.gz
82f3bae3ddb4ede45b848db48c5486fadb58551e74507bda45484257e7194a95 go1.22.6.linux-s390x.tar.gz 47dc49ad45c45e192efa0df7dc7bc5403f5f2d15b5d0dc74ef3018154b616f4d go1.23.1.linux-s390x.tar.gz
85b2eb9d40a930bd3e75d0096a6eb5847aac86c5085e6d13a5845e9ef03f8d4b go1.22.6.netbsd-386.tar.gz fbfbd5efa6a5d581ea7f5e65015f927db0e52135cab057e43d39d5482da54b61 go1.23.1.netbsd-386.tar.gz
6e9acbdc34fb2a942d547c47c9c1989bb6e32b4a37d57fb312499e2bb33b46b7 go1.22.6.netbsd-amd64.tar.gz e96e1cc5cf36113ee6099d1a7306b22cd9c3f975a36bdff954c59f104f22b853 go1.23.1.netbsd-amd64.tar.gz
e6eff3cf0038f2a9b0c9e01e228577a783bddcd8051222a3d949e24ee392e769 go1.22.6.netbsd-arm.tar.gz c394dfc06bfc276a591209a37e09cd39089ec9a9cc3db30b94814ce2e39eb1d4 go1.23.1.netbsd-arm.tar.gz
43a7e2ba22da700b844f7561e3dd5434540ed6c9781be2e9c42e8a8cbf558f8e go1.22.6.netbsd-arm64.tar.gz b3b35d64f32821a68b3e2994032dbefb81978f2ec3f218c7a770623b82d36b8e go1.23.1.netbsd-arm64.tar.gz
a90b758ccb45d8a17af8e140fafa1e97607de5a7ecd53a4c55f69258bfb043d0 go1.22.6.openbsd-386.tar.gz 3c775c4c16c182e33c2c4ac090d9a247a93b3fb18a3df01d87d490f29599faff go1.23.1.openbsd-386.tar.gz
cc13436c4a644e55bedcea65981eb80ca8317b39b129f5563ab3b6da1391bd47 go1.22.6.openbsd-amd64.tar.gz 5edbe53b47c57b32707fd7154536fbe9eaa79053fea01650c93b54cdba13fc0f go1.23.1.openbsd-amd64.tar.gz
aee34f61ba2b0a8f2618f5c7065e20da7714ce7651680509eda30728fe01ee88 go1.22.6.openbsd-arm.tar.gz c30903dd8fa98b8aca8e9db0962ce9f55502aed93e0ef41e5ae148aaa0088de1 go1.23.1.openbsd-arm.tar.gz
c67d57daf8baada93c69c8fb02401270cd33159730b1f2d70d9e724ba1a918cf go1.22.6.openbsd-arm64.tar.gz 12da183489e58f9c6b357bc1b626f85ed7d4220cab31a49d6a49e6ac6a718b67 go1.23.1.openbsd-arm64.tar.gz
03e1f96002e94a6b381bcf66a0a62b9d5f63148682a780d727840ad540185c7c go1.22.6.openbsd-ppc64.tar.gz 9cc9aad37696a4a10c31dcec9e35a308de0b369dad354d54cf07406ac6fa7c6f go1.23.1.openbsd-ppc64.tar.gz
0ac2b5bbe2c8a293d284512630e629bf0578aaa7b7b1f39ac4ee182c7924aaad go1.22.6.plan9-386.tar.gz e1d740dda062ce5a276a0c3ed7d8b6353238bc8ff405f63e2e3480bfd26a5ec5 go1.23.1.openbsd-riscv64.tar.gz
f9afdab8a72a8d874f023f5605482cc94160843ac768dbd840e6f772d16578c7 go1.22.6.plan9-amd64.tar.gz da2a37f9987f01f096859230aa13ecc4ad2e7884465bce91004bc78c64435d65 go1.23.1.plan9-386.tar.gz
4b9f01a47e6a29d57cbb3097b6770583336cef9c8f0d51d3d1451e42a851002e go1.22.6.plan9-arm.tar.gz fd8fff8b0697d55c4a4d02a8dc998192b80a9dc2a057647373d6ff607cad29de go1.23.1.plan9-amd64.tar.gz
46c2552ac7b8d6314a52e14e0a0761aaeebdd6aba5f531de386f4cf2b66ec723 go1.22.6.solaris-amd64.tar.gz 52efbc5804c1c86ba7868aa8ebbc31cc8c2a27b62a60fd57944970d48fc67525 go1.23.1.plan9-arm.tar.gz
a57821dab76af1ef7a6b62db1628f0caa74343e0c7cb829df9ce8ea0713a3e8e go1.22.6.windows-386.msi f54205f21e2143f2ada1bf1c00ddf64590f5139d5c3fb77cc06175f0d8cc7567 go1.23.1.solaris-amd64.tar.gz
eb734bacc9aabca1273b61dd392bb84a9bb33783f5e2fff2cd6ab9885bbefbe6 go1.22.6.windows-386.zip 369a17f0cfd29e5c848e58ffe0d772da20abe334d1c7ca01dbcd55bb3db0b440 go1.23.1.windows-386.msi
1238a3e6892eb8a0eb3fe0640e18ab82ca21cc1a933f16897b2ad081f057b5da go1.22.6.windows-amd64.msi ab866f47d7be56e6b1c67f1d529bf4c23331a339fb0785f435a0552d352cb257 go1.23.1.windows-386.zip
6023083a6e4d3199b44c37e9ba7b25d9674da20fd846a35ee5f9589d81c21a6a go1.22.6.windows-amd64.zip e99dac215ee437b9bb8f8b14bbfe0e8756882c1ed291f30818e8363bc9c047a5 go1.23.1.windows-amd64.msi
6791218c568a3d000cb36317506541d7fd67e7cfe613baaf361ca36cad5e2cd5 go1.22.6.windows-arm.msi 32dedf277c86610e380e1765593edb66876f00223df71690bd6be68ee17675c0 go1.23.1.windows-amd64.zip
ee41ca83bb07c4fd46a1d6b2d083519bb8ca156fcd9db37ee711234d43126e2f go1.22.6.windows-arm.zip 23169c79dc6b54e0dffb25be6b67425ad9759392a58309bc057430a9bf4c8f6a go1.23.1.windows-arm.msi
91c6b3376612095315a0aeae4b03e3da34fabe9dfd4532d023e2a70f913cf22a go1.22.6.windows-arm64.msi 1a57615a09f13534f88e9f2d7efd5743535d1a5719b19e520eef965a634f8efb go1.23.1.windows-arm.zip
7cf55f357ba8116cd3bff992980e20a704ba451b3dab341cf1787b133d900512 go1.22.6.windows-arm64.zip 313e1a543931ad8735b4df8969e00f5f4c2ef07be21f54015ede961a70263d35 go1.23.1.windows-arm64.msi
64ad0954d2c33f556fb1018d62de091254aa6e3a94f1c8a8b16af0d3701d194e go1.23.1.windows-arm64.zip
# version:golangci 1.59.0 # version:golangci 1.59.0
# https://github.com/golangci/golangci-lint/releases/ # https://github.com/golangci/golangci-lint/releases/

View file

@ -50,7 +50,6 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strconv"
"strings" "strings"
"time" "time"
@ -126,8 +125,6 @@ var (
"focal", // 20.04, EOL: 04/2030 "focal", // 20.04, EOL: 04/2030
"jammy", // 22.04, EOL: 04/2032 "jammy", // 22.04, EOL: 04/2032
"noble", // 24.04, EOL: 04/2034 "noble", // 24.04, EOL: 04/2034
"mantic", // 23.10, EOL: 07/2024
} }
// This is where the tests should be unpacked. // This is where the tests should be unpacked.
@ -161,8 +158,8 @@ func main() {
doLint(os.Args[2:]) doLint(os.Args[2:])
case "archive": case "archive":
doArchive(os.Args[2:]) doArchive(os.Args[2:])
case "docker": case "dockerx":
doDocker(os.Args[2:]) doDockerBuildx(os.Args[2:])
case "debsrc": case "debsrc":
doDebianSource(os.Args[2:]) doDebianSource(os.Args[2:])
case "nsis": case "nsis":
@ -239,6 +236,10 @@ func doInstall(cmdline []string) {
// buildFlags returns the go tool flags for building. // buildFlags returns the go tool flags for building.
func buildFlags(env build.Environment, staticLinking bool, buildTags []string) (flags []string) { func buildFlags(env build.Environment, staticLinking bool, buildTags []string) (flags []string) {
var ld []string var ld []string
// See https://github.com/golang/go/issues/33772#issuecomment-528176001
// We need to set --buildid to the linker here, and also pass --build-id to the
// cgo-linker further down.
ld = append(ld, "--buildid=none")
if env.Commit != "" { if env.Commit != "" {
ld = append(ld, "-X", "github.com/maticnetwork/bor/internal/version.gitCommit="+env.Commit) ld = append(ld, "-X", "github.com/maticnetwork/bor/internal/version.gitCommit="+env.Commit)
ld = append(ld, "-X", "github.com/maticnetwork/bor/internal/version.gitDate="+env.Date) ld = append(ld, "-X", "github.com/maticnetwork/bor/internal/version.gitDate="+env.Date)
@ -251,7 +252,11 @@ func buildFlags(env build.Environment, staticLinking bool, buildTags []string) (
if runtime.GOOS == "linux" { if runtime.GOOS == "linux" {
// Enforce the stacksize to 8M, which is the case on most platforms apart from // Enforce the stacksize to 8M, which is the case on most platforms apart from
// alpine Linux. // alpine Linux.
extld := []string{"-Wl,-z,stack-size=0x800000"} // See https://sourceware.org/binutils/docs-2.23.1/ld/Options.html#Options
// regarding the options --build-id=none and --strip-all. It is needed for
// reproducible builds; removing references to temporary files in C-land, and
// making build-id reproducably absent.
extld := []string{"-Wl,-z,stack-size=0x800000,--build-id=none,--strip-all"}
if staticLinking { if staticLinking {
extld = append(extld, "-static") extld = append(extld, "-static")
// Under static linking, use of certain glibc features must be // Under static linking, use of certain glibc features must be
@ -298,7 +303,7 @@ func doTest(cmdline []string) {
gotest := tc.Go("test") gotest := tc.Go("test")
// CI needs a bit more time for the statetests (default 10m). // CI needs a bit more time for the statetests (default 10m).
gotest.Args = append(gotest.Args, "-timeout=20m") gotest.Args = append(gotest.Args, "-timeout=30m")
// Enable CKZG backend in CI. // Enable CKZG backend in CI.
gotest.Args = append(gotest.Args, "-tags=ckzg") gotest.Args = append(gotest.Args, "-tags=ckzg")
@ -349,10 +354,10 @@ func downloadSpecTestFixtures(csdb *build.ChecksumDB, cachedir string) string {
return filepath.Join(cachedir, base) return filepath.Join(cachedir, base)
} }
// hashSourceFiles iterates all files under the top-level project directory // hashAllSourceFiles iterates all files under the top-level project directory
// computing the hash of each file (excluding files within the tests // computing the hash of each file (excluding files within the tests
// subrepo) // subrepo)
func hashSourceFiles() (map[string]common.Hash, error) { func hashAllSourceFiles() (map[string]common.Hash, error) {
res := make(map[string]common.Hash) res := make(map[string]common.Hash)
err := filepath.WalkDir(".", func(path string, d os.DirEntry, err error) error { err := filepath.WalkDir(".", func(path string, d os.DirEntry, err error) error {
if strings.HasPrefix(path, filepath.FromSlash("tests/testdata")) { if strings.HasPrefix(path, filepath.FromSlash("tests/testdata")) {
@ -379,6 +384,56 @@ func hashSourceFiles() (map[string]common.Hash, error) {
return res, nil return res, nil
} }
// hashSourceFiles iterates the provided set of filepaths (relative to the top-level geth project directory)
// computing the hash of each file.
func hashSourceFiles(files []string) (map[string]common.Hash, error) {
res := make(map[string]common.Hash)
for _, filePath := range files {
f, err := os.OpenFile(filePath, os.O_RDONLY, 0666)
if err != nil {
return nil, err
}
hasher := sha256.New()
if _, err := io.Copy(hasher, f); err != nil {
return nil, err
}
res[filePath] = common.Hash(hasher.Sum(nil))
}
return res, nil
}
// compareHashedFilesets compares two maps (key is relative file path to top-level geth directory, value is its hash)
// and returns the list of file paths whose hashes differed.
func compareHashedFilesets(preHashes map[string]common.Hash, postHashes map[string]common.Hash) []string {
updates := []string{}
for path, postHash := range postHashes {
preHash, ok := preHashes[path]
if !ok || preHash != postHash {
updates = append(updates, path)
}
}
return updates
}
func doGoModTidy() {
targetFiles := []string{"go.mod", "go.sum"}
preHashes, err := hashSourceFiles(targetFiles)
if err != nil {
log.Fatal("failed to hash go.mod/go.sum", "err", err)
}
tc := new(build.GoToolchain)
c := tc.Go("mod", "tidy")
build.MustRun(c)
postHashes, err := hashSourceFiles(targetFiles)
updates := compareHashedFilesets(preHashes, postHashes)
for _, updatedFile := range updates {
fmt.Fprintf(os.Stderr, "changed file %s\n", updatedFile)
}
if len(updates) != 0 {
log.Fatal("go.sum and/or go.mod were updated by running 'go mod tidy'")
}
}
// doGenerate ensures that re-generating generated files does not cause // doGenerate ensures that re-generating generated files does not cause
// any mutations in the source file tree: i.e. all generated files were // any mutations in the source file tree: i.e. all generated files were
// updated and committed. Any stale generated files are updated. // updated and committed. Any stale generated files are updated.
@ -395,7 +450,7 @@ func doGenerate() {
var preHashes map[string]common.Hash var preHashes map[string]common.Hash
if *verify { if *verify {
var err error var err error
preHashes, err = hashSourceFiles() preHashes, err = hashAllSourceFiles()
if err != nil { if err != nil {
log.Fatal("failed to compute map of source hashes", "err", err) log.Fatal("failed to compute map of source hashes", "err", err)
} }
@ -410,17 +465,11 @@ func doGenerate() {
return return
} }
// Check if files were changed. // Check if files were changed.
postHashes, err := hashSourceFiles() postHashes, err := hashAllSourceFiles()
if err != nil { if err != nil {
log.Fatal("error computing source tree file hashes", "err", err) log.Fatal("error computing source tree file hashes", "err", err)
} }
updates := []string{} updates := compareHashedFilesets(preHashes, postHashes)
for path, postHash := range postHashes {
preHash, ok := preHashes[path]
if !ok || preHash != postHash {
updates = append(updates, path)
}
}
for _, updatedFile := range updates { for _, updatedFile := range updates {
fmt.Fprintf(os.Stderr, "changed file %s\n", updatedFile) fmt.Fprintf(os.Stderr, "changed file %s\n", updatedFile)
} }
@ -443,6 +492,8 @@ func doLint(cmdline []string) {
linter := downloadLinter(*cachedir) linter := downloadLinter(*cachedir)
lflags := []string{"run", "--config", ".golangci.yml"} lflags := []string{"run", "--config", ".golangci.yml"}
build.MustRunCommandWithOutput(linter, append(lflags, packages...)...) build.MustRunCommandWithOutput(linter, append(lflags, packages...)...)
doGoModTidy()
fmt.Println("You have achieved perfection.") fmt.Println("You have achieved perfection.")
} }
@ -671,10 +722,9 @@ func maybeSkipArchive(env build.Environment) {
} }
// Builds the docker images and optionally uploads them to Docker Hub. // Builds the docker images and optionally uploads them to Docker Hub.
func doDocker(cmdline []string) { func doDockerBuildx(cmdline []string) {
var ( var (
image = flag.Bool("image", false, `Whether to build and push an arch specific docker image`) platform = flag.String("platform", "", `Push a multi-arch docker image for the specified architectures (usually "linux/amd64,linux/arm64")`)
manifest = flag.String("manifest", "", `Push a multi-arch docker image for the specified architectures (usually "amd64,arm64")`)
upload = flag.String("upload", "", `Where to upload the docker image (usually "ethereum/client-go")`) upload = flag.String("upload", "", `Where to upload the docker image (usually "ethereum/client-go")`)
) )
flag.CommandLine.Parse(cmdline) flag.CommandLine.Parse(cmdline)
@ -709,129 +759,26 @@ func doDocker(cmdline []string) {
case strings.HasPrefix(env.Tag, "v1."): case strings.HasPrefix(env.Tag, "v1."):
tags = []string{"stable", fmt.Sprintf("release-1.%d", params.VersionMinor), "v" + params.Version} tags = []string{"stable", fmt.Sprintf("release-1.%d", params.VersionMinor), "v" + params.Version}
} }
// If architecture specific image builds are requested, build and push them // Need to create a mult-arch builder
if *image { build.MustRunCommand("docker", "buildx", "create", "--use", "--name", "multi-arch-builder", "--platform", *platform)
build.MustRunCommand("docker", "build", "--build-arg", "COMMIT="+env.Commit, "--build-arg", "VERSION="+params.VersionWithMeta, "--build-arg", "BUILDNUM="+env.Buildnum, "--tag", fmt.Sprintf("%s:TAG", *upload), ".")
build.MustRunCommand("docker", "build", "--build-arg", "COMMIT="+env.Commit, "--build-arg", "VERSION="+params.VersionWithMeta, "--build-arg", "BUILDNUM="+env.Buildnum, "--tag", fmt.Sprintf("%s:alltools-TAG", *upload), "-f", "Dockerfile.alltools", ".")
// Tag and upload the images to Docker Hub for _, spec := range []struct {
for _, tag := range tags { file string
gethImage := fmt.Sprintf("%s:%s-%s", *upload, tag, runtime.GOARCH) base string
toolImage := fmt.Sprintf("%s:alltools-%s-%s", *upload, tag, runtime.GOARCH) }{
{file: "Dockerfile", base: fmt.Sprintf("%s:", *upload)},
// If the image already exists (non version tag), check the build {file: "Dockerfile.alltools", base: fmt.Sprintf("%s:alltools-", *upload)},
// number to prevent overwriting a newer commit if concurrent builds } {
// are running. This is still a tiny bit racey if two published are for _, tag := range tags { // latest, stable etc
// done at the same time, but that's extremely unlikely even on the gethImage := fmt.Sprintf("%s%s", spec.base, tag)
// master branch. build.MustRunCommand("docker", "buildx", "build",
for _, img := range []string{gethImage, toolImage} { "--build-arg", "COMMIT="+env.Commit,
if exec.Command("docker", "pull", img).Run() != nil { "--build-arg", "VERSION="+params.VersionWithMeta,
continue // Generally the only failure is a missing image, which is good "--build-arg", "BUILDNUM="+env.Buildnum,
} "--tag", gethImage,
buildnum, err := exec.Command("docker", "inspect", "--format", "{{index .Config.Labels \"buildnum\"}}", img).CombinedOutput() "--platform", *platform,
if err != nil { "--push",
log.Fatalf("Failed to inspect container: %v\nOutput: %s", err, string(buildnum)) "--file", spec.file, ".")
}
buildnum = bytes.TrimSpace(buildnum)
if len(buildnum) > 0 && len(env.Buildnum) > 0 {
oldnum, err := strconv.Atoi(string(buildnum))
if err != nil {
log.Fatalf("Failed to parse old image build number: %v", err)
}
newnum, err := strconv.Atoi(env.Buildnum)
if err != nil {
log.Fatalf("Failed to parse current build number: %v", err)
}
if oldnum > newnum {
log.Fatalf("Current build number %d not newer than existing %d", newnum, oldnum)
} else {
log.Printf("Updating %s from build %d to %d", img, oldnum, newnum)
}
}
}
build.MustRunCommand("docker", "image", "tag", fmt.Sprintf("%s:TAG", *upload), gethImage)
build.MustRunCommand("docker", "image", "tag", fmt.Sprintf("%s:alltools-TAG", *upload), toolImage)
build.MustRunCommand("docker", "push", gethImage)
build.MustRunCommand("docker", "push", toolImage)
}
}
// If multi-arch image manifest push is requested, assemble it
if len(*manifest) != 0 {
// Since different architectures are pushed by different builders, wait
// until all required images are updated.
var mismatch bool
for i := 0; i < 2; i++ { // 2 attempts, second is race check
mismatch = false // hope there's no mismatch now
for _, tag := range tags {
for _, arch := range strings.Split(*manifest, ",") {
gethImage := fmt.Sprintf("%s:%s-%s", *upload, tag, arch)
toolImage := fmt.Sprintf("%s:alltools-%s-%s", *upload, tag, arch)
for _, img := range []string{gethImage, toolImage} {
if out, err := exec.Command("docker", "pull", img).CombinedOutput(); err != nil {
log.Printf("Required image %s unavailable: %v\nOutput: %s", img, err, out)
mismatch = true
break
}
buildnum, err := exec.Command("docker", "inspect", "--format", "{{index .Config.Labels \"buildnum\"}}", img).CombinedOutput()
if err != nil {
log.Fatalf("Failed to inspect container: %v\nOutput: %s", err, string(buildnum))
}
buildnum = bytes.TrimSpace(buildnum)
if string(buildnum) != env.Buildnum {
log.Printf("Build number mismatch on %s: want %s, have %s", img, env.Buildnum, buildnum)
mismatch = true
break
}
}
if mismatch {
break
}
}
if mismatch {
break
}
}
if mismatch {
// Build numbers mismatching, retry in a short time to
// avoid concurrent fails in both publisher images. If
// however the retry failed too, it means the concurrent
// builder is still crunching, let that do the publish.
if i == 0 {
time.Sleep(30 * time.Second)
}
continue
}
break
}
if mismatch {
log.Println("Relinquishing publish to other builder")
return
}
// Assemble and push the Geth manifest image
for _, tag := range tags {
gethImage := fmt.Sprintf("%s:%s", *upload, tag)
var gethSubImages []string
for _, arch := range strings.Split(*manifest, ",") {
gethSubImages = append(gethSubImages, gethImage+"-"+arch)
}
build.MustRunCommand("docker", append([]string{"manifest", "create", gethImage}, gethSubImages...)...)
build.MustRunCommand("docker", "manifest", "push", gethImage)
}
// Assemble and push the alltools manifest image
for _, tag := range tags {
toolImage := fmt.Sprintf("%s:alltools-%s", *upload, tag)
var toolSubImages []string
for _, arch := range strings.Split(*manifest, ",") {
toolSubImages = append(toolSubImages, toolImage+"-"+arch)
}
build.MustRunCommand("docker", append([]string{"manifest", "create", toolImage}, toolSubImages...)...)
build.MustRunCommand("docker", "manifest", "push", toolImage)
} }
} }
} }

0
build/deb/ethereum/completions/bash/geth Executable file → Normal file
View file

0
build/goimports.sh Executable file → Normal file
View file

0
build/travis_keepalive.sh Executable file → Normal file
View file

View file

@ -39,7 +39,7 @@ syncmode = "full"
# nodekeyhex = "" # nodekeyhex = ""
[p2p.discovery] [p2p.discovery]
# v4disc = true # v4disc = true
# v5disc = false # v5disc = true
bootnodes = ["enode://b8f1cc9c5d4403703fbf377116469667d2b1823c0daf16b7250aa576bacf399e42c3930ccfcb02c5df6879565a2b8931335565f0e8d3f8e72385ecf4a4bf160a@3.36.224.80:30303", "enode://8729e0c825f3d9cad382555f3e46dcff21af323e89025a0e6312df541f4a9e73abfa562d64906f5e59c51fe6f0501b3e61b07979606c56329c020ed739910759@54.194.245.5:30303"] bootnodes = ["enode://b8f1cc9c5d4403703fbf377116469667d2b1823c0daf16b7250aa576bacf399e42c3930ccfcb02c5df6879565a2b8931335565f0e8d3f8e72385ecf4a4bf160a@3.36.224.80:30303", "enode://8729e0c825f3d9cad382555f3e46dcff21af323e89025a0e6312df541f4a9e73abfa562d64906f5e59c51fe6f0501b3e61b07979606c56329c020ed739910759@54.194.245.5:30303"]
# Uncomment below `bootnodes` field for Amoy # Uncomment below `bootnodes` field for Amoy
# bootnodes = ["enode://bce861be777e91b0a5a49d58a51e14f32f201b4c6c2d1fbea6c7a1f14756cbb3f931f3188d6b65de8b07b53ff28d03b6e366d09e56360d2124a9fc5a15a0913d@54.217.171.196:30303", "enode://4a3dc0081a346d26a73d79dd88216a9402d2292318e2db9947dbc97ea9c4afb2498dc519c0af04420dc13a238c279062da0320181e7c1461216ce4513bfd40bf@13.251.184.185:30303"] # bootnodes = ["enode://bce861be777e91b0a5a49d58a51e14f32f201b4c6c2d1fbea6c7a1f14756cbb3f931f3188d6b65de8b07b53ff28d03b6e366d09e56360d2124a9fc5a15a0913d@54.217.171.196:30303", "enode://4a3dc0081a346d26a73d79dd88216a9402d2292318e2db9947dbc97ea9c4afb2498dc519c0af04420dc13a238c279062da0320181e7c1461216ce4513bfd40bf@13.251.184.185:30303"]

View file

@ -45,7 +45,6 @@ func main() {
//TODO datadir for optional permanent database //TODO datadir for optional permanent database
utils.MainnetFlag, utils.MainnetFlag,
utils.SepoliaFlag, utils.SepoliaFlag,
utils.GoerliFlag,
utils.BlsyncApiFlag, utils.BlsyncApiFlag,
utils.BlsyncJWTSecretFlag, utils.BlsyncJWTSecretFlag,
}, },

View file

@ -29,7 +29,7 @@ GLOBAL OPTIONS:
--loglevel value log level to emit to the screen (default: 4) --loglevel value log level to emit to the screen (default: 4)
--keystore value Directory for the keystore (default: "$HOME/.ethereum/keystore") --keystore value Directory for the keystore (default: "$HOME/.ethereum/keystore")
--configdir value Directory for Clef configuration (default: "$HOME/.clef") --configdir value Directory for Clef configuration (default: "$HOME/.clef")
--chainid value Chain id to use for signing (1=mainnet, 5=Goerli) (default: 1) --chainid value Chain id to use for signing (1=mainnet, 17000=Holesky) (default: 1)
--lightkdf Reduce key-derivation RAM & CPU usage at some expense of KDF strength --lightkdf Reduce key-derivation RAM & CPU usage at some expense of KDF strength
--nousb Disables monitoring for and managing USB hardware wallets --nousb Disables monitoring for and managing USB hardware wallets
--pcscdpath value Path to the smartcard daemon (pcscd) socket file (default: "/run/pcscd/pcscd.comm") --pcscdpath value Path to the smartcard daemon (pcscd) socket file (default: "/run/pcscd/pcscd.comm")

View file

@ -100,7 +100,7 @@ var (
chainIdFlag = &cli.Int64Flag{ chainIdFlag = &cli.Int64Flag{
Name: "chainid", Name: "chainid",
Value: params.MainnetChainConfig.ChainID.Int64(), Value: params.MainnetChainConfig.ChainID.Int64(),
Usage: "Chain id to use for signing (1=mainnet, 5=Goerli)", Usage: "Chain id to use for signing (1=mainnet, 17000=Holesky)",
} }
rpcPortFlag = &cli.IntFlag{ rpcPortFlag = &cli.IntFlag{
Name: "http.port", Name: "http.port",

View file

@ -61,14 +61,7 @@ func TestMain(m *testing.M) {
func runClef(t *testing.T, args ...string) *testproc { func runClef(t *testing.T, args ...string) *testproc {
t.Helper() t.Helper()
ddir, err := os.MkdirTemp("", "cleftest-*") ddir := t.TempDir()
if err != nil {
return nil
}
t.Cleanup(func() {
os.RemoveAll(ddir)
})
return runWithKeystore(t, ddir, args...) return runWithKeystore(t, ddir, args...)
} }

View file

@ -4,8 +4,10 @@ import (
"os" "os"
"github.com/ethereum/go-ethereum/internal/cli" "github.com/ethereum/go-ethereum/internal/cli"
"github.com/ethereum/go-ethereum/params"
) )
func main() { func main() {
params.UpdateBorInfo()
os.Exit(cli.Run(os.Args[1:])) os.Exit(cli.Run(os.Args[1:]))
} }

View file

@ -44,7 +44,7 @@ set to standard output. The following filters are supported:
- `-limit <N>` limits the output set to N entries, taking the top N nodes by score - `-limit <N>` limits the output set to N entries, taking the top N nodes by score
- `-ip <CIDR>` filters nodes by IP subnet - `-ip <CIDR>` filters nodes by IP subnet
- `-min-age <duration>` filters nodes by 'first seen' time - `-min-age <duration>` filters nodes by 'first seen' time
- `-eth-network <mainnet/goerli/sepolia/holesky>` filters nodes by "eth" ENR entry - `-eth-network <mainnet/sepolia/holesky>` filters nodes by "eth" ENR entry
- `-les-server` filters nodes by LES server support - `-les-server` filters nodes by LES server support
- `-snap` filters nodes by snap protocol support - `-snap` filters nodes by snap protocol support

View file

@ -98,8 +98,8 @@ func (c *cloudflareClient) checkZone(name string) error {
if !strings.HasSuffix(name, "."+zone.Name) { if !strings.HasSuffix(name, "."+zone.Name) {
return fmt.Errorf("CloudFlare zone name %q does not match name %q to be deployed", zone.Name, name) return fmt.Errorf("CloudFlare zone name %q does not match name %q to be deployed", zone.Name, name)
} }
// Necessary permissions for Cloudlare management - Zone:Read, DNS:Read, Zone:Edit, DNS:Edit
needPerms := map[string]bool{"#zone:edit": false, "#zone:read": false} needPerms := map[string]bool{"#zone:edit": false, "#zone:read": false, "#dns_records:read": false, "#dns_records:edit": false}
for _, perm := range zone.Permissions { for _, perm := range zone.Permissions {
if _, ok := needPerms[perm]; ok { if _, ok := needPerms[perm]; ok {
needPerms[perm] = true needPerms[perm] = true

0
cmd/devp2p/internal/ethtest/testdata/chain.rlp.gz vendored Executable file → Normal file
View file

View file

@ -259,8 +259,6 @@ func ethFilter(args []string) (nodeFilter, error) {
switch args[0] { switch args[0] {
case "mainnet": case "mainnet":
filter = forkid.NewStaticFilter(params.MainnetChainConfig, core.DefaultGenesisBlock().ToBlock()) filter = forkid.NewStaticFilter(params.MainnetChainConfig, core.DefaultGenesisBlock().ToBlock())
case "goerli":
filter = forkid.NewStaticFilter(params.GoerliChainConfig, core.DefaultGoerliGenesisBlock().ToBlock())
case "sepolia": case "sepolia":
filter = forkid.NewStaticFilter(params.SepoliaChainConfig, core.DefaultSepoliaGenesisBlock().ToBlock()) filter = forkid.NewStaticFilter(params.SepoliaChainConfig, core.DefaultSepoliaGenesisBlock().ToBlock())
case "bor-mumbai": case "bor-mumbai":

View file

@ -66,6 +66,8 @@ type ExecutionResult struct {
WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"` WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"`
CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"` CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"`
CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"` CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"`
RequestsHash *common.Hash `json:"requestsRoot,omitempty"`
DepositRequests *types.Deposits `json:"depositRequests,omitempty"`
} }
type ommer struct { type ommer struct {
@ -201,7 +203,14 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig) evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb)
} }
if pre.Env.BlockHashes != nil && chainConfig.IsPrague(new(big.Int).SetUint64(pre.Env.Number)) {
var (
prevNumber = pre.Env.Number - 1
prevHash = pre.Env.BlockHashes[math.HexOrDecimal64(prevNumber)]
evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
)
core.ProcessParentBlockHash(prevHash, evm, statedb)
}
for i := 0; txIt.Next(); i++ { for i := 0; txIt.Next(); i++ {
tx, err := txIt.Tx() tx, err := txIt.Tx()
if err != nil { if err != nil {
@ -385,9 +394,31 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
execRs.CurrentExcessBlobGas = (*math.HexOrDecimal64)(&excessBlobGas) execRs.CurrentExcessBlobGas = (*math.HexOrDecimal64)(&excessBlobGas)
execRs.CurrentBlobGasUsed = (*math.HexOrDecimal64)(&blobGasUsed) execRs.CurrentBlobGasUsed = (*math.HexOrDecimal64)(&blobGasUsed)
} }
if chainConfig.IsPrague(vmContext.BlockNumber) && chainConfig.Bor == nil {
// Parse the requests from the logs
var allLogs []*types.Log
for _, receipt := range receipts {
allLogs = append(allLogs, receipt.Logs...)
}
requests, err := core.ParseDepositLogs(allLogs, chainConfig)
if err != nil {
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not parse requests logs: %v", err))
}
// Calculate the requests root
h := types.DeriveSha(requests, trie.NewStackTrie(nil))
execRs.RequestsHash = &h
// Get the deposits from the requests
deposits := make(types.Deposits, 0)
for _, req := range requests {
if dep, ok := req.Inner().(*types.Deposit); ok {
deposits = append(deposits, dep)
}
}
execRs.DepositRequests = &deposits
}
// Re-create statedb instance with new root upon the updated database // Re-create statedb instance with new root upon the updated database
// for accessing latest states. // for accessing latest states.
statedb, err = state.New(root, statedb.Database(), nil) statedb, err = state.New(root, statedb.Database())
if err != nil { if err != nil {
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not reopen state: %v", err)) return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not reopen state: %v", err))
} }
@ -396,8 +427,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
} }
func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB { func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB {
sdb := state.NewDatabaseWithConfig(db, &triedb.Config{Preimages: true}) tdb := triedb.NewDatabase(db, &triedb.Config{Preimages: true})
statedb, _ := state.New(types.EmptyRootHash, sdb, nil) sdb := state.NewDatabase(tdb, nil)
statedb, _ := state.New(types.EmptyRootHash, sdb)
for addr, a := range accounts { for addr, a := range accounts {
statedb.SetCode(addr, a.Code) statedb.SetCode(addr, a.Code)
statedb.SetNonce(addr, a.Nonce) statedb.SetNonce(addr, a.Nonce)
@ -408,8 +440,7 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB
} }
// Commit and re-open to start with a clean state. // Commit and re-open to start with a clean state.
root, _ := statedb.Commit(0, false) root, _ := statedb.Commit(0, false)
statedb, _ = state.New(root, sdb, nil) statedb, _ = state.New(root, sdb)
return statedb return statedb
} }

View file

@ -163,8 +163,8 @@ func runCmd(ctx *cli.Context) error {
}) })
defer triedb.Close() defer triedb.Close()
genesis := genesisConfig.MustCommit(db, triedb) genesis := genesisConfig.MustCommit(db, triedb)
sdb := state.NewDatabaseWithNodeDB(db, triedb) sdb := state.NewDatabase(triedb, nil)
statedb, _ = state.New(genesis.Root(), sdb, nil) statedb, _ = state.New(genesis.Root(), sdb)
chainConfig = genesisConfig.Config chainConfig = genesisConfig.Config
if ctx.String(SenderFlag.Name) != "" { if ctx.String(SenderFlag.Name) != "" {
@ -297,7 +297,7 @@ func runCmd(ctx *cli.Context) error {
fmt.Printf("Failed to commit changes %v\n", err) fmt.Printf("Failed to commit changes %v\n", err)
return err return err
} }
dumpdb, err := state.New(root, sdb, nil) dumpdb, err := state.New(root, sdb)
if err != nil { if err != nil {
fmt.Printf("Failed to open statedb %v\n", err) fmt.Printf("Failed to open statedb %v\n", err)
return err return err

View file

@ -110,7 +110,7 @@ func runStateTest(fname string, cfg vm.Config, dump bool) error {
result.Root = &root result.Root = &root
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root) fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
if dump { // Dump any state to aid debugging if dump { // Dump any state to aid debugging
cpy, _ := state.New(root, tstate.StateDB.Database(), nil) cpy, _ := state.New(root, tstate.StateDB.Database())
dump := cpy.RawDump(nil) dump := cpy.RawDump(nil)
result.State = &dump result.State = &dump
} }

View file

@ -226,8 +226,8 @@ func initGenesis(ctx *cli.Context) error {
v := ctx.Int64(utils.OverrideVerkle.Name) v := ctx.Int64(utils.OverrideVerkle.Name)
overrides.OverrideVerkle = new(big.Int).SetInt64(v) overrides.OverrideVerkle = new(big.Int).SetInt64(v)
} }
for _, name := range []string{"chaindata", "lightchaindata"} {
chaindb, err := stack.OpenDatabaseWithFreezer(name, 0, 0, ctx.String(utils.AncientFlag.Name), "", false, false, false) chaindb, err := stack.OpenDatabaseWithFreezer("chaindata", 0, 0, ctx.String(utils.AncientFlag.Name), "", false, false, false)
if err != nil { if err != nil {
utils.Fatalf("Failed to open database: %v", err) utils.Fatalf("Failed to open database: %v", err)
} }
@ -240,8 +240,8 @@ func initGenesis(ctx *cli.Context) error {
if err != nil { if err != nil {
utils.Fatalf("Failed to write genesis block: %v", err) utils.Fatalf("Failed to write genesis block: %v", err)
} }
log.Info("Successfully wrote genesis state", "database", name, "hash", hash)
} log.Info("Successfully wrote genesis state", "database", "chaindata", "hash", hash)
return nil return nil
} }
@ -265,36 +265,22 @@ func dumpGenesis(ctx *cli.Context) error {
// dump whatever already exists in the datadir // dump whatever already exists in the datadir
stack, _ := makeConfigNode(ctx) stack, _ := makeConfigNode(ctx)
for _, name := range []string{"chaindata", "lightchaindata"} {
db, err := stack.OpenDatabase(name, 0, 0, "", true)
db, err := stack.OpenDatabase("chaindata", 0, 0, "", true)
if err != nil { if err != nil {
if !os.IsNotExist(err) {
return err return err
} }
defer db.Close()
continue genesis, err = core.ReadGenesis(db)
}
genesis, err := core.ReadGenesis(db)
if err != nil { if err != nil {
utils.Fatalf("failed to read genesis: %s", err) utils.Fatalf("failed to read genesis: %s", err)
} }
db.Close()
if err := json.NewEncoder(os.Stdout).Encode(*genesis); err != nil { if err := json.NewEncoder(os.Stdout).Encode(*genesis); err != nil {
utils.Fatalf("could not encode stored genesis: %s", err) utils.Fatalf("could not encode stored genesis: %s", err)
} }
return nil
}
if ctx.IsSet(utils.DataDirFlag.Name) {
utils.Fatalf("no existing datadir at %s", stack.Config().DataDir)
}
utils.Fatalf("no network preset provided, and no genesis exists in the default datadir")
return nil return nil
} }
@ -451,8 +437,6 @@ func importHistory(ctx *cli.Context) error {
network = "mainnet" network = "mainnet"
case ctx.Bool(utils.SepoliaFlag.Name): case ctx.Bool(utils.SepoliaFlag.Name):
network = "sepolia" network = "sepolia"
case ctx.Bool(utils.GoerliFlag.Name):
network = "goerli"
} }
} else { } else {
// No network flag set, try to determine network based on files // No network flag set, try to determine network based on files
@ -596,8 +580,7 @@ func parseDumpConfig(ctx *cli.Context, db ethdb.Database) (*state.DumpConfig, co
default: default:
return nil, common.Hash{}, fmt.Errorf("invalid start argument: %x. 20 or 32 hex-encoded bytes required", startArg) return nil, common.Hash{}, fmt.Errorf("invalid start argument: %x. 20 or 32 hex-encoded bytes required", startArg)
} }
conf := &state.DumpConfig{
var conf = &state.DumpConfig{
SkipCode: ctx.Bool(utils.ExcludeCodeFlag.Name), SkipCode: ctx.Bool(utils.ExcludeCodeFlag.Name),
SkipStorage: ctx.Bool(utils.ExcludeStorageFlag.Name), SkipStorage: ctx.Bool(utils.ExcludeStorageFlag.Name),
OnlyWithAddresses: !ctx.Bool(utils.IncludeIncompletesFlag.Name), OnlyWithAddresses: !ctx.Bool(utils.IncludeIncompletesFlag.Name),
@ -625,7 +608,7 @@ func dump(ctx *cli.Context) error {
triedb := utils.MakeTrieDatabase(ctx, db, true, true, false) // always enable preimage lookup triedb := utils.MakeTrieDatabase(ctx, db, true, true, false) // always enable preimage lookup
defer triedb.Close() defer triedb.Close()
state, err := state.New(root, state.NewDatabaseWithNodeDB(db, triedb), nil) state, err := state.New(root, state.NewDatabase(triedb, nil))
if err != nil { if err != nil {
return err return err
} }

View file

@ -79,8 +79,8 @@ var tomlSettings = toml.Config{
}, },
MissingField: func(rt reflect.Type, field string) error { MissingField: func(rt reflect.Type, field string) error {
id := fmt.Sprintf("%s.%s", rt.String(), field) id := fmt.Sprintf("%s.%s", rt.String(), field)
if deprecated(id) { if deprecatedConfigFields[id] {
log.Warn("Config field is deprecated and won't have an effect", "name", id) log.Warn(fmt.Sprintf("Config field '%s' is deprecated and won't have any effect.", id))
return nil return nil
} }
var link string var link string
@ -91,6 +91,19 @@ var tomlSettings = toml.Config{
}, },
} }
var deprecatedConfigFields = map[string]bool{
"ethconfig.Config.EVMInterpreter": true,
"ethconfig.Config.EWASMInterpreter": true,
"ethconfig.Config.TrieCleanCacheJournal": true,
"ethconfig.Config.TrieCleanCacheRejournal": true,
"ethconfig.Config.LightServ": true,
"ethconfig.Config.LightIngress": true,
"ethconfig.Config.LightEgress": true,
"ethconfig.Config.LightPeers": true,
"ethconfig.Config.LightNoPrune": true,
"ethconfig.Config.LightNoSyncServe": true,
}
type ethstatsConfig struct { type ethstatsConfig struct {
URL string `toml:",omitempty"` URL string `toml:",omitempty"`
} }
@ -335,21 +348,6 @@ func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) {
} }
} }
func deprecated(field string) bool {
switch field {
case "ethconfig.Config.EVMInterpreter":
return true
case "ethconfig.Config.EWASMInterpreter":
return true
case "ethconfig.Config.TrieCleanCacheJournal":
return true
case "ethconfig.Config.TrieCleanCacheRejournal":
return true
default:
return false
}
}
func setAccountManagerBackends(conf *node.Config, am *accounts.Manager, keydir string) error { func setAccountManagerBackends(conf *node.Config, am *accounts.Manager, keydir string) error {
scryptN := keystore.StandardScryptN scryptN := keystore.StandardScryptN
scryptP := keystore.StandardScryptP scryptP := keystore.StandardScryptP

View file

@ -129,9 +129,7 @@ func remoteConsole(ctx *cli.Context) error {
} }
if path != "" { if path != "" {
if ctx.Bool(utils.GoerliFlag.Name) { if ctx.Bool(utils.MumbaiFlag.Name) || ctx.Bool(utils.AmoyFlag.Name) || ctx.Bool(utils.BorMainnetFlag.Name) {
path = filepath.Join(path, "goerli")
} else if ctx.Bool(utils.MumbaiFlag.Name) || ctx.Bool(utils.AmoyFlag.Name) || ctx.Bool(utils.BorMainnetFlag.Name) {
homeDir, _ := os.UserHomeDir() homeDir, _ := os.UserHomeDir()
path = filepath.Join(homeDir, "/.bor/data") path = filepath.Join(homeDir, "/.bor/data")
} else if ctx.Bool(utils.SepoliaFlag.Name) { } else if ctx.Bool(utils.SepoliaFlag.Name) {

View file

@ -30,7 +30,7 @@ import (
) )
const ( const (
ipcAPIs = "admin:1.0 bor:1.0 clique:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0" ipcAPIs = "admin:1.0 bor:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0"
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0" httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
) )
@ -38,10 +38,10 @@ const (
// memory and disk IO. If the args don't set --datadir, the // memory and disk IO. If the args don't set --datadir, the
// child g gets a temporary data directory. // child g gets a temporary data directory.
func runMinimalGeth(t *testing.T, args ...string) *testgeth { func runMinimalGeth(t *testing.T, args ...string) *testgeth {
// --goerli to make the 'writing genesis to disk' faster (no accounts) // --holesky to make the 'writing genesis to disk' faster (no accounts)
// --networkid=1337 to avoid cache bump // --networkid=1337 to avoid cache bump
// --syncmode=full to avoid allocating fast sync bloom // --syncmode=full to avoid allocating fast sync bloom
allArgs := []string{"--goerli", "--networkid", "1337", "--authrpc.port", "0", "--syncmode=full", "--port", "0", allArgs := []string{"--holesky", "--networkid", "1337", "--authrpc.port", "0", "--syncmode=full", "--port", "0",
"--nat", "none", "--nodiscover", "--maxpeers", "0", "--cache", "64", "--nat", "none", "--nodiscover", "--maxpeers", "0", "--cache", "64",
"--datadir.minfreedisk", "0"} "--datadir.minfreedisk", "0"}
@ -63,7 +63,7 @@ func TestConsoleWelcome(t *testing.T) {
geth.SetTemplateFunc("gover", runtime.Version) geth.SetTemplateFunc("gover", runtime.Version)
geth.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") }) geth.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") })
geth.SetTemplateFunc("niltime", func() string { geth.SetTemplateFunc("niltime", func() string {
return time.Unix(1548854791, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)") return time.Unix(1695902100, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
}) })
geth.SetTemplateFunc("apis", func() string { return ipcAPIs }) geth.SetTemplateFunc("apis", func() string { return ipcAPIs })
@ -133,7 +133,7 @@ func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) {
attach.SetTemplateFunc("gover", runtime.Version) attach.SetTemplateFunc("gover", runtime.Version)
attach.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") }) attach.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") })
attach.SetTemplateFunc("niltime", func() string { attach.SetTemplateFunc("niltime", func() string {
return time.Unix(1548854791, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)") return time.Unix(1695902100, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
}) })
attach.SetTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") }) attach.SetTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") })
attach.SetTemplateFunc("datadir", func() string { return geth.Datadir }) attach.SetTemplateFunc("datadir", func() string { return geth.Datadir })

View file

@ -164,7 +164,6 @@ var (
utils.BeaconGenesisRootFlag, utils.BeaconGenesisRootFlag,
utils.BeaconGenesisTimeFlag, utils.BeaconGenesisTimeFlag,
utils.BeaconCheckpointFlag, utils.BeaconCheckpointFlag,
utils.CollectWitnessFlag,
}, utils.NetworkFlags, utils.DatabaseFlags) }, utils.NetworkFlags, utils.DatabaseFlags)
rpcFlags = []cli.Flag{ rpcFlags = []cli.Flag{
@ -299,9 +298,6 @@ func main() {
func prepare(ctx *cli.Context) { func prepare(ctx *cli.Context) {
// If we're running a known preset, log it for convenience. // If we're running a known preset, log it for convenience.
switch { switch {
case ctx.IsSet(utils.GoerliFlag.Name):
log.Info("Starting Geth on Görli testnet...")
case ctx.IsSet(utils.SepoliaFlag.Name): case ctx.IsSet(utils.SepoliaFlag.Name):
log.Info("Starting Geth on Sepolia testnet...") log.Info("Starting Geth on Sepolia testnet...")
@ -339,8 +335,8 @@ func prepare(ctx *cli.Context) {
if !ctx.IsSet(utils.CacheFlag.Name) && !ctx.IsSet(utils.NetworkIdFlag.Name) { if !ctx.IsSet(utils.CacheFlag.Name) && !ctx.IsSet(utils.NetworkIdFlag.Name) {
// Make sure we're not on any supported preconfigured testnet either // Make sure we're not on any supported preconfigured testnet either
if !ctx.IsSet(utils.SepoliaFlag.Name) && if !ctx.IsSet(utils.SepoliaFlag.Name) &&
!ctx.IsSet(utils.GoerliFlag.Name) &&
!ctx.IsSet(utils.MumbaiFlag.Name) && !ctx.IsSet(utils.MumbaiFlag.Name) &&
!ctx.IsSet(utils.HoleskyFlag.Name) &&
!ctx.IsSet(utils.AmoyFlag.Name) && !ctx.IsSet(utils.AmoyFlag.Name) &&
!ctx.IsSet(utils.DeveloperFlag.Name) { !ctx.IsSet(utils.DeveloperFlag.Name) {
// Nope, we're really on mainnet. Bump that cache up! // Nope, we're really on mainnet. Bump that cache up!

View file

@ -2,6 +2,7 @@ package utils
import ( import (
"os" "os"
"time"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
@ -22,6 +23,13 @@ var (
Value: "http://localhost:1317", Value: "http://localhost:1317",
} }
// HeimdallTimeoutFlag flag for heimdall timeout
HeimdallTimeoutFlag = &cli.DurationFlag{
Name: "bor.heimdalltimeout",
Usage: "Timeout of Heimdall service",
Value: 5 * time.Second,
}
// WithoutHeimdallFlag no heimdall (for testing purpose) // WithoutHeimdallFlag no heimdall (for testing purpose)
WithoutHeimdallFlag = &cli.BoolFlag{ WithoutHeimdallFlag = &cli.BoolFlag{
Name: "bor.withoutheimdall", Name: "bor.withoutheimdall",
@ -56,6 +64,7 @@ var (
// BorFlags all bor related flags // BorFlags all bor related flags
BorFlags = []cli.Flag{ BorFlags = []cli.Flag{
HeimdallURLFlag, HeimdallURLFlag,
HeimdallTimeoutFlag,
WithoutHeimdallFlag, WithoutHeimdallFlag,
HeimdallgRPCAddressFlag, HeimdallgRPCAddressFlag,
RunHeimdallFlag, RunHeimdallFlag,
@ -67,6 +76,7 @@ var (
// SetBorConfig sets bor config // SetBorConfig sets bor config
func SetBorConfig(ctx *cli.Context, cfg *eth.Config) { func SetBorConfig(ctx *cli.Context, cfg *eth.Config) {
cfg.HeimdallURL = ctx.String(HeimdallURLFlag.Name) cfg.HeimdallURL = ctx.String(HeimdallURLFlag.Name)
cfg.HeimdallTimeout = ctx.Duration(HeimdallTimeoutFlag.Name)
cfg.WithoutHeimdall = ctx.Bool(WithoutHeimdallFlag.Name) cfg.WithoutHeimdall = ctx.Bool(WithoutHeimdallFlag.Name)
cfg.HeimdallgRPCAddress = ctx.String(HeimdallgRPCAddressFlag.Name) cfg.HeimdallgRPCAddress = ctx.String(HeimdallgRPCAddressFlag.Name)
cfg.RunHeimdall = ctx.Bool(RunHeimdallFlag.Name) cfg.RunHeimdall = ctx.Bool(RunHeimdallFlag.Name)

View file

@ -135,7 +135,7 @@ var (
} }
NetworkIdFlag = &cli.Uint64Flag{ NetworkIdFlag = &cli.Uint64Flag{
Name: "networkid", Name: "networkid",
Usage: "Explicitly set network id (integer)(For testnets: use --goerli, --sepolia, --holesky instead)", Usage: "Explicitly set network id (integer)(For testnets: use --sepolia, --holesky instead)",
Value: ethconfig.Defaults.NetworkId, Value: ethconfig.Defaults.NetworkId,
Category: flags.EthCategory, Category: flags.EthCategory,
} }
@ -144,11 +144,6 @@ var (
Usage: "Ethereum mainnet", Usage: "Ethereum mainnet",
Category: flags.EthCategory, Category: flags.EthCategory,
} }
GoerliFlag = &cli.BoolFlag{
Name: "goerli",
Usage: "Görli network: pre-configured proof-of-authority test network",
Category: flags.EthCategory,
}
SepoliaFlag = &cli.BoolFlag{ SepoliaFlag = &cli.BoolFlag{
Name: "sepolia", Name: "sepolia",
Usage: "Sepolia network: pre-configured proof-of-work test network", Usage: "Sepolia network: pre-configured proof-of-work test network",
@ -644,11 +639,6 @@ var (
Usage: "Disables db compaction after import", Usage: "Disables db compaction after import",
Category: flags.LoggingCategory, Category: flags.LoggingCategory,
} }
CollectWitnessFlag = &cli.BoolFlag{
Name: "collectwitness",
Usage: "Enable state witness generation during block execution. Work in progress flag, don't use.",
Category: flags.MiscCategory,
}
// MISC settings // MISC settings
SyncTargetFlag = &cli.StringFlag{ SyncTargetFlag = &cli.StringFlag{
@ -851,8 +841,9 @@ var (
DiscoveryV5Flag = &cli.BoolFlag{ DiscoveryV5Flag = &cli.BoolFlag{
Name: "discovery.v5", Name: "discovery.v5",
Aliases: []string{"discv5"}, Aliases: []string{"discv5"},
Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism", Usage: "Enables the V5 discovery mechanism",
Category: flags.NetworkingCategory, Category: flags.NetworkingCategory,
Value: true,
} }
NetrestrictFlag = &cli.StringFlag{ NetrestrictFlag = &cli.StringFlag{
Name: "netrestrict", Name: "netrestrict",
@ -1004,7 +995,6 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
var ( var (
// TestnetFlags is the flag group of all built-in supported testnets. // TestnetFlags is the flag group of all built-in supported testnets.
TestnetFlags = []cli.Flag{ TestnetFlags = []cli.Flag{
GoerliFlag,
SepoliaFlag, SepoliaFlag,
} }
// NetworkFlags is the flag group of all built-in supported networks. // NetworkFlags is the flag group of all built-in supported networks.
@ -1026,10 +1016,6 @@ var (
// then a subdirectory of the specified datadir will be used. // then a subdirectory of the specified datadir will be used.
func MakeDataDir(ctx *cli.Context) string { func MakeDataDir(ctx *cli.Context) string {
if path := ctx.String(DataDirFlag.Name); path != "" { if path := ctx.String(DataDirFlag.Name); path != "" {
if ctx.Bool(GoerliFlag.Name) {
return filepath.Join(path, "goerli")
}
if ctx.Bool(SepoliaFlag.Name) { if ctx.Bool(SepoliaFlag.Name) {
return filepath.Join(path, "sepolia") return filepath.Join(path, "sepolia")
} }
@ -1083,7 +1069,7 @@ func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) {
// //
// 1. --bootnodes flag // 1. --bootnodes flag
// 2. Config file // 2. Config file
// 3. Network preset flags (e.g. --goerli) // 3. Network preset flags (e.g. --holesky)
// 4. default to mainnet nodes // 4. default to mainnet nodes
func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
urls := params.MainnetBootnodes urls := params.MainnetBootnodes
@ -1096,8 +1082,6 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
switch { switch {
case ctx.Bool(SepoliaFlag.Name): case ctx.Bool(SepoliaFlag.Name):
urls = params.SepoliaBootnodes urls = params.SepoliaBootnodes
case ctx.Bool(GoerliFlag.Name):
urls = params.GoerliBootnodes
} }
} }
cfg.BootstrapNodes = mustParseBootnodes(urls) cfg.BootstrapNodes = mustParseBootnodes(urls)
@ -1378,8 +1362,8 @@ func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error
// setEtherbase retrieves the etherbase from the directly specified command line flags. // setEtherbase retrieves the etherbase from the directly specified command line flags.
func setEtherbase(ctx *cli.Context, cfg *ethconfig.Config) { func setEtherbase(ctx *cli.Context, cfg *ethconfig.Config) {
if !ctx.IsSet(MinerEtherbaseFlag.Name) { if ctx.IsSet(MinerEtherbaseFlag.Name) {
return log.Warn("Option --miner.etherbase is deprecated as the etherbase is set by the consensus client post-merge")
} }
addr := ctx.String(MinerEtherbaseFlag.Name) addr := ctx.String(MinerEtherbaseFlag.Name)
@ -1556,8 +1540,6 @@ func SetDataDir(ctx *cli.Context, cfg *node.Config) {
cfg.DataDir = ctx.String(DataDirFlag.Name) cfg.DataDir = ctx.String(DataDirFlag.Name)
case ctx.Bool(DeveloperFlag.Name): case ctx.Bool(DeveloperFlag.Name):
cfg.DataDir = "" // unless explicitly requested, use memory databases cfg.DataDir = "" // unless explicitly requested, use memory databases
case ctx.Bool(GoerliFlag.Name) && cfg.DataDir == node.DefaultDataDir():
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli")
case ctx.Bool(SepoliaFlag.Name) && cfg.DataDir == node.DefaultDataDir(): case ctx.Bool(SepoliaFlag.Name) && cfg.DataDir == node.DefaultDataDir():
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "sepolia") cfg.DataDir = filepath.Join(node.DefaultDataDir(), "sepolia")
} }
@ -1752,7 +1734,7 @@ func CheckExclusive(ctx *cli.Context, args ...interface{}) {
// SetEthConfig applies eth-related command line flags to the config. // SetEthConfig applies eth-related command line flags to the config.
func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
// Avoid conflicting network flags // Avoid conflicting network flags
CheckExclusive(ctx, MainnetFlag, DeveloperFlag, GoerliFlag, SepoliaFlag, HoleskyFlag) CheckExclusive(ctx, MainnetFlag, DeveloperFlag, SepoliaFlag, HoleskyFlag)
CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer
// Set configurations from CLI flags // Set configurations from CLI flags
@ -1889,9 +1871,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
// TODO(fjl): force-enable this in --dev mode // TODO(fjl): force-enable this in --dev mode
cfg.EnablePreimageRecording = ctx.Bool(VMEnableDebugFlag.Name) cfg.EnablePreimageRecording = ctx.Bool(VMEnableDebugFlag.Name)
} }
if ctx.IsSet(CollectWitnessFlag.Name) {
cfg.EnableWitnessCollection = ctx.Bool(CollectWitnessFlag.Name)
}
if ctx.IsSet(RPCGlobalGasCapFlag.Name) { if ctx.IsSet(RPCGlobalGasCapFlag.Name) {
cfg.RPCGasCap = ctx.Uint64(RPCGlobalGasCapFlag.Name) cfg.RPCGasCap = ctx.Uint64(RPCGlobalGasCapFlag.Name)
@ -1937,13 +1916,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
cfg.Genesis = core.DefaultSepoliaGenesisBlock() cfg.Genesis = core.DefaultSepoliaGenesisBlock()
SetDNSDiscoveryDefaults(cfg, params.SepoliaGenesisHash) SetDNSDiscoveryDefaults(cfg, params.SepoliaGenesisHash)
case ctx.Bool(GoerliFlag.Name):
if !ctx.IsSet(NetworkIdFlag.Name) {
cfg.NetworkId = 5
}
cfg.Genesis = core.DefaultGoerliGenesisBlock()
SetDNSDiscoveryDefaults(cfg, params.GoerliGenesisHash)
case ctx.Bool(DeveloperFlag.Name): case ctx.Bool(DeveloperFlag.Name):
if !ctx.IsSet(NetworkIdFlag.Name) { if !ctx.IsSet(NetworkIdFlag.Name) {
cfg.NetworkId = 1337 cfg.NetworkId = 1337
@ -2071,7 +2043,7 @@ func SetDNSDiscoveryDefaults(cfg *ethconfig.Config, genesis common.Hash) {
// RegisterEthService adds an Ethereum client to the stack. // RegisterEthService adds an Ethereum client to the stack.
// The second return value is the full node instance. // The second return value is the full node instance.
func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (ethapi.Backend, *eth.Ethereum) { func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (*eth.EthAPIBackend, *eth.Ethereum) {
backend, err := eth.New(stack, cfg) backend, err := eth.New(stack, cfg)
if err != nil { if err != nil {
Fatalf("Failed to register the Ethereum service: %v", err) Fatalf("Failed to register the Ethereum service: %v", err)
@ -2081,7 +2053,7 @@ func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (ethapi.Backend
} }
// RegisterEthStatsService configures the Ethereum Stats daemon and adds it to the node. // RegisterEthStatsService configures the Ethereum Stats daemon and adds it to the node.
func RegisterEthStatsService(stack *node.Node, backend ethapi.Backend, url string) { func RegisterEthStatsService(stack *node.Node, backend *eth.EthAPIBackend, url string) {
if err := ethstats.New(stack, backend, backend.Engine(), url); err != nil { if err := ethstats.New(stack, backend, backend.Engine(), url); err != nil {
Fatalf("Failed to register the Ethereum Stats service: %v", err) Fatalf("Failed to register the Ethereum Stats service: %v", err)
} }
@ -2216,8 +2188,6 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly, disableFree
} }
chainDb = remotedb.New(client) chainDb = remotedb.New(client)
case ctx.String(SyncModeFlag.Name) == "light":
chainDb, err = stack.OpenDatabase("lightchaindata", cache, handles, "", readonly)
default: default:
chainDb, err = stack.OpenDatabaseWithFreezer("chaindata", cache, handles, ctx.String(AncientFlag.Name), "", readonly, disableFreeze, false) chainDb, err = stack.OpenDatabaseWithFreezer("chaindata", cache, handles, ctx.String(AncientFlag.Name), "", readonly, disableFreeze, false)
} }
@ -2290,8 +2260,6 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis {
genesis = core.DefaultGenesisBlock() genesis = core.DefaultGenesisBlock()
case ctx.Bool(SepoliaFlag.Name): case ctx.Bool(SepoliaFlag.Name):
genesis = core.DefaultSepoliaGenesisBlock() genesis = core.DefaultSepoliaGenesisBlock()
case ctx.Bool(GoerliFlag.Name):
genesis = core.DefaultGoerliGenesisBlock()
case ctx.Bool(DeveloperFlag.Name): case ctx.Bool(DeveloperFlag.Name):
Fatalf("Developer chains are ephemeral") Fatalf("Developer chains are ephemeral")
} }
@ -2314,6 +2282,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
configs := &ethconfig.Config{ configs := &ethconfig.Config{
Genesis: gspec, Genesis: gspec,
HeimdallURL: ctx.String(HeimdallURLFlag.Name), HeimdallURL: ctx.String(HeimdallURLFlag.Name),
HeimdallTimeout: ctx.Duration(HeimdallTimeoutFlag.Name),
WithoutHeimdall: ctx.Bool(WithoutHeimdallFlag.Name), WithoutHeimdall: ctx.Bool(WithoutHeimdallFlag.Name),
HeimdallgRPCAddress: ctx.String(HeimdallgRPCAddressFlag.Name), HeimdallgRPCAddress: ctx.String(HeimdallgRPCAddressFlag.Name),
RunHeimdall: ctx.Bool(RunHeimdallArgsFlag.Name), RunHeimdall: ctx.Bool(RunHeimdallArgsFlag.Name),
@ -2367,7 +2336,6 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
} }
vmcfg := vm.Config{ vmcfg := vm.Config{
EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name), EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name),
EnableWitnessCollection: ctx.Bool(CollectWitnessFlag.Name),
} }
if ctx.IsSet(VMTraceFlag.Name) { if ctx.IsSet(VMTraceFlag.Name) {
if name := ctx.String(VMTraceFlag.Name); name != "" { if name := ctx.String(VMTraceFlag.Name); name != "" {

View file

@ -92,25 +92,21 @@ var (
LightServeFlag = &cli.IntFlag{ LightServeFlag = &cli.IntFlag{
Name: "light.serve", Name: "light.serve",
Usage: "Maximum percentage of time allowed for serving LES requests (deprecated)", Usage: "Maximum percentage of time allowed for serving LES requests (deprecated)",
Value: ethconfig.Defaults.LightServ,
Category: flags.DeprecatedCategory, Category: flags.DeprecatedCategory,
} }
LightIngressFlag = &cli.IntFlag{ LightIngressFlag = &cli.IntFlag{
Name: "light.ingress", Name: "light.ingress",
Usage: "Incoming bandwidth limit for serving light clients (deprecated)", Usage: "Incoming bandwidth limit for serving light clients (deprecated)",
Value: ethconfig.Defaults.LightIngress,
Category: flags.DeprecatedCategory, Category: flags.DeprecatedCategory,
} }
LightEgressFlag = &cli.IntFlag{ LightEgressFlag = &cli.IntFlag{
Name: "light.egress", Name: "light.egress",
Usage: "Outgoing bandwidth limit for serving light clients (deprecated)", Usage: "Outgoing bandwidth limit for serving light clients (deprecated)",
Value: ethconfig.Defaults.LightEgress,
Category: flags.DeprecatedCategory, Category: flags.DeprecatedCategory,
} }
LightMaxPeersFlag = &cli.IntFlag{ LightMaxPeersFlag = &cli.IntFlag{
Name: "light.maxpeers", Name: "light.maxpeers",
Usage: "Maximum number of light clients to serve, or light servers to attach to (deprecated)", Usage: "Maximum number of light clients to serve, or light servers to attach to (deprecated)",
Value: ethconfig.Defaults.LightPeers,
Category: flags.DeprecatedCategory, Category: flags.DeprecatedCategory,
} }
LightNoPruneFlag = &cli.BoolFlag{ LightNoPruneFlag = &cli.BoolFlag{

View file

@ -87,11 +87,7 @@ func TestHistoryImportAndExport(t *testing.T) {
} }
// Make temp directory for era files. // Make temp directory for era files.
dir, err := os.MkdirTemp("", "history-export-test") dir := t.TempDir()
if err != nil {
t.Fatalf("error creating temp test directory: %v", err)
}
defer os.RemoveAll(dir)
// Export history to temp directory. // Export history to temp directory.
if err := ExportHistory(chain, dir, 0, count, step); err != nil { if err := ExportHistory(chain, dir, 0, count, step); err != nil {

0
common/prque/prque.go Executable file → Normal file
View file

0
common/prque/sstack.go Executable file → Normal file
View file

View file

@ -388,8 +388,39 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
// Assign the final state root to header. // Assign the final state root to header.
header.Root = state.IntermediateRoot(true) header.Root = state.IntermediateRoot(true)
// Assemble and return the final block. // Assemble the final block.
return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)), nil block := types.NewBlock(header, body, receipts, trie.NewStackTrie(nil))
// Create the block witness and attach to block.
// This step needs to happen as late as possible to catch all access events.
if chain.Config().IsVerkle(header.Number) {
keys := state.AccessEvents().Keys()
// Open the pre-tree to prove the pre-state against
parent := chain.GetHeaderByNumber(header.Number.Uint64() - 1)
if parent == nil {
return nil, fmt.Errorf("nil parent header for block %d", header.Number)
}
preTrie, err := state.Database().OpenTrie(parent.Root)
if err != nil {
return nil, fmt.Errorf("error opening pre-state tree root: %w", err)
}
vktPreTrie, okpre := preTrie.(*trie.VerkleTrie)
vktPostTrie, okpost := state.GetTrie().(*trie.VerkleTrie)
if okpre && okpost {
if len(keys) > 0 {
verkleProof, stateDiff, err := vktPreTrie.Proof(vktPostTrie, keys, vktPreTrie.FlatdbNodeResolver)
if err != nil {
return nil, fmt.Errorf("error generating verkle proof for block %d: %w", header.Number, err)
}
block = block.WithWitness(&types.ExecutionWitness{StateDiff: stateDiff, VerkleProof: verkleProof})
}
}
}
return block, nil
} }
// Seal generates a new sealing request for the given input block and pushes // Seal generates a new sealing request for the given input block and pushes

View file

@ -391,6 +391,10 @@ func (c *Bor) verifyHeader(chain consensus.ChainHeaderReader, header *types.Head
return consensus.ErrUnexpectedWithdrawals return consensus.ErrUnexpectedWithdrawals
} }
if header.RequestsHash != nil {
return consensus.ErrUnexpectedRequests
}
// All basic checks passed, verify cascading fields // All basic checks passed, verify cascading fields
return c.verifyCascadingFields(chain, header, parents) return c.verifyCascadingFields(chain, header, parents)
} }
@ -820,6 +824,9 @@ func (c *Bor) Finalize(chain consensus.ChainHeaderReader, header *types.Header,
if body.Withdrawals != nil || header.WithdrawalsHash != nil { if body.Withdrawals != nil || header.WithdrawalsHash != nil {
return return
} }
if body.Requests != nil || header.RequestsHash != nil {
return
}
var ( var (
stateSyncData []*types.StateSyncData stateSyncData []*types.StateSyncData
@ -906,6 +913,9 @@ func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *typ
if body.Withdrawals != nil || header.WithdrawalsHash != nil { if body.Withdrawals != nil || header.WithdrawalsHash != nil {
return nil, consensus.ErrUnexpectedWithdrawals return nil, consensus.ErrUnexpectedWithdrawals
} }
if body.Requests != nil || header.RequestsHash != nil {
return nil, consensus.ErrUnexpectedRequests
}
var ( var (
stateSyncData []*types.StateSyncData stateSyncData []*types.StateSyncData

View file

@ -66,7 +66,7 @@ func TestGenesisContractChange(t *testing.T) {
genesis := genspec.MustCommit(db, triedb.NewDatabase(db, triedb.HashDefaults)) genesis := genspec.MustCommit(db, triedb.NewDatabase(db, triedb.HashDefaults))
statedb, err := state.New(genesis.Root(), state.NewDatabase(db), nil) statedb, err := state.New(genesis.Root(), state.NewDatabase(triedb.NewDatabase(db, triedb.HashDefaults), nil))
require.NoError(t, err) require.NoError(t, err)
chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genspec, nil, b, vm.Config{}, nil, nil, nil) chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genspec, nil, b, vm.Config{}, nil, nil, nil)
@ -84,7 +84,7 @@ func TestGenesisContractChange(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, statedb.Database().TrieDB().Commit(root, true)) require.NoError(t, statedb.Database().TrieDB().Commit(root, true))
statedb, err := state.New(h.Root, state.NewDatabase(db), nil) statedb, err := state.New(h.Root, state.NewDatabase(triedb.NewDatabase(db, triedb.HashDefaults), nil))
require.NoError(t, err) require.NoError(t, err)
return root, statedb return root, statedb

View file

@ -33,7 +33,6 @@ var (
const ( const (
heimdallAPIBodyLimit = 128 * 1024 * 1024 // 128 MB heimdallAPIBodyLimit = 128 * 1024 * 1024 // 128 MB
stateFetchLimit = 50 stateFetchLimit = 50
apiHeimdallTimeout = 5 * time.Second
retryCall = 5 * time.Second retryCall = 5 * time.Second
) )
@ -59,11 +58,11 @@ type Request struct {
start time.Time start time.Time
} }
func NewHeimdallClient(urlString string) *HeimdallClient { func NewHeimdallClient(urlString string, timeout time.Duration) *HeimdallClient {
return &HeimdallClient{ return &HeimdallClient{
urlString: urlString, urlString: urlString,
client: http.Client{ client: http.Client{
Timeout: apiHeimdallTimeout, Timeout: timeout,
}, },
closeCh: make(chan struct{}), closeCh: make(chan struct{}),
} }
@ -294,7 +293,13 @@ func FetchWithRetry[T any](ctx context.Context, client http.Client, url *url.URL
log.Warn("an error while trying fetching from Heimdall", "path", url.Path, "attempt", attempt, "error", err) log.Warn("an error while trying fetching from Heimdall", "path", url.Path, "attempt", attempt, "error", err)
// create a new ticker for retrying the request // create a new ticker for retrying the request
ticker := time.NewTicker(retryCall) var ticker *time.Ticker
if client.Timeout != 0 {
ticker = time.NewTicker(client.Timeout)
} else {
// only reach here when HeimdallClient is HeimdallGRPCClient or HeimdallAppClient
ticker = time.NewTicker(retryCall)
}
defer ticker.Stop() defer ticker.Stop()
const logEach = 5 const logEach = 5
@ -469,7 +474,7 @@ func internalFetch(ctx context.Context, client http.Client, u *url.URL) ([]byte,
} }
func internalFetchWithTimeout(ctx context.Context, client http.Client, url *url.URL) ([]byte, error) { func internalFetchWithTimeout(ctx context.Context, client http.Client, url *url.URL) ([]byte, error) {
ctx, cancel := context.WithTimeout(ctx, apiHeimdallTimeout) ctx, cancel := context.WithTimeout(ctx, client.Timeout)
defer cancel() defer cancel()
// request data once // request data once

View file

@ -143,7 +143,7 @@ func TestFetchCheckpointFromMockHeimdall(t *testing.T) {
require.NoError(t, err, "expect no error in starting mock heimdall server") require.NoError(t, err, "expect no error in starting mock heimdall server")
// Create a new heimdall client and use same port for connection // Create a new heimdall client and use same port for connection
client := NewHeimdallClient(fmt.Sprintf("http://localhost:%d", port)) client := NewHeimdallClient(fmt.Sprintf("http://localhost:%d", port), 5*time.Second)
_, err = client.FetchCheckpoint(context.Background(), -1) _, err = client.FetchCheckpoint(context.Background(), -1)
require.NoError(t, err, "expect no error in fetching checkpoint") require.NoError(t, err, "expect no error in fetching checkpoint")
@ -194,7 +194,7 @@ func TestFetchMilestoneFromMockHeimdall(t *testing.T) {
require.NoError(t, err, "expect no error in starting mock heimdall server") require.NoError(t, err, "expect no error in starting mock heimdall server")
// Create a new heimdall client and use same port for connection // Create a new heimdall client and use same port for connection
client := NewHeimdallClient(fmt.Sprintf("http://localhost:%d", port)) client := NewHeimdallClient(fmt.Sprintf("http://localhost:%d", port), 5*time.Second)
_, err = client.FetchMilestone(context.Background()) _, err = client.FetchMilestone(context.Background())
require.NoError(t, err, "expect no error in fetching milestone") require.NoError(t, err, "expect no error in fetching milestone")
@ -250,7 +250,7 @@ func TestFetchShutdown(t *testing.T) {
require.NoError(t, err, "expect no error in starting mock heimdall server") require.NoError(t, err, "expect no error in starting mock heimdall server")
// Create a new heimdall client and use same port for connection // Create a new heimdall client and use same port for connection
client := NewHeimdallClient(fmt.Sprintf("http://localhost:%d", port)) client := NewHeimdallClient(fmt.Sprintf("http://localhost:%d", port), 5*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)

View file

@ -30,11 +30,11 @@ import (
) )
// This test case is a repro of an annoying bug that took us forever to catch. // This test case is a repro of an annoying bug that took us forever to catch.
// In Clique PoA networks (Görli, etc), consecutive blocks might have // In Clique PoA networks, consecutive blocks might have the same state root (no
// the same state root (no block subsidy, empty block). If a node crashes, the // block subsidy, empty block). If a node crashes, the chain ends up losing the
// chain ends up losing the recent state and needs to regenerate it from blocks // recent state and needs to regenerate it from blocks already in the database.
// already in the database. The bug was that processing the block *prior* to an // The bug was that processing the block *prior* to an empty one **also
// empty one **also completes** the empty one, ending up in a known-block error. // completes** the empty one, ending up in a known-block error.
func TestReimportMirroredState(t *testing.T) { func TestReimportMirroredState(t *testing.T) {
// Initialize a Clique chain with a single signer // Initialize a Clique chain with a single signer
var ( var (
@ -90,7 +90,6 @@ func TestReimportMirroredState(t *testing.T) {
} }
// Insert the first two blocks and make sure the chain is valid // Insert the first two blocks and make sure the chain is valid
db = rawdb.NewMemoryDatabase() db = rawdb.NewMemoryDatabase()
chain, _ = core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil, nil, nil) chain, _ = core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil, nil, nil)
defer chain.Stop() defer chain.Stop()

View file

@ -41,4 +41,7 @@ var (
// ErrUnexpectedWithdrawals is returned if a pre-Shanghai block has withdrawals. // ErrUnexpectedWithdrawals is returned if a pre-Shanghai block has withdrawals.
ErrUnexpectedWithdrawals = errors.New("unexpected withdrawals") ErrUnexpectedWithdrawals = errors.New("unexpected withdrawals")
// ErrUnexpectedRequests is returned if a pre-Shanghai block has requests.
ErrUnexpectedRequests = errors.New("unexpected requests")
) )

View file

@ -137,7 +137,7 @@ func TestCalcBaseFee(t *testing.T) {
} }
} }
// TestCalcBaseFee assumes all blocks are 1559-blocks post Delhi Hard Fork // TestCalcBaseFeeDelhi assumes all blocks are 1559-blocks post Delhi Hard Fork
func TestCalcBaseFeeDelhi(t *testing.T) { func TestCalcBaseFeeDelhi(t *testing.T) {
t.Parallel() t.Parallel()

View file

@ -331,7 +331,6 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
if err != nil { if err != nil {
b.Fatalf("error opening database at %v: %v", dir, err) b.Fatalf("error opening database at %v: %v", dir, err)
} }
chain, err := NewBlockChain(db, &cacheConfig, genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil, nil) chain, err := NewBlockChain(db, &cacheConfig, genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
if err != nil { if err != nil {
b.Fatalf("error creating chain: %v", err) b.Fatalf("error creating chain: %v", err)

View file

@ -20,10 +20,8 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/stateless"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
@ -127,15 +125,17 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
// ValidateState validates the various changes that happen after a state transition, // ValidateState validates the various changes that happen after a state transition,
// such as amount of used gas, the receipt roots and the state root itself. // such as amount of used gas, the receipt roots and the state root itself.
func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64, stateless bool) error { func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, res *ProcessResult, stateless bool) error {
if res == nil {
return fmt.Errorf("nil ProcessResult value")
}
header := block.Header() header := block.Header()
if block.GasUsed() != res.GasUsed {
if block.GasUsed() != usedGas { return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), res.GasUsed)
return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas)
} }
// Validate the received block's bloom with the one derived from the generated receipts. // Validate the received block's bloom with the one derived from the generated receipts.
// For valid blocks this should always validate to true. // For valid blocks this should always validate to true.
rbloom := types.CreateBloom(receipts) rbloom := types.CreateBloom(res.Receipts)
if rbloom != header.Bloom { if rbloom != header.Bloom {
return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom) return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom)
} }
@ -145,10 +145,17 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
return nil return nil
} }
// The receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]])) // The receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]]))
receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil)) receiptSha := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil))
if receiptSha != header.ReceiptHash { if receiptSha != header.ReceiptHash {
return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha)
} }
// Validate the parsed requests match the expected header value.
if header.RequestsHash != nil {
depositSha := types.DeriveSha(res.Requests, trie.NewStackTrie(nil))
if depositSha != *header.RequestsHash {
return fmt.Errorf("invalid deposit root hash (remote: %x local: %x)", *header.RequestsHash, depositSha)
}
}
// Validate the state root against the received state root and throw // Validate the state root against the received state root and throw
// an error if they don't match. // an error if they don't match.
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root { if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
@ -158,28 +165,6 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
return nil return nil
} }
// ValidateWitness cross validates a block execution with stateless remote clients.
//
// Normally we'd distribute the block witness to remote cross validators, wait
// for them to respond and then merge the results. For now, however, it's only
// Geth, so do an internal stateless run.
func (v *BlockValidator) ValidateWitness(witness *stateless.Witness, receiptRoot common.Hash, stateRoot common.Hash) error {
// Run the cross client stateless execution
// TODO(karalabe): Self-stateless for now, swap with other clients
crossReceiptRoot, crossStateRoot, err := ExecuteStateless(v.config, witness)
if err != nil {
return fmt.Errorf("stateless execution failed: %v", err)
}
// Stateless cross execution suceeeded, validate the withheld computed fields
if crossReceiptRoot != receiptRoot {
return fmt.Errorf("cross validator receipt root mismatch (cross: %x local: %x)", crossReceiptRoot, receiptRoot)
}
if crossStateRoot != stateRoot {
return fmt.Errorf("cross validator state root mismatch (cross: %x local: %x)", crossStateRoot, stateRoot)
}
return nil
}
// CalcGasLimit computes the gas limit of the next block after parent. It aims // CalcGasLimit computes the gas limit of the next block after parent. It aims
// to keep the baseline gas close to the provided target, and increase it towards // to keep the baseline gas close to the provided target, and increase it towards
// the target if the baseline gas is lower. // the target if the baseline gas is lower.

View file

@ -211,7 +211,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) {
t.Fatalf("post-block %d: unexpected result returned: %v", i, result) t.Fatalf("post-block %d: unexpected result returned: %v", i, result)
case <-time.After(25 * time.Millisecond): case <-time.After(25 * time.Millisecond):
} }
chain.InsertBlockWithoutSetHead(postBlocks[i]) chain.InsertBlockWithoutSetHead(postBlocks[i], false)
} }
// Verify the blocks with pre-merge blocks and post-merge blocks // Verify the blocks with pre-merge blocks and post-merge blocks

View file

@ -42,6 +42,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/state/snapshot"
"github.com/ethereum/go-ethereum/core/stateless"
"github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
@ -78,17 +79,21 @@ var (
storageUpdateTimer = metrics.NewRegisteredResettingTimer("chain/storage/updates", nil) storageUpdateTimer = metrics.NewRegisteredResettingTimer("chain/storage/updates", nil)
storageCommitTimer = metrics.NewRegisteredResettingTimer("chain/storage/commits", nil) storageCommitTimer = metrics.NewRegisteredResettingTimer("chain/storage/commits", nil)
accountReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/account/single/reads", nil) //nolint:golint,unused
storageReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/storage/single/reads", nil) //nolint:golint,unused
snapshotCommitTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/commits", nil)
triedbCommitTimer = metrics.NewRegisteredResettingTimer("chain/triedb/commits", nil)
snapshotAccountReadTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/account/reads", nil) snapshotAccountReadTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/account/reads", nil)
snapshotStorageReadTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/storage/reads", nil) snapshotStorageReadTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/storage/reads", nil)
snapshotCommitTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/commits", nil)
borConsensusTime = metrics.NewRegisteredTimer("chain/bor/consensus", nil) borConsensusTime = metrics.NewRegisteredTimer("chain/bor/consensus", nil)
blockImportTimer = metrics.NewRegisteredMeter("chain/imports", nil) blockImportTimer = metrics.NewRegisteredMeter("chain/imports", nil)
triedbCommitTimer = metrics.NewRegisteredTimer("chain/triedb/commits", nil)
blockInsertTimer = metrics.NewRegisteredTimer("chain/inserts", nil) blockInsertTimer = metrics.NewRegisteredTimer("chain/inserts", nil)
blockValidationTimer = metrics.NewRegisteredTimer("chain/validation", nil) blockValidationTimer = metrics.NewRegisteredTimer("chain/validation", nil)
blockCrossValidationTimer = metrics.NewRegisteredResettingTimer("chain/crossvalidation", nil) //nolint:golint,unused
blockExecutionTimer = metrics.NewRegisteredTimer("chain/execution", nil) blockExecutionTimer = metrics.NewRegisteredTimer("chain/execution", nil)
blockWriteTimer = metrics.NewRegisteredTimer("chain/write", nil) blockWriteTimer = metrics.NewRegisteredTimer("chain/write", nil)
blockExecutionParallelCounter = metrics.NewRegisteredCounter("chain/execution/parallel", nil) blockExecutionParallelCounter = metrics.NewRegisteredCounter("chain/execution/parallel", nil)
@ -237,7 +242,7 @@ type BlockChain struct {
lastWrite uint64 // Last block when the state was flushed lastWrite uint64 // Last block when the state was flushed
flushInterval atomic.Int64 // Time interval (processing time) after which to flush a state flushInterval atomic.Int64 // Time interval (processing time) after which to flush a state
triedb *triedb.Database // The database handler for maintaining trie nodes. triedb *triedb.Database // The database handler for maintaining trie nodes.
stateCache state.Database // State database to reuse between imports (contains state cache) statedb *state.CachingDB // State database to reuse between imports (contains state cache)
txIndexer *txIndexer // Transaction indexer, might be nil if not enabled txIndexer *txIndexer // Transaction indexer, might be nil if not enabled
hc *HeaderChain hc *HeaderChain
@ -357,7 +362,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit)) bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit))
bc.forker = NewForkChoice(bc, shouldPreserve, checker) bc.forker = NewForkChoice(bc, shouldPreserve, checker)
bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb) bc.statedb = state.NewDatabase(bc.triedb, nil)
bc.validator = NewBlockValidator(chainConfig, bc) bc.validator = NewBlockValidator(chainConfig, bc)
bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc) bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc)
bc.processor = NewStateProcessor(chainConfig, bc, bc.hc) bc.processor = NewStateProcessor(chainConfig, bc, bc.hc)
@ -525,11 +530,10 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
AsyncBuild: !bc.cacheConfig.SnapshotWait, AsyncBuild: !bc.cacheConfig.SnapshotWait,
} }
bc.snaps, _ = snapshot.New(snapconfig, bc.db, bc.triedb, head.Root) bc.snaps, _ = snapshot.New(snapconfig, bc.db, bc.triedb, head.Root)
}
// Start future block processor. // Re-initialize the state database with snapshot
// bc.wg.Add(1) bc.statedb = state.NewDatabase(bc.triedb, bc.snaps)
// go bc.updateFutureBlocks() }
// Rewind the chain in case of an incompatible config upgrade. // Rewind the chain in case of an incompatible config upgrade.
if compat, ok := genesisErr.(*params.ConfigCompatError); ok { if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
@ -616,7 +620,7 @@ func (bc *BlockChain) ProcessBlock(block *types.Block, parent *types.Header) (_
processorCount := 0 processorCount := 0
if bc.parallelProcessor != nil { if bc.parallelProcessor != nil {
parallelStatedb, err := state.New(parent.Root, bc.stateCache, bc.snaps) parallelStatedb, err := state.New(parent.Root, bc.statedb)
if err != nil { if err != nil {
return nil, nil, 0, nil, 0, err return nil, nil, 0, nil, 0, err
} }
@ -627,19 +631,22 @@ func (bc *BlockChain) ProcessBlock(block *types.Block, parent *types.Header) (_
go func() { go func() {
parallelStatedb.StartPrefetcher("chain", nil) parallelStatedb.StartPrefetcher("chain", nil)
pstart := time.Now() pstart := time.Now()
receipts, logs, usedGas, err := bc.parallelProcessor.Process(block, parallelStatedb, bc.vmConfig, ctx) res, err := bc.parallelProcessor.Process(block, parallelStatedb, bc.vmConfig, ctx)
blockExecutionParallelTimer.UpdateSince(pstart) blockExecutionParallelTimer.UpdateSince(pstart)
if err == nil { if err == nil {
vstart := time.Now() vstart := time.Now()
err = bc.validator.ValidateState(block, parallelStatedb, receipts, usedGas, false) err = bc.validator.ValidateState(block, parallelStatedb, res, false)
vtime = time.Since(vstart) vtime = time.Since(vstart)
} }
resultChan <- Result{receipts, logs, usedGas, err, parallelStatedb, blockExecutionParallelCounter, true} if res == nil {
res = &ProcessResult{}
}
resultChan <- Result{res.Receipts, res.Logs, res.GasUsed, err, parallelStatedb, blockExecutionParallelCounter, true}
}() }()
} }
if bc.processor != nil && !bc.enforceParallelProcessor { if bc.processor != nil && !bc.enforceParallelProcessor {
statedb, err := state.New(parent.Root, bc.stateCache, bc.snaps) statedb, err := state.New(parent.Root, bc.statedb)
if err != nil { if err != nil {
return nil, nil, 0, nil, 0, err return nil, nil, 0, nil, 0, err
} }
@ -650,14 +657,17 @@ func (bc *BlockChain) ProcessBlock(block *types.Block, parent *types.Header) (_
go func() { go func() {
statedb.StartPrefetcher("chain", nil) statedb.StartPrefetcher("chain", nil)
pstart := time.Now() pstart := time.Now()
receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig, ctx) res, err := bc.processor.Process(block, statedb, bc.vmConfig, ctx)
blockExecutionSerialTimer.UpdateSince(pstart) blockExecutionSerialTimer.UpdateSince(pstart)
if err == nil { if err == nil {
vstart := time.Now() vstart := time.Now()
err = bc.validator.ValidateState(block, statedb, receipts, usedGas, false) err = bc.validator.ValidateState(block, statedb, res, false)
vtime = time.Since(vstart) vtime = time.Since(vstart)
} }
resultChan <- Result{receipts, logs, usedGas, err, statedb, blockExecutionSerialCounter, false} if res == nil {
res = &ProcessResult{}
}
resultChan <- Result{res.Receipts, res.Logs, res.GasUsed, err, statedb, blockExecutionSerialCounter, false}
}() }()
} }
@ -2063,7 +2073,9 @@ func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) {
return 0, errChainStopped return 0, errChainStopped
} }
defer bc.chainmu.Unlock() defer bc.chainmu.Unlock()
return bc.insertChain(chain, true)
_, n, err := bc.insertChain(chain, true, false) // No witness collection for mass inserts (would get super large)
return n, err
} }
// insertChain is the internal implementation of InsertChain, which assumes that // insertChain is the internal implementation of InsertChain, which assumes that
@ -2074,10 +2086,10 @@ func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) {
// racey behaviour. If a sidechain import is in progress, and the historic state // racey behaviour. If a sidechain import is in progress, and the historic state
// is imported, but then new canon-head is added before the actual sidechain // is imported, but then new canon-head is added before the actual sidechain
// completes, then the historic state could be pruned again // completes, then the historic state could be pruned again
func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) { func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness bool) (*stateless.Witness, int, error) {
// If the chain is terminating, don't even bother starting up. // If the chain is terminating, don't even bother starting up.
if bc.insertStopped() { if bc.insertStopped() {
return 0, nil return nil, 0, nil
} }
// Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss) // Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss)
@ -2113,13 +2125,13 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
// Check the validity of incoming chain // Check the validity of incoming chain
isValid, err1 := bc.forker.ValidateReorg(bc.CurrentBlock(), headers) isValid, err1 := bc.forker.ValidateReorg(bc.CurrentBlock(), headers)
if err1 != nil { if err1 != nil {
return it.index, err1 return nil, it.index, err1
} }
if !isValid { if !isValid {
// The chain to be imported is invalid as the blocks doesn't match with // The chain to be imported is invalid as the blocks doesn't match with
// the whitelisted block number. // the whitelisted block number.
return it.index, whitelist.ErrMismatch return nil, it.index, whitelist.ErrMismatch
} }
// Left-trim all the known blocks that don't need to build snapshot // Left-trim all the known blocks that don't need to build snapshot
@ -2137,7 +2149,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
for block != nil && bc.skipBlock(err, it) { for block != nil && bc.skipBlock(err, it) {
reorg, err = bc.forker.ReorgNeeded(current, block.Header()) reorg, err = bc.forker.ReorgNeeded(current, block.Header())
if err != nil { if err != nil {
return it.index, err return nil, it.index, err
} }
if reorg { if reorg {
@ -2169,7 +2181,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
log.Debug("Writing previously known block", "number", block.Number(), "hash", block.Hash()) log.Debug("Writing previously known block", "number", block.Number(), "hash", block.Hash())
if err := bc.writeKnownBlock(block); err != nil { if err := bc.writeKnownBlock(block); err != nil {
return it.index, err return nil, it.index, err
} }
lastCanon = block lastCanon = block
@ -2185,13 +2197,12 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
if setHead { if setHead {
// First block is pruned, insert as sidechain and reorg only if TD grows enough // First block is pruned, insert as sidechain and reorg only if TD grows enough
log.Debug("Pruned ancestor, inserting as sidechain", "number", block.Number(), "hash", block.Hash()) log.Debug("Pruned ancestor, inserting as sidechain", "number", block.Number(), "hash", block.Hash())
return bc.insertSideChain(block, it) return bc.insertSideChain(block, it, makeWitness)
} else { } else {
// We're post-merge and the parent is pruned, try to recover the parent state // We're post-merge and the parent is pruned, try to recover the parent state
log.Debug("Pruned ancestor", "number", block.Number(), "hash", block.Hash()) log.Debug("Pruned ancestor", "number", block.Number(), "hash", block.Hash())
_, err := bc.recoverAncestors(block) _, err := bc.recoverAncestors(block, makeWitness)
return nil, it.index, err
return it.index, err
} }
// First block is future, shove it (and all children) to the future queue (unknown ancestor) // First block is future, shove it (and all children) to the future queue (unknown ancestor)
case errors.Is(err, consensus.ErrFutureBlock) || (errors.Is(err, consensus.ErrUnknownAncestor) && bc.futureBlocks.Contains(it.first().ParentHash())): case errors.Is(err, consensus.ErrFutureBlock) || (errors.Is(err, consensus.ErrUnknownAncestor) && bc.futureBlocks.Contains(it.first().ParentHash())):
@ -2199,7 +2210,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
log.Debug("Future block, postponing import", "number", block.Number(), "hash", block.Hash()) log.Debug("Future block, postponing import", "number", block.Number(), "hash", block.Hash())
if err := bc.addFutureBlock(block); err != nil { if err := bc.addFutureBlock(block); err != nil {
return it.index, err return nil, it.index, err
} }
block, err = it.next() block, err = it.next()
@ -2209,7 +2220,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
stats.ignored += it.remaining() stats.ignored += it.remaining()
// If there are any still remaining, mark as ignored // If there are any still remaining, mark as ignored
return it.index, err return nil, it.index, err
// Some other error(except ErrKnownBlock) occurred, abort. // Some other error(except ErrKnownBlock) occurred, abort.
// ErrKnownBlock is allowed here since some known blocks // ErrKnownBlock is allowed here since some known blocks
@ -2218,8 +2229,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
stats.ignored += len(it.chain) stats.ignored += len(it.chain)
bc.reportBlock(block, nil, err) bc.reportBlock(block, nil, err)
return nil, it.index, err
return it.index, err
} }
// No validation errors for the first block (or chain prefix skipped) // No validation errors for the first block (or chain prefix skipped)
var activeState *state.StateDB var activeState *state.StateDB
@ -2233,6 +2243,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
} }
}() }()
// Track the singleton witness from this chain insertion (if any)
var witness *stateless.Witness
// accumulator for canonical blocks // accumulator for canonical blocks
var canonAccum []*types.Block var canonAccum []*types.Block
@ -2261,7 +2274,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
// If the header is a banned one, straight out abort // If the header is a banned one, straight out abort
if BadHashes[block.Hash()] { if BadHashes[block.Hash()] {
bc.reportBlock(block, nil, ErrBannedHash) bc.reportBlock(block, nil, ErrBannedHash)
return it.index, ErrBannedHash return nil, it.index, ErrBannedHash
} }
// If the block is known (in the middle of the chain), it's a special case for // If the block is known (in the middle of the chain), it's a special case for
@ -2296,7 +2309,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
} }
if err := bc.writeKnownBlock(block); err != nil { if err := bc.writeKnownBlock(block); err != nil {
return it.index, err return nil, it.index, err
} }
stats.processed++ stats.processed++
@ -2308,14 +2321,12 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
Safe: bc.CurrentSafeBlock(), Safe: bc.CurrentSafeBlock(),
}) })
} }
// We can assume that logs are empty here, since the only way for consecutive // We can assume that logs are empty here, since the only way for consecutive
// Clique blocks to have the same state is if there are no transactions. // Clique blocks to have the same state is if there are no transactions.
lastCanon = block lastCanon = block
continue continue
} }
// Retrieve the parent block and it's state to execute on top // Retrieve the parent block and it's state to execute on top
start := time.Now() start := time.Now()
@ -2330,7 +2341,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
if !bc.cacheConfig.TrieCleanNoPrefetch { if !bc.cacheConfig.TrieCleanNoPrefetch {
if followup, err := it.peek(); followup != nil && err == nil { if followup, err := it.peek(); followup != nil && err == nil {
throwaway, _ := state.New(parent.Root, bc.stateCache, bc.snaps) throwaway, _ := state.New(parent.Root, bc.statedb)
go func(start time.Time, followup *types.Block, throwaway *state.StateDB) { go func(start time.Time, followup *types.Block, throwaway *state.StateDB) {
// Disable tracing for prefetcher executions. // Disable tracing for prefetcher executions.
@ -2353,10 +2364,10 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
activeState = statedb activeState = statedb
if err != nil { if err != nil {
bc.reportBlock(block, receipts, err) bc.reportBlock(block, &ProcessResult{Receipts: receipts}, err)
followupInterrupt.Store(true) followupInterrupt.Store(true)
return it.index, err return nil, it.index, err
} }
// BOR state sync feed related changes // BOR state sync feed related changes
@ -2398,10 +2409,11 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
// so that it's considered as a `past` chain and the validation doesn't get bypassed. // so that it's considered as a `past` chain and the validation doesn't get bypassed.
isValid, err = bc.forker.ValidateReorg(block.Header(), []*types.Header{block.Header()}) isValid, err = bc.forker.ValidateReorg(block.Header(), []*types.Header{block.Header()})
if err != nil { if err != nil {
return it.index, err return nil, it.index, err
} }
if !isValid { if !isValid {
return it.index, whitelist.ErrMismatch return nil, it.index, whitelist.ErrMismatch
} }
if !setHead { if !setHead {
@ -2414,7 +2426,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
followupInterrupt.Store(true) followupInterrupt.Store(true)
if err != nil { if err != nil {
return it.index, err return nil, it.index, err
} }
// Update the metrics touched during block commit // Update the metrics touched during block commit
@ -2441,7 +2453,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
// After merge we expect few side chains. Simply count // After merge we expect few side chains. Simply count
// all blocks the CL gives us for GC processing time // all blocks the CL gives us for GC processing time
bc.gcproc += proctime bc.gcproc += proctime
return it.index, nil // Direct block insertion of a single block return witness, it.index, nil // Direct block insertion of a single block
} }
// BOR // BOR
@ -2487,14 +2499,14 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
// Any blocks remaining here? The only ones we care about are the future ones // Any blocks remaining here? The only ones we care about are the future ones
if block != nil && errors.Is(err, consensus.ErrFutureBlock) { if block != nil && errors.Is(err, consensus.ErrFutureBlock) {
if err := bc.addFutureBlock(block); err != nil { if err := bc.addFutureBlock(block); err != nil {
return it.index, err return nil, it.index, err
} }
block, err = it.next() block, err = it.next()
for ; block != nil && errors.Is(err, consensus.ErrUnknownAncestor); block, err = it.next() { for ; block != nil && errors.Is(err, consensus.ErrUnknownAncestor); block, err = it.next() {
if err := bc.addFutureBlock(block); err != nil { if err := bc.addFutureBlock(block); err != nil {
return it.index, err return nil, it.index, err
} }
stats.queued++ stats.queued++
@ -2502,7 +2514,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
} }
stats.ignored += it.remaining() stats.ignored += it.remaining()
return it.index, err return witness, it.index, err
} }
// blockProcessingResult is a summary of block processing // blockProcessingResult is a summary of block processing
@ -2535,42 +2547,68 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
// Process block using the parent state as reference point // Process block using the parent state as reference point
pstart := time.Now() pstart := time.Now()
receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig, context.Background()) res, err := bc.processor.Process(block, statedb, bc.vmConfig, context.Background())
if err != nil { if err != nil {
bc.reportBlock(block, receipts, err) bc.reportBlock(block, res, err)
return nil, err return nil, err
} }
ptime := time.Since(pstart) ptime := time.Since(pstart)
vstart := time.Now() vstart := time.Now()
if err := bc.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil { if err := bc.validator.ValidateState(block, statedb, res, false); err != nil {
bc.reportBlock(block, receipts, err) bc.reportBlock(block, res, err)
return nil, err return nil, err
} }
vtime := time.Since(vstart) vtime := time.Since(vstart)
if witness := statedb.Witness(); witness != nil { // If witnesses was generated and stateless self-validation requested, do
if err = bc.validator.ValidateWitness(witness, block.ReceiptHash(), block.Root()); err != nil { // that now. Self validation should *never* run in production, it's more of
bc.reportBlock(block, receipts, err) // a tight integration to enable running *all* consensus tests through the
return nil, fmt.Errorf("cross verification failed: %v", err) // witness builder/runner, which would otherwise be impossible due to the
// various invalid chain states/behaviors being contained in those tests.
xvstart := time.Now()
if witness := statedb.Witness(); witness != nil && bc.vmConfig.StatelessSelfValidation {
log.Warn("Running stateless self-validation", "block", block.Number(), "hash", block.Hash())
// Remove critical computed fields from the block to force true recalculation
context := block.Header()
context.Root = common.Hash{}
context.ReceiptHash = common.Hash{}
task := types.NewBlockWithHeader(context).WithBody(*block.Body())
// Run the stateless self-cross-validation
crossStateRoot, crossReceiptRoot, err := ExecuteStateless(bc.chainConfig, task, witness)
if err != nil {
return nil, fmt.Errorf("stateless self-validation failed: %v", err)
}
if crossStateRoot != block.Root() {
return nil, fmt.Errorf("stateless self-validation root mismatch (cross: %x local: %x)", crossStateRoot, block.Root())
}
if crossReceiptRoot != block.ReceiptHash() {
return nil, fmt.Errorf("stateless self-validation receipt root mismatch (cross: %x local: %x)", crossReceiptRoot, block.ReceiptHash())
} }
} }
proctime := time.Since(start) // processing + validation xvtime := time.Since(xvstart)
proctime := time.Since(start) // processing + validation + cross validation
// Update the metrics touched during block processing and validation // Update the metrics touched during block processing and validation
accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing) accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing)
storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing) storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing)
snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing) if statedb.AccountLoaded != 0 {
snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing) accountReadSingleTimer.Update(statedb.AccountReads / time.Duration(statedb.AccountLoaded))
}
if statedb.StorageLoaded != 0 {
storageReadSingleTimer.Update(statedb.StorageReads / time.Duration(statedb.StorageLoaded))
}
accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation) accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation)
storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation) storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation)
accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation) accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation)
triehash := statedb.AccountHashes // The time spent on tries hashing triehash := statedb.AccountHashes // The time spent on tries hashing
trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update
trieRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read blockExecutionTimer.Update(ptime - (statedb.AccountReads + statedb.StorageReads)) // The time spent on EVM processing
trieRead += statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read
blockExecutionTimer.Update(ptime - trieRead) // The time spent on EVM processing
blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation
blockCrossValidationTimer.Update(xvtime) // The time spent on stateless cross validation
// Write the block to the chain and get the status. // Write the block to the chain and get the status.
var ( var (
@ -2579,9 +2617,9 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
) )
if !setHead { if !setHead {
// Don't set the head, only insert the block // Don't set the head, only insert the block
_, err = bc.writeBlockWithState(block, receipts, logs, statedb) _, err = bc.writeBlockWithState(block, res.Receipts, res.Logs, statedb)
} else { } else {
status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false) status, err = bc.writeBlockAndSetHead(block, res.Receipts, res.Logs, statedb, false)
} }
if err != nil { if err != nil {
return nil, err return nil, err
@ -2595,7 +2633,7 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
blockWriteTimer.Update(time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits) blockWriteTimer.Update(time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits)
blockInsertTimer.UpdateSince(start) blockInsertTimer.UpdateSince(start)
return &blockProcessingResult{usedGas: usedGas, procTime: proctime, status: status}, nil return &blockProcessingResult{usedGas: res.GasUsed, procTime: proctime, status: status}, nil
} }
// insertSideChain is called when an import batch hits upon a pruned ancestor // insertSideChain is called when an import batch hits upon a pruned ancestor
@ -2605,7 +2643,7 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
// The method writes all (header-and-body-valid) blocks to disk, then tries to // The method writes all (header-and-body-valid) blocks to disk, then tries to
// switch over to the new chain if the TD exceeded the current chain. // switch over to the new chain if the TD exceeded the current chain.
// insertSideChain is only used pre-merge. // insertSideChain is only used pre-merge.
func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (int, error) { func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator, makeWitness bool) (*stateless.Witness, int, error) {
var ( var (
externTd *big.Int externTd *big.Int
lastBlock = block lastBlock = block
@ -2644,7 +2682,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
// If someone legitimately side-mines blocks, they would still be imported as usual. However, // If someone legitimately side-mines blocks, they would still be imported as usual. However,
// we cannot risk writing unverified blocks to disk when they obviously target the pruning // we cannot risk writing unverified blocks to disk when they obviously target the pruning
// mechanism. // mechanism.
return it.index, errors.New("sidechain ghost-state attack") return nil, it.index, errors.New("sidechain ghost-state attack")
} }
} }
@ -2658,7 +2696,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
start := time.Now() start := time.Now()
if err := bc.writeBlockWithoutState(block, externTd); err != nil { if err := bc.writeBlockWithoutState(block, externTd); err != nil {
return it.index, err return nil, it.index, err
} }
log.Debug("Injected sidechain block", "number", block.Number(), "hash", block.Hash(), log.Debug("Injected sidechain block", "number", block.Number(), "hash", block.Hash(),
@ -2677,19 +2715,19 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
// blocks to regenerate the required state // blocks to regenerate the required state
reorg, err := bc.forker.ReorgNeeded(current, lastBlock.Header()) reorg, err := bc.forker.ReorgNeeded(current, lastBlock.Header())
if err != nil { if err != nil {
return it.index, err return nil, it.index, err
} }
isValid, err := bc.forker.ValidateReorg(current, headers) isValid, err := bc.forker.ValidateReorg(current, headers)
if err != nil { if err != nil {
return it.index, err return nil, it.index, err
} }
if !reorg || !isValid { if !reorg || !isValid {
localTd := bc.GetTd(current.Hash(), current.Number.Uint64()) localTd := bc.GetTd(current.Hash(), current.Number.Uint64())
log.Info("Sidechain written to disk", "start", it.first().NumberU64(), "end", it.previous().Number, "sidetd", externTd, "localtd", localTd) log.Info("Sidechain written to disk", "start", it.first().NumberU64(), "end", it.previous().Number, "sidetd", externTd, "localtd", localTd)
return it.index, err return nil, it.index, err
} }
// Gather all the sidechain hashes (full blocks may be memory heavy) // Gather all the sidechain hashes (full blocks may be memory heavy)
var ( var (
@ -2701,7 +2739,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
for parent != nil && !bc.HasState(parent.Root) { for parent != nil && !bc.HasState(parent.Root) {
if bc.stateRecoverable(parent.Root) { if bc.stateRecoverable(parent.Root) {
if err := bc.triedb.Recover(parent.Root); err != nil { if err := bc.triedb.Recover(parent.Root); err != nil {
return 0, err return nil, 0, err
} }
break break
} }
@ -2712,7 +2750,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
} }
if parent == nil { if parent == nil {
return it.index, errors.New("missing parent") return nil, it.index, errors.New("missing parent")
} }
// Import all the pruned blocks to make the state available // Import all the pruned blocks to make the state available
var ( var (
@ -2732,8 +2770,8 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
// memory here. // memory here.
if len(blocks) >= 2048 || memory > 64*1024*1024 { if len(blocks) >= 2048 || memory > 64*1024*1024 {
log.Info("Importing heavy sidechain segment", "blocks", len(blocks), "start", blocks[0].NumberU64(), "end", block.NumberU64()) log.Info("Importing heavy sidechain segment", "blocks", len(blocks), "start", blocks[0].NumberU64(), "end", block.NumberU64())
if _, err := bc.insertChain(blocks, true); err != nil { if _, _, err := bc.insertChain(blocks, true, false); err != nil {
return 0, err return nil, 0, err
} }
blocks, memory = blocks[:0], 0 blocks, memory = blocks[:0], 0
@ -2741,24 +2779,23 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
// If the chain is terminating, stop processing blocks // If the chain is terminating, stop processing blocks
if bc.insertStopped() { if bc.insertStopped() {
log.Debug("Abort during blocks processing") log.Debug("Abort during blocks processing")
return 0, nil return nil, 0, nil
} }
} }
} }
if len(blocks) > 0 { if len(blocks) > 0 {
log.Info("Importing sidechain segment", "start", blocks[0].NumberU64(), "end", blocks[len(blocks)-1].NumberU64()) log.Info("Importing sidechain segment", "start", blocks[0].NumberU64(), "end", blocks[len(blocks)-1].NumberU64())
return bc.insertChain(blocks, true) return bc.insertChain(blocks, true, makeWitness)
} }
return nil, 0, nil
return 0, nil
} }
// recoverAncestors finds the closest ancestor with available state and re-execute // recoverAncestors finds the closest ancestor with available state and re-execute
// all the ancestor blocks since that. // all the ancestor blocks since that.
// recoverAncestors is only used post-merge. // recoverAncestors is only used post-merge.
// We return the hash of the latest block that we could correctly validate. // We return the hash of the latest block that we could correctly validate.
func (bc *BlockChain) recoverAncestors(block *types.Block) (common.Hash, error) { func (bc *BlockChain) recoverAncestors(block *types.Block, makeWitness bool) (common.Hash, error) {
// Gather all the sidechain hashes (full blocks may be memory heavy) // Gather all the sidechain hashes (full blocks may be memory heavy)
var ( var (
hashes []common.Hash hashes []common.Hash
@ -2801,7 +2838,7 @@ func (bc *BlockChain) recoverAncestors(block *types.Block) (common.Hash, error)
} else { } else {
b = bc.GetBlock(hashes[i], numbers[i]) b = bc.GetBlock(hashes[i], numbers[i])
} }
if _, err := bc.insertChain(types.Blocks{b}, false); err != nil { if _, _, err := bc.insertChain(types.Blocks{b}, false, makeWitness && i == 0); err != nil {
return b.ParentHash(), err return b.ParentHash(), err
} }
} }
@ -3122,14 +3159,14 @@ func ExportN(w io.Writer, blocks []*types.Block) error {
// The key difference between the InsertChain is it won't do the canonical chain // The key difference between the InsertChain is it won't do the canonical chain
// updating. It relies on the additional SetCanonical call to finalize the entire // updating. It relies on the additional SetCanonical call to finalize the entire
// procedure. // procedure.
func (bc *BlockChain) InsertBlockWithoutSetHead(block *types.Block) error { func (bc *BlockChain) InsertBlockWithoutSetHead(block *types.Block, makeWitness bool) (*stateless.Witness, error) {
if !bc.chainmu.TryLock() { if !bc.chainmu.TryLock() {
return errChainStopped return nil, errChainStopped
} }
defer bc.chainmu.Unlock() defer bc.chainmu.Unlock()
_, err := bc.insertChain(types.Blocks{block}, false) witness, _, err := bc.insertChain(types.Blocks{block}, false, makeWitness)
return err return witness, err
} }
// SetCanonical rewinds the chain to set the new head block as the specified // SetCanonical rewinds the chain to set the new head block as the specified
@ -3143,7 +3180,7 @@ func (bc *BlockChain) SetCanonical(head *types.Block) (common.Hash, error) {
// Re-execute the reorged chain in case the head state is missing. // Re-execute the reorged chain in case the head state is missing.
if !bc.HasState(head.Root()) { if !bc.HasState(head.Root()) {
if latestValidHash, err := bc.recoverAncestors(head); err != nil { if latestValidHash, err := bc.recoverAncestors(head, false); err != nil {
return latestValidHash, err return latestValidHash, err
} }
@ -3230,7 +3267,11 @@ func (bc *BlockChain) skipBlock(err error, it *insertIterator) bool {
} }
// reportBlock logs a bad block error. // reportBlock logs a bad block error.
func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, err error) { func (bc *BlockChain) reportBlock(block *types.Block, res *ProcessResult, err error) {
var receipts types.Receipts
if res != nil {
receipts = res.Receipts
}
rawdb.WriteBadBlock(bc.db, block) rawdb.WriteBadBlock(bc.db, block)
log.Error(summarizeBadBlock(block, receipts, bc.Config(), err)) log.Error(summarizeBadBlock(block, receipts, bc.Config(), err))
} }
@ -3281,7 +3322,6 @@ func (bc *BlockChain) InsertHeaderChain(chain []*types.Header) (int, error) {
} }
defer bc.chainmu.Unlock() defer bc.chainmu.Unlock()
_, err := bc.hc.InsertHeaderChain(chain, start, bc.forker) _, err := bc.hc.InsertHeaderChain(chain, start, bc.forker)
return 0, err return 0, err
} }

View file

@ -343,7 +343,7 @@ func (bc *BlockChain) GetTd(hash common.Hash, number uint64) *big.Int {
// HasState checks if state trie is fully present in the database or not. // HasState checks if state trie is fully present in the database or not.
func (bc *BlockChain) HasState(hash common.Hash) bool { func (bc *BlockChain) HasState(hash common.Hash) bool {
_, err := bc.stateCache.OpenTrie(hash) _, err := bc.statedb.OpenTrie(hash)
return err == nil return err == nil
} }
@ -377,12 +377,9 @@ func (bc *BlockChain) stateRecoverable(root common.Hash) bool {
// If the code doesn't exist in the in-memory cache, check the storage with // If the code doesn't exist in the in-memory cache, check the storage with
// new code scheme. // new code scheme.
func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) { func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) {
type codeReader interface {
ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error)
}
// TODO(rjl493456442) The associated account address is also required // TODO(rjl493456442) The associated account address is also required
// in Verkle scheme. Fix it once snap-sync is supported for Verkle. // in Verkle scheme. Fix it once snap-sync is supported for Verkle.
return bc.stateCache.(codeReader).ContractCodeWithPrefix(common.Address{}, hash) return bc.statedb.ContractCodeWithPrefix(common.Address{}, hash)
} }
// State returns a new mutable state based on the current HEAD block. // State returns a new mutable state based on the current HEAD block.
@ -392,7 +389,7 @@ func (bc *BlockChain) State() (*state.StateDB, error) {
// StateAt returns a new mutable state based on a particular point in time. // StateAt returns a new mutable state based on a particular point in time.
func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) { func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) {
return state.New(root, bc.stateCache, bc.snaps) return state.New(root, bc.statedb)
} }
// Config retrieves the chain's fork configuration. // Config retrieves the chain's fork configuration.
@ -418,7 +415,7 @@ func (bc *BlockChain) Processor() Processor {
// StateCache returns the caching database underpinning the blockchain instance. // StateCache returns the caching database underpinning the blockchain instance.
func (bc *BlockChain) StateCache() state.Database { func (bc *BlockChain) StateCache() state.Database {
return bc.stateCache return bc.statedb
} }
// GasLimit returns the gas limit of the current HEAD block. // GasLimit returns the gas limit of the current HEAD block.

View file

@ -1797,8 +1797,8 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme string) { func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme string) {
// It's hard to follow the test case, visualize the input // It's hard to follow the test case, visualize the input
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
// fmt.Println(tt.dump(true)) // fmt.Println(tt.dump(false))
// Create a temporary persistent database // Create a temporary persistent database
datadir := t.TempDir() datadir := t.TempDir()
@ -1952,7 +1952,7 @@ func TestIssue23496(t *testing.T) {
func testIssue23496(t *testing.T, scheme string) { func testIssue23496(t *testing.T, scheme string) {
// It's hard to follow the test case, visualize the input // It's hard to follow the test case, visualize the input
//log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
// Create a temporary persistent database // Create a temporary persistent database
datadir := t.TempDir() datadir := t.TempDir()

View file

@ -1961,7 +1961,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme string) { func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme string) {
// It's hard to follow the test case, visualize the input // It's hard to follow the test case, visualize the input
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
// fmt.Println(tt.dump(false)) // fmt.Println(tt.dump(false))
// Create a temporary persistent database // Create a temporary persistent database
@ -2042,7 +2042,7 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme
dbconfig.HashDB = hashdb.Defaults dbconfig.HashDB = hashdb.Defaults
} }
chain.triedb = triedb.NewDatabase(chain.db, dbconfig) chain.triedb = triedb.NewDatabase(chain.db, dbconfig)
chain.stateCache = state.NewDatabaseWithNodeDB(chain.db, chain.triedb) chain.statedb = state.NewDatabase(chain.triedb, chain.snaps)
// Force run a freeze cycle // Force run a freeze cycle
type freezer interface { type freezer interface {

View file

@ -226,8 +226,8 @@ type snapshotTest struct {
func (snaptest *snapshotTest) test(t *testing.T) { func (snaptest *snapshotTest) test(t *testing.T) {
// It's hard to follow the test case, visualize the input // It's hard to follow the test case, visualize the input
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
// fmt.Println(tt.dump()) // fmt.Println(snaptest.dump())
chain, blocks := snaptest.prepare(t) chain, blocks := snaptest.prepare(t)
// Restart the chain normally // Restart the chain normally
@ -249,8 +249,8 @@ type crashSnapshotTest struct {
func (snaptest *crashSnapshotTest) test(t *testing.T) { func (snaptest *crashSnapshotTest) test(t *testing.T) {
// It's hard to follow the test case, visualize the input // It's hard to follow the test case, visualize the input
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
// fmt.Println(tt.dump()) // fmt.Println(snaptest.dump())
chain, blocks := snaptest.prepare(t) chain, blocks := snaptest.prepare(t)
// Pull the plug on the database, simulating a hard crash // Pull the plug on the database, simulating a hard crash
@ -303,8 +303,8 @@ type gappedSnapshotTest struct {
func (snaptest *gappedSnapshotTest) test(t *testing.T) { func (snaptest *gappedSnapshotTest) test(t *testing.T) {
// It's hard to follow the test case, visualize the input // It's hard to follow the test case, visualize the input
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
// fmt.Println(tt.dump()) // fmt.Println(snaptest.dump())
chain, blocks := snaptest.prepare(t) chain, blocks := snaptest.prepare(t)
// Insert blocks without enabling snapshot if gapping is required. // Insert blocks without enabling snapshot if gapping is required.
@ -347,8 +347,8 @@ type setHeadSnapshotTest struct {
func (snaptest *setHeadSnapshotTest) test(t *testing.T) { func (snaptest *setHeadSnapshotTest) test(t *testing.T) {
// It's hard to follow the test case, visualize the input // It's hard to follow the test case, visualize the input
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
// fmt.Println(tt.dump()) // fmt.Println(snaptest.dump())
chain, blocks := snaptest.prepare(t) chain, blocks := snaptest.prepare(t)
// Rewind the chain if setHead operation is required. // Rewind the chain if setHead operation is required.
@ -376,8 +376,8 @@ type wipeCrashSnapshotTest struct {
func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
// It's hard to follow the test case, visualize the input // It's hard to follow the test case, visualize the input
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
// fmt.Println(tt.dump()) // fmt.Println(snaptest.dump())
chain, blocks := snaptest.prepare(t) chain, blocks := snaptest.prepare(t)
// Firstly, stop the chain properly, with all snapshot journal // Firstly, stop the chain properly, with all snapshot journal

View file

@ -23,6 +23,7 @@ import (
"math/big" "math/big"
"math/rand" "math/rand"
"os" "os"
"path"
"sync" "sync"
"testing" "testing"
"time" "time"
@ -170,15 +171,23 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
return err return err
} }
_, err = state.New(blockchain.GetBlockByHash(block.ParentHash()).Root(), blockchain.statedb)
receipts, _, usedGas, statedb, _, err := blockchain.ProcessBlock(block, blockchain.GetBlockByHash(block.ParentHash()).Header())
if err != nil { if err != nil {
blockchain.reportBlock(block, receipts, err)
return err return err
} }
if err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil { receipts, logs, usedGas, statedb, _, err := blockchain.ProcessBlock(block, blockchain.GetBlockByHash(block.ParentHash()).Header())
blockchain.reportBlock(block, receipts, err) res := &ProcessResult{
Receipts: receipts,
Logs: logs,
GasUsed: usedGas,
}
if err != nil {
blockchain.reportBlock(block, res, err)
return err
}
err = blockchain.validator.ValidateState(block, statedb, res, false)
if err != nil {
blockchain.reportBlock(block, res, err)
return err return err
} }
@ -225,8 +234,8 @@ func testParallelBlockChainImport(t *testing.T, scheme string, enforceParallelPr
type AlwaysFailParallelStateProcessor struct { type AlwaysFailParallelStateProcessor struct {
} }
func (p *AlwaysFailParallelStateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config, interruptCtx context.Context) (types.Receipts, []*types.Log, uint64, error) { func (p *AlwaysFailParallelStateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config, interruptCtx context.Context) (*ProcessResult, error) {
return nil, nil, 0, errors.New("always fail") return nil, errors.New("always fail")
} }
type SlowSerialStateProcessor struct { type SlowSerialStateProcessor struct {
@ -237,7 +246,7 @@ func NewSlowSerialStateProcessor(s Processor) *SlowSerialStateProcessor {
return &SlowSerialStateProcessor{s: s} return &SlowSerialStateProcessor{s: s}
} }
func (p *SlowSerialStateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config, interruptCtx context.Context) (types.Receipts, []*types.Log, uint64, error) { func (p *SlowSerialStateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config, interruptCtx context.Context) (*ProcessResult, error) {
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
return p.s.Process(block, statedb, cfg, interruptCtx) return p.s.Process(block, statedb, cfg, interruptCtx)
} }
@ -1442,7 +1451,6 @@ func testSideLogRebirth(t *testing.T, scheme string) {
if _, err := blockchain.InsertChain(sideChain); err != nil { if _, err := blockchain.InsertChain(sideChain); err != nil {
t.Fatalf("failed to insert forked chain: %v", err) t.Fatalf("failed to insert forked chain: %v", err)
} }
checkLogEvents(t, newLogCh, rmLogsCh, 0, 0) checkLogEvents(t, newLogCh, rmLogsCh, 0, 0)
// Generate a new block based on side chain. // Generate a new block based on side chain.
@ -1450,7 +1458,6 @@ func testSideLogRebirth(t *testing.T, scheme string) {
if _, err := blockchain.InsertChain(newBlocks); err != nil { if _, err := blockchain.InsertChain(newBlocks); err != nil {
t.Fatalf("failed to insert forked chain: %v", err) t.Fatalf("failed to insert forked chain: %v", err)
} }
checkLogEvents(t, newLogCh, rmLogsCh, 1, 0) checkLogEvents(t, newLogCh, rmLogsCh, 1, 0)
} }
@ -2005,7 +2012,6 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) {
if _, err := chain.InsertChain(competitor[:len(competitor)-2]); err != nil { if _, err := chain.InsertChain(competitor[:len(competitor)-2]); err != nil {
t.Fatalf("failed to insert competitor chain: %v", err) t.Fatalf("failed to insert competitor chain: %v", err)
} }
for i, block := range competitor[:len(competitor)-2] { for i, block := range competitor[:len(competitor)-2] {
if chain.HasState(block.Root()) { if chain.HasState(block.Root()) {
t.Fatalf("competitor %d: low TD chain became processed", i) t.Fatalf("competitor %d: low TD chain became processed", i)
@ -2376,9 +2382,9 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
// [ Cn, Cn+1, Cc, Sn+3 ... Sm] // [ Cn, Cn+1, Cc, Sn+3 ... Sm]
// ^ ^ ^ pruned // ^ ^ ^ pruned
func TestPrunedImportSide(t *testing.T) { func TestPrunedImportSide(t *testing.T) {
//glogger := log.NewGlogHandler(log.StreamHandler(os.Stdout, log.TerminalFormat(false))) // glogger := log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false))
//glogger.Verbosity(3) // glogger.Verbosity(3)
//log.Root().SetHandler(log.Handler(glogger)) // log.SetDefault(log.NewLogger(glogger))
testSideImport(t, 3, 3, -1) testSideImport(t, 3, 3, -1)
testSideImport(t, 3, -3, -1) testSideImport(t, 3, -3, -1)
testSideImport(t, 10, 0, -1) testSideImport(t, 10, 0, -1)
@ -2387,9 +2393,9 @@ func TestPrunedImportSide(t *testing.T) {
} }
func TestPrunedImportSideWithMerging(t *testing.T) { func TestPrunedImportSideWithMerging(t *testing.T) {
//glogger := log.NewGlogHandler(log.StreamHandler(os.Stdout, log.TerminalFormat(false))) // glogger := log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false))
//glogger.Verbosity(3) // glogger.Verbosity(3)
//log.Root().SetHandler(log.Handler(glogger)) // log.SetDefault(log.NewLogger(glogger))
testSideImport(t, 3, 3, 0) testSideImport(t, 3, 3, 0)
testSideImport(t, 3, -3, 0) testSideImport(t, 3, -3, 0)
testSideImport(t, 10, 0, 0) testSideImport(t, 10, 0, 0)
@ -3049,7 +3055,21 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) {
// Generate and import the canonical chain // Generate and import the canonical chain
_, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*state.TriesInMemory, nil) _, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*state.TriesInMemory, nil)
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil, nil) // Construct a database with freezer enabled
datadir := t.TempDir()
ancient := path.Join(datadir, "ancient")
db, err := rawdb.Open(rawdb.OpenOptions{
Directory: datadir,
AncientsDirectory: ancient,
Ephemeral: true,
})
if err != nil {
t.Fatalf("Failed to create persistent database: %v", err)
}
defer db.Close()
chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }
@ -3972,7 +3992,7 @@ func TestSetCanonical(t *testing.T) {
} }
func testSetCanonical(t *testing.T, scheme string) { func testSetCanonical(t *testing.T, scheme string) {
//log.Root().SetHandler(log.LvlFilterHandler(log.LvlDebug, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
var ( var (
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
@ -4024,7 +4044,7 @@ func testSetCanonical(t *testing.T, scheme string) {
}) })
for _, block := range side { for _, block := range side {
err := chain.InsertBlockWithoutSetHead(block) _, err := chain.InsertBlockWithoutSetHead(block, false)
if err != nil { if err != nil {
t.Fatalf("Failed to insert into chain: %v", err) t.Fatalf("Failed to insert into chain: %v", err)
} }
@ -4583,7 +4603,6 @@ func TestEIP3651(t *testing.T) {
b.AddTx(tx) b.AddTx(tx)
}) })
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr).Hooks()}, nil, nil, nil) chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr).Hooks()}, nil, nil, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create tester chain: %v", err) t.Fatalf("failed to create tester chain: %v", err)
} }

View file

@ -359,7 +359,18 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
gen(i, b) gen(i, b)
} }
body := types.Body{Transactions: b.txs, Uncles: b.uncles, Withdrawals: b.withdrawals} var requests types.Requests
if config.IsPrague(b.header.Number) && config.Bor == nil {
for _, r := range b.receipts {
d, err := ParseDepositLogs(r.Logs, config)
if err != nil {
panic(fmt.Sprintf("failed to parse deposit log: %v", err))
}
requests = append(requests, d...)
}
}
body := types.Body{Transactions: b.txs, Uncles: b.uncles, Withdrawals: b.withdrawals, Requests: requests}
block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, &body, b.receipts) block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, &body, b.receipts)
if err != nil { if err != nil {
panic(err) panic(err)
@ -381,7 +392,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
defer triedb.Close() defer triedb.Close()
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
statedb, err := state.New(parent.Root(), state.NewDatabaseWithNodeDB(db, triedb), nil) statedb, err := state.New(parent.Root(), state.NewDatabase(triedb, nil))
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -482,15 +493,14 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine
panic(fmt.Sprintf("trie write error: %v", err)) panic(fmt.Sprintf("trie write error: %v", err))
} }
// TODO uncomment when proof generation is merged proofs = append(proofs, block.ExecutionWitness().VerkleProof)
// proofs = append(proofs, block.ExecutionWitness().VerkleProof) keyvals = append(keyvals, block.ExecutionWitness().StateDiff)
// keyvals = append(keyvals, block.ExecutionWitness().StateDiff)
return block, b.receipts return block, b.receipts
} }
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
statedb, err := state.New(parent.Root(), state.NewDatabaseWithNodeDB(db, trdb), nil) statedb, err := state.New(parent.Root(), state.NewDatabase(trdb, nil))
if err != nil { if err != nil {
panic(err) panic(err)
} }

View file

@ -50,7 +50,6 @@ func TestDAOForkRangeExtradata(t *testing.T) {
BaseFee: big.NewInt(params.InitialBaseFee), BaseFee: big.NewInt(params.InitialBaseFee),
Config: &proConf, Config: &proConf,
} }
proBc, _ := NewBlockChain(proDb, nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil, nil) proBc, _ := NewBlockChain(proDb, nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
defer proBc.Stop() defer proBc.Stop()
@ -63,7 +62,6 @@ func TestDAOForkRangeExtradata(t *testing.T) {
BaseFee: big.NewInt(params.InitialBaseFee), BaseFee: big.NewInt(params.InitialBaseFee),
Config: &conConf, Config: &conConf,
} }
conBc, _ := NewBlockChain(conDb, nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil, nil) conBc, _ := NewBlockChain(conDb, nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
defer conBc.Stop() defer conBc.Stop()

View file

@ -81,25 +81,6 @@ func TestCreation(t *testing.T) {
// {50000000, 2000000000, ID{Hash: checksumToBytes(0x9f3d2254), Next: 0}}, // Future Cancun block // {50000000, 2000000000, ID{Hash: checksumToBytes(0x9f3d2254), Next: 0}}, // Future Cancun block
}, },
}, },
// Goerli test cases
{
params.GoerliChainConfig,
core.DefaultGoerliGenesisBlock().ToBlock(),
[]testcase{
{0, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block
{1561650, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Last Petersburg block
{1561651, 0, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // First Istanbul block
{4460643, 0, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // Last Istanbul block
{4460644, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // First Berlin block
{5000000, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // Last Berlin block
// {5062605, 0, ID{Hash: checksumToBytes(0xB8C6299D), Next: 1678832736}}, // First London block
// {6000000, 1678832735, ID{Hash: checksumToBytes(0xB8C6299D), Next: 1678832736}}, // Last London block
// {6000001, 1678832736, ID{Hash: checksumToBytes(0xf9843abf), Next: 1705473120}}, // First Shanghai block
// {6500002, 1705473119, ID{Hash: checksumToBytes(0xf9843abf), Next: 1705473120}}, // Last Shanghai block
// {6500003, 1705473120, ID{Hash: checksumToBytes(0x70cc14e2), Next: 0}}, // First Cancun block
// {6500003, 2705473120, ID{Hash: checksumToBytes(0x70cc14e2), Next: 0}}, // Future Cancun block
},
},
// Sepolia test cases // Sepolia test cases
{ {
params.SepoliaChainConfig, params.SepoliaChainConfig,

View file

@ -141,8 +141,8 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) {
} }
// Create an ephemeral in-memory database for computing hash, // Create an ephemeral in-memory database for computing hash,
// all the derived states will be discarded to not pollute disk. // all the derived states will be discarded to not pollute disk.
db := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), config) db := rawdb.NewMemoryDatabase()
statedb, err := state.New(types.EmptyRootHash, db, nil) statedb, err := state.New(types.EmptyRootHash, state.NewDatabase(triedb.NewDatabase(db, config), nil))
if err != nil { if err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
@ -161,13 +161,12 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) {
return statedb.Commit(0, false) return statedb.Commit(0, false)
} }
// flushAlloc is very similar with hash, but the main difference is all the generated // flushAlloc is very similar with hash, but the main difference is all the
// states will be persisted into the given database. Also, the genesis state // generated states will be persisted into the given database.
// specification will be flushed as well. func flushAlloc(ga *types.GenesisAlloc, triedb *triedb.Database) (common.Hash, error) {
func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Database, blockhash common.Hash) error { statedb, err := state.New(types.EmptyRootHash, state.NewDatabase(triedb, nil))
statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil)
if err != nil { if err != nil {
return err return common.Hash{}, err
} }
for addr, account := range *ga { for addr, account := range *ga {
@ -185,23 +184,15 @@ func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Databa
} }
root, err := statedb.Commit(0, false) root, err := statedb.Commit(0, false)
if err != nil { if err != nil {
return err return common.Hash{}, err
} }
// Commit newly generated states into disk if it's not empty. // Commit newly generated states into disk if it's not empty.
if root != types.EmptyRootHash { if root != types.EmptyRootHash {
if err := triedb.Commit(root, true); err != nil { if err := triedb.Commit(root, true); err != nil {
return err return common.Hash{}, err
} }
} }
// Marshal the genesis state specification and persist. return root, nil
blob, err := json.Marshal(ga)
if err != nil {
return err
}
rawdb.WriteGenesisStateSpec(db, blockhash, blob)
return nil
} }
func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc types.GenesisAlloc, err error) { func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc types.GenesisAlloc, err error) {
@ -223,8 +214,6 @@ func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc types.Gene
switch blockhash { switch blockhash {
case params.MainnetGenesisHash: case params.MainnetGenesisHash:
genesis = DefaultGenesisBlock() genesis = DefaultGenesisBlock()
case params.GoerliGenesisHash:
genesis = DefaultGoerliGenesisBlock()
case params.SepoliaGenesisHash: case params.SepoliaGenesisHash:
genesis = DefaultSepoliaGenesisBlock() genesis = DefaultSepoliaGenesisBlock()
case params.HoleskyGenesisHash: case params.HoleskyGenesisHash:
@ -464,7 +453,11 @@ func (g *Genesis) ToBlock() *types.Block {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return g.toBlockWithRoot(root)
}
// toBlockWithRoot constructs the genesis block with the given genesis state root.
func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block {
head := &types.Header{ head := &types.Header{
Number: new(big.Int).SetUint64(g.Number), Number: new(big.Int).SetUint64(g.Number),
Nonce: types.EncodeNonce(g.Nonce), Nonce: types.EncodeNonce(g.Nonce),
@ -494,28 +487,43 @@ func (g *Genesis) ToBlock() *types.Block {
head.BaseFee = new(big.Int).SetUint64(params.InitialBaseFee) head.BaseFee = new(big.Int).SetUint64(params.InitialBaseFee)
} }
} }
var (
var withdrawals []*types.Withdrawal withdrawals []*types.Withdrawal
requests types.Requests
)
if conf := g.Config; conf != nil { if conf := g.Config; conf != nil {
num := big.NewInt(int64(g.Number)) num := big.NewInt(int64(g.Number))
if conf.IsShanghai(num) { if conf.IsShanghai(num) {
head.WithdrawalsHash = nil head.WithdrawalsHash = &types.EmptyWithdrawalsHash
withdrawals = nil withdrawals = make([]*types.Withdrawal, 0)
} }
if conf.IsCancun(num) { if conf.IsCancun(num) {
head.ParentBeaconRoot = nil // EIP-4788: The parentBeaconBlockRoot of the genesis block is always
head.ExcessBlobGas = nil // the zero hash. This is because the genesis block does not have a parent
head.BlobGasUsed = nil // by definition.
head.ParentBeaconRoot = new(common.Hash)
// EIP-4844 fields
head.ExcessBlobGas = g.ExcessBlobGas
head.BlobGasUsed = g.BlobGasUsed
if head.ExcessBlobGas == nil {
head.ExcessBlobGas = new(uint64)
}
if head.BlobGasUsed == nil {
head.BlobGasUsed = new(uint64)
} }
} }
return types.NewBlock(head, &types.Body{Withdrawals: withdrawals}, nil, trie.NewStackTrie(nil)) if conf.IsPrague(num) {
head.RequestsHash = &types.EmptyRequestsHash
requests = make(types.Requests, 0)
}
}
return types.NewBlock(head, &types.Body{Withdrawals: withdrawals, Requests: requests}, nil, trie.NewStackTrie(nil))
} }
// Commit writes the block and state of a genesis specification to the database. // Commit writes the block and state of a genesis specification to the database.
// The block is committed as the canonical head block. // The block is committed as the canonical head block.
func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Block, error) { func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Block, error) {
block := g.ToBlock() if g.Number != 0 {
if block.Number().Sign() != 0 {
return nil, errors.New("can't commit genesis block with number > 0") return nil, errors.New("can't commit genesis block with number > 0")
} }
config := g.Config config := g.Config
@ -525,15 +533,22 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo
if err := config.CheckConfigForkOrder(); err != nil { if err := config.CheckConfigForkOrder(); err != nil {
return nil, err return nil, err
} }
if config.Clique != nil && len(block.Extra()) < 32+crypto.SignatureLength { if config.Clique != nil && len(g.ExtraData) < 32+crypto.SignatureLength {
return nil, errors.New("can't start clique chain without signers") return nil, errors.New("can't start clique chain without signers")
} }
// All the checks has passed, flushAlloc the states derived from the genesis // flush the data to disk and compute the state root
// specification as well as the specification itself into the provided root, err := flushAlloc(&g.Alloc, triedb)
// database. if err != nil {
if err := flushAlloc(&g.Alloc, db, triedb, block.Hash()); err != nil {
return nil, err return nil, err
} }
block := g.toBlockWithRoot(root)
// Marshal the genesis state specification and persist.
blob, err := json.Marshal(g.Alloc)
if err != nil {
return nil, err
}
rawdb.WriteGenesisStateSpec(db, block.Hash(), blob)
rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty()) rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty())
rawdb.WriteBlock(db, block) rawdb.WriteBlock(db, block)
rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), nil) rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), nil)
@ -577,18 +592,6 @@ func DefaultGenesisBlock() *Genesis {
} }
} }
// DefaultGoerliGenesisBlock returns the Görli network genesis block.
func DefaultGoerliGenesisBlock() *Genesis {
return &Genesis{
Config: params.GoerliChainConfig,
Timestamp: 1548854791,
ExtraData: hexutil.MustDecode("0x22466c6578692069732061207468696e6722202d204166726900000000000000e0a2bd4258d2768837baa26a28fe71dc079f84c70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
GasLimit: 10485760,
Difficulty: big.NewInt(1),
Alloc: decodePrealloc(goerliAllocData),
}
}
// DefaultSepoliaGenesisBlock returns the Sepolia network genesis block. // DefaultSepoliaGenesisBlock returns the Sepolia network genesis block.
func DefaultSepoliaGenesisBlock() *Genesis { func DefaultSepoliaGenesisBlock() *Genesis {
return &Genesis{ return &Genesis{
@ -679,6 +682,8 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis {
common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b
// Pre-deploy EIP-4788 system contract // Pre-deploy EIP-4788 system contract
params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0}, params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0},
// Pre-deploy EIP-2935 history contract.
params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode, Balance: common.Big0},
}, },
} }
if faucet != nil { if faucet != nil {

File diff suppressed because one or more lines are too long

View file

@ -35,15 +35,6 @@ import (
"github.com/ethereum/go-ethereum/triedb/pathdb" "github.com/ethereum/go-ethereum/triedb/pathdb"
) )
func TestInvalidCliqueConfig(t *testing.T) {
block := DefaultGoerliGenesisBlock()
block.ExtraData = []byte{}
db := rawdb.NewMemoryDatabase()
if _, err := block.Commit(db, triedb.NewDatabase(db, nil)); err == nil {
t.Fatal("Expected error on invalid clique config")
}
}
func TestSetupGenesis(t *testing.T) { func TestSetupGenesis(t *testing.T) {
testSetupGenesis(t, rawdb.HashScheme) testSetupGenesis(t, rawdb.HashScheme)
testSetupGenesis(t, rawdb.PathScheme) testSetupGenesis(t, rawdb.PathScheme)
@ -106,15 +97,15 @@ func testSetupGenesis(t *testing.T, scheme string) {
wantConfig: customg.Config, wantConfig: customg.Config,
}, },
{ {
name: "custom block in DB, genesis == goerli", name: "custom block in DB, genesis == sepolia",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
tdb := triedb.NewDatabase(db, newDbConfig(scheme)) tdb := triedb.NewDatabase(db, newDbConfig(scheme))
customg.Commit(db, tdb) customg.Commit(db, tdb)
return SetupGenesisBlock(db, tdb, DefaultGoerliGenesisBlock()) return SetupGenesisBlock(db, tdb, DefaultSepoliaGenesisBlock())
}, },
wantErr: &GenesisMismatchError{Stored: customghash, New: params.GoerliGenesisHash}, wantErr: &GenesisMismatchError{Stored: customghash, New: params.SepoliaGenesisHash},
wantHash: params.GoerliGenesisHash, wantHash: params.SepoliaGenesisHash,
wantConfig: params.GoerliChainConfig, wantConfig: params.SepoliaChainConfig,
}, },
{ {
name: "compatible config in DB", name: "compatible config in DB",
@ -187,7 +178,6 @@ func TestGenesisHashes(t *testing.T) {
want common.Hash want common.Hash
}{ }{
{DefaultGenesisBlock(), params.MainnetGenesisHash}, {DefaultGenesisBlock(), params.MainnetGenesisHash},
{DefaultGoerliGenesisBlock(), params.GoerliGenesisHash},
{DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash}, {DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash},
} { } {
// Test via MustCommit // Test via MustCommit
@ -313,7 +303,7 @@ func TestVerkleGenesisCommit(t *testing.T) {
}, },
} }
expected := common.FromHex("14398d42be3394ff8d50681816a4b7bf8d8283306f577faba2d5bc57498de23b") expected := common.FromHex("4a83dc39eb688dbcfaf581d60e82de18f875e38786ebce5833342011d6fef37b")
got := genesis.ToBlock().Root().Bytes() got := genesis.ToBlock().Root().Bytes()
if !bytes.Equal(got, expected) { if !bytes.Equal(got, expected) {
t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got) t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got)

View file

@ -265,7 +265,7 @@ var parallelizabilityTimer = metrics.NewRegisteredTimer("block/parallelizability
// returns the amount of gas that was used in the process. If any of the // returns the amount of gas that was used in the process. If any of the
// transactions failed to execute due to insufficient gas it will return an error. // transactions failed to execute due to insufficient gas it will return an error.
// nolint:gocognit // nolint:gocognit
func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config, interruptCtx context.Context) (types.Receipts, []*types.Log, uint64, error) { func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config, interruptCtx context.Context) (*ProcessResult, error) {
var ( var (
receipts types.Receipts receipts types.Receipts
header = block.Header() header = block.Header()
@ -301,13 +301,18 @@ func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.Stat
} }
blockContext := NewEVMBlockContext(header, p.bc, nil) blockContext := NewEVMBlockContext(header, p.bc, nil)
context := NewEVMBlockContext(header, p.bc.hc, nil)
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg)
if p.config.IsPrague(block.Number()) {
ProcessParentBlockHash(block.ParentHash(), vmenv, statedb)
}
// Iterate over and process the individual transactions // Iterate over and process the individual transactions
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
msg, err := TransactionToMessage(tx, types.MakeSigner(p.config, header.Number, header.Time), header.BaseFee) msg, err := TransactionToMessage(tx, types.MakeSigner(p.config, header.Number, header.Time), header.BaseFee)
if err != nil { if err != nil {
log.Error("error creating message", "err", err) log.Error("error creating message", "err", err)
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
} }
cleansdb := statedb.Copy() cleansdb := statedb.Copy()
@ -386,13 +391,27 @@ func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.Stat
} }
if err != nil { if err != nil {
return nil, nil, 0, err return nil, err
}
// Read requests if Prague is enabled.
var requests types.Requests
if p.config.IsPrague(block.Number()) && p.config.Bor == nil {
requests, err = ParseDepositLogs(allLogs, p.config)
if err != nil {
return nil, err
}
} }
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards) // Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
p.engine.Finalize(p.bc, header, statedb, block.Body()) p.engine.Finalize(p.bc, header, statedb, block.Body())
return receipts, allLogs, *usedGas, nil return &ProcessResult{
Receipts: receipts,
Requests: requests,
Logs: allLogs,
GasUsed: *usedGas,
}, nil
} }
func GetDeps(txDependency [][]uint64) map[int][]int { func GetDeps(txDependency [][]uint64) map[int][]int {

View file

@ -303,6 +303,10 @@ func ParseStateScheme(provided string, disk ethdb.Database) (string, error) {
log.Info("State scheme set to already existing", "scheme", stored) log.Info("State scheme set to already existing", "scheme", stored)
return stored, nil // reuse scheme of persistent scheme return stored, nil // reuse scheme of persistent scheme
} }
// If state scheme is specified, ensure it's valid.
if provided != HashScheme && provided != PathScheme {
return "", fmt.Errorf("invalid state scheme %s", provided)
}
// If state scheme is specified, ensure it's compatible with // If state scheme is specified, ensure it's compatible with
// persistent state. // persistent state.
if stored == "" || provided == stored { if stored == "" || provided == stored {

View file

@ -164,12 +164,6 @@ func (db *nofreezedb) ReadAncients(fn func(reader ethdb.AncientReaderOp) error)
return fn(db) return fn(db)
} }
// MigrateTable processes the entries in a given table in sequence
// converting them to a new format if they're of an old format.
func (db *nofreezedb) MigrateTable(kind string, convert convertLegacyFn) error {
return errNotSupported
}
// AncientDatadir returns an error as we don't have a backing chain freezer. // AncientDatadir returns an error as we don't have a backing chain freezer.
func (db *nofreezedb) AncientDatadir() (string, error) { func (db *nofreezedb) AncientDatadir() (string, error) {
return "", errNotSupported return "", errNotSupported

View file

@ -54,13 +54,11 @@ var (
// freezerTableSize defines the maximum size of freezer data files. // freezerTableSize defines the maximum size of freezer data files.
const freezerTableSize = 2 * 1000 * 1000 * 1000 const freezerTableSize = 2 * 1000 * 1000 * 1000
// Freezer is a memory mapped append-only database to store immutable ordered // Freezer is an append-only database to store immutable ordered data into
// data into flat files: // flat files:
// //
// - The append-only nature ensures that disk writes are minimized. // - The append-only nature ensures that disk writes are minimized.
// - The memory mapping ensures we can max out system memory for caching without // - The in-order data ensures that disk reads are always optimized.
// reserving it for go-ethereum. This would also reduce the memory requirements
// of Geth, and thus also GC overhead.
type Freezer struct { type Freezer struct {
frozen atomic.Uint64 // Number of items already frozen frozen atomic.Uint64 // Number of items already frozen
tail atomic.Uint64 // Number of the first stored item in the freezer tail atomic.Uint64 // Number of the first stored item in the freezer
@ -162,7 +160,7 @@ func NewFreezer(datadir string, namespace string, readonly bool, offset uint64,
return freezer, nil return freezer, nil
} }
// Close terminates the chain freezer, unmapping all the data files. // Close terminates the chain freezer, closing all the data files.
func (f *Freezer) Close() error { func (f *Freezer) Close() error {
f.writeLock.Lock() f.writeLock.Lock()
defer f.writeLock.Unlock() defer f.writeLock.Unlock()

View file

@ -413,13 +413,6 @@ func (f *MemoryFreezer) Sync() error {
return nil return nil
} }
// MigrateTable processes and migrates entries of a given table to a new format.
// The second argument is a function that takes a raw entry and returns it
// in the newest format.
func (f *MemoryFreezer) MigrateTable(string, func([]byte) ([]byte, error)) error {
return errors.New("not implemented")
}
// Close releases all the sources held by the memory freezer. It will panic if // Close releases all the sources held by the memory freezer. It will panic if
// any following invocation is made to a closed freezer. // any following invocation is made to a closed freezer.
func (f *MemoryFreezer) Close() error { func (f *MemoryFreezer) Close() error {

View file

@ -219,15 +219,6 @@ func (f *resettableFreezer) Sync() error {
return f.freezer.Sync() return f.freezer.Sync()
} }
// MigrateTable processes the entries in a given table in sequence
// converting them to a new format if they're of an old format.
func (f *resettableFreezer) MigrateTable(kind string, convert convertLegacyFn) error {
f.lock.RLock()
defer f.lock.RUnlock()
return f.freezer.MigrateTable(kind, convert)
}
// cleanup removes the directory located in the specified path // cleanup removes the directory located in the specified path
// has the name with deletion marker suffix. // has the name with deletion marker suffix.
func cleanup(path string) error { func cleanup(path string) error {

View file

@ -22,8 +22,6 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"math/rand" "math/rand"
"os"
"path/filepath"
"sync" "sync"
"testing" "testing"
@ -418,99 +416,6 @@ func checkAncientCount(t *testing.T, f *Freezer, kind string, n uint64) {
} }
} }
func TestRenameWindows(t *testing.T) {
var (
fname = "file.bin"
fname2 = "file2.bin"
data = []byte{1, 2, 3, 4}
data2 = []byte{2, 3, 4, 5}
data3 = []byte{3, 5, 6, 7}
dataLen = 4
)
// Create 2 temp dirs
dir1 := t.TempDir()
dir2 := t.TempDir()
// Create file in dir1 and fill with data
f, err := os.Create(filepath.Join(dir1, fname))
if err != nil {
t.Fatal(err)
}
f2, err := os.Create(filepath.Join(dir1, fname2))
if err != nil {
t.Fatal(err)
}
f3, err := os.Create(filepath.Join(dir2, fname2))
if err != nil {
t.Fatal(err)
}
if _, err := f.Write(data); err != nil {
t.Fatal(err)
}
if _, err := f2.Write(data2); err != nil {
t.Fatal(err)
}
if _, err := f3.Write(data3); err != nil {
t.Fatal(err)
}
if err := f.Close(); err != nil {
t.Fatal(err)
}
if err := f2.Close(); err != nil {
t.Fatal(err)
}
if err := f3.Close(); err != nil {
t.Fatal(err)
}
if err := os.Rename(f.Name(), filepath.Join(dir2, fname)); err != nil {
t.Fatal(err)
}
if err := os.Rename(f2.Name(), filepath.Join(dir2, fname2)); err != nil {
t.Fatal(err)
}
// Check file contents
f, err = os.Open(filepath.Join(dir2, fname))
if err != nil {
t.Fatal(err)
}
defer f.Close()
defer os.Remove(f.Name())
buf := make([]byte, dataLen)
if _, err := f.Read(buf); err != nil {
t.Fatal(err)
}
if !bytes.Equal(buf, data) {
t.Errorf("unexpected file contents. Got %v\n", buf)
}
f, err = os.Open(filepath.Join(dir2, fname2))
if err != nil {
t.Fatal(err)
}
defer f.Close()
defer os.Remove(f.Name())
if _, err := f.Read(buf); err != nil {
t.Fatal(err)
}
if !bytes.Equal(buf, data2) {
t.Errorf("unexpected file contents. Got %v\n", buf)
}
}
func TestFreezerCloseSync(t *testing.T) { func TestFreezerCloseSync(t *testing.T) {
t.Parallel() t.Parallel()

View file

@ -123,12 +123,6 @@ func (t *table) Sync() error {
return t.db.Sync() return t.db.Sync()
} }
// MigrateTable processes the entries in a given table in sequence
// converting them to a new format if they're of an old format.
func (t *table) MigrateTable(kind string, convert convertLegacyFn) error {
return t.db.MigrateTable(kind, convert)
}
// AncientDatadir returns the ancient datadir of the underlying database. // AncientDatadir returns the ancient datadir of the underlying database.
func (t *table) AncientDatadir() (string, error) { func (t *table) AncientDatadir() (string, error) {
return t.db.AncientDatadir() return t.db.AncientDatadir()

View file

@ -28,8 +28,8 @@ import (
// mode specifies how a tree location has been accessed // mode specifies how a tree location has been accessed
// for the byte value: // for the byte value:
// * the first bit is set if the branch has been edited // * the first bit is set if the branch has been read
// * the second bit is set if the branch has been read // * the second bit is set if the branch has been edited
type mode byte type mode byte
const ( const (
@ -94,11 +94,8 @@ func (ae *AccessEvents) Copy() *AccessEvents {
// member fields of an account. // member fields of an account.
func (ae *AccessEvents) AddAccount(addr common.Address, isWrite bool) uint64 { func (ae *AccessEvents) AddAccount(addr common.Address, isWrite bool) uint64 {
var gas uint64 var gas uint64
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite) gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, isWrite)
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, isWrite) gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, isWrite)
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, isWrite)
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, isWrite)
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, isWrite)
return gas return gas
} }
@ -107,8 +104,7 @@ func (ae *AccessEvents) AddAccount(addr common.Address, isWrite bool) uint64 {
// call to that account. // call to that account.
func (ae *AccessEvents) MessageCallGas(destination common.Address) uint64 { func (ae *AccessEvents) MessageCallGas(destination common.Address) uint64 {
var gas uint64 var gas uint64
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.VersionLeafKey, false) gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.BasicDataLeafKey, false)
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.CodeSizeLeafKey, false)
return gas return gas
} }
@ -116,41 +112,43 @@ func (ae *AccessEvents) MessageCallGas(destination common.Address) uint64 {
// cold balance member fields of the caller and the callee accounts. // cold balance member fields of the caller and the callee accounts.
func (ae *AccessEvents) ValueTransferGas(callerAddr, targetAddr common.Address) uint64 { func (ae *AccessEvents) ValueTransferGas(callerAddr, targetAddr common.Address) uint64 {
var gas uint64 var gas uint64
gas += ae.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BalanceLeafKey, true) gas += ae.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BasicDataLeafKey, true)
gas += ae.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BalanceLeafKey, true) gas += ae.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BasicDataLeafKey, true)
return gas
}
// ContractCreateCPreheck charges access costs before
// a contract creation is initiated. It is just reads, because the
// address collision is done before the transfer, and so no write
// are guaranteed to happen at this point.
func (ae *AccessEvents) ContractCreatePreCheckGas(addr common.Address) uint64 {
var gas uint64
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, false)
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, false)
return gas return gas
} }
// ContractCreateInitGas returns the access gas costs for the initialization of // ContractCreateInitGas returns the access gas costs for the initialization of
// a contract creation. // a contract creation.
func (ae *AccessEvents) ContractCreateInitGas(addr common.Address, createSendsValue bool) uint64 { func (ae *AccessEvents) ContractCreateInitGas(addr common.Address) uint64 {
var gas uint64 var gas uint64
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, true) gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, true)
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, true) gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, true)
if createSendsValue {
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, true)
}
return gas return gas
} }
// AddTxOrigin adds the member fields of the sender account to the access event list, // AddTxOrigin adds the member fields of the sender account to the access event list,
// so that cold accesses are not charged, since they are covered by the 21000 gas. // so that cold accesses are not charged, since they are covered by the 21000 gas.
func (ae *AccessEvents) AddTxOrigin(originAddr common.Address) { func (ae *AccessEvents) AddTxOrigin(originAddr common.Address) {
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.VersionLeafKey, false) ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.BasicDataLeafKey, true)
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.BalanceLeafKey, true) ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeHashLeafKey, false)
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.NonceLeafKey, true)
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeKeccakLeafKey, false)
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeSizeLeafKey, false)
} }
// AddTxDestination adds the member fields of the sender account to the access event list, // AddTxDestination adds the member fields of the sender account to the access event list,
// so that cold accesses are not charged, since they are covered by the 21000 gas. // so that cold accesses are not charged, since they are covered by the 21000 gas.
func (ae *AccessEvents) AddTxDestination(addr common.Address, sendsValue bool) { func (ae *AccessEvents) AddTxDestination(addr common.Address, sendsValue bool) {
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, false) ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, sendsValue)
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, sendsValue) ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, false)
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, false)
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, false)
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, false)
} }
// SlotGas returns the amount of gas to be charged for a cold storage access. // SlotGas returns the amount of gas to be charged for a cold storage access.
@ -275,39 +273,12 @@ func (ae *AccessEvents) CodeChunksRangeGas(contractAddr common.Address, startPC,
return statelessGasCharged return statelessGasCharged
} }
// VersionGas adds the account's version to the accessed data, and returns the // BasicDataGas adds the account's basic data to the accessed data, and returns the
// amount of gas that it costs. // amount of gas that it costs.
// Note that an access in write mode implies an access in read mode, whereas an // Note that an access in write mode implies an access in read mode, whereas an
// access in read mode does not imply an access in write mode. // access in read mode does not imply an access in write mode.
func (ae *AccessEvents) VersionGas(addr common.Address, isWrite bool) uint64 { func (ae *AccessEvents) BasicDataGas(addr common.Address, isWrite bool) uint64 {
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite) return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, isWrite)
}
// BalanceGas adds the account's balance to the accessed data, and returns the
// amount of gas that it costs.
// in write mode. If false, the charged gas corresponds to an access in read mode.
// Note that an access in write mode implies an access in read mode, whereas an access in
// read mode does not imply an access in write mode.
func (ae *AccessEvents) BalanceGas(addr common.Address, isWrite bool) uint64 {
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, isWrite)
}
// NonceGas adds the account's nonce to the accessed data, and returns the
// amount of gas that it costs.
// in write mode. If false, the charged gas corresponds to an access in read mode.
// Note that an access in write mode implies an access in read mode, whereas an access in
// read mode does not imply an access in write mode.
func (ae *AccessEvents) NonceGas(addr common.Address, isWrite bool) uint64 {
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, isWrite)
}
// CodeSizeGas adds the account's code size to the accessed data, and returns the
// amount of gas that it costs.
// in write mode. If false, the charged gas corresponds to an access in read mode.
// Note that an access in write mode implies an access in read mode, whereas an access in
// read mode does not imply an access in write mode.
func (ae *AccessEvents) CodeSizeGas(addr common.Address, isWrite bool) uint64 {
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, isWrite)
} }
// CodeHashGas adds the account's code hash to the accessed data, and returns the // CodeHashGas adds the account's code hash to the accessed data, and returns the
@ -316,5 +287,5 @@ func (ae *AccessEvents) CodeSizeGas(addr common.Address, isWrite bool) uint64 {
// Note that an access in write mode implies an access in read mode, whereas an access in // Note that an access in write mode implies an access in read mode, whereas an access in
// read mode does not imply an access in write mode. // read mode does not imply an access in write mode.
func (ae *AccessEvents) CodeHashGas(addr common.Address, isWrite bool) uint64 { func (ae *AccessEvents) CodeHashGas(addr common.Address, isWrite bool) uint64 {
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, isWrite) return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, isWrite)
} }

View file

@ -40,55 +40,43 @@ func TestAccountHeaderGas(t *testing.T) {
ae := NewAccessEvents(utils.NewPointCache(1024)) ae := NewAccessEvents(utils.NewPointCache(1024))
// Check cold read cost // Check cold read cost
gas := ae.VersionGas(testAddr, false) gas := ae.BasicDataGas(testAddr, false)
if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost; gas != want { if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost; gas != want {
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
} }
// Check warm read cost // Check warm read cost
gas = ae.VersionGas(testAddr, false) gas = ae.BasicDataGas(testAddr, false)
if gas != 0 { if gas != 0 {
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0) t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
} }
// Check cold read costs in the same group no longer incur the branch read cost // Check cold read costs in the same group no longer incur the branch read cost
gas = ae.BalanceGas(testAddr, false)
if gas != params.WitnessChunkReadCost {
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
}
gas = ae.NonceGas(testAddr, false)
if gas != params.WitnessChunkReadCost {
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
}
gas = ae.CodeSizeGas(testAddr, false)
if gas != params.WitnessChunkReadCost {
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
}
gas = ae.CodeHashGas(testAddr, false) gas = ae.CodeHashGas(testAddr, false)
if gas != params.WitnessChunkReadCost { if gas != params.WitnessChunkReadCost {
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost) t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
} }
// Check cold write cost // Check cold write cost
gas = ae.VersionGas(testAddr, true) gas = ae.BasicDataGas(testAddr, true)
if want := params.WitnessBranchWriteCost + params.WitnessChunkWriteCost; gas != want { if want := params.WitnessBranchWriteCost + params.WitnessChunkWriteCost; gas != want {
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
} }
// Check warm write cost // Check warm write cost
gas = ae.VersionGas(testAddr, true) gas = ae.BasicDataGas(testAddr, true)
if gas != 0 { if gas != 0 {
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0) t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
} }
// Check a write without a read charges both read and write costs // Check a write without a read charges both read and write costs
gas = ae.BalanceGas(testAddr2, true) gas = ae.BasicDataGas(testAddr2, true)
if want := params.WitnessBranchReadCost + params.WitnessBranchWriteCost + params.WitnessChunkWriteCost + params.WitnessChunkReadCost; gas != want { if want := params.WitnessBranchReadCost + params.WitnessBranchWriteCost + params.WitnessChunkWriteCost + params.WitnessChunkReadCost; gas != want {
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
} }
// Check that a write followed by a read charges nothing // Check that a write followed by a read charges nothing
gas = ae.BalanceGas(testAddr2, false) gas = ae.BasicDataGas(testAddr2, false)
if gas != 0 { if gas != 0 {
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0) t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
} }
@ -112,13 +100,13 @@ func TestContractCreateInitGas(t *testing.T) {
} }
// Check cold read cost, without a value // Check cold read cost, without a value
gas := ae.ContractCreateInitGas(testAddr, false) gas := ae.ContractCreateInitGas(testAddr)
if want := params.WitnessBranchWriteCost + params.WitnessBranchReadCost + params.WitnessChunkWriteCost*2 + params.WitnessChunkReadCost*2; gas != want { if want := params.WitnessBranchWriteCost + params.WitnessBranchReadCost + 2*params.WitnessChunkWriteCost + 2*params.WitnessChunkReadCost; gas != want {
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
} }
// Check warm read cost // Check warm read cost
gas = ae.ContractCreateInitGas(testAddr, false) gas = ae.ContractCreateInitGas(testAddr)
if gas != 0 { if gas != 0 {
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0) t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
} }
@ -131,17 +119,17 @@ func TestMessageCallGas(t *testing.T) {
// Check cold read cost, without a value // Check cold read cost, without a value
gas := ae.MessageCallGas(testAddr) gas := ae.MessageCallGas(testAddr)
if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost*2; gas != want { if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost; gas != want {
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
} }
// Check that reading the version and code size of the same account does not incur the branch read cost // Check that reading the basic data and code hash of the same account does not incur the branch read cost
gas = ae.VersionGas(testAddr, false) gas = ae.BasicDataGas(testAddr, false)
if gas != 0 { if gas != 0 {
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0) t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
} }
gas = ae.CodeSizeGas(testAddr, false) gas = ae.CodeHashGas(testAddr, false)
if gas != 0 { if gas != params.WitnessChunkReadCost {
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0) t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
} }

View file

@ -23,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/common/lru"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state/snapshot"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
@ -45,29 +46,29 @@ const (
// Database wraps access to tries and contract code. // Database wraps access to tries and contract code.
type Database interface { type Database interface {
// Reader returns a state reader associated with the specified state root.
Reader(root common.Hash) (Reader, error)
// OpenTrie opens the main account trie. // OpenTrie opens the main account trie.
OpenTrie(root common.Hash) (Trie, error) OpenTrie(root common.Hash) (Trie, error)
// OpenStorageTrie opens the storage trie of an account. // OpenStorageTrie opens the storage trie of an account.
OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, trie Trie) (Trie, error) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, trie Trie) (Trie, error)
// CopyTrie returns an independent copy of the given trie.
CopyTrie(Trie) Trie
// ContractCode retrieves a particular contract's code. // ContractCode retrieves a particular contract's code.
ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error) ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error)
// ContractCodeSize retrieves a particular contracts code's size. // ContractCodeSize retrieves a particular contracts code's size.
ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error)
// DiskDB returns the underlying key-value disk database.
DiskDB() ethdb.KeyValueStore
// PointCache returns the cache holding points used in verkle tree key computation // PointCache returns the cache holding points used in verkle tree key computation
PointCache() *utils.PointCache PointCache() *utils.PointCache
// TrieDB returns the underlying trie database for managing trie nodes. // TrieDB returns the underlying trie database for managing trie nodes.
TrieDB() *triedb.Database TrieDB() *triedb.Database
// Snapshot returns the underlying state snapshot.
Snapshot() *snapshot.Tree
} }
// Trie is a Ethereum Merkle Patricia trie. // Trie is a Ethereum Merkle Patricia trie.
@ -94,7 +95,7 @@ type Trie interface {
// UpdateAccount abstracts an account write to the trie. It encodes the // UpdateAccount abstracts an account write to the trie. It encodes the
// provided account object with associated algorithm and then updates it // provided account object with associated algorithm and then updates it
// in the trie with provided address. // in the trie with provided address.
UpdateAccount(address common.Address, account *types.StateAccount) error UpdateAccount(address common.Address, account *types.StateAccount, codeLen int) error
// UpdateStorage associates key with value in the trie. If value has length zero, // UpdateStorage associates key with value in the trie. If value has length zero,
// any existing value is deleted from the trie. The value bytes must not be modified // any existing value is deleted from the trie. The value bytes must not be modified
@ -147,47 +148,62 @@ type Trie interface {
IsVerkle() bool IsVerkle() bool
} }
// NewDatabase creates a backing store for state. The returned database is safe for // CachingDB is an implementation of Database interface. It leverages both trie and
// concurrent use, but does not retain any recent trie nodes in memory. To keep some // state snapshot to provide functionalities for state access. It's meant to be a
// historical state in memory, use the NewDatabaseWithConfig constructor. // long-live object and has a few caches inside for sharing between blocks.
func NewDatabase(db ethdb.Database) Database { type CachingDB struct {
return NewDatabaseWithConfig(db, nil)
}
// NewDatabaseWithConfig creates a backing store for state. The returned database
// is safe for concurrent use and retains a lot of collapsed RLP trie nodes in a
// large memory cache.
func NewDatabaseWithConfig(db ethdb.Database, config *triedb.Config) Database {
return &cachingDB{
disk: db,
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
triedb: triedb.NewDatabase(db, config),
pointCache: utils.NewPointCache(pointCacheSize),
}
}
// NewDatabaseWithNodeDB creates a state database with an already initialized node database.
func NewDatabaseWithNodeDB(db ethdb.Database, triedb *triedb.Database) Database {
return &cachingDB{
disk: db,
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
triedb: triedb,
pointCache: utils.NewPointCache(pointCacheSize),
}
}
type cachingDB struct {
disk ethdb.KeyValueStore disk ethdb.KeyValueStore
codeSizeCache *lru.Cache[common.Hash, int]
codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
triedb *triedb.Database triedb *triedb.Database
snap *snapshot.Tree
codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
codeSizeCache *lru.Cache[common.Hash, int]
pointCache *utils.PointCache pointCache *utils.PointCache
} }
// NewDatabase creates a state database with the provided data sources.
func NewDatabase(triedb *triedb.Database, snap *snapshot.Tree) *CachingDB {
return &CachingDB{
disk: triedb.Disk(),
triedb: triedb,
snap: snap,
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
pointCache: utils.NewPointCache(pointCacheSize),
}
}
// NewDatabaseForTesting is similar to NewDatabase, but it initializes the caching
// db by using an ephemeral memory db with default config for testing.
func NewDatabaseForTesting() *CachingDB {
return NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil), nil)
}
// Reader returns a state reader associated with the specified state root.
func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) {
var readers []Reader
// Set up the state snapshot reader if available. This feature
// is optional and may be partially useful if it's not fully
// generated.
if db.snap != nil {
sr, err := newStateReader(stateRoot, db.snap)
if err == nil {
readers = append(readers, sr) // snap reader is optional
}
}
// Set up the trie reader, which is expected to always be available
// as the gatekeeper unless the state is corrupted.
tr, err := newTrieReader(stateRoot, db.triedb, db.pointCache)
if err != nil {
return nil, err
}
readers = append(readers, tr)
return newMultiReader(readers...)
}
// OpenTrie opens the main account trie at a specific root hash. // OpenTrie opens the main account trie at a specific root hash.
func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { func (db *CachingDB) OpenTrie(root common.Hash) (Trie, error) {
if db.triedb.IsVerkle() { if db.triedb.IsVerkle() {
return trie.NewVerkleTrie(root, db.triedb, db.pointCache) return trie.NewVerkleTrie(root, db.triedb, db.pointCache)
} }
@ -200,7 +216,7 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
} }
// OpenStorageTrie opens the storage trie of an account. // OpenStorageTrie opens the storage trie of an account.
func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, self Trie) (Trie, error) { func (db *CachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, self Trie) (Trie, error) {
// In the verkle case, there is only one tree. But the two-tree structure // In the verkle case, there is only one tree. But the two-tree structure
// is hardcoded in the codebase. So we need to return the same trie in this // is hardcoded in the codebase. So we need to return the same trie in this
// case. // case.
@ -215,20 +231,8 @@ func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Addre
return tr, nil return tr, nil
} }
// CopyTrie returns an independent copy of the given trie.
func (db *cachingDB) CopyTrie(t Trie) Trie {
switch t := t.(type) {
case *trie.StateTrie:
return t.Copy()
case *trie.VerkleTrie:
return t.Copy()
default:
panic(fmt.Errorf("unknown trie type %T", t))
}
}
// ContractCode retrieves a particular contract's code. // ContractCode retrieves a particular contract's code.
func (db *cachingDB) ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) { func (db *CachingDB) ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) {
code, _ := db.codeCache.Get(codeHash) code, _ := db.codeCache.Get(codeHash)
if len(code) > 0 { if len(code) > 0 {
return code, nil return code, nil
@ -249,7 +253,7 @@ func (db *cachingDB) ContractCode(address common.Address, codeHash common.Hash)
// ContractCodeWithPrefix retrieves a particular contract's code. If the // ContractCodeWithPrefix retrieves a particular contract's code. If the
// code can't be found in the cache, then check the existence with **new** // code can't be found in the cache, then check the existence with **new**
// db scheme. // db scheme.
func (db *cachingDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) { func (db *CachingDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) {
code, _ := db.codeCache.Get(codeHash) code, _ := db.codeCache.Get(codeHash)
if len(code) > 0 { if len(code) > 0 {
return code, nil return code, nil
@ -268,7 +272,7 @@ func (db *cachingDB) ContractCodeWithPrefix(address common.Address, codeHash com
} }
// ContractCodeSize retrieves a particular contracts code's size. // ContractCodeSize retrieves a particular contracts code's size.
func (db *cachingDB) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) { func (db *CachingDB) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) {
if cached, ok := db.codeSizeCache.Get(codeHash); ok { if cached, ok := db.codeSizeCache.Get(codeHash); ok {
return cached, nil return cached, nil
} }
@ -276,17 +280,29 @@ func (db *cachingDB) ContractCodeSize(addr common.Address, codeHash common.Hash)
return len(code), err return len(code), err
} }
// DiskDB returns the underlying key-value disk database.
func (db *cachingDB) DiskDB() ethdb.KeyValueStore {
return db.disk
}
// TrieDB retrieves any intermediate trie-node caching layer. // TrieDB retrieves any intermediate trie-node caching layer.
func (db *cachingDB) TrieDB() *triedb.Database { func (db *CachingDB) TrieDB() *triedb.Database {
return db.triedb return db.triedb
} }
// PointCache returns the cache of evaluated curve points. // PointCache returns the cache of evaluated curve points.
func (db *cachingDB) PointCache() *utils.PointCache { func (db *CachingDB) PointCache() *utils.PointCache {
return db.pointCache return db.pointCache
} }
// Snapshot returns the underlying state snapshot.
func (db *CachingDB) Snapshot() *snapshot.Tree {
return db.snap
}
// mustCopyTrie returns a deep-copied trie.
func mustCopyTrie(t Trie) Trie {
switch t := t.(type) {
case *trie.StateTrie:
return t.Copy()
case *trie.VerkleTrie:
return t.Copy()
default:
panic(fmt.Errorf("unknown trie type %T", t))
}
}

View file

@ -35,7 +35,7 @@ func testNodeIteratorCoverage(t *testing.T, scheme string) {
db, sdb, ndb, root, _ := makeTestState(scheme) db, sdb, ndb, root, _ := makeTestState(scheme)
ndb.Commit(root, false) ndb.Commit(root, false)
state, err := New(root, sdb, nil) state, err := New(root, sdb)
if err != nil { if err != nil {
t.Fatalf("failed to create state trie at %x: %v", root, err) t.Fatalf("failed to create state trie at %x: %v", root, err)
} }

View file

@ -17,13 +17,21 @@
package state package state
import ( import (
"fmt"
"maps" "maps"
"slices"
"sort"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/blockstm" "github.com/ethereum/go-ethereum/core/types"
"github.com/holiman/uint256" "github.com/holiman/uint256"
) )
type revision struct {
id int
journalIndex int
}
// journalEntry is a modification entry in the state change journal that can be // journalEntry is a modification entry in the state change journal that can be
// reverted on demand. // reverted on demand.
type journalEntry interface { type journalEntry interface {
@ -43,6 +51,9 @@ type journalEntry interface {
type journal struct { type journal struct {
entries []journalEntry // Current changes tracked by the journal entries []journalEntry // Current changes tracked by the journal
dirties map[common.Address]int // Dirty accounts and the number of changes dirties map[common.Address]int // Dirty accounts and the number of changes
validRevisions []revision
nextRevisionId int
} }
// newJournal creates a new initialized journal. // newJournal creates a new initialized journal.
@ -52,6 +63,40 @@ func newJournal() *journal {
} }
} }
// reset clears the journal, after this operation the journal can be used anew.
// It is semantically similar to calling 'newJournal', but the underlying slices
// can be reused.
func (j *journal) reset() {
j.entries = j.entries[:0]
j.validRevisions = j.validRevisions[:0]
clear(j.dirties)
j.nextRevisionId = 0
}
// snapshot returns an identifier for the current revision of the state.
func (j *journal) snapshot() int {
id := j.nextRevisionId
j.nextRevisionId++
j.validRevisions = append(j.validRevisions, revision{id, j.length()})
return id
}
// revertToSnapshot reverts all state changes made since the given revision.
func (j *journal) revertToSnapshot(revid int, s *StateDB) {
// Find the snapshot in the stack of valid snapshots.
idx := sort.Search(len(j.validRevisions), func(i int) bool {
return j.validRevisions[i].id >= revid
})
if idx == len(j.validRevisions) || j.validRevisions[idx].id != revid {
panic(fmt.Errorf("revision id %v cannot be reverted", revid))
}
snapshot := j.validRevisions[idx].journalIndex
// Replay the journal to undo changes and remove invalidated snapshots
j.revert(s, snapshot)
j.validRevisions = j.validRevisions[:idx]
}
// append inserts a new modification entry to the end of the change journal. // append inserts a new modification entry to the end of the change journal.
func (j *journal) append(entry journalEntry) { func (j *journal) append(entry journalEntry) {
j.entries = append(j.entries, entry) j.entries = append(j.entries, entry)
@ -99,46 +144,120 @@ func (j *journal) copy() *journal {
return &journal{ return &journal{
entries: entries, entries: entries,
dirties: maps.Clone(j.dirties), dirties: maps.Clone(j.dirties),
validRevisions: slices.Clone(j.validRevisions),
nextRevisionId: j.nextRevisionId,
} }
} }
func (j *journal) logChange(txHash common.Hash) {
j.append(addLogChange{txhash: txHash})
}
func (j *journal) createObject(addr common.Address) {
j.append(createObjectChange{account: addr})
}
func (j *journal) createContract(addr common.Address) {
j.append(createContractChange{account: addr})
}
func (j *journal) destruct(addr common.Address) {
j.append(selfDestructChange{account: addr})
}
func (j *journal) storageChange(addr common.Address, key, prev, origin common.Hash) {
j.append(storageChange{
account: addr,
key: key,
prevvalue: prev,
origvalue: origin,
})
}
func (j *journal) transientStateChange(addr common.Address, key, prev common.Hash) {
j.append(transientStorageChange{
account: addr,
key: key,
prevalue: prev,
})
}
func (j *journal) refundChange(previous uint64) {
j.append(refundChange{prev: previous})
}
func (j *journal) balanceChange(addr common.Address, previous *uint256.Int) {
j.append(balanceChange{
account: addr,
prev: previous.Clone(),
})
}
func (j *journal) setCode(address common.Address) {
j.append(codeChange{account: address})
}
func (j *journal) nonceChange(address common.Address, prev uint64) {
j.append(nonceChange{
account: address,
prev: prev,
})
}
func (j *journal) touchChange(address common.Address) {
j.append(touchChange{
account: address,
})
if address == ripemd {
// Explicitly put it in the dirty-cache, which is otherwise generated from
// flattened journals.
j.dirty(address)
}
}
func (j *journal) accessListAddAccount(addr common.Address) {
j.append(accessListAddAccountChange{addr})
}
func (j *journal) accessListAddSlot(addr common.Address, slot common.Hash) {
j.append(accessListAddSlotChange{
address: addr,
slot: slot,
})
}
type ( type (
// Changes to the account trie. // Changes to the account trie.
createObjectChange struct { createObjectChange struct {
account *common.Address account common.Address
} }
// createContractChange represents an account becoming a contract-account. // createContractChange represents an account becoming a contract-account.
// This event happens prior to executing initcode. The journal-event simply // This event happens prior to executing initcode. The journal-event simply
// manages the created-flag, in order to allow same-tx destruction. // manages the created-flag, in order to allow same-tx destruction.
createContractChange struct { createContractChange struct {
account common.Address account common.Address
} }
selfDestructChange struct { selfDestructChange struct {
account *common.Address account common.Address
prev bool // whether account had already self-destructed
prevbalance *uint256.Int
} }
// Changes to individual accounts. // Changes to individual accounts.
balanceChange struct { balanceChange struct {
account *common.Address account common.Address
prev *uint256.Int prev *uint256.Int
} }
nonceChange struct { nonceChange struct {
account *common.Address account common.Address
prev uint64 prev uint64
} }
storageChange struct { storageChange struct {
account *common.Address account common.Address
key common.Hash key common.Hash
prevvalue common.Hash prevvalue common.Hash
origvalue common.Hash origvalue common.Hash
} }
codeChange struct { codeChange struct {
account *common.Address account common.Address
prevcode, prevhash []byte
} }
// Changes to other state values. // Changes to other state values.
@ -148,36 +267,32 @@ type (
addLogChange struct { addLogChange struct {
txhash common.Hash txhash common.Hash
} }
addPreimageChange struct {
hash common.Hash
}
touchChange struct { touchChange struct {
account *common.Address account common.Address
} }
// Changes to the access list // Changes to the access list
accessListAddAccountChange struct { accessListAddAccountChange struct {
address *common.Address address common.Address
} }
accessListAddSlotChange struct { accessListAddSlotChange struct {
address *common.Address address common.Address
slot *common.Hash slot common.Hash
} }
// Changes to transient storage // Changes to transient storage
transientStorageChange struct { transientStorageChange struct {
account *common.Address account common.Address
key, prevalue common.Hash key, prevalue common.Hash
} }
) )
func (ch createObjectChange) revert(s *StateDB) { func (ch createObjectChange) revert(s *StateDB) {
delete(s.stateObjects, *ch.account) delete(s.stateObjects, ch.account)
RevertWrite(s, blockstm.NewAddressKey(*ch.account))
} }
func (ch createObjectChange) dirtied() *common.Address { func (ch createObjectChange) dirtied() *common.Address {
return ch.account return &ch.account
} }
func (ch createObjectChange) copy() journalEntry { func (ch createObjectChange) copy() journalEntry {
@ -201,23 +316,19 @@ func (ch createContractChange) copy() journalEntry {
} }
func (ch selfDestructChange) revert(s *StateDB) { func (ch selfDestructChange) revert(s *StateDB) {
obj := s.getStateObject(*ch.account) obj := s.getStateObject(ch.account)
if obj != nil { if obj != nil {
obj.selfDestructed = ch.prev obj.selfDestructed = false
obj.setBalance(ch.prevbalance)
RevertWrite(s, blockstm.NewSubpathKey(*ch.account, SuicidePath))
} }
} }
func (ch selfDestructChange) dirtied() *common.Address { func (ch selfDestructChange) dirtied() *common.Address {
return ch.account return &ch.account
} }
func (ch selfDestructChange) copy() journalEntry { func (ch selfDestructChange) copy() journalEntry {
return selfDestructChange{ return selfDestructChange{
account: ch.account, account: ch.account,
prev: ch.prev,
prevbalance: new(uint256.Int).Set(ch.prevbalance),
} }
} }
@ -227,7 +338,7 @@ func (ch touchChange) revert(s *StateDB) {
} }
func (ch touchChange) dirtied() *common.Address { func (ch touchChange) dirtied() *common.Address {
return ch.account return &ch.account
} }
func (ch touchChange) copy() journalEntry { func (ch touchChange) copy() journalEntry {
@ -237,11 +348,11 @@ func (ch touchChange) copy() journalEntry {
} }
func (ch balanceChange) revert(s *StateDB) { func (ch balanceChange) revert(s *StateDB) {
s.getStateObject(*ch.account).setBalance(ch.prev) s.getStateObject(ch.account).setBalance(ch.prev)
} }
func (ch balanceChange) dirtied() *common.Address { func (ch balanceChange) dirtied() *common.Address {
return ch.account return &ch.account
} }
func (ch balanceChange) copy() journalEntry { func (ch balanceChange) copy() journalEntry {
@ -252,11 +363,11 @@ func (ch balanceChange) copy() journalEntry {
} }
func (ch nonceChange) revert(s *StateDB) { func (ch nonceChange) revert(s *StateDB) {
s.getStateObject(*ch.account).setNonce(ch.prev) s.getStateObject(ch.account).setNonce(ch.prev)
} }
func (ch nonceChange) dirtied() *common.Address { func (ch nonceChange) dirtied() *common.Address {
return ch.account return &ch.account
} }
func (ch nonceChange) copy() journalEntry { func (ch nonceChange) copy() journalEntry {
@ -267,29 +378,23 @@ func (ch nonceChange) copy() journalEntry {
} }
func (ch codeChange) revert(s *StateDB) { func (ch codeChange) revert(s *StateDB) {
s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode) s.getStateObject(ch.account).setCode(types.EmptyCodeHash, nil)
RevertWrite(s, blockstm.NewSubpathKey(*ch.account, CodePath))
} }
func (ch codeChange) dirtied() *common.Address { func (ch codeChange) dirtied() *common.Address {
return ch.account return &ch.account
} }
func (ch codeChange) copy() journalEntry { func (ch codeChange) copy() journalEntry {
return codeChange{ return codeChange{account: ch.account}
account: ch.account,
prevhash: common.CopyBytes(ch.prevhash),
prevcode: common.CopyBytes(ch.prevcode),
}
} }
func (ch storageChange) revert(s *StateDB) { func (ch storageChange) revert(s *StateDB) {
s.getStateObject(*ch.account).setState(ch.key, ch.prevvalue, ch.origvalue) s.getStateObject(ch.account).setState(ch.key, ch.prevvalue, ch.origvalue)
RevertWrite(s, blockstm.NewStateKey(*ch.account, ch.key))
} }
func (ch storageChange) dirtied() *common.Address { func (ch storageChange) dirtied() *common.Address {
return ch.account return &ch.account
} }
func (ch storageChange) copy() journalEntry { func (ch storageChange) copy() journalEntry {
@ -301,7 +406,7 @@ func (ch storageChange) copy() journalEntry {
} }
func (ch transientStorageChange) revert(s *StateDB) { func (ch transientStorageChange) revert(s *StateDB) {
s.setTransientState(*ch.account, ch.key, ch.prevalue) s.setTransientState(ch.account, ch.key, ch.prevalue)
} }
func (ch transientStorageChange) dirtied() *common.Address { func (ch transientStorageChange) dirtied() *common.Address {
@ -351,20 +456,6 @@ func (ch addLogChange) copy() journalEntry {
} }
} }
func (ch addPreimageChange) revert(s *StateDB) {
delete(s.preimages, ch.hash)
}
func (ch addPreimageChange) dirtied() *common.Address {
return nil
}
func (ch addPreimageChange) copy() journalEntry {
return addPreimageChange{
hash: ch.hash,
}
}
func (ch accessListAddAccountChange) revert(s *StateDB) { func (ch accessListAddAccountChange) revert(s *StateDB) {
/* /*
One important invariant here, is that whenever a (addr, slot) is added, if the One important invariant here, is that whenever a (addr, slot) is added, if the
@ -375,7 +466,7 @@ func (ch accessListAddAccountChange) revert(s *StateDB) {
(addr) at this point, since no storage adds can remain when come upon (addr) at this point, since no storage adds can remain when come upon
a single (addr) change. a single (addr) change.
*/ */
s.accessList.DeleteAddress(*ch.address) s.accessList.DeleteAddress(ch.address)
} }
func (ch accessListAddAccountChange) dirtied() *common.Address { func (ch accessListAddAccountChange) dirtied() *common.Address {
@ -389,7 +480,7 @@ func (ch accessListAddAccountChange) copy() journalEntry {
} }
func (ch accessListAddSlotChange) revert(s *StateDB) { func (ch accessListAddSlotChange) revert(s *StateDB) {
s.accessList.DeleteSlot(*ch.address, *ch.slot) s.accessList.DeleteSlot(ch.address, ch.slot)
} }
func (ch accessListAddSlotChange) dirtied() *common.Address { func (ch accessListAddSlotChange) dirtied() *common.Address {

View file

@ -19,6 +19,8 @@ package state
import "github.com/ethereum/go-ethereum/metrics" import "github.com/ethereum/go-ethereum/metrics"
var ( var (
accountReadMeters = metrics.NewRegisteredMeter("state/read/accounts", nil)
storageReadMeters = metrics.NewRegisteredMeter("state/read/storage", nil)
accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil) accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil)
storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil) storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil)
accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil) accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil)

View file

@ -274,11 +274,10 @@ func (p *Pruner) Prune(root common.Hash) error {
// is the presence of root can indicate the presence of the // is the presence of root can indicate the presence of the
// entire trie. // entire trie.
if !rawdb.HasLegacyTrieNode(p.db, root) { if !rawdb.HasLegacyTrieNode(p.db, root) {
// The special case is for clique based networks(goerli // The special case is for clique based networks, it's possible
// and some other private networks), it's possible that two // that two consecutive blocks will have same root. In this case
// consecutive blocks will have same root. In this case snapshot // snapshot difflayer won't be created. So HEAD-127 may not paired
// difflayer won't be created. So HEAD-127 may not paired with // with head-127 layer. Instead the paired layer is higher than the
// head-127 layer. Instead the paired layer is higher than the
// bottom-most diff layer. Try to find the bottom-most snapshot // bottom-most diff layer. Try to find the bottom-most snapshot
// layer with state available. // layer with state available.
// //

321
core/state/reader.go Normal file
View file

@ -0,0 +1,321 @@
// Copyright 2024 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package state
import (
"errors"
"maps"
"sync"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state/snapshot"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/trie/utils"
"github.com/ethereum/go-ethereum/triedb"
)
// Reader defines the interface for accessing accounts and storage slots
// associated with a specific state.
type Reader interface {
// Account retrieves the account associated with a particular address.
//
// - Returns a nil account if it does not exist
// - Returns an error only if an unexpected issue occurs
// - The returned account is safe to modify after the call
Account(addr common.Address) (*types.StateAccount, error)
// Storage retrieves the storage slot associated with a particular account
// address and slot key.
//
// - Returns an empty slot if it does not exist
// - Returns an error only if an unexpected issue occurs
// - The returned storage slot is safe to modify after the call
Storage(addr common.Address, slot common.Hash) (common.Hash, error)
// Copy returns a deep-copied state reader.
Copy() Reader
}
// stateReader is a wrapper over the state snapshot and implements the Reader
// interface. It provides an efficient way to access flat state.
type stateReader struct {
snap snapshot.Snapshot
buff crypto.KeccakState
}
// newStateReader constructs a flat state reader with on the specified state root.
func newStateReader(root common.Hash, snaps *snapshot.Tree) (*stateReader, error) {
snap := snaps.Snapshot(root)
if snap == nil {
return nil, errors.New("snapshot is not available")
}
return &stateReader{
snap: snap,
buff: crypto.NewKeccakState(),
}, nil
}
// Account implements Reader, retrieving the account specified by the address.
//
// An error will be returned if the associated snapshot is already stale or
// the requested account is not yet covered by the snapshot.
//
// The returned account might be nil if it's not existent.
func (r *stateReader) Account(addr common.Address) (*types.StateAccount, error) {
ret, err := r.snap.Account(crypto.HashData(r.buff, addr.Bytes()))
if err != nil {
return nil, err
}
if ret == nil {
return nil, nil
}
acct := &types.StateAccount{
Nonce: ret.Nonce,
Balance: ret.Balance,
CodeHash: ret.CodeHash,
Root: common.BytesToHash(ret.Root),
}
if len(acct.CodeHash) == 0 {
acct.CodeHash = types.EmptyCodeHash.Bytes()
}
if acct.Root == (common.Hash{}) {
acct.Root = types.EmptyRootHash
}
return acct, nil
}
// Storage implements Reader, retrieving the storage slot specified by the
// address and slot key.
//
// An error will be returned if the associated snapshot is already stale or
// the requested storage slot is not yet covered by the snapshot.
//
// The returned storage slot might be empty if it's not existent.
func (r *stateReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) {
addrHash := crypto.HashData(r.buff, addr.Bytes())
slotHash := crypto.HashData(r.buff, key.Bytes())
ret, err := r.snap.Storage(addrHash, slotHash)
if err != nil {
return common.Hash{}, err
}
if len(ret) == 0 {
return common.Hash{}, nil
}
// Perform the rlp-decode as the slot value is RLP-encoded in the state
// snapshot.
_, content, _, err := rlp.Split(ret)
if err != nil {
return common.Hash{}, err
}
var value common.Hash
value.SetBytes(content)
return value, nil
}
// Copy implements Reader, returning a deep-copied snap reader.
func (r *stateReader) Copy() Reader {
return &stateReader{
snap: r.snap,
buff: crypto.NewKeccakState(),
}
}
// trieReader implements the Reader interface, providing functions to access
// state from the referenced trie.
type trieReader struct {
root common.Hash // State root which uniquely represent a state
db *triedb.Database // Database for loading trie
buff crypto.KeccakState // Buffer for keccak256 hashing
mainTrie Trie // Main trie, resolved in constructor
subRoots map[common.Address]common.Hash // Set of storage roots, cached when the account is resolved
subTries map[common.Address]Trie // Group of storage tries, cached when it's resolved
muSubRoot sync.Mutex
muSubTries sync.Mutex
}
// trieReader constructs a trie reader of the specific state. An error will be
// returned if the associated trie specified by root is not existent.
func newTrieReader(root common.Hash, db *triedb.Database, cache *utils.PointCache) (*trieReader, error) {
var (
tr Trie
err error
)
if !db.IsVerkle() {
tr, err = trie.NewStateTrie(trie.StateTrieID(root), db)
} else {
tr, err = trie.NewVerkleTrie(root, db, cache)
}
if err != nil {
return nil, err
}
return &trieReader{
root: root,
db: db,
buff: crypto.NewKeccakState(),
mainTrie: tr,
subRoots: make(map[common.Address]common.Hash),
subTries: make(map[common.Address]Trie),
}, nil
}
// Account implements Reader, retrieving the account specified by the address.
//
// An error will be returned if the trie state is corrupted. An nil account
// will be returned if it's not existent in the trie.
func (r *trieReader) Account(addr common.Address) (*types.StateAccount, error) {
account, err := r.mainTrie.GetAccount(addr)
if err != nil {
return nil, err
}
r.muSubRoot.Lock()
if account == nil {
r.subRoots[addr] = types.EmptyRootHash
} else {
r.subRoots[addr] = account.Root
}
r.muSubRoot.Unlock()
return account, nil
}
// Storage implements Reader, retrieving the storage slot specified by the
// address and slot key.
//
// An error will be returned if the trie state is corrupted. An empty storage
// slot will be returned if it's not existent in the trie.
func (r *trieReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) {
var (
tr Trie
found bool
value common.Hash
)
if r.db.IsVerkle() {
tr = r.mainTrie
} else {
tr, found = r.subTries[addr]
if !found {
root, ok := r.subRoots[addr]
// The storage slot is accessed without account caching. It's unexpected
// behavior but try to resolve the account first anyway.
if !ok {
_, err := r.Account(addr)
if err != nil {
return common.Hash{}, err
}
root = r.subRoots[addr]
}
var err error
tr, err = trie.NewStateTrie(trie.StorageTrieID(r.root, crypto.HashData(r.buff, addr.Bytes()), root), r.db)
if err != nil {
return common.Hash{}, err
}
r.muSubTries.Lock()
r.subTries[addr] = tr
r.muSubTries.Unlock()
}
}
ret, err := tr.GetStorage(addr, key.Bytes())
if err != nil {
return common.Hash{}, err
}
value.SetBytes(ret)
return value, nil
}
// Copy implements Reader, returning a deep-copied trie reader.
func (r *trieReader) Copy() Reader {
tries := make(map[common.Address]Trie)
for addr, tr := range r.subTries {
tries[addr] = mustCopyTrie(tr)
}
return &trieReader{
root: r.root,
db: r.db,
buff: crypto.NewKeccakState(),
mainTrie: mustCopyTrie(r.mainTrie),
subRoots: maps.Clone(r.subRoots),
subTries: tries,
}
}
// multiReader is the aggregation of a list of Reader interface, providing state
// access by leveraging all readers. The checking priority is determined by the
// position in the reader list.
type multiReader struct {
readers []Reader // List of readers, sorted by checking priority
}
// newMultiReader constructs a multiReader instance with the given readers. The
// priority among readers is assumed to be sorted. Note, it must contain at least
// one reader for constructing a multiReader.
func newMultiReader(readers ...Reader) (*multiReader, error) {
if len(readers) == 0 {
return nil, errors.New("empty reader set")
}
return &multiReader{
readers: readers,
}, nil
}
// Account implementing Reader interface, retrieving the account associated with
// a particular address.
//
// - Returns a nil account if it does not exist
// - Returns an error only if an unexpected issue occurs
// - The returned account is safe to modify after the call
func (r *multiReader) Account(addr common.Address) (*types.StateAccount, error) {
var errs []error
for _, reader := range r.readers {
acct, err := reader.Account(addr)
if err == nil {
return acct, nil
}
errs = append(errs, err)
}
return nil, errors.Join(errs...)
}
// Storage implementing Reader interface, retrieving the storage slot associated
// with a particular account address and slot key.
//
// - Returns an empty slot if it does not exist
// - Returns an error only if an unexpected issue occurs
// - The returned storage slot is safe to modify after the call
func (r *multiReader) Storage(addr common.Address, slot common.Hash) (common.Hash, error) {
var errs []error
for _, reader := range r.readers {
slot, err := reader.Storage(addr, slot)
if err == nil {
return slot, nil
}
errs = append(errs, err)
}
return common.Hash{}, errors.Join(errs...)
}
// Copy implementing Reader interface, returning a deep-copied state reader.
func (r *multiReader) Copy() Reader {
var readers []Reader
for _, reader := range r.readers {
readers = append(readers, reader.Copy())
}
return &multiReader{readers: readers}
}

Some files were not shown because too many files have changed in this diff Show more