mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 13:46:43 +00:00
Merge branch 'main' of github.com:berachain/bera-geth into update-main
This commit is contained in:
commit
effa365faa
77 changed files with 2174 additions and 501 deletions
10
.claude/settings.local.json
Normal file
10
.claude/settings.local.json
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(git add:*)",
|
||||||
|
"Bash(git commit:*)",
|
||||||
|
"Bash(git push:*)"
|
||||||
|
],
|
||||||
|
"deny": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
### Note we cannot use cron-triggered builds right now, Gitea seems to have
|
|
||||||
### a few bugs in that area. So this workflow is scheduled using an external
|
|
||||||
### triggering mechanism and workflow_dispatch.
|
|
||||||
#
|
|
||||||
# schedule:
|
|
||||||
# - cron: '0 15 * * *'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
azure-cleanup:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: 1.24
|
|
||||||
cache: false
|
|
||||||
|
|
||||||
- name: Run cleanup script
|
|
||||||
run: |
|
|
||||||
go run build/ci.go purge -store gethstore/builds -days 14
|
|
||||||
env:
|
|
||||||
AZURE_BLOBSTORE_TOKEN: ${{ secrets.AZURE_BLOBSTORE_TOKEN }}
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "v*"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
### Note we cannot use cron-triggered builds right now, Gitea seems to have
|
|
||||||
### a few bugs in that area. So this workflow is scheduled using an external
|
|
||||||
### triggering mechanism and workflow_dispatch.
|
|
||||||
#
|
|
||||||
# schedule:
|
|
||||||
# - cron: '0 16 * * *'
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
ppa:
|
|
||||||
name: PPA Upload
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Show environment
|
|
||||||
run: |
|
|
||||||
env
|
|
||||||
|
|
||||||
- name: Set up Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: 1.24
|
|
||||||
cache: false
|
|
||||||
|
|
||||||
- name: Install deb toolchain
|
|
||||||
run: |
|
|
||||||
apt-get update
|
|
||||||
apt-get -yq --no-install-suggests --no-install-recommends install devscripts debhelper dput fakeroot
|
|
||||||
|
|
||||||
- name: Add launchpad to known_hosts
|
|
||||||
run: |
|
|
||||||
echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts
|
|
||||||
|
|
||||||
- name: Run ci.go
|
|
||||||
run: |
|
|
||||||
go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>"
|
|
||||||
env:
|
|
||||||
PPA_SIGNING_KEY: ${{ secrets.PPA_SIGNING_KEY }}
|
|
||||||
PPA_SSH_KEY: ${{ secrets.PPA_SSH_KEY }}
|
|
||||||
31
.github/CODEOWNERS
vendored
31
.github/CODEOWNERS
vendored
|
|
@ -1,33 +1,4 @@
|
||||||
# Lines starting with '#' are comments.
|
# Lines starting with '#' are comments.
|
||||||
# Each line is a file pattern followed by one or more owners.
|
# Each line is a file pattern followed by one or more owners.
|
||||||
|
|
||||||
accounts/usbwallet/ @gballet
|
* @calbera
|
||||||
accounts/scwallet/ @gballet
|
|
||||||
accounts/abi/ @gballet @MariusVanDerWijden
|
|
||||||
beacon/engine/ @MariusVanDerWijden @lightclient @fjl
|
|
||||||
beacon/light/ @zsfelfoldi
|
|
||||||
beacon/merkle/ @zsfelfoldi
|
|
||||||
beacon/types/ @zsfelfoldi @fjl
|
|
||||||
beacon/params/ @zsfelfoldi @fjl
|
|
||||||
cmd/evm/ @MariusVanDerWijden @lightclient
|
|
||||||
core/state/ @rjl493456442
|
|
||||||
crypto/ @gballet @jwasinger @fjl
|
|
||||||
core/ @rjl493456442
|
|
||||||
eth/ @rjl493456442
|
|
||||||
eth/catalyst/ @MariusVanDerWijden @lightclient @fjl @jwasinger
|
|
||||||
eth/tracers/ @s1na
|
|
||||||
ethclient/ @fjl
|
|
||||||
ethdb/ @rjl493456442
|
|
||||||
event/ @fjl
|
|
||||||
trie/ @rjl493456442
|
|
||||||
triedb/ @rjl493456442
|
|
||||||
core/tracing/ @s1na
|
|
||||||
graphql/ @s1na
|
|
||||||
internal/ethapi/ @fjl @s1na @lightclient
|
|
||||||
internal/era/ @lightclient
|
|
||||||
miner/ @MariusVanDerWijden @fjl @rjl493456442
|
|
||||||
node/ @fjl
|
|
||||||
p2p/ @fjl @zsfelfoldi
|
|
||||||
rlp/ @fjl
|
|
||||||
params/ @fjl @gballet @rjl493456442 @zsfelfoldi
|
|
||||||
rpc/ @fjl
|
|
||||||
|
|
|
||||||
2
.github/CONTRIBUTING.md
vendored
2
.github/CONTRIBUTING.md
vendored
|
|
@ -21,7 +21,7 @@ Please make sure your contributions adhere to our coding guidelines:
|
||||||
(i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
|
(i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
|
||||||
* Code must be documented adhering to the official Go
|
* Code must be documented adhering to the official Go
|
||||||
[commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
|
[commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
|
||||||
* Pull requests need to be based on and opened against the `master` branch.
|
* Pull requests need to be based on and opened against the `main` branch.
|
||||||
* Commit messages should be prefixed with the package(s) they modify.
|
* Commit messages should be prefixed with the package(s) they modify.
|
||||||
* E.g. "eth, rpc: make trace configs optional"
|
* E.g. "eth, rpc: make trace configs optional"
|
||||||
|
|
||||||
|
|
|
||||||
11
.github/dependabot.yml
vendored
Normal file
11
.github/dependabot.yml
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
# To get started with Dependabot version updates, you'll need to specify which
|
||||||
|
# package ecosystems to update and where the package manifests are located.
|
||||||
|
# Please see the documentation for all configuration options:
|
||||||
|
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "gomod" # See documentation for possible values
|
||||||
|
directory: "/" # Location of package manifests
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
BIN
.github/meta/bera-geth.png
vendored
Normal file
BIN
.github/meta/bera-geth.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
2
.github/no-response.yml
vendored
2
.github/no-response.yml
vendored
|
|
@ -1,5 +1,5 @@
|
||||||
# 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: 366
|
||||||
# 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
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
|
name: CI
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches: [ main ]
|
||||||
- master
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches: [ main ]
|
||||||
- master
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
name: Lint
|
name: Lint
|
||||||
runs-on: self-hosted-ghr
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
|
|
@ -34,15 +34,9 @@ jobs:
|
||||||
go run build/ci.go check_generate
|
go run build/ci.go check_generate
|
||||||
go run build/ci.go check_baddeps
|
go run build/ci.go check_baddeps
|
||||||
|
|
||||||
test:
|
tests:
|
||||||
name: Test
|
name: Tests
|
||||||
needs: lint
|
runs-on: ubuntu-latest
|
||||||
runs-on: self-hosted-ghr
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
go:
|
|
||||||
- '1.24'
|
|
||||||
- '1.23'
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
|
|
@ -51,8 +45,8 @@ jobs:
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go }}
|
go-version: 1.24.0
|
||||||
cache: false
|
cache: false
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: go test ./...
|
run: go test -short ./...
|
||||||
43
.github/workflows/docker.yml
vendored
Normal file
43
.github/workflows/docker.yml
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
name: Docker
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "v1.*"
|
||||||
|
branches:
|
||||||
|
- "main"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
name: Docker Image
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
attestations: write
|
||||||
|
id-token: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: 1.24
|
||||||
|
cache: false
|
||||||
|
|
||||||
|
- name: Login to GitHub Container Registry
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and push multi-arch images to GHCR
|
||||||
|
run: |
|
||||||
|
go run build/ci.go dockerx -platform linux/amd64,linux/arm64 -hub ghcr.io/berachain/bera-geth -upload
|
||||||
13
.github/workflows/release.asc
vendored
Normal file
13
.github/workflows/release.asc
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
mDMEaFNE5RYJKwYBBAHaRw8BAQdAzKOuVGKVlxDTv29pw/g7reYDWw0d7Lma13oe
|
||||||
|
vBBggee0G2JlcmEtZ2V0aC1saW51eC1zaWduaW5nLWtleYiTBBMWCgA7FiEECD2r
|
||||||
|
J1G161Sj6o/AVxC/N/yI0gUFAmhTROUCGwMFCwkIBwICIgIGFQoJCAsCBBYCAwEC
|
||||||
|
HgcCF4AACgkQVxC/N/yI0gVTYwD+KiFp07+KNJ/eUlsc2j6Utz9zU7aHKEEh4LNF
|
||||||
|
uahgRC4A/i1+QkR9oo14o3lbg8yWPnI5v8QQwBd7i3GNExxPXrsMuDgEaFNE5RIK
|
||||||
|
KwYBBAGXVQEFAQEHQF1SxadHSBJud54oIYyHxq/r8GFmPyahf4ISUI/62X4BAwEI
|
||||||
|
B4h4BBgWCgAgFiEECD2rJ1G161Sj6o/AVxC/N/yI0gUFAmhTROUCGwwACgkQVxC/
|
||||||
|
N/yI0gV08QEAhpMEKbnYk9GzBSvRdgtHaYeLLqUtTp1W7Ug+RUO4338A/RWO27B8
|
||||||
|
8mAF2WACCu8lLErv5V/YI3rkDiu/MSit+p0A
|
||||||
|
=Ubr7
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
226
.github/workflows/release.yml
vendored
Normal file
226
.github/workflows/release.yml
vendored
Normal file
|
|
@ -0,0 +1,226 @@
|
||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "v1.*"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
extract-version:
|
||||||
|
name: Extract Version
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Extract version
|
||||||
|
run: echo "VERSION=$(echo ${GITHUB_REF#refs/tags/})" >> $GITHUB_OUTPUT
|
||||||
|
id: extract_version
|
||||||
|
outputs:
|
||||||
|
VERSION: ${{ steps.extract_version.outputs.VERSION }}
|
||||||
|
|
||||||
|
linux-intel:
|
||||||
|
name: Linux Build (intel)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: 1.24
|
||||||
|
cache: false
|
||||||
|
|
||||||
|
- name: Install cross toolchain
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get -yq --no-install-suggests --no-install-recommends install gcc-multilib
|
||||||
|
|
||||||
|
- name: Build (amd64)
|
||||||
|
run: |
|
||||||
|
go run build/ci.go install -static -arch amd64 -dlgo
|
||||||
|
|
||||||
|
- name: Create archive (amd64)
|
||||||
|
run: |
|
||||||
|
go run build/ci.go archive -arch amd64 -type tar
|
||||||
|
- name: Upload artifacts (amd64)
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: bera-geth-linux-amd64-archives
|
||||||
|
path: |
|
||||||
|
bera-geth-linux-amd64-*.tar.gz
|
||||||
|
bera-geth-alltools-linux-amd64-*.tar.gz
|
||||||
|
- name: Cleanup bin
|
||||||
|
run: rm -f build/bin/*
|
||||||
|
|
||||||
|
linux-arm:
|
||||||
|
name: Linux Build (arm)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: 1.24
|
||||||
|
cache: false
|
||||||
|
|
||||||
|
- name: Install cross toolchain
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get -yq --no-install-suggests --no-install-recommends install gcc-arm-linux-gnueabi libc6-dev-armel-cross gcc-arm-linux-gnueabihf libc6-dev-armhf-cross gcc-aarch64-linux-gnu libc6-dev-arm64-cross
|
||||||
|
sudo ln -s /usr/include/asm-generic /usr/include/asm
|
||||||
|
|
||||||
|
- name: Build (arm64)
|
||||||
|
run: |
|
||||||
|
go run build/ci.go install -static -dlgo -arch arm64 -cc aarch64-linux-gnu-gcc
|
||||||
|
|
||||||
|
- name: Create archive (arm64)
|
||||||
|
run: |
|
||||||
|
go run build/ci.go archive -arch arm64 -type tar
|
||||||
|
- name: Upload artifacts (arm64)
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: bera-geth-linux-arm64-archives
|
||||||
|
path: |
|
||||||
|
bera-geth-linux-arm64-*.tar.gz
|
||||||
|
bera-geth-alltools-linux-arm64-*.tar.gz
|
||||||
|
- name: Cleanup bin
|
||||||
|
run: rm -fr build/bin/*
|
||||||
|
|
||||||
|
draft-release:
|
||||||
|
name: Draft Release
|
||||||
|
needs: [extract-version, linux-intel, linux-arm]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
VERSION: ${{ needs.extract-version.outputs.VERSION }}
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # This is necessary for generating the changelog
|
||||||
|
|
||||||
|
- name: Download all artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: ./artifacts
|
||||||
|
|
||||||
|
- name: Generate full changelog
|
||||||
|
id: changelog
|
||||||
|
run: |
|
||||||
|
echo "CHANGELOG<<EOF" >> $GITHUB_OUTPUT
|
||||||
|
echo "$(git log --pretty=format:"- %s" $(git describe --tags --abbrev=0 ${{ env.VERSION }}^)..${{ env.VERSION }})" >> $GITHUB_OUTPUT
|
||||||
|
echo "EOF" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Create release draft
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
# Debug: Show what was downloaded
|
||||||
|
echo "Contents of artifacts directory:"
|
||||||
|
ls -la ./artifacts/ || echo "Artifacts directory not found"
|
||||||
|
|
||||||
|
# Move all artifacts to current directory
|
||||||
|
if [ -d "./artifacts" ]; then
|
||||||
|
find ./artifacts -name "*.tar.gz" -exec mv {} . \;
|
||||||
|
else
|
||||||
|
echo "Warning: No artifacts directory found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# List available files for debugging
|
||||||
|
echo "Available files:"
|
||||||
|
ls -la *.tar.gz || echo "No tar.gz files found"
|
||||||
|
|
||||||
|
# Get actual archive names
|
||||||
|
GETH_AMD64=$(ls bera-geth-linux-amd64-*.tar.gz 2>/dev/null | grep -v alltools | head -1)
|
||||||
|
GETH_ARM64=$(ls bera-geth-linux-arm64-*.tar.gz 2>/dev/null | grep -v alltools | head -1)
|
||||||
|
GETH_ALLTOOLS_AMD64=$(ls bera-geth-alltools-linux-amd64-*.tar.gz 2>/dev/null | head -1)
|
||||||
|
GETH_ALLTOOLS_ARM64=$(ls bera-geth-alltools-linux-arm64-*.tar.gz 2>/dev/null | head -1)
|
||||||
|
|
||||||
|
echo "Found archives:"
|
||||||
|
echo " AMD64: ${GETH_AMD64:-NOT FOUND}"
|
||||||
|
echo " ARM64: ${GETH_ARM64:-NOT FOUND}"
|
||||||
|
echo " Alltools AMD64: ${GETH_ALLTOOLS_AMD64:-NOT FOUND}"
|
||||||
|
echo " Alltools ARM64: ${GETH_ALLTOOLS_ARM64:-NOT FOUND}"
|
||||||
|
|
||||||
|
# For tag builds, use the actual tag
|
||||||
|
RELEASE_TAG="${{ env.VERSION }}"
|
||||||
|
echo "Release tag: $RELEASE_TAG"
|
||||||
|
echo "GitHub ref: ${{ github.ref }}"
|
||||||
|
echo "GitHub SHA: ${{ github.sha }}"
|
||||||
|
|
||||||
|
# The tag should already exist since it triggered this workflow
|
||||||
|
# We just need to ensure gh release uses it correctly
|
||||||
|
|
||||||
|
body=$(cat <<- 'ENDBODY'
|
||||||
|

|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Add a summary, including:
|
||||||
|
|
||||||
|
- Critical bug fixes
|
||||||
|
- New features
|
||||||
|
- Any breaking changes (and what to expect)
|
||||||
|
|
||||||
|
## Update Priority
|
||||||
|
|
||||||
|
This table provides priorities for which classes of users should update particular components.
|
||||||
|
|
||||||
|
| User Class | Priority |
|
||||||
|
|----------------------|-----------------|
|
||||||
|
| Payload Builders | <TODO> |
|
||||||
|
| Non-Payload Builders | <TODO> |
|
||||||
|
|
||||||
|
## All Changes
|
||||||
|
|
||||||
|
${{ steps.changelog.outputs.CHANGELOG }}
|
||||||
|
|
||||||
|
## Binaries
|
||||||
|
|
||||||
|
| System | Architecture | Binary | Notes |
|
||||||
|
|:---:|:---:|:---:|:---|
|
||||||
|
| <img src="https://simpleicons.org/icons/linux.svg" style="width: 32px;"/> | amd64 | [GETH_AMD64_PLACEHOLDER](https://github.com/${{ github.repository }}/releases/download/RELEASE_TAG_PLACEHOLDER/GETH_AMD64_PLACEHOLDER) | Most Linux systems |
|
||||||
|
| <img src="https://simpleicons.org/icons/linux.svg" style="width: 32px;"/> | arm64 | [GETH_ARM64_PLACEHOLDER](https://github.com/${{ github.repository }}/releases/download/RELEASE_TAG_PLACEHOLDER/GETH_ARM64_PLACEHOLDER) | 64-bit ARM systems |
|
||||||
|
| <img src="https://simpleicons.org/icons/linux.svg" style="width: 32px;"/> | amd64 | [GETH_ALLTOOLS_AMD64_PLACEHOLDER](https://github.com/${{ github.repository }}/releases/download/RELEASE_TAG_PLACEHOLDER/GETH_ALLTOOLS_AMD64_PLACEHOLDER) | All tools bundle (amd64) |
|
||||||
|
| <img src="https://simpleicons.org/icons/linux.svg" style="width: 32px;"/> | arm64 | [GETH_ALLTOOLS_ARM64_PLACEHOLDER](https://github.com/${{ github.repository }}/releases/download/RELEASE_TAG_PLACEHOLDER/GETH_ALLTOOLS_ARM64_PLACEHOLDER) | All tools bundle (arm64) |
|
||||||
|
| **System** | **Option** | - | **Resource** |
|
||||||
|
| <img src="https://simpleicons.org/icons/docker.svg" style="width: 32px;"/> | Docker | | [ghcr.io/berachain/bera-geth](https://ghcr.io/berachain/bera-geth) |
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
The archives contain the geth binary and license file. Extract and run:
|
||||||
|
```bash
|
||||||
|
tar -xzf GETH_AMD64_PLACEHOLDER
|
||||||
|
./geth
|
||||||
|
```
|
||||||
|
|
||||||
|
The **alltools** archives additionally contain:
|
||||||
|
- `abigen` - Source code generator for Ethereum contracts
|
||||||
|
- `evm` - Developer utility for the Ethereum Virtual Machine
|
||||||
|
- `rlpdump` - Developer utility for RLP data
|
||||||
|
- `clef` - Ethereum account management tool
|
||||||
|
|
||||||
|
ENDBODY
|
||||||
|
)
|
||||||
|
|
||||||
|
# Replace placeholders with actual filenames and release tag
|
||||||
|
body="${body//GETH_AMD64_PLACEHOLDER/$GETH_AMD64}"
|
||||||
|
body="${body//GETH_ARM64_PLACEHOLDER/$GETH_ARM64}"
|
||||||
|
body="${body//GETH_ALLTOOLS_AMD64_PLACEHOLDER/$GETH_ALLTOOLS_AMD64}"
|
||||||
|
body="${body//GETH_ALLTOOLS_ARM64_PLACEHOLDER/$GETH_ALLTOOLS_ARM64}"
|
||||||
|
body="${body//RELEASE_TAG_PLACEHOLDER/$RELEASE_TAG}"
|
||||||
|
|
||||||
|
# Create assets array for gh release
|
||||||
|
assets=()
|
||||||
|
for asset in bera-geth-*.tar.gz; do
|
||||||
|
if [ -f "$asset" ]; then
|
||||||
|
assets+=("$asset")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Create the release with the actual tag
|
||||||
|
# Using --target with GITHUB_SHA ensures we create the release at the right commit
|
||||||
|
echo "$body" | gh release create "$RELEASE_TAG" \
|
||||||
|
--draft \
|
||||||
|
--title "Bera Geth $RELEASE_TAG" \
|
||||||
|
-F - \
|
||||||
|
"${assets[@]}"
|
||||||
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -55,4 +55,7 @@ cmd/ethkey/ethkey
|
||||||
cmd/evm/evm
|
cmd/evm/evm
|
||||||
cmd/geth/geth
|
cmd/geth/geth
|
||||||
cmd/rlpdump/rlpdump
|
cmd/rlpdump/rlpdump
|
||||||
cmd/workload/workload
|
cmd/workload/workload
|
||||||
|
|
||||||
|
# claude
|
||||||
|
.claude
|
||||||
|
|
|
||||||
22
CHANGELOG.md
Normal file
22
CHANGELOG.md
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
|
and this project adheres to
|
||||||
|
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [v1.TBD.0]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Add support for the Berachain mainnet (`--berachain`) and Bepolia networks
|
||||||
|
(`--bepolia`)
|
||||||
|
- Add support for configuring the Prague1 fork on Berachain networks.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- BRIP-2: Allowed configuration of the `MinimumBaseFeeWei`. For Berachain, this will be set as 1 gwei. (https://github.com/berachain/bera-geth/pull/2)
|
||||||
|
- BRIP-2: Allowed configuration of the `BaseFeeChangeDenominator`. For Berachain, this will be set as 48 (a 6x increase corresponding to 6x faster block times). (https://github.com/berachain/bera-geth/pull/2)
|
||||||
|
- [WIP] Updated release GH workflow to publish tarballs and push built images to GHCR.
|
||||||
|
- Removed support for appveyor, gitea, travis, circleci.
|
||||||
145
CLAUDE.md
Normal file
145
CLAUDE.md
Normal file
|
|
@ -0,0 +1,145 @@
|
||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
This is **bera-geth**, Berachain's fork of go-ethereum that implements the Berachain blockchain network. Key differences from upstream:
|
||||||
|
|
||||||
|
- **Custom base fee mechanism**: 1 gwei minimum with 6x faster adjustments via Prague1 fork
|
||||||
|
- **Networks**: Berachain mainnet (Chain ID 80094) and Bepolia testnet (Chain ID 80069)
|
||||||
|
- **Optimized for faster block times** while maintaining Ethereum compatibility
|
||||||
|
|
||||||
|
## Development Commands
|
||||||
|
|
||||||
|
### Building
|
||||||
|
```bash
|
||||||
|
make geth # Build main geth binary
|
||||||
|
make all # Build all executables
|
||||||
|
make evm # Build EVM utility
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
```bash
|
||||||
|
make test # Run all tests
|
||||||
|
go test ./path/to/package # Run specific package tests
|
||||||
|
go test -run TestName # Run specific test
|
||||||
|
```
|
||||||
|
|
||||||
|
### Code Quality
|
||||||
|
```bash
|
||||||
|
make lint # Run linters
|
||||||
|
make fmt # Format code with gofmt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Development Tools
|
||||||
|
```bash
|
||||||
|
make devtools # Install development dependencies
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cleaning
|
||||||
|
```bash
|
||||||
|
make clean # Clean build artifacts
|
||||||
|
```
|
||||||
|
|
||||||
|
## Codebase Architecture
|
||||||
|
|
||||||
|
### Core Components
|
||||||
|
|
||||||
|
**Core Blockchain Logic** (`/core/`)
|
||||||
|
- `blockchain.go` - Main blockchain state management
|
||||||
|
- `state_processor.go` - Transaction execution
|
||||||
|
- `types/` - Core data structures (blocks, transactions, receipts)
|
||||||
|
- `vm/` - Ethereum Virtual Machine implementation
|
||||||
|
- `txpool/` - Transaction pool management
|
||||||
|
|
||||||
|
**Consensus Layer** (`/consensus/`)
|
||||||
|
- `beacon/` - Proof-of-stake consensus (primary)
|
||||||
|
- `misc/eip1559/` - Base fee calculation with Berachain modifications
|
||||||
|
- `clique/` - Proof-of-authority for testing
|
||||||
|
|
||||||
|
**Network Protocol** (`/eth/`)
|
||||||
|
- `backend.go` - Main Ethereum service
|
||||||
|
- `downloader/` - Block/state synchronization
|
||||||
|
- `protocols/` - Network protocol handlers
|
||||||
|
|
||||||
|
**P2P Networking** (`/p2p/`)
|
||||||
|
- `discover/` - Node discovery protocols
|
||||||
|
- `rlpx/` - Encrypted communication
|
||||||
|
|
||||||
|
### Key Entry Points
|
||||||
|
|
||||||
|
**Main Binary**: `/cmd/geth/main.go`
|
||||||
|
- CLI application setup
|
||||||
|
- Network selection logic
|
||||||
|
- Node initialization
|
||||||
|
|
||||||
|
**Other Executables**: `/cmd/`
|
||||||
|
- `clef/` - Account management
|
||||||
|
- `abigen/` - ABI binding generator
|
||||||
|
- `evm/` - Standalone EVM executor
|
||||||
|
|
||||||
|
### Configuration Management
|
||||||
|
|
||||||
|
**Chain Configs**: `/params/config.go`
|
||||||
|
- Network parameters and fork schedules
|
||||||
|
- Berachain/Bepolia network definitions
|
||||||
|
- Prague1 fork configuration
|
||||||
|
|
||||||
|
**Network Discovery**: `/params/bootnodes.go`
|
||||||
|
- Bootstrap nodes for peer discovery
|
||||||
|
|
||||||
|
### Berachain-Specific Modifications
|
||||||
|
|
||||||
|
**Base Fee Changes** (`/consensus/misc/eip1559/eip1559.go:116-121`)
|
||||||
|
- Prague1 fork enforces 1 gwei minimum base fee
|
||||||
|
- BaseFeeChangeDenominator set to 48 (6x faster adjustment)
|
||||||
|
|
||||||
|
**Network Configurations** (`/params/config.go:77-99, 107-129`)
|
||||||
|
- BerachainChainConfig with Chain ID 80094
|
||||||
|
- BepoliaChainConfig with Chain ID 80069
|
||||||
|
- Custom Prague1 fork activation parameters
|
||||||
|
|
||||||
|
### Test Organization
|
||||||
|
|
||||||
|
Tests follow Go conventions with `*_test.go` files alongside source code:
|
||||||
|
- Unit tests in package directories
|
||||||
|
- Integration tests in `/tests/`
|
||||||
|
- Consensus tests for Ethereum specification compliance
|
||||||
|
- EVM operation tests in `/core/vm/testdata/`
|
||||||
|
|
||||||
|
### Build System
|
||||||
|
|
||||||
|
**Primary Build**: `/build/ci.go`
|
||||||
|
- Cross-platform compilation
|
||||||
|
- Docker image building
|
||||||
|
- Release packaging
|
||||||
|
|
||||||
|
**Simple Builds**: `/Makefile`
|
||||||
|
- Development-focused targets
|
||||||
|
- Requires Go 1.23+ and C compiler
|
||||||
|
|
||||||
|
## Development Workflow
|
||||||
|
|
||||||
|
1. **Architecture Understanding**: The codebase follows Ethereum's layered architecture (consensus → state → networking → application)
|
||||||
|
2. **Testing Strategy**: Always run tests after changes with `make test`
|
||||||
|
3. **Code Style**: Use `make fmt` and `make lint` before committing
|
||||||
|
4. **Network Testing**: Use `--bepolia` flag for testnet development
|
||||||
|
5. **Debugging**: Use `./build/bin/geth --help` for comprehensive CLI options
|
||||||
|
|
||||||
|
## Network-Specific Usage
|
||||||
|
|
||||||
|
### Berachain Mainnet
|
||||||
|
```bash
|
||||||
|
./build/bin/geth --berachain
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bepolia Testnet
|
||||||
|
```bash
|
||||||
|
./build/bin/geth --bepolia
|
||||||
|
```
|
||||||
|
|
||||||
|
### Development Mode
|
||||||
|
```bash
|
||||||
|
./build/bin/geth --dev
|
||||||
|
```
|
||||||
12
Dockerfile
12
Dockerfile
|
|
@ -9,18 +9,18 @@ FROM golang:1.24-alpine AS builder
|
||||||
RUN apk add --no-cache gcc musl-dev linux-headers git
|
RUN apk add --no-cache gcc musl-dev linux-headers git
|
||||||
|
|
||||||
# Get dependencies - will also be cached if we won't change go.mod/go.sum
|
# Get dependencies - will also be cached if we won't change go.mod/go.sum
|
||||||
COPY go.mod /go-ethereum/
|
COPY go.mod /bera-geth/
|
||||||
COPY go.sum /go-ethereum/
|
COPY go.sum /bera-geth/
|
||||||
RUN cd /go-ethereum && go mod download
|
RUN cd /bera-geth && go mod download
|
||||||
|
|
||||||
ADD . /go-ethereum
|
ADD . /bera-geth
|
||||||
RUN cd /go-ethereum && go run build/ci.go install -static ./cmd/geth
|
RUN cd /bera-geth && go run build/ci.go install -static ./cmd/geth
|
||||||
|
|
||||||
# Pull Geth into a second stage deploy alpine container
|
# Pull Geth into a second stage deploy alpine container
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
|
|
||||||
RUN apk add --no-cache ca-certificates
|
RUN apk add --no-cache ca-certificates
|
||||||
COPY --from=builder /go-ethereum/build/bin/geth /usr/local/bin/
|
COPY --from=builder /bera-geth/build/bin/geth /usr/local/bin/
|
||||||
|
|
||||||
EXPOSE 8545 8546 30303 30303/udp
|
EXPOSE 8545 8546 30303 30303/udp
|
||||||
ENTRYPOINT ["geth"]
|
ENTRYPOINT ["geth"]
|
||||||
|
|
|
||||||
|
|
@ -9,25 +9,25 @@ FROM golang:1.24-alpine AS builder
|
||||||
RUN apk add --no-cache gcc musl-dev linux-headers git
|
RUN apk add --no-cache gcc musl-dev linux-headers git
|
||||||
|
|
||||||
# Get dependencies - will also be cached if we won't change go.mod/go.sum
|
# Get dependencies - will also be cached if we won't change go.mod/go.sum
|
||||||
COPY go.mod /go-ethereum/
|
COPY go.mod /bera-geth/
|
||||||
COPY go.sum /go-ethereum/
|
COPY go.sum /bera-geth/
|
||||||
RUN cd /go-ethereum && go mod download
|
RUN cd /bera-geth && go mod download
|
||||||
|
|
||||||
ADD . /go-ethereum
|
ADD . /bera-geth
|
||||||
|
|
||||||
# This is not strictly necessary, but it matches the "Dockerfile" steps, thus
|
# This is not strictly necessary, but it matches the "Dockerfile" steps, thus
|
||||||
# makes it so that under certain circumstances, the docker layer can be cached,
|
# makes it so that under certain circumstances, the docker layer can be cached,
|
||||||
# and the builder can jump to the next (build all) command, with the go cache fully loaded.
|
# and the builder can jump to the next (build all) command, with the go cache fully loaded.
|
||||||
#
|
#
|
||||||
RUN cd /go-ethereum && go run build/ci.go install -static ./cmd/geth
|
RUN cd /bera-geth && go run build/ci.go install -static ./cmd/geth
|
||||||
|
|
||||||
RUN cd /go-ethereum && go run build/ci.go install -static
|
RUN cd /bera-geth && go run build/ci.go install -static
|
||||||
|
|
||||||
# Pull all binaries into a second stage deploy alpine container
|
# Pull all binaries into a second stage deploy alpine container
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
|
|
||||||
RUN apk add --no-cache ca-certificates
|
RUN apk add --no-cache ca-certificates
|
||||||
COPY --from=builder /go-ethereum/build/bin/* /usr/local/bin/
|
COPY --from=builder /bera-geth/build/bin/* /usr/local/bin/
|
||||||
|
|
||||||
EXPOSE 8545 8546 30303 30303/udp
|
EXPOSE 8545 8546 30303 30303/udp
|
||||||
|
|
||||||
|
|
|
||||||
59
appveyor.yml
59
appveyor.yml
|
|
@ -1,59 +0,0 @@
|
||||||
clone_depth: 5
|
|
||||||
version: "{branch}.{build}"
|
|
||||||
|
|
||||||
image:
|
|
||||||
- Ubuntu
|
|
||||||
- Visual Studio 2019
|
|
||||||
|
|
||||||
environment:
|
|
||||||
matrix:
|
|
||||||
- GETH_ARCH: amd64
|
|
||||||
GETH_MINGW: 'C:\msys64\mingw64'
|
|
||||||
- GETH_ARCH: 386
|
|
||||||
GETH_MINGW: 'C:\msys64\mingw32'
|
|
||||||
|
|
||||||
install:
|
|
||||||
- git submodule update --init --depth 1 --recursive
|
|
||||||
- go version
|
|
||||||
|
|
||||||
for:
|
|
||||||
# Linux has its own script without -arch and -cc.
|
|
||||||
# The linux builder also runs lint.
|
|
||||||
- matrix:
|
|
||||||
only:
|
|
||||||
- image: Ubuntu
|
|
||||||
build_script:
|
|
||||||
- go run build/ci.go lint
|
|
||||||
- go run build/ci.go check_generate
|
|
||||||
- go run build/ci.go check_baddeps
|
|
||||||
- go run build/ci.go install -dlgo
|
|
||||||
test_script:
|
|
||||||
- go run build/ci.go test -dlgo -short
|
|
||||||
|
|
||||||
# linux/386 is disabled.
|
|
||||||
- matrix:
|
|
||||||
exclude:
|
|
||||||
- image: Ubuntu
|
|
||||||
GETH_ARCH: 386
|
|
||||||
|
|
||||||
# Windows builds for amd64 + 386.
|
|
||||||
- matrix:
|
|
||||||
only:
|
|
||||||
- image: Visual Studio 2019
|
|
||||||
environment:
|
|
||||||
# We use gcc from MSYS2 because it is the most recent compiler version available on
|
|
||||||
# AppVeyor. Note: gcc.exe only works properly if the corresponding bin/ directory is
|
|
||||||
# contained in PATH.
|
|
||||||
GETH_CC: '%GETH_MINGW%\bin\gcc.exe'
|
|
||||||
PATH: '%GETH_MINGW%\bin;C:\Program Files (x86)\NSIS\;%PATH%'
|
|
||||||
build_script:
|
|
||||||
- 'echo %GETH_ARCH%'
|
|
||||||
- 'echo %GETH_CC%'
|
|
||||||
- '%GETH_CC% --version'
|
|
||||||
- go run build/ci.go install -dlgo -arch %GETH_ARCH% -cc %GETH_CC%
|
|
||||||
after_build:
|
|
||||||
# Upload builds. Note that ci.go makes this a no-op PR builds.
|
|
||||||
- go run build/ci.go archive -arch %GETH_ARCH% -type zip -signer WINDOWS_SIGNING_KEY -upload gethstore/builds
|
|
||||||
- go run build/ci.go nsis -arch %GETH_ARCH% -signer WINDOWS_SIGNING_KEY -upload gethstore/builds
|
|
||||||
test_script:
|
|
||||||
- go run build/ci.go test -dlgo -arch %GETH_ARCH% -cc %GETH_CC% -short
|
|
||||||
|
|
@ -101,6 +101,17 @@ func (ec *engineClient) callNewPayload(fork string, event types.ChainHeadEvent)
|
||||||
params = []any{execData}
|
params = []any{execData}
|
||||||
)
|
)
|
||||||
switch fork {
|
switch fork {
|
||||||
|
case "electra1":
|
||||||
|
// TODO(BRIP-4): Add ParentProposerPubkey to the chainHeadEvent to add to the newPayload call.
|
||||||
|
method = "engine_newPayloadV4P11"
|
||||||
|
parentBeaconRoot := event.BeaconHead.ParentRoot
|
||||||
|
blobHashes := collectBlobHashes(event.Block)
|
||||||
|
hexRequests := make([]hexutil.Bytes, len(event.ExecRequests))
|
||||||
|
for i := range event.ExecRequests {
|
||||||
|
hexRequests[i] = hexutil.Bytes(event.ExecRequests[i])
|
||||||
|
}
|
||||||
|
parentProposerPubkey := &common.Pubkey{}
|
||||||
|
params = append(params, blobHashes, parentBeaconRoot, hexRequests, parentProposerPubkey)
|
||||||
case "electra":
|
case "electra":
|
||||||
method = "engine_newPayloadV4"
|
method = "engine_newPayloadV4"
|
||||||
parentBeaconRoot := event.BeaconHead.ParentRoot
|
parentBeaconRoot := event.BeaconHead.ParentRoot
|
||||||
|
|
@ -145,6 +156,8 @@ func (ec *engineClient) callForkchoiceUpdated(fork string, event types.ChainHead
|
||||||
|
|
||||||
var method string
|
var method string
|
||||||
switch fork {
|
switch fork {
|
||||||
|
case "electra1":
|
||||||
|
method = "engine_forkchoiceUpdatedV3P11"
|
||||||
case "deneb", "electra":
|
case "deneb", "electra":
|
||||||
method = "engine_forkchoiceUpdatedV3"
|
method = "engine_forkchoiceUpdatedV3"
|
||||||
case "capella":
|
case "capella":
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ func (p PayloadAttributes) MarshalJSON() ([]byte, error) {
|
||||||
SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
|
SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||||
|
ProposerPubkey *common.Pubkey `json:"parentProposerPubkey"`
|
||||||
}
|
}
|
||||||
var enc PayloadAttributes
|
var enc PayloadAttributes
|
||||||
enc.Timestamp = hexutil.Uint64(p.Timestamp)
|
enc.Timestamp = hexutil.Uint64(p.Timestamp)
|
||||||
|
|
@ -28,6 +29,7 @@ func (p PayloadAttributes) MarshalJSON() ([]byte, error) {
|
||||||
enc.SuggestedFeeRecipient = p.SuggestedFeeRecipient
|
enc.SuggestedFeeRecipient = p.SuggestedFeeRecipient
|
||||||
enc.Withdrawals = p.Withdrawals
|
enc.Withdrawals = p.Withdrawals
|
||||||
enc.BeaconRoot = p.BeaconRoot
|
enc.BeaconRoot = p.BeaconRoot
|
||||||
|
enc.ProposerPubkey = p.ProposerPubkey
|
||||||
return json.Marshal(&enc)
|
return json.Marshal(&enc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -39,6 +41,7 @@ func (p *PayloadAttributes) UnmarshalJSON(input []byte) error {
|
||||||
SuggestedFeeRecipient *common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
|
SuggestedFeeRecipient *common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||||
|
ProposerPubkey *common.Pubkey `json:"parentProposerPubkey"`
|
||||||
}
|
}
|
||||||
var dec PayloadAttributes
|
var dec PayloadAttributes
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
|
@ -62,5 +65,8 @@ func (p *PayloadAttributes) UnmarshalJSON(input []byte) error {
|
||||||
if dec.BeaconRoot != nil {
|
if dec.BeaconRoot != nil {
|
||||||
p.BeaconRoot = dec.BeaconRoot
|
p.BeaconRoot = dec.BeaconRoot
|
||||||
}
|
}
|
||||||
|
if dec.ProposerPubkey != nil {
|
||||||
|
p.ProposerPubkey = dec.ProposerPubkey
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,10 @@ import (
|
||||||
type PayloadVersion byte
|
type PayloadVersion byte
|
||||||
|
|
||||||
var (
|
var (
|
||||||
PayloadV1 PayloadVersion = 0x1
|
PayloadV1 PayloadVersion = 0x1
|
||||||
PayloadV2 PayloadVersion = 0x2
|
PayloadV2 PayloadVersion = 0x2
|
||||||
PayloadV3 PayloadVersion = 0x3
|
PayloadV3 PayloadVersion = 0x3
|
||||||
|
PayloadV3P11 PayloadVersion = 0x31
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate go run github.com/fjl/gencodec -type PayloadAttributes -field-override payloadAttributesMarshaling -out gen_blockparams.go
|
//go:generate go run github.com/fjl/gencodec -type PayloadAttributes -field-override payloadAttributesMarshaling -out gen_blockparams.go
|
||||||
|
|
@ -48,6 +49,7 @@ type PayloadAttributes struct {
|
||||||
SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
|
SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||||
|
ProposerPubkey *common.Pubkey `json:"parentProposerPubkey"` // Berachain: only used prague1 and onwards
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSON type overrides for PayloadAttributes.
|
// JSON type overrides for PayloadAttributes.
|
||||||
|
|
@ -218,8 +220,8 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
|
||||||
// and that the blockhash of the constructed block matches the parameters. Nil
|
// and that the blockhash of the constructed block matches the parameters. Nil
|
||||||
// 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, requests [][]byte) (*types.Block, error) {
|
func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte, proposerPubkey *common.Pubkey) (*types.Block, error) {
|
||||||
block, err := ExecutableDataToBlockNoHash(data, versionedHashes, beaconRoot, requests)
|
block, err := ExecutableDataToBlockNoHash(data, versionedHashes, beaconRoot, requests, proposerPubkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -232,7 +234,7 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b
|
||||||
// ExecutableDataToBlockNoHash is analogous to ExecutableDataToBlock, but is used
|
// ExecutableDataToBlockNoHash is analogous to ExecutableDataToBlock, but is used
|
||||||
// for stateless execution, so it skips checking if the executable data hashes to
|
// 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).
|
// the requested hash (stateless has to *compute* the root hash, it's not given).
|
||||||
func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte) (*types.Block, error) {
|
func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte, proposerPubkey *common.Pubkey) (*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
|
||||||
|
|
@ -275,26 +277,27 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H
|
||||||
}
|
}
|
||||||
|
|
||||||
header := &types.Header{
|
header := &types.Header{
|
||||||
ParentHash: data.ParentHash,
|
ParentHash: data.ParentHash,
|
||||||
UncleHash: types.EmptyUncleHash,
|
UncleHash: types.EmptyUncleHash,
|
||||||
Coinbase: data.FeeRecipient,
|
Coinbase: data.FeeRecipient,
|
||||||
Root: data.StateRoot,
|
Root: data.StateRoot,
|
||||||
TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)),
|
TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)),
|
||||||
ReceiptHash: data.ReceiptsRoot,
|
ReceiptHash: data.ReceiptsRoot,
|
||||||
Bloom: types.BytesToBloom(data.LogsBloom),
|
Bloom: types.BytesToBloom(data.LogsBloom),
|
||||||
Difficulty: common.Big0,
|
Difficulty: common.Big0,
|
||||||
Number: new(big.Int).SetUint64(data.Number),
|
Number: new(big.Int).SetUint64(data.Number),
|
||||||
GasLimit: data.GasLimit,
|
GasLimit: data.GasLimit,
|
||||||
GasUsed: data.GasUsed,
|
GasUsed: data.GasUsed,
|
||||||
Time: data.Timestamp,
|
Time: data.Timestamp,
|
||||||
BaseFee: data.BaseFeePerGas,
|
BaseFee: data.BaseFeePerGas,
|
||||||
Extra: data.ExtraData,
|
Extra: data.ExtraData,
|
||||||
MixDigest: data.Random,
|
MixDigest: data.Random,
|
||||||
WithdrawalsHash: withdrawalsRoot,
|
WithdrawalsHash: withdrawalsRoot,
|
||||||
ExcessBlobGas: data.ExcessBlobGas,
|
ExcessBlobGas: data.ExcessBlobGas,
|
||||||
BlobGasUsed: data.BlobGasUsed,
|
BlobGasUsed: data.BlobGasUsed,
|
||||||
ParentBeaconRoot: beaconRoot,
|
ParentBeaconRoot: beaconRoot,
|
||||||
RequestsHash: requestsHash,
|
RequestsHash: requestsHash,
|
||||||
|
ParentProposerPubkey: proposerPubkey,
|
||||||
}
|
}
|
||||||
return types.NewBlockWithHeader(header).
|
return types.NewBlockWithHeader(header).
|
||||||
WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals}).
|
WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals}).
|
||||||
|
|
|
||||||
26
build/ci.go
26
build/ci.go
|
|
@ -572,9 +572,9 @@ func doArchive(cmdline []string) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
env = build.Env()
|
env = build.Env()
|
||||||
basegeth = archiveBasename(*arch, version.Archive(env.Commit))
|
basegeth = archiveBasename(*arch, version.Archive(env.Tag, env.Commit))
|
||||||
geth = "geth-" + basegeth + ext
|
geth = "bera-geth-" + basegeth + ext
|
||||||
alltools = "geth-alltools-" + basegeth + ext
|
alltools = "bera-geth-alltools-" + basegeth + ext
|
||||||
)
|
)
|
||||||
maybeSkipArchive(env)
|
maybeSkipArchive(env)
|
||||||
if err := build.WriteArchive(geth, gethArchiveFiles); err != nil {
|
if err := build.WriteArchive(geth, gethArchiveFiles); err != nil {
|
||||||
|
|
@ -650,17 +650,17 @@ func maybeSkipArchive(env build.Environment) {
|
||||||
log.Printf("skipping archive creation because this is a PR build")
|
log.Printf("skipping archive creation because this is a PR build")
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
if env.Branch != "master" && !strings.HasPrefix(env.Tag, "v1.") {
|
if env.Branch != "main" && !strings.HasPrefix(env.Tag, "v1.") {
|
||||||
log.Printf("skipping archive creation because branch %q, tag %q is not on the inclusion list", env.Branch, env.Tag)
|
log.Printf("skipping archive creation because branch %q, tag %q is not on the inclusion list", env.Branch, env.Tag)
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Builds the docker images and optionally uploads them to Docker Hub.
|
// Builds the docker images and optionally uploads them to GHCR.
|
||||||
func doDockerBuildx(cmdline []string) {
|
func doDockerBuildx(cmdline []string) {
|
||||||
var (
|
var (
|
||||||
platform = flag.String("platform", "", `Push a multi-arch docker image for the specified architectures (usually "linux/amd64,linux/arm64")`)
|
platform = flag.String("platform", "", `Push a multi-arch docker image for the specified architectures (usually "linux/amd64,linux/arm64")`)
|
||||||
hubImage = flag.String("hub", "ethereum/client-go", `Where to upload the docker image`)
|
hubImage = flag.String("hub", "ghcr.io/berachain/bera-geth", `Where to upload the docker image`)
|
||||||
upload = flag.Bool("upload", false, `Whether to trigger upload`)
|
upload = flag.Bool("upload", false, `Whether to trigger upload`)
|
||||||
)
|
)
|
||||||
flag.CommandLine.Parse(cmdline)
|
flag.CommandLine.Parse(cmdline)
|
||||||
|
|
@ -679,21 +679,17 @@ func doDockerBuildx(cmdline []string) {
|
||||||
build.MustRun(auther)
|
build.MustRun(auther)
|
||||||
}
|
}
|
||||||
// Retrieve the version infos to build and push to the following paths:
|
// Retrieve the version infos to build and push to the following paths:
|
||||||
// - ethereum/client-go:latest - Pushes to the master branch, Geth only
|
// - ethereum/client-go:latest - Pushes to the main branch, Geth only
|
||||||
// - ethereum/client-go:stable - Version tag publish on GitHub, Geth only
|
// - ethereum/client-go:alltools-latest - Pushes to the main branch, Geth & tools
|
||||||
// - ethereum/client-go:alltools-latest - Pushes to the master branch, Geth & tools
|
|
||||||
// - ethereum/client-go:alltools-stable - Version tag publish on GitHub, Geth & tools
|
|
||||||
// - ethereum/client-go:release-<major>.<minor> - Version tag publish on GitHub, Geth only
|
|
||||||
// - ethereum/client-go:alltools-release-<major>.<minor> - Version tag publish on GitHub, Geth & tools
|
|
||||||
// - ethereum/client-go:v<major>.<minor>.<patch> - Version tag publish on GitHub, Geth only
|
// - ethereum/client-go:v<major>.<minor>.<patch> - Version tag publish on GitHub, Geth only
|
||||||
// - ethereum/client-go:alltools-v<major>.<minor>.<patch> - Version tag publish on GitHub, Geth & tools
|
// - ethereum/client-go:alltools-v<major>.<minor>.<patch> - Version tag publish on GitHub, Geth & tools
|
||||||
var tags []string
|
var tags []string
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case env.Branch == "master":
|
case env.Branch == "main":
|
||||||
tags = []string{"latest"}
|
tags = []string{"latest"}
|
||||||
case strings.HasPrefix(env.Tag, "v1."):
|
case strings.HasPrefix(env.Tag, "v1."):
|
||||||
tags = []string{"stable", fmt.Sprintf("release-%v", version.Family), "v" + version.Semantic}
|
tags = []string{env.Tag}
|
||||||
}
|
}
|
||||||
// Need to create a mult-arch builder
|
// Need to create a mult-arch builder
|
||||||
check := exec.Command("docker", "buildx", "inspect", "multi-arch-builder")
|
check := exec.Command("docker", "buildx", "inspect", "multi-arch-builder")
|
||||||
|
|
@ -1097,7 +1093,7 @@ func doWindowsInstaller(cmdline []string) {
|
||||||
if env.Commit != "" {
|
if env.Commit != "" {
|
||||||
ver[2] += "-" + env.Commit[:8]
|
ver[2] += "-" + env.Commit[:8]
|
||||||
}
|
}
|
||||||
installer, err := filepath.Abs("geth-" + archiveBasename(*arch, version.Archive(env.Commit)) + ".exe")
|
installer, err := filepath.Abs("geth-" + archiveBasename(*arch, version.Archive(env.Tag, env.Commit)) + ".exe")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to convert installer file path: %v", err)
|
log.Fatalf("Failed to convert installer file path: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
32
circle.yml
32
circle.yml
|
|
@ -1,32 +0,0 @@
|
||||||
machine:
|
|
||||||
services:
|
|
||||||
- docker
|
|
||||||
|
|
||||||
dependencies:
|
|
||||||
cache_directories:
|
|
||||||
- "~/.ethash" # Cache the ethash DAG generated by hive for consecutive builds
|
|
||||||
- "~/.docker" # Cache all docker images manually to avoid lengthy rebuilds
|
|
||||||
override:
|
|
||||||
# Restore all previously cached docker images
|
|
||||||
- mkdir -p ~/.docker
|
|
||||||
- for img in `ls ~/.docker`; do docker load -i ~/.docker/$img; done
|
|
||||||
|
|
||||||
# Pull in and hive, restore cached ethash DAGs and do a dry run
|
|
||||||
- go get -u github.com/karalabe/hive
|
|
||||||
- (cd ~/.go_workspace/src/github.com/karalabe/hive && mkdir -p workspace/ethash/ ~/.ethash)
|
|
||||||
- (cd ~/.go_workspace/src/github.com/karalabe/hive && cp -r ~/.ethash/. workspace/ethash/)
|
|
||||||
- (cd ~/.go_workspace/src/github.com/karalabe/hive && hive --docker-noshell --client=NONE --test=. --sim=. --loglevel=6)
|
|
||||||
|
|
||||||
# Cache all the docker images and the ethash DAGs
|
|
||||||
- for img in `docker images | grep -v "^<none>" | tail -n +2 | awk '{print $1}'`; do docker save $img > ~/.docker/`echo $img | tr '/' ':'`.tar; done
|
|
||||||
- cp -r ~/.go_workspace/src/github.com/karalabe/hive/workspace/ethash/. ~/.ethash
|
|
||||||
|
|
||||||
test:
|
|
||||||
override:
|
|
||||||
# Build Geth and move into a known folder
|
|
||||||
- make geth
|
|
||||||
- cp ./build/bin/geth $HOME/geth
|
|
||||||
|
|
||||||
# Run hive and move all generated logs into the public artifacts folder
|
|
||||||
- (cd ~/.go_workspace/src/github.com/karalabe/hive && hive --docker-noshell --client=go-ethereum:local --override=$HOME/geth --test=. --sim=.)
|
|
||||||
- cp -r ~/.go_workspace/src/github.com/karalabe/hive/workspace/logs/* $CIRCLE_ARTIFACTS
|
|
||||||
|
|
@ -236,6 +236,10 @@ func ethFilter(args []string) (nodeFilter, error) {
|
||||||
filter = forkid.NewStaticFilter(params.HoleskyChainConfig, core.DefaultHoleskyGenesisBlock().ToBlock())
|
filter = forkid.NewStaticFilter(params.HoleskyChainConfig, core.DefaultHoleskyGenesisBlock().ToBlock())
|
||||||
case "hoodi":
|
case "hoodi":
|
||||||
filter = forkid.NewStaticFilter(params.HoodiChainConfig, core.DefaultHoodiGenesisBlock().ToBlock())
|
filter = forkid.NewStaticFilter(params.HoodiChainConfig, core.DefaultHoodiGenesisBlock().ToBlock())
|
||||||
|
case "berachain":
|
||||||
|
filter = forkid.NewStaticFilter(params.BerachainChainConfig, core.DefaultBerachainGenesisBlock().ToBlock())
|
||||||
|
case "bepolia":
|
||||||
|
filter = forkid.NewStaticFilter(params.BepoliaChainConfig, core.DefaultBepoliaGenesisBlock().ToBlock())
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown network %q", args[0])
|
return nil, fmt.Errorf("unknown network %q", args[0])
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ type header struct {
|
||||||
BlobGasUsed *uint64 `json:"blobGasUsed" rlp:"optional"`
|
BlobGasUsed *uint64 `json:"blobGasUsed" rlp:"optional"`
|
||||||
ExcessBlobGas *uint64 `json:"excessBlobGas" rlp:"optional"`
|
ExcessBlobGas *uint64 `json:"excessBlobGas" rlp:"optional"`
|
||||||
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
||||||
|
ParentProposerPubkey *common.Pubkey `json:"parentProposerPubkey" rlp:"optional"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type headerMarshaling struct {
|
type headerMarshaling struct {
|
||||||
|
|
@ -117,25 +118,26 @@ func (c *cliqueInput) UnmarshalJSON(input []byte) error {
|
||||||
// ToBlock converts i into a *types.Block
|
// ToBlock converts i into a *types.Block
|
||||||
func (i *bbInput) ToBlock() *types.Block {
|
func (i *bbInput) ToBlock() *types.Block {
|
||||||
header := &types.Header{
|
header := &types.Header{
|
||||||
ParentHash: i.Header.ParentHash,
|
ParentHash: i.Header.ParentHash,
|
||||||
UncleHash: types.EmptyUncleHash,
|
UncleHash: types.EmptyUncleHash,
|
||||||
Coinbase: common.Address{},
|
Coinbase: common.Address{},
|
||||||
Root: i.Header.Root,
|
Root: i.Header.Root,
|
||||||
TxHash: types.EmptyTxsHash,
|
TxHash: types.EmptyTxsHash,
|
||||||
ReceiptHash: types.EmptyReceiptsHash,
|
ReceiptHash: types.EmptyReceiptsHash,
|
||||||
Bloom: i.Header.Bloom,
|
Bloom: i.Header.Bloom,
|
||||||
Difficulty: common.Big0,
|
Difficulty: common.Big0,
|
||||||
Number: i.Header.Number,
|
Number: i.Header.Number,
|
||||||
GasLimit: i.Header.GasLimit,
|
GasLimit: i.Header.GasLimit,
|
||||||
GasUsed: i.Header.GasUsed,
|
GasUsed: i.Header.GasUsed,
|
||||||
Time: i.Header.Time,
|
Time: i.Header.Time,
|
||||||
Extra: i.Header.Extra,
|
Extra: i.Header.Extra,
|
||||||
MixDigest: i.Header.MixDigest,
|
MixDigest: i.Header.MixDigest,
|
||||||
BaseFee: i.Header.BaseFee,
|
BaseFee: i.Header.BaseFee,
|
||||||
WithdrawalsHash: i.Header.WithdrawalsHash,
|
WithdrawalsHash: i.Header.WithdrawalsHash,
|
||||||
BlobGasUsed: i.Header.BlobGasUsed,
|
BlobGasUsed: i.Header.BlobGasUsed,
|
||||||
ExcessBlobGas: i.Header.ExcessBlobGas,
|
ExcessBlobGas: i.Header.ExcessBlobGas,
|
||||||
ParentBeaconRoot: i.Header.ParentBeaconBlockRoot,
|
ParentBeaconRoot: i.Header.ParentBeaconBlockRoot,
|
||||||
|
ParentProposerPubkey: i.Header.ParentProposerPubkey,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill optional values.
|
// Fill optional values.
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ type stEnv struct {
|
||||||
ParentExcessBlobGas *uint64 `json:"parentExcessBlobGas,omitempty"`
|
ParentExcessBlobGas *uint64 `json:"parentExcessBlobGas,omitempty"`
|
||||||
ParentBlobGasUsed *uint64 `json:"parentBlobGasUsed,omitempty"`
|
ParentBlobGasUsed *uint64 `json:"parentBlobGasUsed,omitempty"`
|
||||||
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||||
|
ParentProposerPubkey *common.Pubkey `json:"parentProposerPubkey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type stEnvMarshaling struct {
|
type stEnvMarshaling struct {
|
||||||
|
|
@ -220,6 +221,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
)
|
)
|
||||||
core.ProcessParentBlockHash(prevHash, evm)
|
core.ProcessParentBlockHash(prevHash, evm)
|
||||||
}
|
}
|
||||||
|
// TODO(BRIP-4): Validate Prague1 block rules.
|
||||||
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 {
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ func (h header) MarshalJSON() ([]byte, error) {
|
||||||
BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed" rlp:"optional"`
|
BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed" rlp:"optional"`
|
||||||
ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas" rlp:"optional"`
|
ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas" rlp:"optional"`
|
||||||
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
||||||
|
ParentProposerPubkey *common.Pubkey `json:"parentProposerPubkey" rlp:"optional"`
|
||||||
}
|
}
|
||||||
var enc header
|
var enc header
|
||||||
enc.ParentHash = h.ParentHash
|
enc.ParentHash = h.ParentHash
|
||||||
|
|
@ -60,6 +61,7 @@ func (h header) MarshalJSON() ([]byte, error) {
|
||||||
enc.BlobGasUsed = (*math.HexOrDecimal64)(h.BlobGasUsed)
|
enc.BlobGasUsed = (*math.HexOrDecimal64)(h.BlobGasUsed)
|
||||||
enc.ExcessBlobGas = (*math.HexOrDecimal64)(h.ExcessBlobGas)
|
enc.ExcessBlobGas = (*math.HexOrDecimal64)(h.ExcessBlobGas)
|
||||||
enc.ParentBeaconBlockRoot = h.ParentBeaconBlockRoot
|
enc.ParentBeaconBlockRoot = h.ParentBeaconBlockRoot
|
||||||
|
enc.ParentProposerPubkey = h.ParentProposerPubkey
|
||||||
return json.Marshal(&enc)
|
return json.Marshal(&enc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,6 +88,7 @@ func (h *header) UnmarshalJSON(input []byte) error {
|
||||||
BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed" rlp:"optional"`
|
BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed" rlp:"optional"`
|
||||||
ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas" rlp:"optional"`
|
ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas" rlp:"optional"`
|
||||||
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
||||||
|
ParentProposerPubkey *common.Pubkey `json:"parentProposerPubkey" rlp:"optional"`
|
||||||
}
|
}
|
||||||
var dec header
|
var dec header
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
|
@ -155,5 +158,8 @@ func (h *header) UnmarshalJSON(input []byte) error {
|
||||||
if dec.ParentBeaconBlockRoot != nil {
|
if dec.ParentBeaconBlockRoot != nil {
|
||||||
h.ParentBeaconBlockRoot = dec.ParentBeaconBlockRoot
|
h.ParentBeaconBlockRoot = dec.ParentBeaconBlockRoot
|
||||||
}
|
}
|
||||||
|
if dec.ParentProposerPubkey != nil {
|
||||||
|
h.ParentProposerPubkey = dec.ParentProposerPubkey
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ func (s stEnv) MarshalJSON() ([]byte, error) {
|
||||||
ParentExcessBlobGas *math.HexOrDecimal64 `json:"parentExcessBlobGas,omitempty"`
|
ParentExcessBlobGas *math.HexOrDecimal64 `json:"parentExcessBlobGas,omitempty"`
|
||||||
ParentBlobGasUsed *math.HexOrDecimal64 `json:"parentBlobGasUsed,omitempty"`
|
ParentBlobGasUsed *math.HexOrDecimal64 `json:"parentBlobGasUsed,omitempty"`
|
||||||
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||||
|
ParentProposerPubkey *common.Pubkey `json:"parentProposerPubkey"`
|
||||||
}
|
}
|
||||||
var enc stEnv
|
var enc stEnv
|
||||||
enc.Coinbase = common.UnprefixedAddress(s.Coinbase)
|
enc.Coinbase = common.UnprefixedAddress(s.Coinbase)
|
||||||
|
|
@ -59,6 +60,7 @@ func (s stEnv) MarshalJSON() ([]byte, error) {
|
||||||
enc.ParentExcessBlobGas = (*math.HexOrDecimal64)(s.ParentExcessBlobGas)
|
enc.ParentExcessBlobGas = (*math.HexOrDecimal64)(s.ParentExcessBlobGas)
|
||||||
enc.ParentBlobGasUsed = (*math.HexOrDecimal64)(s.ParentBlobGasUsed)
|
enc.ParentBlobGasUsed = (*math.HexOrDecimal64)(s.ParentBlobGasUsed)
|
||||||
enc.ParentBeaconBlockRoot = s.ParentBeaconBlockRoot
|
enc.ParentBeaconBlockRoot = s.ParentBeaconBlockRoot
|
||||||
|
enc.ParentProposerPubkey = s.ParentProposerPubkey
|
||||||
return json.Marshal(&enc)
|
return json.Marshal(&enc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,6 +87,7 @@ func (s *stEnv) UnmarshalJSON(input []byte) error {
|
||||||
ParentExcessBlobGas *math.HexOrDecimal64 `json:"parentExcessBlobGas,omitempty"`
|
ParentExcessBlobGas *math.HexOrDecimal64 `json:"parentExcessBlobGas,omitempty"`
|
||||||
ParentBlobGasUsed *math.HexOrDecimal64 `json:"parentBlobGasUsed,omitempty"`
|
ParentBlobGasUsed *math.HexOrDecimal64 `json:"parentBlobGasUsed,omitempty"`
|
||||||
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||||
|
ParentProposerPubkey *common.Pubkey `json:"parentProposerPubkey"`
|
||||||
}
|
}
|
||||||
var dec stEnv
|
var dec stEnv
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
|
@ -154,5 +157,8 @@ func (s *stEnv) UnmarshalJSON(input []byte) error {
|
||||||
if dec.ParentBeaconBlockRoot != nil {
|
if dec.ParentBeaconBlockRoot != nil {
|
||||||
s.ParentBeaconBlockRoot = dec.ParentBeaconBlockRoot
|
s.ParentBeaconBlockRoot = dec.ParentBeaconBlockRoot
|
||||||
}
|
}
|
||||||
|
if dec.ParentProposerPubkey != nil {
|
||||||
|
s.ParentProposerPubkey = dec.ParentProposerPubkey
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,9 @@ func Transition(ctx *cli.Context) error {
|
||||||
if err := applyCancunChecks(&prestate.Env, chainConfig); err != nil {
|
if err := applyCancunChecks(&prestate.Env, chainConfig); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := applyPrague1Checks(&prestate.Env, chainConfig); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Configure tracer
|
// Configure tracer
|
||||||
if ctx.IsSet(TraceTracerFlag.Name) { // Custom tracing
|
if ctx.IsSet(TraceTracerFlag.Name) { // Custom tracing
|
||||||
|
|
@ -265,6 +268,19 @@ func applyCancunChecks(env *stEnv, chainConfig *params.ChainConfig) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func applyPrague1Checks(env *stEnv, chainConfig *params.ChainConfig) error {
|
||||||
|
if !chainConfig.IsPrague1(big.NewInt(int64(env.Number)), env.Timestamp) {
|
||||||
|
env.ParentProposerPubkey = nil // un-set it if it has been set too early
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Post-prague1
|
||||||
|
// We require BRIP-0004 proposer pubkey to be set in the env
|
||||||
|
if env.ParentProposerPubkey == nil {
|
||||||
|
return NewError(ErrorConfig, errors.New("post-prague1 env requires parentProposerPubkey to be set"))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type Alloc map[common.Address]types.Account
|
type Alloc map[common.Address]types.Account
|
||||||
|
|
||||||
func (g Alloc) OnRoot(common.Hash) {}
|
func (g Alloc) OnRoot(common.Hash) {}
|
||||||
|
|
|
||||||
|
|
@ -479,6 +479,10 @@ func importHistory(ctx *cli.Context) error {
|
||||||
network = "holesky"
|
network = "holesky"
|
||||||
case ctx.Bool(utils.HoodiFlag.Name):
|
case ctx.Bool(utils.HoodiFlag.Name):
|
||||||
network = "hoodi"
|
network = "hoodi"
|
||||||
|
case ctx.Bool(utils.BerachainFlag.Name):
|
||||||
|
network = "berachain"
|
||||||
|
case ctx.Bool(utils.BepoliaFlag.Name):
|
||||||
|
network = "bepolia"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// No network flag set, try to determine network based on files
|
// No network flag set, try to determine network based on files
|
||||||
|
|
@ -715,6 +719,10 @@ func downloadEra(ctx *cli.Context) error {
|
||||||
case ctx.IsSet(utils.MainnetFlag.Name):
|
case ctx.IsSet(utils.MainnetFlag.Name):
|
||||||
case ctx.IsSet(utils.SepoliaFlag.Name):
|
case ctx.IsSet(utils.SepoliaFlag.Name):
|
||||||
network = "sepolia"
|
network = "sepolia"
|
||||||
|
case ctx.IsSet(utils.BerachainFlag.Name):
|
||||||
|
network = "berachain"
|
||||||
|
case ctx.IsSet(utils.BepoliaFlag.Name):
|
||||||
|
network = "bepolia"
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported network, no known era1 checksums")
|
return fmt.Errorf("unsupported network, no known era1 checksums")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -285,6 +285,9 @@ 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.MainnetFlag.Name):
|
||||||
|
log.Info("Starting Geth on Ethereum mainnet...")
|
||||||
|
|
||||||
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...")
|
||||||
|
|
||||||
|
|
@ -294,15 +297,20 @@ func prepare(ctx *cli.Context) {
|
||||||
case ctx.IsSet(utils.HoodiFlag.Name):
|
case ctx.IsSet(utils.HoodiFlag.Name):
|
||||||
log.Info("Starting Geth on Hoodi testnet...")
|
log.Info("Starting Geth on Hoodi testnet...")
|
||||||
|
|
||||||
case !ctx.IsSet(utils.NetworkIdFlag.Name):
|
case ctx.IsSet(utils.BepoliaFlag.Name):
|
||||||
log.Info("Starting Geth on Ethereum mainnet...")
|
log.Info("Starting Geth on Bepolia testnet...")
|
||||||
|
|
||||||
|
case !ctx.IsSet(utils.NetworkIdFlag.Name), ctx.IsSet(utils.BerachainFlag.Name):
|
||||||
|
log.Info("Starting Geth on Berachain mainnet...")
|
||||||
}
|
}
|
||||||
// If we're a full node on mainnet without --cache specified, bump default cache allowance
|
|
||||||
|
// If we're a full node on Berachain mainnet without --cache specified, bump default cache allowance
|
||||||
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.HoleskyFlag.Name) &&
|
if !ctx.IsSet(utils.HoleskyFlag.Name) &&
|
||||||
!ctx.IsSet(utils.SepoliaFlag.Name) &&
|
!ctx.IsSet(utils.SepoliaFlag.Name) &&
|
||||||
!ctx.IsSet(utils.HoodiFlag.Name) &&
|
!ctx.IsSet(utils.HoodiFlag.Name) &&
|
||||||
|
!ctx.IsSet(utils.BepoliaFlag.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!
|
||||||
log.Info("Bumping default cache on mainnet", "provided", ctx.Int(utils.CacheFlag.Name), "updated", 4096)
|
log.Info("Bumping default cache on mainnet", "provided", ctx.Int(utils.CacheFlag.Name), "updated", 4096)
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ var (
|
||||||
}
|
}
|
||||||
NetworkIdFlag = &cli.Uint64Flag{
|
NetworkIdFlag = &cli.Uint64Flag{
|
||||||
Name: "networkid",
|
Name: "networkid",
|
||||||
Usage: "Explicitly set network id (integer)(For testnets: use --sepolia, --holesky, --hoodi instead)",
|
Usage: "Explicitly set network id (integer)(Testnet: use --bepolia)(For Ethereum: use --mainnet, --sepolia, etc.)",
|
||||||
Value: ethconfig.Defaults.NetworkId,
|
Value: ethconfig.Defaults.NetworkId,
|
||||||
Category: flags.EthCategory,
|
Category: flags.EthCategory,
|
||||||
}
|
}
|
||||||
|
|
@ -163,6 +163,17 @@ var (
|
||||||
Usage: "Hoodi network: pre-configured proof-of-stake test network",
|
Usage: "Hoodi network: pre-configured proof-of-stake test network",
|
||||||
Category: flags.EthCategory,
|
Category: flags.EthCategory,
|
||||||
}
|
}
|
||||||
|
// Berachain
|
||||||
|
BerachainFlag = &cli.BoolFlag{
|
||||||
|
Name: "berachain",
|
||||||
|
Usage: "Berachain mainnet",
|
||||||
|
Category: flags.EthCategory,
|
||||||
|
}
|
||||||
|
BepoliaFlag = &cli.BoolFlag{
|
||||||
|
Name: "bepolia",
|
||||||
|
Usage: "Bepolia network: pre-configured proof-of-stake test network",
|
||||||
|
Category: flags.EthCategory,
|
||||||
|
}
|
||||||
// Dev mode
|
// Dev mode
|
||||||
DeveloperFlag = &cli.BoolFlag{
|
DeveloperFlag = &cli.BoolFlag{
|
||||||
Name: "dev",
|
Name: "dev",
|
||||||
|
|
@ -449,7 +460,7 @@ var (
|
||||||
// Performance tuning settings
|
// Performance tuning settings
|
||||||
CacheFlag = &cli.IntFlag{
|
CacheFlag = &cli.IntFlag{
|
||||||
Name: "cache",
|
Name: "cache",
|
||||||
Usage: "Megabytes of memory allocated to internal caching (default = 4096 mainnet full node, 128 light mode)",
|
Usage: "Megabytes of memory allocated to internal caching (default = 4096 berachain mainnet full node, 128 light mode)",
|
||||||
Value: 1024,
|
Value: 1024,
|
||||||
Category: flags.PerfCategory,
|
Category: flags.PerfCategory,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,8 @@ var (
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
testSepoliaFlag,
|
testSepoliaFlag,
|
||||||
testMainnetFlag,
|
testMainnetFlag,
|
||||||
|
testBepoliaFlag,
|
||||||
|
testBerachainFlag,
|
||||||
filterQueryFileFlag,
|
filterQueryFileFlag,
|
||||||
filterErrorFileFlag,
|
filterErrorFileFlag,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,16 @@ var (
|
||||||
Usage: "Use test cases for mainnet network",
|
Usage: "Use test cases for mainnet network",
|
||||||
Category: flags.TestingCategory,
|
Category: flags.TestingCategory,
|
||||||
}
|
}
|
||||||
|
testBepoliaFlag = &cli.BoolFlag{
|
||||||
|
Name: "bepolia",
|
||||||
|
Usage: "Use test cases for bepolia network",
|
||||||
|
Category: flags.TestingCategory,
|
||||||
|
}
|
||||||
|
testBerachainFlag = &cli.BoolFlag{
|
||||||
|
Name: "berachain",
|
||||||
|
Usage: "Use test cases for berachain mainnet network",
|
||||||
|
Category: flags.TestingCategory,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// testConfig holds the parameters for testing.
|
// testConfig holds the parameters for testing.
|
||||||
|
|
@ -117,10 +127,13 @@ func validateHistoryPruneErr(err error, blockNum uint64, historyPruneBlock *uint
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(bera): Add test filter & history queries for Berachain mainnet & Bepolia in queries/ folder
|
||||||
func testConfigFromCLI(ctx *cli.Context) (cfg testConfig) {
|
func testConfigFromCLI(ctx *cli.Context) (cfg testConfig) {
|
||||||
flags.CheckExclusive(ctx, testMainnetFlag, testSepoliaFlag)
|
flags.CheckExclusive(ctx, testMainnetFlag, testSepoliaFlag, testBerachainFlag, testBepoliaFlag)
|
||||||
if (ctx.IsSet(testMainnetFlag.Name) || ctx.IsSet(testSepoliaFlag.Name)) && ctx.IsSet(filterQueryFileFlag.Name) {
|
if (ctx.IsSet(testMainnetFlag.Name) || ctx.IsSet(testSepoliaFlag.Name) || ctx.IsSet(testBerachainFlag.Name) || ctx.IsSet(testBepoliaFlag.Name)) &&
|
||||||
exit(filterQueryFileFlag.Name + " cannot be used with " + testMainnetFlag.Name + " or " + testSepoliaFlag.Name)
|
ctx.IsSet(filterQueryFileFlag.Name) {
|
||||||
|
exit(filterQueryFileFlag.Name + " cannot be used with " + testMainnetFlag.Name + " or " +
|
||||||
|
testSepoliaFlag.Name + "or" + testBerachainFlag.Name + " or " + testBepoliaFlag.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// configure ethclient
|
// configure ethclient
|
||||||
|
|
@ -166,6 +179,44 @@ func testConfigFromCLI(ctx *cli.Context) (cfg testConfig) {
|
||||||
}
|
}
|
||||||
cfg.historyPruneBlock = new(uint64)
|
cfg.historyPruneBlock = new(uint64)
|
||||||
*cfg.historyPruneBlock = history.PrunePoints[params.SepoliaGenesisHash].BlockNumber
|
*cfg.historyPruneBlock = history.PrunePoints[params.SepoliaGenesisHash].BlockNumber
|
||||||
|
case ctx.Bool(testBerachainFlag.Name):
|
||||||
|
cfg.fsys = builtinTestFiles
|
||||||
|
if ctx.IsSet(filterQueryFileFlag.Name) {
|
||||||
|
cfg.filterQueryFile = ctx.String(filterQueryFileFlag.Name)
|
||||||
|
} else {
|
||||||
|
cfg.filterQueryFile = "queries/filter_queries_berachain.json"
|
||||||
|
}
|
||||||
|
if ctx.IsSet(historyTestFileFlag.Name) {
|
||||||
|
cfg.historyTestFile = ctx.String(historyTestFileFlag.Name)
|
||||||
|
} else {
|
||||||
|
cfg.historyTestFile = "queries/history_berachain.json"
|
||||||
|
}
|
||||||
|
if ctx.IsSet(traceTestFileFlag.Name) {
|
||||||
|
cfg.traceTestFile = ctx.String(traceTestFileFlag.Name)
|
||||||
|
} else {
|
||||||
|
cfg.traceTestFile = "queries/trace_berachain.json"
|
||||||
|
}
|
||||||
|
cfg.historyPruneBlock = new(uint64)
|
||||||
|
*cfg.historyPruneBlock = history.PrunePoints[params.BerachainGenesisHash].BlockNumber
|
||||||
|
case ctx.Bool(testBepoliaFlag.Name):
|
||||||
|
cfg.fsys = builtinTestFiles
|
||||||
|
if ctx.IsSet(filterQueryFileFlag.Name) {
|
||||||
|
cfg.filterQueryFile = ctx.String(filterQueryFileFlag.Name)
|
||||||
|
} else {
|
||||||
|
cfg.filterQueryFile = "queries/filter_queries_bepolia.json"
|
||||||
|
}
|
||||||
|
if ctx.IsSet(historyTestFileFlag.Name) {
|
||||||
|
cfg.historyTestFile = ctx.String(historyTestFileFlag.Name)
|
||||||
|
} else {
|
||||||
|
cfg.historyTestFile = "queries/history_bepolia.json"
|
||||||
|
}
|
||||||
|
if ctx.IsSet(traceTestFileFlag.Name) {
|
||||||
|
cfg.traceTestFile = ctx.String(traceTestFileFlag.Name)
|
||||||
|
} else {
|
||||||
|
cfg.traceTestFile = "queries/trace_bepolia.json"
|
||||||
|
}
|
||||||
|
cfg.historyPruneBlock = new(uint64)
|
||||||
|
*cfg.historyPruneBlock = history.PrunePoints[params.BepoliaGenesisHash].BlockNumber
|
||||||
default:
|
default:
|
||||||
cfg.fsys = os.DirFS(".")
|
cfg.fsys = os.DirFS(".")
|
||||||
cfg.filterQueryFile = ctx.String(filterQueryFileFlag.Name)
|
cfg.filterQueryFile = ctx.String(filterQueryFileFlag.Name)
|
||||||
|
|
|
||||||
|
|
@ -39,11 +39,16 @@ const (
|
||||||
HashLength = 32
|
HashLength = 32
|
||||||
// AddressLength is the expected length of the address
|
// AddressLength is the expected length of the address
|
||||||
AddressLength = 20
|
AddressLength = 20
|
||||||
|
|
||||||
|
// Berachain: PubkeyLength represents the expected byte length of a BLS12-381 public key
|
||||||
|
// as used by the beacon chain.
|
||||||
|
PubkeyLength = 48
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
hashT = reflect.TypeOf(Hash{})
|
hashT = reflect.TypeOf(Hash{})
|
||||||
addressT = reflect.TypeOf(Address{})
|
addressT = reflect.TypeOf(Address{})
|
||||||
|
pubkeyT = reflect.TypeOf(Pubkey{})
|
||||||
|
|
||||||
// MaxAddress represents the maximum possible address value.
|
// MaxAddress represents the maximum possible address value.
|
||||||
MaxAddress = HexToAddress("0xffffffffffffffffffffffffffffffffffffffff")
|
MaxAddress = HexToAddress("0xffffffffffffffffffffffffffffffffffffffff")
|
||||||
|
|
@ -486,3 +491,60 @@ func (b PrettyBytes) TerminalString() string {
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%#x...%x (%dB)", b[:3], b[len(b)-3:], len(b))
|
return fmt.Sprintf("%#x...%x (%dB)", b[:3], b[len(b)-3:], len(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/////////// Berachain: Pubkey
|
||||||
|
|
||||||
|
// Pubkey represents a fixed-length 48-byte BLS public key.
|
||||||
|
// JSON and text serialization use 0x-prefixed hex strings.
|
||||||
|
type Pubkey [PubkeyLength]byte
|
||||||
|
|
||||||
|
// Bytes returns a copy of the underlying byte slice.
|
||||||
|
func (p Pubkey) Bytes() []byte { return p[:] }
|
||||||
|
|
||||||
|
// String returns the hex-encoded string representation of the pubkey.
|
||||||
|
func (p Pubkey) String() string { return hexutil.Encode(p[:]) }
|
||||||
|
|
||||||
|
// Format implements fmt.Formatter.
|
||||||
|
// Pubkey supports the %v, %s, %q, %x, %X and %d format verbs.
|
||||||
|
func (p Pubkey) Format(s fmt.State, c rune) {
|
||||||
|
hexb := make([]byte, 2+len(p)*2)
|
||||||
|
copy(hexb, "0x")
|
||||||
|
hex.Encode(hexb[2:], p[:])
|
||||||
|
|
||||||
|
switch c {
|
||||||
|
case 'x', 'X':
|
||||||
|
if !s.Flag('#') {
|
||||||
|
hexb = hexb[2:]
|
||||||
|
}
|
||||||
|
if c == 'X' {
|
||||||
|
hexb = bytes.ToUpper(hexb)
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case 'v', 's':
|
||||||
|
s.Write(hexb)
|
||||||
|
case 'q':
|
||||||
|
q := []byte{'"'}
|
||||||
|
s.Write(q)
|
||||||
|
s.Write(hexb)
|
||||||
|
s.Write(q)
|
||||||
|
case 'd':
|
||||||
|
fmt.Fprint(s, ([len(p)]byte)(p))
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(s, "%%!%c(pubkey=%x)", c, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText encodes the pubkey as a 0x-prefixed hex string.
|
||||||
|
func (p Pubkey) MarshalText() ([]byte, error) {
|
||||||
|
return hexutil.Bytes(p[:]).MarshalText()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText decodes a 0x-prefixed hex string into the pubkey.
|
||||||
|
func (p *Pubkey) UnmarshalText(input []byte) error {
|
||||||
|
return hexutil.UnmarshalFixedText("Pubkey", input, p[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON decodes a JSON string containing the 0x-prefixed hex pubkey.
|
||||||
|
func (p *Pubkey) UnmarshalJSON(input []byte) error {
|
||||||
|
return hexutil.UnmarshalFixedJSON(pubkeyT, input, p[:])
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -282,6 +282,17 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Berachain specific: verify the existence of the proposer pubkey.
|
||||||
|
prague1 := chain.Config().IsPrague1(header.Number, header.Time)
|
||||||
|
if !prague1 {
|
||||||
|
if header.ParentProposerPubkey != nil {
|
||||||
|
return fmt.Errorf("invalid proposer pubkey: have %#x, expected nil", header.ParentProposerPubkey)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if header.ParentProposerPubkey == nil {
|
||||||
|
return errors.New("header is missing proposer pubkey")
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,21 @@ func VerifyEIP1559Header(config *params.ChainConfig, parent, header *types.Heade
|
||||||
|
|
||||||
// CalcBaseFee calculates the basefee of the header.
|
// CalcBaseFee calculates the basefee of the header.
|
||||||
func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int {
|
func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int {
|
||||||
|
calculatedBaseFee := calcBaseFee(config, parent)
|
||||||
|
|
||||||
|
// Starting at the Prague1 fork, the base fee must be at least the minimum base fee.
|
||||||
|
if config.IsPrague1(parent.Number, parent.Time) {
|
||||||
|
minBaseFee := new(big.Int).SetUint64(config.Berachain.Prague1.MinimumBaseFeeWei)
|
||||||
|
if calculatedBaseFee.Cmp(minBaseFee) < 0 {
|
||||||
|
calculatedBaseFee = minBaseFee
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return calculatedBaseFee
|
||||||
|
}
|
||||||
|
|
||||||
|
// calcBaseFee calculates the basefee of the header in wei.
|
||||||
|
func calcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int {
|
||||||
// If the current block is the first EIP-1559 block, return the InitialBaseFee.
|
// If the current block is the first EIP-1559 block, return the InitialBaseFee.
|
||||||
if !config.IsLondon(parent.Number) {
|
if !config.IsLondon(parent.Number) {
|
||||||
return new(big.Int).SetUint64(params.InitialBaseFee)
|
return new(big.Int).SetUint64(params.InitialBaseFee)
|
||||||
|
|
@ -76,7 +91,7 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int {
|
||||||
num.SetUint64(parent.GasUsed - parentGasTarget)
|
num.SetUint64(parent.GasUsed - parentGasTarget)
|
||||||
num.Mul(num, parent.BaseFee)
|
num.Mul(num, parent.BaseFee)
|
||||||
num.Div(num, denom.SetUint64(parentGasTarget))
|
num.Div(num, denom.SetUint64(parentGasTarget))
|
||||||
num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator()))
|
num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator(parent.Number, parent.Time)))
|
||||||
if num.Cmp(common.Big1) < 0 {
|
if num.Cmp(common.Big1) < 0 {
|
||||||
return num.Add(parent.BaseFee, common.Big1)
|
return num.Add(parent.BaseFee, common.Big1)
|
||||||
}
|
}
|
||||||
|
|
@ -87,7 +102,7 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int {
|
||||||
num.SetUint64(parentGasTarget - parent.GasUsed)
|
num.SetUint64(parentGasTarget - parent.GasUsed)
|
||||||
num.Mul(num, parent.BaseFee)
|
num.Mul(num, parent.BaseFee)
|
||||||
num.Div(num, denom.SetUint64(parentGasTarget))
|
num.Div(num, denom.SetUint64(parentGasTarget))
|
||||||
num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator()))
|
num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator(parent.Number, parent.Time)))
|
||||||
|
|
||||||
baseFee := num.Sub(parent.BaseFee, num)
|
baseFee := num.Sub(parent.BaseFee, num)
|
||||||
if baseFee.Cmp(common.Big0) < 0 {
|
if baseFee.Cmp(common.Big0) < 0 {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,9 @@ package core
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"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/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
@ -47,7 +49,7 @@ func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain) *Bloc
|
||||||
|
|
||||||
// ValidateBody validates the given block's uncles and verifies the block
|
// ValidateBody validates the given block's uncles and verifies the block
|
||||||
// header's transaction and uncle roots. The headers are assumed to be already
|
// header's transaction and uncle roots. The headers are assumed to be already
|
||||||
// validated at this point.
|
// validated at this point. Also it the Prague1 block according to BRIP-0004.
|
||||||
func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
||||||
// check EIP 7934 RLP-encoded block size cap
|
// check EIP 7934 RLP-encoded block size cap
|
||||||
if v.config.IsOsaka(block.Number(), block.Time()) && block.Size() > params.MaxBlockSize {
|
if v.config.IsOsaka(block.Number(), block.Time()) && block.Size() > params.MaxBlockSize {
|
||||||
|
|
@ -85,9 +87,37 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
||||||
return errors.New("withdrawals present in block body")
|
return errors.New("withdrawals present in block body")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Berachain: Pre-compute expected PoL tx hash when in Prague1.
|
||||||
|
isPrague1 := v.config.IsPrague1(block.Number(), block.Time())
|
||||||
|
var expectedPoLHash common.Hash
|
||||||
|
if isPrague1 {
|
||||||
|
polTx, err := types.NewPoLTx(
|
||||||
|
v.config.ChainID,
|
||||||
|
v.config.Berachain.Prague1.PoLDistributorAddress,
|
||||||
|
new(big.Int).Sub(block.Number(), big.NewInt(1)),
|
||||||
|
params.PoLTxGasLimit,
|
||||||
|
block.BaseFee(),
|
||||||
|
block.ProposerPubkey(),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create expected PoL tx: %w", err)
|
||||||
|
}
|
||||||
|
expectedPoLHash = polTx.Hash()
|
||||||
|
}
|
||||||
|
|
||||||
// Blob transactions may be present after the Cancun fork.
|
// Blob transactions may be present after the Cancun fork.
|
||||||
var blobs int
|
var blobs int
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
|
// Berachain: validate the PoL tx is only the first tx in the block.
|
||||||
|
switch {
|
||||||
|
case isPrague1 && i == 0:
|
||||||
|
if tx.Hash() != expectedPoLHash {
|
||||||
|
return fmt.Errorf("PoL tx hash mismatch: have %v, want %v", tx.Hash(), expectedPoLHash)
|
||||||
|
}
|
||||||
|
case tx.Type() == types.PoLTxType:
|
||||||
|
return fmt.Errorf("invalid block: tx at index %d is a PoL tx", i)
|
||||||
|
}
|
||||||
|
|
||||||
// Count the number of blobs to validate against the header's blobGasUsed
|
// Count the number of blobs to validate against the header's blobGasUsed
|
||||||
blobs += len(tx.BlobHashes())
|
blobs += len(tx.BlobHashes())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,127 @@ import (
|
||||||
"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/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Berachain:Prague-1 PoL validation tests
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// newPrague1Config returns a ChainConfig where Prague (and Prague-1) are active
|
||||||
|
// from timestamp 0. The caller can specify the PoL distributor address.
|
||||||
|
func newPrague1Config(distributor common.Address) *params.ChainConfig {
|
||||||
|
zero := uint64(0)
|
||||||
|
cfg := *params.AllDevChainProtocolChanges // copy
|
||||||
|
cfg.Berachain.Prague1 = params.Prague1Config{
|
||||||
|
Time: &zero,
|
||||||
|
PoLDistributorAddress: distributor,
|
||||||
|
}
|
||||||
|
return &cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildTestChain initialises an in-memory blockchain with the provided config
|
||||||
|
// and returns the chain and its validator.
|
||||||
|
func buildTestChain(t *testing.T, cfg *params.ChainConfig) (*BlockChain, Validator) {
|
||||||
|
t.Helper()
|
||||||
|
db := rawdb.NewMemoryDatabase()
|
||||||
|
genesis := &Genesis{Config: cfg}
|
||||||
|
chain, err := NewBlockChain(db, genesis, ethash.NewFaker(), nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create blockchain: %v", err)
|
||||||
|
}
|
||||||
|
return chain, chain.Validator()
|
||||||
|
}
|
||||||
|
|
||||||
|
// samplePubkey returns a deterministic 48-byte pubkey for tests.
|
||||||
|
func samplePubkey() *common.Pubkey {
|
||||||
|
var pk common.Pubkey
|
||||||
|
for i := 0; i < common.PubkeyLength; i++ {
|
||||||
|
pk[i] = byte(i)
|
||||||
|
}
|
||||||
|
return &pk
|
||||||
|
}
|
||||||
|
|
||||||
|
// makeBlock builds a child block on top of parent with the supplied txs and timestamp.
|
||||||
|
func makeBlock(parent *types.Header, txs types.Transactions, timestamp uint64) *types.Block {
|
||||||
|
header := &types.Header{
|
||||||
|
ParentHash: parent.Hash(),
|
||||||
|
Number: new(big.Int).Add(parent.Number, big.NewInt(1)),
|
||||||
|
Time: timestamp,
|
||||||
|
GasLimit: params.GenesisGasLimit * 10,
|
||||||
|
Difficulty: big.NewInt(1),
|
||||||
|
ParentProposerPubkey: samplePubkey(),
|
||||||
|
BaseFee: big.NewInt(1000000000),
|
||||||
|
}
|
||||||
|
return types.NewBlock(header, &types.Body{Transactions: txs}, nil, trie.NewStackTrie(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateBody_Prague1_Valid(t *testing.T) {
|
||||||
|
distributor := common.HexToAddress("0x1111111111111111111111111111111111111111")
|
||||||
|
cfg := newPrague1Config(distributor)
|
||||||
|
chain, validator := buildTestChain(t, cfg)
|
||||||
|
|
||||||
|
// Build PoL tx + dummy tx.
|
||||||
|
polTx, err := types.NewPoLTx(cfg.ChainID, distributor, big.NewInt(0), params.PoLTxGasLimit, big.NewInt(1000000000), samplePubkey())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create PoL tx: %v", err)
|
||||||
|
}
|
||||||
|
dummyTx := types.NewTx(&types.LegacyTx{Nonce: 1})
|
||||||
|
|
||||||
|
block := makeBlock(chain.CurrentHeader(), types.Transactions{polTx, dummyTx}, 1)
|
||||||
|
|
||||||
|
if err := validator.ValidateBody(block); err != nil {
|
||||||
|
t.Fatalf("ValidateBody returned error for valid Prague1 block: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateBody_Prague1_InvalidHash(t *testing.T) {
|
||||||
|
distributor := common.HexToAddress("0x2222222222222222222222222222222222222222")
|
||||||
|
cfg := newPrague1Config(distributor)
|
||||||
|
chain, validator := buildTestChain(t, cfg)
|
||||||
|
|
||||||
|
// PoL tx with WRONG pubkey (different from header.ParentProposerPubkey).
|
||||||
|
wrongPk := &common.Pubkey{}
|
||||||
|
polTx, _ := types.NewPoLTx(cfg.ChainID, distributor, big.NewInt(0), params.PoLTxGasLimit, big.NewInt(1000000000), wrongPk)
|
||||||
|
block := makeBlock(chain.CurrentHeader(), types.Transactions{polTx}, 1)
|
||||||
|
|
||||||
|
if err := validator.ValidateBody(block); err == nil {
|
||||||
|
t.Fatalf("expected error due to invalid PoL hash, got nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateBody_Prague1_MisplacedPoL(t *testing.T) {
|
||||||
|
distributor := common.HexToAddress("0x3333333333333333333333333333333333333333")
|
||||||
|
cfg := newPrague1Config(distributor)
|
||||||
|
chain, validator := buildTestChain(t, cfg)
|
||||||
|
|
||||||
|
polTx, _ := types.NewPoLTx(cfg.ChainID, distributor, big.NewInt(0), params.PoLTxGasLimit, big.NewInt(1000000000), samplePubkey())
|
||||||
|
dummyTx := types.NewTx(&types.LegacyTx{Nonce: 1})
|
||||||
|
// PoL tx placed second.
|
||||||
|
block := makeBlock(chain.CurrentHeader(), types.Transactions{dummyTx, polTx}, 1)
|
||||||
|
|
||||||
|
if err := validator.ValidateBody(block); err == nil {
|
||||||
|
t.Fatalf("expected error for PoL tx at index >0, got nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateBody_PrePrague1_PoLProhibited(t *testing.T) {
|
||||||
|
distributor := common.HexToAddress("0x4444444444444444444444444444444444444444")
|
||||||
|
// Prague time active, but Prague1 *future* at timestamp 1000.
|
||||||
|
future := uint64(1000)
|
||||||
|
cfg := *params.AllDevChainProtocolChanges
|
||||||
|
cfg.Berachain.Prague1.Time = &future
|
||||||
|
cfg.Berachain.Prague1.PoLDistributorAddress = distributor
|
||||||
|
chain, validator := buildTestChain(t, &cfg)
|
||||||
|
|
||||||
|
polTx, _ := types.NewPoLTx(cfg.ChainID, distributor, big.NewInt(0), params.PoLTxGasLimit, big.NewInt(1000000000), samplePubkey())
|
||||||
|
block := makeBlock(chain.CurrentHeader(), types.Transactions{polTx}, 1) // timestamp 1 < future
|
||||||
|
|
||||||
|
if err := validator.ValidateBody(block); err == nil {
|
||||||
|
t.Fatalf("expected error: PoL tx before Prague1 fork should be invalid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Tests that simple header verification works, for both good and bad blocks.
|
// Tests that simple header verification works, for both good and bad blocks.
|
||||||
func TestHeaderVerification(t *testing.T) {
|
func TestHeaderVerification(t *testing.T) {
|
||||||
testHeaderVerification(t, rawdb.HashScheme)
|
testHeaderVerification(t, rawdb.HashScheme)
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,12 @@ func (b *BlockGen) SetParentBeaconRoot(root common.Hash) {
|
||||||
ProcessBeaconBlockRoot(root, vm.NewEVM(blockContext, b.statedb, b.cm.config, vm.Config{}))
|
ProcessBeaconBlockRoot(root, vm.NewEVM(blockContext, b.statedb, b.cm.config, vm.Config{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetParentProposerPubkey sets the parent proposer pubkey field of the generated
|
||||||
|
// block.
|
||||||
|
func (b *BlockGen) SetParentProposerPubkey(pubkey common.Pubkey) {
|
||||||
|
b.header.ParentProposerPubkey = &pubkey
|
||||||
|
}
|
||||||
|
|
||||||
// addTx adds a transaction to the generated block. If no coinbase has
|
// addTx adds a transaction to the generated block. If no coinbase has
|
||||||
// been set, the block's coinbase is set to the zero address.
|
// been set, the block's coinbase is set to the zero address.
|
||||||
//
|
//
|
||||||
|
|
@ -116,9 +122,16 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti
|
||||||
var (
|
var (
|
||||||
blockContext = NewEVMBlockContext(b.header, bc, &b.header.Coinbase)
|
blockContext = NewEVMBlockContext(b.header, bc, &b.header.Coinbase)
|
||||||
evm = vm.NewEVM(blockContext, b.statedb, b.cm.config, vmConfig)
|
evm = vm.NewEVM(blockContext, b.statedb, b.cm.config, vmConfig)
|
||||||
|
gasPool = b.gasPool
|
||||||
|
gasUsed = &b.header.GasUsed
|
||||||
)
|
)
|
||||||
|
// Berachain: PoL txs do not count towards block gas.
|
||||||
|
if tx.Type() == types.PoLTxType {
|
||||||
|
gasPool = new(GasPool).AddGas(params.PoLTxGasLimit)
|
||||||
|
gasUsed = new(uint64)
|
||||||
|
}
|
||||||
b.statedb.SetTxContext(tx.Hash(), len(b.txs))
|
b.statedb.SetTxContext(tx.Hash(), len(b.txs))
|
||||||
receipt, err := ApplyTransaction(evm, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed)
|
receipt, err := ApplyTransaction(evm, gasPool, b.statedb, b.header, tx, gasUsed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -617,6 +630,9 @@ func (cm *chainMaker) makeHeader(parent *types.Block, state *state.StateDB, engi
|
||||||
header.BlobGasUsed = new(uint64)
|
header.BlobGasUsed = new(uint64)
|
||||||
header.ParentBeaconRoot = new(common.Hash)
|
header.ParentBeaconRoot = new(common.Hash)
|
||||||
}
|
}
|
||||||
|
if cm.config.IsPrague1(header.Number, header.Time) {
|
||||||
|
header.ParentProposerPubkey = new(common.Pubkey)
|
||||||
|
}
|
||||||
return header
|
return header
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -223,6 +223,10 @@ func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc types.Gene
|
||||||
genesis = DefaultHoleskyGenesisBlock()
|
genesis = DefaultHoleskyGenesisBlock()
|
||||||
case params.HoodiGenesisHash:
|
case params.HoodiGenesisHash:
|
||||||
genesis = DefaultHoodiGenesisBlock()
|
genesis = DefaultHoodiGenesisBlock()
|
||||||
|
case params.BerachainGenesisHash:
|
||||||
|
genesis = DefaultBerachainGenesisBlock()
|
||||||
|
case params.BepoliaGenesisHash:
|
||||||
|
genesis = DefaultBepoliaGenesisBlock()
|
||||||
}
|
}
|
||||||
if genesis != nil {
|
if genesis != nil {
|
||||||
return genesis.Alloc, nil
|
return genesis.Alloc, nil
|
||||||
|
|
@ -438,6 +442,10 @@ func (g *Genesis) chainConfigOrDefault(ghash common.Hash, stored *params.ChainCo
|
||||||
return params.SepoliaChainConfig
|
return params.SepoliaChainConfig
|
||||||
case ghash == params.HoodiGenesisHash:
|
case ghash == params.HoodiGenesisHash:
|
||||||
return params.HoodiChainConfig
|
return params.HoodiChainConfig
|
||||||
|
case ghash == params.BerachainGenesisHash:
|
||||||
|
return params.BerachainChainConfig
|
||||||
|
case ghash == params.BepoliaGenesisHash:
|
||||||
|
return params.BepoliaChainConfig
|
||||||
default:
|
default:
|
||||||
return stored
|
return stored
|
||||||
}
|
}
|
||||||
|
|
@ -518,6 +526,12 @@ func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block {
|
||||||
if conf.IsPrague(num, g.Timestamp) {
|
if conf.IsPrague(num, g.Timestamp) {
|
||||||
head.RequestsHash = &types.EmptyRequestsHash
|
head.RequestsHash = &types.EmptyRequestsHash
|
||||||
}
|
}
|
||||||
|
if conf.IsPrague1(num, g.Timestamp) {
|
||||||
|
// BRIP-0004: The parentProposerPubkey of the genesis block is always
|
||||||
|
// the zero pubkey. This is because the genesis block does not have a parent
|
||||||
|
// by definition.
|
||||||
|
head.ParentProposerPubkey = new(common.Pubkey)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return types.NewBlock(head, &types.Body{Withdrawals: withdrawals}, nil, trie.NewStackTrie(nil))
|
return types.NewBlock(head, &types.Body{Withdrawals: withdrawals}, nil, trie.NewStackTrie(nil))
|
||||||
}
|
}
|
||||||
|
|
@ -644,6 +658,32 @@ func DefaultHoodiGenesisBlock() *Genesis {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefaultBerachainGenesisBlock returns the Berachain main net genesis block.
|
||||||
|
func DefaultBerachainGenesisBlock() *Genesis {
|
||||||
|
return &Genesis{
|
||||||
|
Config: params.BerachainChainConfig,
|
||||||
|
Nonce: 0x1234,
|
||||||
|
ExtraData: []byte{},
|
||||||
|
GasLimit: 0x1c9c380,
|
||||||
|
Difficulty: big.NewInt(0x01),
|
||||||
|
Timestamp: 1737381600,
|
||||||
|
Alloc: decodePrealloc(berachainAllocData),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultBepoliaGenesisBlock returns the Bepolia network genesis block.
|
||||||
|
func DefaultBepoliaGenesisBlock() *Genesis {
|
||||||
|
return &Genesis{
|
||||||
|
Config: params.BepoliaChainConfig,
|
||||||
|
Nonce: 0x1234,
|
||||||
|
ExtraData: []byte{},
|
||||||
|
GasLimit: 0x1c9c380,
|
||||||
|
Difficulty: big.NewInt(0x01),
|
||||||
|
Timestamp: 1739976735,
|
||||||
|
Alloc: decodePrealloc(bepoliaAllocData),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// DeveloperGenesisBlock returns the 'geth --dev' genesis block.
|
// DeveloperGenesisBlock returns the 'geth --dev' genesis block.
|
||||||
func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis {
|
func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis {
|
||||||
// Override the default period to the user requested one
|
// Override the default period to the user requested one
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -84,6 +84,15 @@ func testSetupGenesis(t *testing.T, scheme string) {
|
||||||
wantHash: params.MainnetGenesisHash,
|
wantHash: params.MainnetGenesisHash,
|
||||||
wantConfig: params.MainnetChainConfig,
|
wantConfig: params.MainnetChainConfig,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "berachain block in DB, genesis == nil",
|
||||||
|
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
|
||||||
|
DefaultBerachainGenesisBlock().MustCommit(db, triedb.NewDatabase(db, newDbConfig(scheme)))
|
||||||
|
return SetupGenesisBlock(db, triedb.NewDatabase(db, newDbConfig(scheme)), nil)
|
||||||
|
},
|
||||||
|
wantHash: params.BerachainGenesisHash,
|
||||||
|
wantConfig: params.BerachainChainConfig,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "custom block in DB, genesis == nil",
|
name: "custom block in DB, genesis == nil",
|
||||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
|
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
|
||||||
|
|
@ -103,6 +112,15 @@ func testSetupGenesis(t *testing.T, scheme string) {
|
||||||
},
|
},
|
||||||
wantErr: &GenesisMismatchError{Stored: customghash, New: params.SepoliaGenesisHash},
|
wantErr: &GenesisMismatchError{Stored: customghash, New: params.SepoliaGenesisHash},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "custom block in DB, genesis == bepolia",
|
||||||
|
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
|
||||||
|
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
||||||
|
customg.Commit(db, tdb)
|
||||||
|
return SetupGenesisBlock(db, tdb, DefaultBepoliaGenesisBlock())
|
||||||
|
},
|
||||||
|
wantErr: &GenesisMismatchError{Stored: customghash, New: params.BepoliaGenesisHash},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "custom block in DB, genesis == hoodi",
|
name: "custom block in DB, genesis == hoodi",
|
||||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
|
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
|
||||||
|
|
@ -188,6 +206,8 @@ func TestGenesisHashes(t *testing.T) {
|
||||||
{DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash},
|
{DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash},
|
||||||
{DefaultHoleskyGenesisBlock(), params.HoleskyGenesisHash},
|
{DefaultHoleskyGenesisBlock(), params.HoleskyGenesisHash},
|
||||||
{DefaultHoodiGenesisBlock(), params.HoodiGenesisHash},
|
{DefaultHoodiGenesisBlock(), params.HoodiGenesisHash},
|
||||||
|
{DefaultBerachainGenesisBlock(), params.BerachainGenesisHash},
|
||||||
|
{DefaultBepoliaGenesisBlock(), params.BepoliaGenesisHash},
|
||||||
} {
|
} {
|
||||||
// Test via MustCommit
|
// Test via MustCommit
|
||||||
db := rawdb.NewMemoryDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
|
|
|
||||||
|
|
@ -413,6 +413,10 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr
|
||||||
nBlobs += len(tx.BlobHashes())
|
nBlobs += len(tx.BlobHashes())
|
||||||
}
|
}
|
||||||
header.Root = common.BytesToHash(hasher.Sum(nil))
|
header.Root = common.BytesToHash(hasher.Sum(nil))
|
||||||
|
if config.IsPrague1(header.Number, header.Time) {
|
||||||
|
proposerPubkey := common.Pubkey{0x01, 0x02, 0x03}
|
||||||
|
header.ParentProposerPubkey = &proposerPubkey
|
||||||
|
}
|
||||||
if config.IsCancun(header.Number, header.Time) {
|
if config.IsCancun(header.Number, header.Time) {
|
||||||
excess := eip4844.CalcExcessBlobGas(config, parent.Header(), header.Time)
|
excess := eip4844.CalcExcessBlobGas(config, parent.Header(), header.Time)
|
||||||
used := uint64(nBlobs * params.BlobTxBlobGasPerBlob)
|
used := uint64(nBlobs * params.BlobTxBlobGasPerBlob)
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,9 @@ type Message struct {
|
||||||
|
|
||||||
// When SkipFromEOACheck is true, the message sender is not checked to be an EOA.
|
// When SkipFromEOACheck is true, the message sender is not checked to be an EOA.
|
||||||
SkipFromEOACheck bool
|
SkipFromEOACheck bool
|
||||||
|
|
||||||
|
// Berachain:IsPoLTx is true if the message is a PoL tx.
|
||||||
|
IsPoLTx bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransactionToMessage converts a transaction into a Message.
|
// TransactionToMessage converts a transaction into a Message.
|
||||||
|
|
@ -185,6 +188,7 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In
|
||||||
SkipFromEOACheck: false,
|
SkipFromEOACheck: false,
|
||||||
BlobHashes: tx.BlobHashes(),
|
BlobHashes: tx.BlobHashes(),
|
||||||
BlobGasFeeCap: tx.BlobGasFeeCap(),
|
BlobGasFeeCap: tx.BlobGasFeeCap(),
|
||||||
|
IsPoLTx: tx.Type() == types.PoLTxType,
|
||||||
}
|
}
|
||||||
// If baseFee provided, set gasPrice to effectiveGasPrice.
|
// If baseFee provided, set gasPrice to effectiveGasPrice.
|
||||||
if baseFee != nil {
|
if baseFee != nil {
|
||||||
|
|
@ -207,9 +211,30 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In
|
||||||
// state and would never be accepted within a block.
|
// state and would never be accepted within a block.
|
||||||
func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, error) {
|
func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, error) {
|
||||||
evm.SetTxContext(NewEVMTxContext(msg))
|
evm.SetTxContext(NewEVMTxContext(msg))
|
||||||
|
|
||||||
|
// Berachain: ApplyPoLMessage is used to apply the PoL tx to the EVM, skipping the
|
||||||
|
// normal state transition checks.
|
||||||
|
if msg.IsPoLTx {
|
||||||
|
return ApplyPoLMessage(msg, evm), nil
|
||||||
|
}
|
||||||
|
|
||||||
return newStateTransition(evm, msg, gp).execute()
|
return newStateTransition(evm, msg, gp).execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Berachain: ApplyPoLMessage applies the BRIP-0004 PoL tx to the EVM. No gas is consumed.
|
||||||
|
func ApplyPoLMessage(msg *Message, evm *vm.EVM) *ExecutionResult {
|
||||||
|
evm.StateDB.AddAddressToAccessList(*msg.To)
|
||||||
|
|
||||||
|
result := &ExecutionResult{}
|
||||||
|
ret, leftOverGas, err := evm.Call(msg.From, *msg.To, msg.Data, msg.GasLimit, common.U2560)
|
||||||
|
if err != nil {
|
||||||
|
result.Err = fmt.Errorf("PoL tx failed to execute: %v", err)
|
||||||
|
}
|
||||||
|
result.ReturnData = ret
|
||||||
|
result.MaxUsedGas = msg.GasLimit - leftOverGas // To inform how much gas was needed to run the msg.
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// stateTransition represents a state transition.
|
// stateTransition represents a state transition.
|
||||||
//
|
//
|
||||||
// == The State Transitioning Model
|
// == The State Transitioning Model
|
||||||
|
|
|
||||||
|
|
@ -327,6 +327,11 @@ func (p *TxPool) Add(txs []*types.Transaction, sync bool) []error {
|
||||||
// Mark this transaction belonging to no-subpool
|
// Mark this transaction belonging to no-subpool
|
||||||
splits[i] = -1
|
splits[i] = -1
|
||||||
|
|
||||||
|
// Berachain: PoL txs are rejected.
|
||||||
|
if tx.Type() == types.PoLTxType {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Try to find a subpool that accepts the transaction
|
// Try to find a subpool that accepts the transaction
|
||||||
for j, subpool := range p.subpools {
|
for j, subpool := range p.subpools {
|
||||||
if subpool.Filter(tx) {
|
if subpool.Filter(tx) {
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,9 @@ type Header struct {
|
||||||
|
|
||||||
// RequestsHash was added by EIP-7685 and is ignored in legacy headers.
|
// RequestsHash was added by EIP-7685 and is ignored in legacy headers.
|
||||||
RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
|
RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
|
||||||
|
|
||||||
|
// ParentProposerPubkey was added by BRIP-0004 and is ignored in legacy headers.
|
||||||
|
ParentProposerPubkey *common.Pubkey `json:"parentProposerPubkey" rlp:"optional"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// field type overrides for gencodec
|
// field type overrides for gencodec
|
||||||
|
|
@ -329,6 +332,10 @@ func CopyHeader(h *Header) *Header {
|
||||||
cpy.RequestsHash = new(common.Hash)
|
cpy.RequestsHash = new(common.Hash)
|
||||||
*cpy.RequestsHash = *h.RequestsHash
|
*cpy.RequestsHash = *h.RequestsHash
|
||||||
}
|
}
|
||||||
|
if h.ParentProposerPubkey != nil {
|
||||||
|
cpy.ParentProposerPubkey = new(common.Pubkey)
|
||||||
|
*cpy.ParentProposerPubkey = *h.ParentProposerPubkey
|
||||||
|
}
|
||||||
return &cpy
|
return &cpy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -408,8 +415,9 @@ func (b *Block) BaseFee() *big.Int {
|
||||||
return new(big.Int).Set(b.header.BaseFee)
|
return new(big.Int).Set(b.header.BaseFee)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Block) BeaconRoot() *common.Hash { return b.header.ParentBeaconRoot }
|
func (b *Block) BeaconRoot() *common.Hash { return b.header.ParentBeaconRoot }
|
||||||
func (b *Block) RequestsHash() *common.Hash { return b.header.RequestsHash }
|
func (b *Block) RequestsHash() *common.Hash { return b.header.RequestsHash }
|
||||||
|
func (b *Block) ProposerPubkey() *common.Pubkey { return b.header.ParentProposerPubkey }
|
||||||
|
|
||||||
func (b *Block) ExcessBlobGas() *uint64 {
|
func (b *Block) ExcessBlobGas() *uint64 {
|
||||||
var excessBlobGas *uint64
|
var excessBlobGas *uint64
|
||||||
|
|
|
||||||
|
|
@ -16,28 +16,29 @@ var _ = (*headerMarshaling)(nil)
|
||||||
// MarshalJSON marshals as JSON.
|
// MarshalJSON marshals as JSON.
|
||||||
func (h Header) MarshalJSON() ([]byte, error) {
|
func (h Header) MarshalJSON() ([]byte, error) {
|
||||||
type Header struct {
|
type Header struct {
|
||||||
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
||||||
UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
|
UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
|
||||||
Coinbase common.Address `json:"miner"`
|
Coinbase common.Address `json:"miner"`
|
||||||
Root common.Hash `json:"stateRoot" gencodec:"required"`
|
Root common.Hash `json:"stateRoot" gencodec:"required"`
|
||||||
TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
|
TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
|
||||||
ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
|
ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
|
||||||
Bloom Bloom `json:"logsBloom" gencodec:"required"`
|
Bloom Bloom `json:"logsBloom" gencodec:"required"`
|
||||||
Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"`
|
Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"`
|
||||||
Number *hexutil.Big `json:"number" gencodec:"required"`
|
Number *hexutil.Big `json:"number" gencodec:"required"`
|
||||||
GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
|
GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
|
||||||
GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
||||||
Time hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
Time hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
||||||
Extra hexutil.Bytes `json:"extraData" gencodec:"required"`
|
Extra hexutil.Bytes `json:"extraData" gencodec:"required"`
|
||||||
MixDigest common.Hash `json:"mixHash"`
|
MixDigest common.Hash `json:"mixHash"`
|
||||||
Nonce BlockNonce `json:"nonce"`
|
Nonce BlockNonce `json:"nonce"`
|
||||||
BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"`
|
BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"`
|
||||||
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
|
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
|
||||||
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"`
|
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"`
|
||||||
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"`
|
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"`
|
||||||
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
||||||
RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
|
RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
|
||||||
Hash common.Hash `json:"hash"`
|
ParentProposerPubkey *common.Pubkey `json:"parentProposerPubkey" rlp:"optional"`
|
||||||
|
Hash common.Hash `json:"hash"`
|
||||||
}
|
}
|
||||||
var enc Header
|
var enc Header
|
||||||
enc.ParentHash = h.ParentHash
|
enc.ParentHash = h.ParentHash
|
||||||
|
|
@ -61,6 +62,7 @@ func (h Header) MarshalJSON() ([]byte, error) {
|
||||||
enc.ExcessBlobGas = (*hexutil.Uint64)(h.ExcessBlobGas)
|
enc.ExcessBlobGas = (*hexutil.Uint64)(h.ExcessBlobGas)
|
||||||
enc.ParentBeaconRoot = h.ParentBeaconRoot
|
enc.ParentBeaconRoot = h.ParentBeaconRoot
|
||||||
enc.RequestsHash = h.RequestsHash
|
enc.RequestsHash = h.RequestsHash
|
||||||
|
enc.ParentProposerPubkey = h.ParentProposerPubkey
|
||||||
enc.Hash = h.Hash()
|
enc.Hash = h.Hash()
|
||||||
return json.Marshal(&enc)
|
return json.Marshal(&enc)
|
||||||
}
|
}
|
||||||
|
|
@ -68,27 +70,28 @@ func (h Header) MarshalJSON() ([]byte, error) {
|
||||||
// UnmarshalJSON unmarshals from JSON.
|
// UnmarshalJSON unmarshals from JSON.
|
||||||
func (h *Header) UnmarshalJSON(input []byte) error {
|
func (h *Header) UnmarshalJSON(input []byte) error {
|
||||||
type Header struct {
|
type Header struct {
|
||||||
ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
|
ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
|
||||||
UncleHash *common.Hash `json:"sha3Uncles" gencodec:"required"`
|
UncleHash *common.Hash `json:"sha3Uncles" gencodec:"required"`
|
||||||
Coinbase *common.Address `json:"miner"`
|
Coinbase *common.Address `json:"miner"`
|
||||||
Root *common.Hash `json:"stateRoot" gencodec:"required"`
|
Root *common.Hash `json:"stateRoot" gencodec:"required"`
|
||||||
TxHash *common.Hash `json:"transactionsRoot" gencodec:"required"`
|
TxHash *common.Hash `json:"transactionsRoot" gencodec:"required"`
|
||||||
ReceiptHash *common.Hash `json:"receiptsRoot" gencodec:"required"`
|
ReceiptHash *common.Hash `json:"receiptsRoot" gencodec:"required"`
|
||||||
Bloom *Bloom `json:"logsBloom" gencodec:"required"`
|
Bloom *Bloom `json:"logsBloom" gencodec:"required"`
|
||||||
Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"`
|
Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"`
|
||||||
Number *hexutil.Big `json:"number" gencodec:"required"`
|
Number *hexutil.Big `json:"number" gencodec:"required"`
|
||||||
GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
|
GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
|
||||||
GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
||||||
Time *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
Time *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
||||||
Extra *hexutil.Bytes `json:"extraData" gencodec:"required"`
|
Extra *hexutil.Bytes `json:"extraData" gencodec:"required"`
|
||||||
MixDigest *common.Hash `json:"mixHash"`
|
MixDigest *common.Hash `json:"mixHash"`
|
||||||
Nonce *BlockNonce `json:"nonce"`
|
Nonce *BlockNonce `json:"nonce"`
|
||||||
BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"`
|
BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"`
|
||||||
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
|
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
|
||||||
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"`
|
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"`
|
||||||
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"`
|
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"`
|
||||||
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
||||||
RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
|
RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
|
||||||
|
ParentProposerPubkey *common.Pubkey `json:"parentProposerPubkey" rlp:"optional"`
|
||||||
}
|
}
|
||||||
var dec Header
|
var dec Header
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
|
@ -169,5 +172,8 @@ func (h *Header) UnmarshalJSON(input []byte) error {
|
||||||
if dec.RequestsHash != nil {
|
if dec.RequestsHash != nil {
|
||||||
h.RequestsHash = dec.RequestsHash
|
h.RequestsHash = dec.RequestsHash
|
||||||
}
|
}
|
||||||
|
if dec.ParentProposerPubkey != nil {
|
||||||
|
h.ParentProposerPubkey = dec.ParentProposerPubkey
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,8 @@ func (obj *Header) EncodeRLP(_w io.Writer) error {
|
||||||
_tmp4 := obj.ExcessBlobGas != nil
|
_tmp4 := obj.ExcessBlobGas != nil
|
||||||
_tmp5 := obj.ParentBeaconRoot != nil
|
_tmp5 := obj.ParentBeaconRoot != nil
|
||||||
_tmp6 := obj.RequestsHash != nil
|
_tmp6 := obj.RequestsHash != nil
|
||||||
if _tmp1 || _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 {
|
_tmp7 := obj.ParentProposerPubkey != nil
|
||||||
|
if _tmp1 || _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 {
|
||||||
if obj.BaseFee == nil {
|
if obj.BaseFee == nil {
|
||||||
w.Write(rlp.EmptyString)
|
w.Write(rlp.EmptyString)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -53,41 +54,48 @@ func (obj *Header) EncodeRLP(_w io.Writer) error {
|
||||||
w.WriteBigInt(obj.BaseFee)
|
w.WriteBigInt(obj.BaseFee)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 {
|
if _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 {
|
||||||
if obj.WithdrawalsHash == nil {
|
if obj.WithdrawalsHash == nil {
|
||||||
w.Write([]byte{0x80})
|
w.Write([]byte{0x80})
|
||||||
} else {
|
} else {
|
||||||
w.WriteBytes(obj.WithdrawalsHash[:])
|
w.WriteBytes(obj.WithdrawalsHash[:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _tmp3 || _tmp4 || _tmp5 || _tmp6 {
|
if _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 {
|
||||||
if obj.BlobGasUsed == nil {
|
if obj.BlobGasUsed == nil {
|
||||||
w.Write([]byte{0x80})
|
w.Write([]byte{0x80})
|
||||||
} else {
|
} else {
|
||||||
w.WriteUint64((*obj.BlobGasUsed))
|
w.WriteUint64((*obj.BlobGasUsed))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _tmp4 || _tmp5 || _tmp6 {
|
if _tmp4 || _tmp5 || _tmp6 || _tmp7 {
|
||||||
if obj.ExcessBlobGas == nil {
|
if obj.ExcessBlobGas == nil {
|
||||||
w.Write([]byte{0x80})
|
w.Write([]byte{0x80})
|
||||||
} else {
|
} else {
|
||||||
w.WriteUint64((*obj.ExcessBlobGas))
|
w.WriteUint64((*obj.ExcessBlobGas))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _tmp5 || _tmp6 {
|
if _tmp5 || _tmp6 || _tmp7 {
|
||||||
if obj.ParentBeaconRoot == nil {
|
if obj.ParentBeaconRoot == nil {
|
||||||
w.Write([]byte{0x80})
|
w.Write([]byte{0x80})
|
||||||
} else {
|
} else {
|
||||||
w.WriteBytes(obj.ParentBeaconRoot[:])
|
w.WriteBytes(obj.ParentBeaconRoot[:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _tmp6 {
|
if _tmp6 || _tmp7 {
|
||||||
if obj.RequestsHash == nil {
|
if obj.RequestsHash == nil {
|
||||||
w.Write([]byte{0x80})
|
w.Write([]byte{0x80})
|
||||||
} else {
|
} else {
|
||||||
w.WriteBytes(obj.RequestsHash[:])
|
w.WriteBytes(obj.RequestsHash[:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if _tmp7 {
|
||||||
|
if obj.ParentProposerPubkey == nil {
|
||||||
|
w.Write([]byte{0x80})
|
||||||
|
} else {
|
||||||
|
w.WriteBytes(obj.ParentProposerPubkey[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
w.ListEnd(_tmp0)
|
w.ListEnd(_tmp0)
|
||||||
return w.Flush()
|
return w.Flush()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -205,7 +205,7 @@ func (r *Receipt) decodeTyped(b []byte) error {
|
||||||
return errShortTypedReceipt
|
return errShortTypedReceipt
|
||||||
}
|
}
|
||||||
switch b[0] {
|
switch b[0] {
|
||||||
case DynamicFeeTxType, AccessListTxType, BlobTxType, SetCodeTxType:
|
case DynamicFeeTxType, AccessListTxType, BlobTxType, SetCodeTxType, PoLTxType:
|
||||||
var data receiptRLP
|
var data receiptRLP
|
||||||
err := rlp.DecodeBytes(b[1:], &data)
|
err := rlp.DecodeBytes(b[1:], &data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -368,7 +368,7 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) {
|
||||||
}
|
}
|
||||||
w.WriteByte(r.Type)
|
w.WriteByte(r.Type)
|
||||||
switch r.Type {
|
switch r.Type {
|
||||||
case AccessListTxType, DynamicFeeTxType, BlobTxType, SetCodeTxType:
|
case AccessListTxType, DynamicFeeTxType, BlobTxType, SetCodeTxType, PoLTxType:
|
||||||
rlp.Encode(w, data)
|
rlp.Encode(w, data)
|
||||||
default:
|
default:
|
||||||
// For unsupported types, write nothing. Since this is for
|
// For unsupported types, write nothing. Since this is for
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,9 @@ const (
|
||||||
DynamicFeeTxType = 0x02
|
DynamicFeeTxType = 0x02
|
||||||
BlobTxType = 0x03
|
BlobTxType = 0x03
|
||||||
SetCodeTxType = 0x04
|
SetCodeTxType = 0x04
|
||||||
|
|
||||||
|
// Berachain specific.
|
||||||
|
PoLTxType = 0x7E
|
||||||
)
|
)
|
||||||
|
|
||||||
// Transaction is an Ethereum transaction.
|
// Transaction is an Ethereum transaction.
|
||||||
|
|
@ -211,6 +214,8 @@ func (tx *Transaction) decodeTyped(b []byte) (TxData, error) {
|
||||||
inner = new(BlobTx)
|
inner = new(BlobTx)
|
||||||
case SetCodeTxType:
|
case SetCodeTxType:
|
||||||
inner = new(SetCodeTx)
|
inner = new(SetCodeTx)
|
||||||
|
case PoLTxType:
|
||||||
|
inner = new(PoLTx)
|
||||||
default:
|
default:
|
||||||
return nil, ErrTxTypeNotSupported
|
return nil, ErrTxTypeNotSupported
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -507,6 +507,33 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case PoLTxType:
|
||||||
|
var itx PoLTx
|
||||||
|
inner = &itx
|
||||||
|
if dec.ChainID == nil {
|
||||||
|
return errors.New("missing required field 'chainId' in transaction")
|
||||||
|
}
|
||||||
|
itx.ChainID = (*big.Int)(dec.ChainID)
|
||||||
|
if dec.To == nil {
|
||||||
|
return errors.New("missing required field 'to' in transaction")
|
||||||
|
}
|
||||||
|
itx.To = *dec.To
|
||||||
|
if dec.Nonce == nil {
|
||||||
|
return errors.New("missing required field 'nonce' in transaction")
|
||||||
|
}
|
||||||
|
itx.Nonce = uint64(*dec.Nonce)
|
||||||
|
if dec.Gas == nil {
|
||||||
|
return errors.New("missing required field 'gas' for txdata")
|
||||||
|
}
|
||||||
|
itx.GasLimit = uint64(*dec.Gas)
|
||||||
|
if dec.Value == nil {
|
||||||
|
return errors.New("missing required field 'value' in transaction")
|
||||||
|
}
|
||||||
|
if dec.Input == nil {
|
||||||
|
return errors.New("missing required field 'input' in transaction")
|
||||||
|
}
|
||||||
|
itx.Data = *dec.Input
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return ErrTxTypeNotSupported
|
return ErrTxTypeNotSupported
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,8 @@ type sigCache struct {
|
||||||
func MakeSigner(config *params.ChainConfig, blockNumber *big.Int, blockTime uint64) Signer {
|
func MakeSigner(config *params.ChainConfig, blockNumber *big.Int, blockTime uint64) Signer {
|
||||||
var signer Signer
|
var signer Signer
|
||||||
switch {
|
switch {
|
||||||
|
case config.IsPrague1(blockNumber, blockTime):
|
||||||
|
signer = NewPrague1Signer(config.ChainID)
|
||||||
case config.IsPrague(blockNumber, blockTime):
|
case config.IsPrague(blockNumber, blockTime):
|
||||||
signer = NewPragueSigner(config.ChainID)
|
signer = NewPragueSigner(config.ChainID)
|
||||||
case config.IsCancun(blockNumber, blockTime):
|
case config.IsCancun(blockNumber, blockTime):
|
||||||
|
|
@ -71,6 +73,8 @@ func LatestSigner(config *params.ChainConfig) Signer {
|
||||||
var signer Signer
|
var signer Signer
|
||||||
if config.ChainID != nil {
|
if config.ChainID != nil {
|
||||||
switch {
|
switch {
|
||||||
|
case config.Berachain.Prague1.Time != nil:
|
||||||
|
signer = NewPrague1Signer(config.ChainID)
|
||||||
case config.PragueTime != nil:
|
case config.PragueTime != nil:
|
||||||
signer = NewPragueSigner(config.ChainID)
|
signer = NewPragueSigner(config.ChainID)
|
||||||
case config.CancunTime != nil:
|
case config.CancunTime != nil:
|
||||||
|
|
@ -100,7 +104,7 @@ func LatestSigner(config *params.ChainConfig) Signer {
|
||||||
func LatestSignerForChainID(chainID *big.Int) Signer {
|
func LatestSignerForChainID(chainID *big.Int) Signer {
|
||||||
var signer Signer
|
var signer Signer
|
||||||
if chainID != nil {
|
if chainID != nil {
|
||||||
signer = NewPragueSigner(chainID)
|
signer = NewPrague1Signer(chainID)
|
||||||
} else {
|
} else {
|
||||||
signer = HomesteadSigner{}
|
signer = HomesteadSigner{}
|
||||||
}
|
}
|
||||||
|
|
@ -219,6 +223,9 @@ func newModernSigner(chainID *big.Int, fork forks.Fork) Signer {
|
||||||
if fork >= forks.Prague {
|
if fork >= forks.Prague {
|
||||||
s.txtypes[SetCodeTxType] = struct{}{}
|
s.txtypes[SetCodeTxType] = struct{}{}
|
||||||
}
|
}
|
||||||
|
if fork >= forks.Prague1 {
|
||||||
|
s.txtypes[PoLTxType] = struct{}{}
|
||||||
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -251,6 +258,12 @@ func (s *modernSigner) Sender(tx *Transaction) (common.Address, error) {
|
||||||
if tx.ChainId().Cmp(s.chainID) != 0 {
|
if tx.ChainId().Cmp(s.chainID) != 0 {
|
||||||
return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainID)
|
return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Berachain specific: PoLTx is sent by system address and carries no signature.
|
||||||
|
if tt == PoLTxType {
|
||||||
|
return params.SystemAddress, nil
|
||||||
|
}
|
||||||
|
|
||||||
// 'modern' txs are defined to use 0 and 1 as their recovery
|
// 'modern' txs are defined to use 0 and 1 as their recovery
|
||||||
// id, add 27 to become equivalent to unprotected Homestead signatures.
|
// id, add 27 to become equivalent to unprotected Homestead signatures.
|
||||||
V, R, S := tx.RawSignatureValues()
|
V, R, S := tx.RawSignatureValues()
|
||||||
|
|
@ -276,6 +289,18 @@ func (s *modernSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *bi
|
||||||
return R, S, V, nil
|
return R, S, V, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewPrague1Signer returns a signer that accepts
|
||||||
|
// - BRIP-0004 PoL transactions
|
||||||
|
// - EIP-7702 set code transactions
|
||||||
|
// - EIP-4844 blob transactions
|
||||||
|
// - EIP-1559 dynamic fee transactions
|
||||||
|
// - EIP-2930 access list transactions,
|
||||||
|
// - EIP-155 replay protected transactions, and
|
||||||
|
// - legacy Homestead transactions.
|
||||||
|
func NewPrague1Signer(chainId *big.Int) Signer {
|
||||||
|
return newModernSigner(chainId, forks.Prague1)
|
||||||
|
}
|
||||||
|
|
||||||
// NewPragueSigner returns a signer that accepts
|
// NewPragueSigner returns a signer that accepts
|
||||||
// - EIP-7702 set code transactions
|
// - EIP-7702 set code transactions
|
||||||
// - EIP-4844 blob transactions
|
// - EIP-4844 blob transactions
|
||||||
|
|
|
||||||
179
core/types/tx_pol.go
Normal file
179
core/types/tx_pol.go
Normal file
|
|
@ -0,0 +1,179 @@
|
||||||
|
// Copyright 2025 Berachain Foundation
|
||||||
|
// This file is part of the bera-geth library.
|
||||||
|
//
|
||||||
|
// The bera-geth 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 bera-geth 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 bera-geth library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PoLTx implements the TxData interface.
|
||||||
|
var _ TxData = (*PoLTx)(nil)
|
||||||
|
|
||||||
|
// PoLTx represents an BRIP-0004 transaction. No gas is consumed for execution.
|
||||||
|
type PoLTx struct {
|
||||||
|
ChainID *big.Int
|
||||||
|
From common.Address // system address
|
||||||
|
To common.Address // address of the PoL Distributor contract
|
||||||
|
Nonce uint64 // block number distributing for
|
||||||
|
GasLimit uint64 // artificial gas limit for the PoL tx, not consumed against the block gas limit
|
||||||
|
GasPrice *big.Int // gas price is set to the baseFee to make the tx valid for EIP-1559 rules
|
||||||
|
Data []byte // encodes the pubkey distributing for
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPoLTx creates a new PoL transaction.
|
||||||
|
func NewPoLTx(
|
||||||
|
chainID *big.Int,
|
||||||
|
distributorAddress common.Address,
|
||||||
|
distributionBlockNumber *big.Int,
|
||||||
|
gasLimit uint64,
|
||||||
|
baseFee *big.Int,
|
||||||
|
pubkey *common.Pubkey,
|
||||||
|
) (*Transaction, error) {
|
||||||
|
data, err := getDistributeForData(pubkey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return NewTx(&PoLTx{
|
||||||
|
ChainID: chainID,
|
||||||
|
From: params.SystemAddress,
|
||||||
|
To: distributorAddress,
|
||||||
|
Nonce: distributionBlockNumber.Uint64(),
|
||||||
|
GasLimit: gasLimit,
|
||||||
|
GasPrice: baseFee,
|
||||||
|
Data: data,
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*PoLTx) txType() byte { return PoLTxType }
|
||||||
|
|
||||||
|
// copy creates a deep copy of the transaction data and initializes all fields.
|
||||||
|
func (tx *PoLTx) copy() TxData {
|
||||||
|
cpy := &PoLTx{
|
||||||
|
ChainID: new(big.Int),
|
||||||
|
From: tx.From,
|
||||||
|
To: tx.To,
|
||||||
|
Nonce: tx.Nonce,
|
||||||
|
GasLimit: tx.GasLimit,
|
||||||
|
GasPrice: new(big.Int),
|
||||||
|
Data: common.CopyBytes(tx.Data),
|
||||||
|
}
|
||||||
|
if tx.ChainID != nil {
|
||||||
|
cpy.ChainID.Set(tx.ChainID)
|
||||||
|
}
|
||||||
|
if tx.GasPrice != nil {
|
||||||
|
cpy.GasPrice.Set(tx.GasPrice)
|
||||||
|
}
|
||||||
|
return cpy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *PoLTx) chainID() *big.Int { return tx.ChainID }
|
||||||
|
func (*PoLTx) accessList() AccessList { return nil }
|
||||||
|
func (tx *PoLTx) data() []byte { return tx.Data }
|
||||||
|
func (tx *PoLTx) gas() uint64 { return tx.GasLimit }
|
||||||
|
func (tx *PoLTx) gasPrice() *big.Int { return tx.GasPrice }
|
||||||
|
func (tx *PoLTx) gasTipCap() *big.Int { return tx.GasPrice }
|
||||||
|
func (tx *PoLTx) gasFeeCap() *big.Int { return tx.GasPrice }
|
||||||
|
func (*PoLTx) value() *big.Int { return new(big.Int) }
|
||||||
|
func (tx *PoLTx) nonce() uint64 { return tx.Nonce }
|
||||||
|
func (tx *PoLTx) to() *common.Address { return &tx.To }
|
||||||
|
|
||||||
|
// No-op: PoLTx is originated from the system address and carries no signature.
|
||||||
|
func (*PoLTx) rawSignatureValues() (v, r, s *big.Int) {
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*PoLTx) setSignatureValues(chainID, v, r, s *big.Int) {
|
||||||
|
// No-op: PoLTx is originated from the system address and carries no signature.
|
||||||
|
}
|
||||||
|
|
||||||
|
// effectiveGasPrice returns the gas price. PoLTx does not pay for gas, but we
|
||||||
|
// return the baseFee here to make the receipt valid for a 1559 tx.
|
||||||
|
func (tx *PoLTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
|
||||||
|
return dst.Set(tx.GasPrice)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *PoLTx) encode(b *bytes.Buffer) error {
|
||||||
|
return rlp.Encode(b, tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *PoLTx) decode(input []byte) error {
|
||||||
|
return rlp.DecodeBytes(input, tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *PoLTx) sigHash(chainID *big.Int) common.Hash {
|
||||||
|
return prefixedRlpHash(
|
||||||
|
PoLTxType, // tx type: 0x7E
|
||||||
|
[]any{
|
||||||
|
chainID, // chainID: EIP-155 chain ID
|
||||||
|
tx.From, // from = system address
|
||||||
|
tx.To, // to = address of the PoL Distributor contract
|
||||||
|
tx.Nonce, // nonce = block number distributing for
|
||||||
|
tx.GasLimit, // gasLimit = artificial gas limit for execution
|
||||||
|
tx.GasPrice, // gasPrice = baseFee to make the tx valid for EIP-1559 rules
|
||||||
|
tx.Data, // data ~= pubkey distributing for
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
bytesType, _ = abi.NewType("bytes", "", nil)
|
||||||
|
distributeForMethod = abi.NewMethod(
|
||||||
|
"distributeFor", "distributeFor", abi.Function, "nonpayable", false, false, []abi.Argument{
|
||||||
|
{Name: "pubkey", Type: bytesType, Indexed: false},
|
||||||
|
}, nil,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// getDistributeForData returns the tx data for the `distributeFor(bytes pubkey)` method.
|
||||||
|
func getDistributeForData(pubkey *common.Pubkey) ([]byte, error) {
|
||||||
|
var pubkeyBytes []byte
|
||||||
|
if pubkey == nil {
|
||||||
|
pubkeyBytes = common.Pubkey{}.Bytes()
|
||||||
|
} else {
|
||||||
|
pubkeyBytes = pubkey.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
arguments, err := distributeForMethod.Inputs.Pack(pubkeyBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return append(distributeForMethod.ID, arguments...), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPoLDistribution returns true if the transaction is a PoL distribution.
|
||||||
|
func IsPoLDistribution(to *common.Address, data []byte, distributorAddress common.Address) bool {
|
||||||
|
// Txs that call the `distributeFor(bytes pubkey)` method on the PoL Distributor
|
||||||
|
// contract are also consideredPoL txs.
|
||||||
|
return to != nil && *to == distributorAddress && isDistributeForCall(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// isDistributeForCall returns true if the provided calldata corresponds to a
|
||||||
|
// call to the `distributeFor(bytes pubkey)` method defined in BRIP-0004.
|
||||||
|
//
|
||||||
|
// The function checks that the first four bytes (the function selector) match
|
||||||
|
// the ID of the `distributeFor` ABI method declared in tx_pol.go.
|
||||||
|
func isDistributeForCall(data []byte) bool {
|
||||||
|
if len(data) < 4 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return bytes.Equal(data[:4], distributeForMethod.ID)
|
||||||
|
}
|
||||||
128
core/types/tx_pol_test.go
Normal file
128
core/types/tx_pol_test.go
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
// Copyright 2025 Berachain Foundation
|
||||||
|
// This file is part of the bera-geth library.
|
||||||
|
//
|
||||||
|
// The bera-geth 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 bera-geth 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 bera-geth library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
// samplePubkey returns a deterministic 48-byte pubkey for tests.
|
||||||
|
func samplePubkey() *common.Pubkey {
|
||||||
|
var pk common.Pubkey
|
||||||
|
for i := 0; i < common.PubkeyLength; i++ {
|
||||||
|
pk[i] = byte(i)
|
||||||
|
}
|
||||||
|
return &pk
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestNewPoLTx_DataPacking verifies that NewPoLTx produces the expected calldata
|
||||||
|
// (function selector + ABI-encoded pubkey) and that the transaction fields are
|
||||||
|
// wired up correctly.
|
||||||
|
func TestNewPoLTx_DataPacking(t *testing.T) {
|
||||||
|
chainID := big.NewInt(1)
|
||||||
|
distributor := common.HexToAddress("0x000000000000000000000000000000000000dEaD")
|
||||||
|
blockNum := big.NewInt(123)
|
||||||
|
pubkey := samplePubkey()
|
||||||
|
baseFee := big.NewInt(1000000000)
|
||||||
|
|
||||||
|
tx, err := NewPoLTx(chainID, distributor, blockNum, params.PoLTxGasLimit, baseFee, pubkey)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewPoLTx returned error: %v", err)
|
||||||
|
}
|
||||||
|
if tx.Type() != PoLTxType {
|
||||||
|
t.Fatalf("unexpected tx type: have %d, want %d", tx.Type(), PoLTxType)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedData, err := getDistributeForData(pubkey)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("getDistributeForData failed: %v", err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(tx.Data(), expectedData) {
|
||||||
|
t.Fatalf("calldata mismatch\n have: %x\n want: %x", tx.Data(), expectedData)
|
||||||
|
}
|
||||||
|
// Extra sanity: first 4 bytes must equal the method selector.
|
||||||
|
if !bytes.Equal(tx.Data()[:4], distributeForMethod.ID) {
|
||||||
|
t.Fatalf("calldata selector mismatch")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestNewPoLTx_NegativeBlockNumber ensures negative block numbers are handled
|
||||||
|
// without panicking (uint64 wrap-around is expected).
|
||||||
|
func TestNewPoLTx_NegativeBlockNumber(t *testing.T) {
|
||||||
|
chainID := big.NewInt(1)
|
||||||
|
distributor := common.Address{}
|
||||||
|
negBlock := big.NewInt(-1)
|
||||||
|
baseFee := big.NewInt(1000000000)
|
||||||
|
|
||||||
|
tx, err := NewPoLTx(chainID, distributor, negBlock, params.PoLTxGasLimit, baseFee, samplePubkey())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if got, want := tx.Nonce(), negBlock.Uint64(); got != want {
|
||||||
|
t.Fatalf("nonce mismatch: have %d, want %d", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestIsPoLDistribution exercises positive and negative cases for the helper.
|
||||||
|
func TestIsPoLDistribution(t *testing.T) {
|
||||||
|
distributor := common.HexToAddress("0x1000000000000000000000000000000000000001")
|
||||||
|
baseFee := big.NewInt(1000000000)
|
||||||
|
tx, err := NewPoLTx(big.NewInt(1), distributor, big.NewInt(0), params.PoLTxGasLimit, baseFee, samplePubkey())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to build PoL tx: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Positive case.
|
||||||
|
if !IsPoLDistribution(&distributor, tx.Data(), distributor) {
|
||||||
|
t.Fatalf("expected IsPoLDistribution to return true for valid PoL call")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrong address.
|
||||||
|
otherAddr := common.HexToAddress("0x0200000000000000000000000000000000000002")
|
||||||
|
if IsPoLDistribution(&otherAddr, tx.Data(), distributor) {
|
||||||
|
t.Fatalf("expected false when distributor address mismatches")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Too-short data.
|
||||||
|
shortData := []byte{0x01, 0x02, 0x03}
|
||||||
|
if IsPoLDistribution(&distributor, shortData, distributor) {
|
||||||
|
t.Fatalf("expected false for data shorter than selector")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nil address.
|
||||||
|
if IsPoLDistribution(nil, tx.Data(), distributor) {
|
||||||
|
t.Fatalf("expected false when to==nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestPoLTx_RawSignatureValues confirms that PoLTx reports no signature.
|
||||||
|
func TestPoLTx_RawSignatureValues(t *testing.T) {
|
||||||
|
baseFee := big.NewInt(1000000000)
|
||||||
|
tx, err := NewPoLTx(big.NewInt(1), common.Address{}, big.NewInt(0), params.PoLTxGasLimit, baseFee, samplePubkey())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create PoL tx: %v", err)
|
||||||
|
}
|
||||||
|
v, r, s := tx.RawSignatureValues()
|
||||||
|
if v != nil || r != nil || s != nil {
|
||||||
|
t.Fatalf("expected nil signature values, have v=%v r=%v s=%v", v, r, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -87,14 +87,17 @@ var caps = []string{
|
||||||
"engine_forkchoiceUpdatedV1",
|
"engine_forkchoiceUpdatedV1",
|
||||||
"engine_forkchoiceUpdatedV2",
|
"engine_forkchoiceUpdatedV2",
|
||||||
"engine_forkchoiceUpdatedV3",
|
"engine_forkchoiceUpdatedV3",
|
||||||
|
"engine_forkchoiceUpdatedV3P11",
|
||||||
"engine_forkchoiceUpdatedWithWitnessV1",
|
"engine_forkchoiceUpdatedWithWitnessV1",
|
||||||
"engine_forkchoiceUpdatedWithWitnessV2",
|
"engine_forkchoiceUpdatedWithWitnessV2",
|
||||||
"engine_forkchoiceUpdatedWithWitnessV3",
|
"engine_forkchoiceUpdatedWithWitnessV3",
|
||||||
|
"engine_forkchoiceUpdatedWithWitnessV3P11",
|
||||||
"engine_exchangeTransitionConfigurationV1",
|
"engine_exchangeTransitionConfigurationV1",
|
||||||
"engine_getPayloadV1",
|
"engine_getPayloadV1",
|
||||||
"engine_getPayloadV2",
|
"engine_getPayloadV2",
|
||||||
"engine_getPayloadV3",
|
"engine_getPayloadV3",
|
||||||
"engine_getPayloadV4",
|
"engine_getPayloadV4",
|
||||||
|
"engine_getPayloadV4P11",
|
||||||
"engine_getPayloadV5",
|
"engine_getPayloadV5",
|
||||||
"engine_getBlobsV1",
|
"engine_getBlobsV1",
|
||||||
"engine_getBlobsV2",
|
"engine_getBlobsV2",
|
||||||
|
|
@ -102,14 +105,17 @@ var caps = []string{
|
||||||
"engine_newPayloadV2",
|
"engine_newPayloadV2",
|
||||||
"engine_newPayloadV3",
|
"engine_newPayloadV3",
|
||||||
"engine_newPayloadV4",
|
"engine_newPayloadV4",
|
||||||
|
"engine_newPayloadV4P11",
|
||||||
"engine_newPayloadWithWitnessV1",
|
"engine_newPayloadWithWitnessV1",
|
||||||
"engine_newPayloadWithWitnessV2",
|
"engine_newPayloadWithWitnessV2",
|
||||||
"engine_newPayloadWithWitnessV3",
|
"engine_newPayloadWithWitnessV3",
|
||||||
"engine_newPayloadWithWitnessV4",
|
"engine_newPayloadWithWitnessV4",
|
||||||
|
"engine_newPayloadWithWitnessV4P11",
|
||||||
"engine_executeStatelessPayloadV1",
|
"engine_executeStatelessPayloadV1",
|
||||||
"engine_executeStatelessPayloadV2",
|
"engine_executeStatelessPayloadV2",
|
||||||
"engine_executeStatelessPayloadV3",
|
"engine_executeStatelessPayloadV3",
|
||||||
"engine_executeStatelessPayloadV4",
|
"engine_executeStatelessPayloadV4",
|
||||||
|
"engine_executeStatelessPayloadV4P11",
|
||||||
"engine_getPayloadBodiesByHashV1",
|
"engine_getPayloadBodiesByHashV1",
|
||||||
"engine_getPayloadBodiesByHashV2",
|
"engine_getPayloadBodiesByHashV2",
|
||||||
"engine_getPayloadBodiesByRangeV1",
|
"engine_getPayloadBodiesByRangeV1",
|
||||||
|
|
@ -209,6 +215,8 @@ func newConsensusAPIWithoutHeartbeat(eth *eth.Ethereum) *ConsensusAPI {
|
||||||
func (api *ConsensusAPI) ForkchoiceUpdatedV1(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
|
func (api *ConsensusAPI) ForkchoiceUpdatedV1(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
|
||||||
if payloadAttributes != nil {
|
if payloadAttributes != nil {
|
||||||
switch {
|
switch {
|
||||||
|
case payloadAttributes.ProposerPubkey != nil:
|
||||||
|
return engine.STATUS_INVALID, attributesErr("proposer pubkey not supported in V1")
|
||||||
case payloadAttributes.Withdrawals != nil || payloadAttributes.BeaconRoot != nil:
|
case payloadAttributes.Withdrawals != nil || payloadAttributes.BeaconRoot != nil:
|
||||||
return engine.STATUS_INVALID, paramsErr("withdrawals and beacon root not supported in V1")
|
return engine.STATUS_INVALID, paramsErr("withdrawals and beacon root not supported in V1")
|
||||||
case !api.checkFork(payloadAttributes.Timestamp, forks.Paris, forks.Shanghai):
|
case !api.checkFork(payloadAttributes.Timestamp, forks.Paris, forks.Shanghai):
|
||||||
|
|
@ -223,6 +231,8 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update engine.ForkchoiceStateV1, pa
|
||||||
func (api *ConsensusAPI) ForkchoiceUpdatedV2(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
|
func (api *ConsensusAPI) ForkchoiceUpdatedV2(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
|
||||||
if params != nil {
|
if params != nil {
|
||||||
switch {
|
switch {
|
||||||
|
case params.ProposerPubkey != nil:
|
||||||
|
return engine.STATUS_INVALID, attributesErr("unexpected proposer pubkey")
|
||||||
case params.BeaconRoot != nil:
|
case params.BeaconRoot != nil:
|
||||||
return engine.STATUS_INVALID, attributesErr("unexpected beacon root")
|
return engine.STATUS_INVALID, attributesErr("unexpected beacon root")
|
||||||
case api.checkFork(params.Timestamp, forks.Paris) && params.Withdrawals != nil:
|
case api.checkFork(params.Timestamp, forks.Paris) && params.Withdrawals != nil:
|
||||||
|
|
@ -241,6 +251,8 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV2(update engine.ForkchoiceStateV1, pa
|
||||||
func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
|
func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
|
||||||
if params != nil {
|
if params != nil {
|
||||||
switch {
|
switch {
|
||||||
|
case params.ProposerPubkey != nil:
|
||||||
|
return engine.STATUS_INVALID, attributesErr("unexpected proposer pubkey")
|
||||||
case params.Withdrawals == nil:
|
case params.Withdrawals == nil:
|
||||||
return engine.STATUS_INVALID, attributesErr("missing withdrawals")
|
return engine.STATUS_INVALID, attributesErr("missing withdrawals")
|
||||||
case params.BeaconRoot == nil:
|
case params.BeaconRoot == nil:
|
||||||
|
|
@ -256,6 +268,28 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, pa
|
||||||
return api.forkchoiceUpdated(update, params, engine.PayloadV3, false)
|
return api.forkchoiceUpdated(update, params, engine.PayloadV3, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ForkchoiceUpdatedV3P11 is equivalent to V3 with the addition of parents proposer pubkey
|
||||||
|
// in the payload attributes. It supports only PayloadAttributesV3P11.
|
||||||
|
func (api *ConsensusAPI) ForkchoiceUpdatedV3P11(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
|
||||||
|
if params != nil {
|
||||||
|
switch {
|
||||||
|
case params.Withdrawals == nil:
|
||||||
|
return engine.STATUS_INVALID, attributesErr("missing withdrawals")
|
||||||
|
case params.BeaconRoot == nil:
|
||||||
|
return engine.STATUS_INVALID, attributesErr("missing beacon root")
|
||||||
|
case params.ProposerPubkey == nil:
|
||||||
|
return engine.STATUS_INVALID, attributesErr("missing proposer pubkey")
|
||||||
|
case !api.checkFork(params.Timestamp, forks.Prague1):
|
||||||
|
return engine.STATUS_INVALID, unsupportedForkErr("fcuV3P11 must only be called for prague1 payloads")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO(matt): the spec requires that fcu is applied when called on a valid
|
||||||
|
// hash, even if params are wrong. To do this we need to split up
|
||||||
|
// forkchoiceUpdate into a function that only updates the head and then a
|
||||||
|
// function that kicks off block construction.
|
||||||
|
return api.forkchoiceUpdated(update, params, engine.PayloadV3P11, false)
|
||||||
|
}
|
||||||
|
|
||||||
func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes, payloadVersion engine.PayloadVersion, payloadWitness bool) (engine.ForkChoiceResponse, error) {
|
func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes, payloadVersion engine.PayloadVersion, payloadWitness bool) (engine.ForkChoiceResponse, error) {
|
||||||
api.forkchoiceLock.Lock()
|
api.forkchoiceLock.Lock()
|
||||||
defer api.forkchoiceLock.Unlock()
|
defer api.forkchoiceLock.Unlock()
|
||||||
|
|
@ -383,13 +417,14 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
|
||||||
// will replace it arbitrarily many times in between.
|
// will replace it arbitrarily many times in between.
|
||||||
if payloadAttributes != nil {
|
if payloadAttributes != nil {
|
||||||
args := &miner.BuildPayloadArgs{
|
args := &miner.BuildPayloadArgs{
|
||||||
Parent: update.HeadBlockHash,
|
Parent: update.HeadBlockHash,
|
||||||
Timestamp: payloadAttributes.Timestamp,
|
Timestamp: payloadAttributes.Timestamp,
|
||||||
FeeRecipient: payloadAttributes.SuggestedFeeRecipient,
|
FeeRecipient: payloadAttributes.SuggestedFeeRecipient,
|
||||||
Random: payloadAttributes.Random,
|
Random: payloadAttributes.Random,
|
||||||
Withdrawals: payloadAttributes.Withdrawals,
|
Withdrawals: payloadAttributes.Withdrawals,
|
||||||
BeaconRoot: payloadAttributes.BeaconRoot,
|
BeaconRoot: payloadAttributes.BeaconRoot,
|
||||||
Version: payloadVersion,
|
ProposerPubkey: payloadAttributes.ProposerPubkey,
|
||||||
|
Version: payloadVersion,
|
||||||
}
|
}
|
||||||
id := args.Id()
|
id := args.Id()
|
||||||
// If we already are busy generating this work, then we do not need
|
// If we already are busy generating this work, then we do not need
|
||||||
|
|
@ -472,6 +507,14 @@ func (api *ConsensusAPI) GetPayloadV4(payloadID engine.PayloadID) (*engine.Execu
|
||||||
return api.getPayload(payloadID, false)
|
return api.getPayload(payloadID, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPayloadV4P11 returns a cached payload by id.
|
||||||
|
func (api *ConsensusAPI) GetPayloadV4P11(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) {
|
||||||
|
if !payloadID.Is(engine.PayloadV3P11) {
|
||||||
|
return nil, engine.UnsupportedFork
|
||||||
|
}
|
||||||
|
return api.getPayload(payloadID, false)
|
||||||
|
}
|
||||||
|
|
||||||
// GetPayloadV5 returns a cached payload by id.
|
// GetPayloadV5 returns a cached payload by id.
|
||||||
func (api *ConsensusAPI) GetPayloadV5(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) {
|
func (api *ConsensusAPI) GetPayloadV5(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) {
|
||||||
if !payloadID.Is(engine.PayloadV3) {
|
if !payloadID.Is(engine.PayloadV3) {
|
||||||
|
|
@ -592,7 +635,7 @@ func (api *ConsensusAPI) NewPayloadV1(params engine.ExecutableData) (engine.Payl
|
||||||
if params.Withdrawals != nil {
|
if params.Withdrawals != nil {
|
||||||
return invalidStatus, paramsErr("withdrawals not supported in V1")
|
return invalidStatus, paramsErr("withdrawals not supported in V1")
|
||||||
}
|
}
|
||||||
return api.newPayload(params, nil, nil, nil, false)
|
return api.newPayload(params, nil, nil, nil, false, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPayloadV2 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
|
// NewPayloadV2 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
|
||||||
|
|
@ -613,7 +656,7 @@ func (api *ConsensusAPI) NewPayloadV2(params engine.ExecutableData) (engine.Payl
|
||||||
case params.BlobGasUsed != nil:
|
case params.BlobGasUsed != nil:
|
||||||
return invalidStatus, paramsErr("non-nil blobGasUsed pre-cancun")
|
return invalidStatus, paramsErr("non-nil blobGasUsed pre-cancun")
|
||||||
}
|
}
|
||||||
return api.newPayload(params, nil, nil, nil, false)
|
return api.newPayload(params, nil, nil, nil, false, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPayloadV3 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
|
// NewPayloadV3 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
|
||||||
|
|
@ -632,7 +675,7 @@ func (api *ConsensusAPI) NewPayloadV3(params engine.ExecutableData, versionedHas
|
||||||
case !api.checkFork(params.Timestamp, forks.Cancun):
|
case !api.checkFork(params.Timestamp, forks.Cancun):
|
||||||
return invalidStatus, unsupportedForkErr("newPayloadV3 must only be called for cancun payloads")
|
return invalidStatus, unsupportedForkErr("newPayloadV3 must only be called for cancun payloads")
|
||||||
}
|
}
|
||||||
return api.newPayload(params, versionedHashes, beaconRoot, nil, false)
|
return api.newPayload(params, versionedHashes, beaconRoot, nil, false, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPayloadV4 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
|
// NewPayloadV4 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
|
||||||
|
|
@ -657,10 +700,37 @@ func (api *ConsensusAPI) NewPayloadV4(params engine.ExecutableData, versionedHas
|
||||||
if err := validateRequests(requests); err != nil {
|
if err := validateRequests(requests); err != nil {
|
||||||
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(err)
|
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(err)
|
||||||
}
|
}
|
||||||
return api.newPayload(params, versionedHashes, beaconRoot, requests, false)
|
return api.newPayload(params, versionedHashes, beaconRoot, requests, false, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte, witness bool) (engine.PayloadStatusV1, error) {
|
// NewPayloadV4P11 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
|
||||||
|
func (api *ConsensusAPI) NewPayloadV4P11(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, executionRequests []hexutil.Bytes, proposerPubkey *common.Pubkey) (engine.PayloadStatusV1, error) {
|
||||||
|
switch {
|
||||||
|
case params.Withdrawals == nil:
|
||||||
|
return invalidStatus, paramsErr("nil withdrawals post-shanghai")
|
||||||
|
case params.ExcessBlobGas == nil:
|
||||||
|
return invalidStatus, paramsErr("nil excessBlobGas post-cancun")
|
||||||
|
case params.BlobGasUsed == nil:
|
||||||
|
return invalidStatus, paramsErr("nil blobGasUsed post-cancun")
|
||||||
|
case versionedHashes == nil:
|
||||||
|
return invalidStatus, paramsErr("nil versionedHashes post-cancun")
|
||||||
|
case beaconRoot == nil:
|
||||||
|
return invalidStatus, paramsErr("nil beaconRoot post-cancun")
|
||||||
|
case executionRequests == nil:
|
||||||
|
return invalidStatus, paramsErr("nil executionRequests post-prague")
|
||||||
|
case proposerPubkey == nil:
|
||||||
|
return invalidStatus, paramsErr("nil proposerPubkey post-prague1")
|
||||||
|
case !api.checkFork(params.Timestamp, forks.Prague1):
|
||||||
|
return invalidStatus, unsupportedForkErr("newPayloadV4P11 must only be called for prague1 payloads")
|
||||||
|
}
|
||||||
|
requests := convertRequests(executionRequests)
|
||||||
|
if err := validateRequests(requests); err != nil {
|
||||||
|
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(err)
|
||||||
|
}
|
||||||
|
return api.newPayload(params, versionedHashes, beaconRoot, requests, false, proposerPubkey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte, witness bool, proposerPubkey *common.Pubkey) (engine.PayloadStatusV1, error) {
|
||||||
// The locking here is, strictly, not required. Without these locks, this can happen:
|
// The locking here is, strictly, not required. Without these locks, this can happen:
|
||||||
//
|
//
|
||||||
// 1. NewPayload( execdata-N ) is invoked from the CL. It goes all the way down to
|
// 1. NewPayload( execdata-N ) is invoked from the CL. It goes all the way down to
|
||||||
|
|
@ -678,7 +748,7 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe
|
||||||
defer api.newPayloadLock.Unlock()
|
defer api.newPayloadLock.Unlock()
|
||||||
|
|
||||||
log.Trace("Engine API request received", "method", "NewPayload", "number", params.Number, "hash", params.BlockHash)
|
log.Trace("Engine API request received", "method", "NewPayload", "number", params.Number, "hash", params.BlockHash)
|
||||||
block, err := engine.ExecutableDataToBlock(params, versionedHashes, beaconRoot, requests)
|
block, err := engine.ExecutableDataToBlock(params, versionedHashes, beaconRoot, requests, proposerPubkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bgu := "nil"
|
bgu := "nil"
|
||||||
if params.BlobGasUsed != nil {
|
if params.BlobGasUsed != nil {
|
||||||
|
|
|
||||||
|
|
@ -305,7 +305,7 @@ func TestEth2NewBlock(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create the executable data, block %d: %v", i, err)
|
t.Fatalf("Failed to create the executable data, block %d: %v", i, err)
|
||||||
}
|
}
|
||||||
block, err := engine.ExecutableDataToBlock(*execData, nil, nil, nil)
|
block, err := engine.ExecutableDataToBlock(*execData, nil, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to convert executable data to block %v", err)
|
t.Fatalf("Failed to convert executable data to block %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -347,7 +347,7 @@ func TestEth2NewBlock(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create the executable data %v", err)
|
t.Fatalf("Failed to create the executable data %v", err)
|
||||||
}
|
}
|
||||||
block, err := engine.ExecutableDataToBlock(*execData, nil, nil, nil)
|
block, err := engine.ExecutableDataToBlock(*execData, nil, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to convert executable data to block %v", err)
|
t.Fatalf("Failed to convert executable data to block %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -472,10 +472,10 @@ func TestFullAPI(t *testing.T) {
|
||||||
ethservice.TxPool().Add([]*types.Transaction{tx}, false)
|
ethservice.TxPool().Add([]*types.Transaction{tx}, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
setupBlocks(t, ethservice, 10, parent, callback, nil, nil)
|
setupBlocks(t, ethservice, 10, parent, callback, nil, nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Header, callback func(parent *types.Header), withdrawals [][]*types.Withdrawal, beaconRoots []common.Hash) []*types.Header {
|
func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Header, callback func(parent *types.Header), withdrawals [][]*types.Withdrawal, beaconRoots []common.Hash, proposerPubkeys []common.Pubkey) []*types.Header {
|
||||||
api := NewConsensusAPI(ethservice)
|
api := NewConsensusAPI(ethservice)
|
||||||
var blocks []*types.Header
|
var blocks []*types.Header
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
|
|
@ -488,9 +488,13 @@ func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.He
|
||||||
if beaconRoots != nil {
|
if beaconRoots != nil {
|
||||||
h = &beaconRoots[i]
|
h = &beaconRoots[i]
|
||||||
}
|
}
|
||||||
|
var p *common.Pubkey
|
||||||
|
if proposerPubkeys != nil {
|
||||||
|
p = &proposerPubkeys[i]
|
||||||
|
}
|
||||||
|
|
||||||
envelope := getNewEnvelope(t, api, parent, w, h)
|
envelope := getNewEnvelope(t, api, parent, w, h, p)
|
||||||
execResp, err := api.newPayload(*envelope.ExecutionPayload, []common.Hash{}, h, envelope.Requests, false)
|
execResp, err := api.newPayload(*envelope.ExecutionPayload, []common.Hash{}, h, envelope.Requests, false, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("can't execute payload: %v", err)
|
t.Fatalf("can't execute payload: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -660,12 +664,13 @@ func TestNewPayloadOnInvalidChain(t *testing.T) {
|
||||||
|
|
||||||
func assembleEnvelope(api *ConsensusAPI, parentHash common.Hash, params *engine.PayloadAttributes) (*engine.ExecutionPayloadEnvelope, error) {
|
func assembleEnvelope(api *ConsensusAPI, parentHash common.Hash, params *engine.PayloadAttributes) (*engine.ExecutionPayloadEnvelope, error) {
|
||||||
args := &miner.BuildPayloadArgs{
|
args := &miner.BuildPayloadArgs{
|
||||||
Parent: parentHash,
|
Parent: parentHash,
|
||||||
Timestamp: params.Timestamp,
|
Timestamp: params.Timestamp,
|
||||||
FeeRecipient: params.SuggestedFeeRecipient,
|
FeeRecipient: params.SuggestedFeeRecipient,
|
||||||
Random: params.Random,
|
Random: params.Random,
|
||||||
Withdrawals: params.Withdrawals,
|
Withdrawals: params.Withdrawals,
|
||||||
BeaconRoot: params.BeaconRoot,
|
BeaconRoot: params.BeaconRoot,
|
||||||
|
ProposerPubkey: params.ProposerPubkey,
|
||||||
}
|
}
|
||||||
payload, err := api.eth.Miner().BuildPayload(args, false)
|
payload, err := api.eth.Miner().BuildPayload(args, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -691,10 +696,10 @@ func TestEmptyBlocks(t *testing.T) {
|
||||||
api := NewConsensusAPI(ethservice)
|
api := NewConsensusAPI(ethservice)
|
||||||
|
|
||||||
// Setup 10 blocks on the canonical chain
|
// Setup 10 blocks on the canonical chain
|
||||||
setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}, nil, nil)
|
setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}, nil, nil, nil)
|
||||||
|
|
||||||
// (1) check LatestValidHash by sending a normal payload (P1'')
|
// (1) check LatestValidHash by sending a normal payload (P1'')
|
||||||
payload := getNewPayload(t, api, commonAncestor, nil, nil)
|
payload := getNewPayload(t, api, commonAncestor, nil, nil, nil)
|
||||||
|
|
||||||
status, err := api.NewPayloadV1(*payload)
|
status, err := api.NewPayloadV1(*payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -708,7 +713,7 @@ func TestEmptyBlocks(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// (2) Now send P1' which is invalid
|
// (2) Now send P1' which is invalid
|
||||||
payload = getNewPayload(t, api, commonAncestor, nil, nil)
|
payload = getNewPayload(t, api, commonAncestor, nil, nil, nil)
|
||||||
payload.GasUsed += 1
|
payload.GasUsed += 1
|
||||||
payload = setBlockhash(payload)
|
payload = setBlockhash(payload)
|
||||||
// Now latestValidHash should be the common ancestor
|
// Now latestValidHash should be the common ancestor
|
||||||
|
|
@ -726,7 +731,7 @@ func TestEmptyBlocks(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// (3) Now send a payload with unknown parent
|
// (3) Now send a payload with unknown parent
|
||||||
payload = getNewPayload(t, api, commonAncestor, nil, nil)
|
payload = getNewPayload(t, api, commonAncestor, nil, nil, nil)
|
||||||
payload.ParentHash = common.Hash{1}
|
payload.ParentHash = common.Hash{1}
|
||||||
payload = setBlockhash(payload)
|
payload = setBlockhash(payload)
|
||||||
// Now latestValidHash should be the common ancestor
|
// Now latestValidHash should be the common ancestor
|
||||||
|
|
@ -742,13 +747,14 @@ func TestEmptyBlocks(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNewEnvelope(t *testing.T, api *ConsensusAPI, parent *types.Header, withdrawals []*types.Withdrawal, beaconRoot *common.Hash) *engine.ExecutionPayloadEnvelope {
|
func getNewEnvelope(t *testing.T, api *ConsensusAPI, parent *types.Header, withdrawals []*types.Withdrawal, beaconRoot *common.Hash, proposerPubkey *common.Pubkey) *engine.ExecutionPayloadEnvelope {
|
||||||
params := engine.PayloadAttributes{
|
params := engine.PayloadAttributes{
|
||||||
Timestamp: parent.Time + 1,
|
Timestamp: parent.Time + 1,
|
||||||
Random: crypto.Keccak256Hash([]byte{byte(1)}),
|
Random: crypto.Keccak256Hash([]byte{byte(1)}),
|
||||||
SuggestedFeeRecipient: parent.Coinbase,
|
SuggestedFeeRecipient: parent.Coinbase,
|
||||||
Withdrawals: withdrawals,
|
Withdrawals: withdrawals,
|
||||||
BeaconRoot: beaconRoot,
|
BeaconRoot: beaconRoot,
|
||||||
|
ProposerPubkey: proposerPubkey,
|
||||||
}
|
}
|
||||||
|
|
||||||
envelope, err := assembleEnvelope(api, parent.Hash(), ¶ms)
|
envelope, err := assembleEnvelope(api, parent.Hash(), ¶ms)
|
||||||
|
|
@ -758,8 +764,8 @@ func getNewEnvelope(t *testing.T, api *ConsensusAPI, parent *types.Header, withd
|
||||||
return envelope
|
return envelope
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Header, withdrawals []*types.Withdrawal, beaconRoot *common.Hash) *engine.ExecutableData {
|
func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Header, withdrawals []*types.Withdrawal, beaconRoot *common.Hash, proposerPubkey *common.Pubkey) *engine.ExecutableData {
|
||||||
return getNewEnvelope(t, api, parent, withdrawals, beaconRoot).ExecutionPayload
|
return getNewEnvelope(t, api, parent, withdrawals, beaconRoot, proposerPubkey).ExecutionPayload
|
||||||
}
|
}
|
||||||
|
|
||||||
// setBlockhash sets the blockhash of a modified ExecutableData.
|
// setBlockhash sets the blockhash of a modified ExecutableData.
|
||||||
|
|
@ -820,7 +826,7 @@ func TestTrickRemoteBlockCache(t *testing.T) {
|
||||||
commonAncestor := ethserviceA.BlockChain().CurrentBlock()
|
commonAncestor := ethserviceA.BlockChain().CurrentBlock()
|
||||||
|
|
||||||
// Setup 10 blocks on the canonical chain
|
// Setup 10 blocks on the canonical chain
|
||||||
setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Header) {}, nil, nil)
|
setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Header) {}, nil, nil, nil)
|
||||||
commonAncestor = ethserviceA.BlockChain().CurrentBlock()
|
commonAncestor = ethserviceA.BlockChain().CurrentBlock()
|
||||||
|
|
||||||
var invalidChain []*engine.ExecutableData
|
var invalidChain []*engine.ExecutableData
|
||||||
|
|
@ -829,7 +835,7 @@ func TestTrickRemoteBlockCache(t *testing.T) {
|
||||||
//invalidChain = append(invalidChain, payload1)
|
//invalidChain = append(invalidChain, payload1)
|
||||||
|
|
||||||
// create an invalid payload2 (P2)
|
// create an invalid payload2 (P2)
|
||||||
payload2 := getNewPayload(t, apiA, commonAncestor, nil, nil)
|
payload2 := getNewPayload(t, apiA, commonAncestor, nil, nil, nil)
|
||||||
//payload2.ParentHash = payload1.BlockHash
|
//payload2.ParentHash = payload1.BlockHash
|
||||||
payload2.GasUsed += 1
|
payload2.GasUsed += 1
|
||||||
payload2 = setBlockhash(payload2)
|
payload2 = setBlockhash(payload2)
|
||||||
|
|
@ -838,7 +844,7 @@ func TestTrickRemoteBlockCache(t *testing.T) {
|
||||||
head := payload2
|
head := payload2
|
||||||
// create some valid payloads on top
|
// create some valid payloads on top
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
payload := getNewPayload(t, apiA, commonAncestor, nil, nil)
|
payload := getNewPayload(t, apiA, commonAncestor, nil, nil, nil)
|
||||||
payload.ParentHash = head.BlockHash
|
payload.ParentHash = head.BlockHash
|
||||||
payload = setBlockhash(payload)
|
payload = setBlockhash(payload)
|
||||||
invalidChain = append(invalidChain, payload)
|
invalidChain = append(invalidChain, payload)
|
||||||
|
|
@ -875,10 +881,10 @@ func TestInvalidBloom(t *testing.T) {
|
||||||
api := NewConsensusAPI(ethservice)
|
api := NewConsensusAPI(ethservice)
|
||||||
|
|
||||||
// Setup 10 blocks on the canonical chain
|
// Setup 10 blocks on the canonical chain
|
||||||
setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}, nil, nil)
|
setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}, nil, nil, nil)
|
||||||
|
|
||||||
// (1) check LatestValidHash by sending a normal payload (P1'')
|
// (1) check LatestValidHash by sending a normal payload (P1'')
|
||||||
payload := getNewPayload(t, api, commonAncestor, nil, nil)
|
payload := getNewPayload(t, api, commonAncestor, nil, nil, nil)
|
||||||
payload.LogsBloom = append(payload.LogsBloom, byte(1))
|
payload.LogsBloom = append(payload.LogsBloom, byte(1))
|
||||||
status, err := api.NewPayloadV1(*payload)
|
status, err := api.NewPayloadV1(*payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -935,7 +941,7 @@ func TestSimultaneousNewBlock(t *testing.T) {
|
||||||
t.Fatal(testErr)
|
t.Fatal(testErr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
block, err := engine.ExecutableDataToBlock(*execData, nil, nil, nil)
|
block, err := engine.ExecutableDataToBlock(*execData, nil, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to convert executable data to block %v", err)
|
t.Fatalf("Failed to convert executable data to block %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1275,7 +1281,7 @@ func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the blocks.
|
// Create the blocks.
|
||||||
newHeaders := setupBlocks(t, ethservice, 10, parent, callback, withdrawals, beaconRoots)
|
newHeaders := setupBlocks(t, ethservice, 10, parent, callback, withdrawals, beaconRoots, nil)
|
||||||
newBlocks := make([]*types.Block, len(newHeaders))
|
newBlocks := make([]*types.Block, len(newHeaders))
|
||||||
for i, header := range newHeaders {
|
for i, header := range newHeaders {
|
||||||
newBlocks[i] = ethservice.BlockChain().GetBlock(header.Hash(), header.Number.Uint64())
|
newBlocks[i] = ethservice.BlockChain().GetBlock(header.Hash(), header.Number.Uint64())
|
||||||
|
|
@ -1529,7 +1535,7 @@ func TestBlockToPayloadWithBlobs(t *testing.T) {
|
||||||
if got := len(envelope.BlobsBundle.Blobs); got != want {
|
if got := len(envelope.BlobsBundle.Blobs); got != want {
|
||||||
t.Fatalf("invalid number of blobs: got %v, want %v", got, want)
|
t.Fatalf("invalid number of blobs: got %v, want %v", got, want)
|
||||||
}
|
}
|
||||||
_, err := engine.ExecutableDataToBlock(*envelope.ExecutionPayload, make([]common.Hash, 1), nil, nil)
|
_, err := engine.ExecutableDataToBlock(*envelope.ExecutionPayload, make([]common.Hash, 1), nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,8 @@ type SimulatedBeacon struct {
|
||||||
|
|
||||||
func payloadVersion(config *params.ChainConfig, time uint64) engine.PayloadVersion {
|
func payloadVersion(config *params.ChainConfig, time uint64) engine.PayloadVersion {
|
||||||
switch config.LatestFork(time) {
|
switch config.LatestFork(time) {
|
||||||
|
case forks.Prague1:
|
||||||
|
return engine.PayloadV3P11
|
||||||
case forks.Prague, forks.Cancun:
|
case forks.Prague, forks.Cancun:
|
||||||
return engine.PayloadV3
|
return engine.PayloadV3
|
||||||
case forks.Paris, forks.Shanghai:
|
case forks.Paris, forks.Shanghai:
|
||||||
|
|
@ -191,6 +193,10 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u
|
||||||
}
|
}
|
||||||
|
|
||||||
version := payloadVersion(c.eth.BlockChain().Config(), timestamp)
|
version := payloadVersion(c.eth.BlockChain().Config(), timestamp)
|
||||||
|
var proposerPubkey *common.Pubkey
|
||||||
|
if version == engine.PayloadV3P11 {
|
||||||
|
proposerPubkey = &common.Pubkey{}
|
||||||
|
}
|
||||||
|
|
||||||
var random [32]byte
|
var random [32]byte
|
||||||
rand.Read(random[:])
|
rand.Read(random[:])
|
||||||
|
|
@ -200,6 +206,7 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u
|
||||||
Withdrawals: withdrawals,
|
Withdrawals: withdrawals,
|
||||||
Random: random,
|
Random: random,
|
||||||
BeaconRoot: &common.Hash{},
|
BeaconRoot: &common.Hash{},
|
||||||
|
ProposerPubkey: proposerPubkey,
|
||||||
}, version, false)
|
}, version, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -256,7 +263,7 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the payload as canon
|
// Mark the payload as canon
|
||||||
_, err = c.engineAPI.newPayload(*payload, blobHashes, beaconRoot, requests, false)
|
_, err = c.engineAPI.newPayload(*payload, blobHashes, beaconRoot, requests, false, proposerPubkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -317,6 +324,7 @@ func (c *SimulatedBeacon) Commit() common.Hash {
|
||||||
withdrawals := c.withdrawals.pop(10)
|
withdrawals := c.withdrawals.pop(10)
|
||||||
if err := c.sealBlock(withdrawals, uint64(time.Now().Unix())); err != nil {
|
if err := c.sealBlock(withdrawals, uint64(time.Now().Unix())); err != nil {
|
||||||
log.Warn("Error performing sealing work", "err", err)
|
log.Warn("Error performing sealing work", "err", err)
|
||||||
|
panic(err)
|
||||||
}
|
}
|
||||||
return c.eth.BlockChain().CurrentBlock().Hash()
|
return c.eth.BlockChain().CurrentBlock().Hash()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,8 @@ import (
|
||||||
func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV1(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
|
func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV1(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
|
||||||
if payloadAttributes != nil {
|
if payloadAttributes != nil {
|
||||||
switch {
|
switch {
|
||||||
|
case payloadAttributes.ProposerPubkey != nil:
|
||||||
|
return engine.STATUS_INVALID, attributesErr("proposer pubkey not supported in V1")
|
||||||
case payloadAttributes.Withdrawals != nil || payloadAttributes.BeaconRoot != nil:
|
case payloadAttributes.Withdrawals != nil || payloadAttributes.BeaconRoot != nil:
|
||||||
return engine.STATUS_INVALID, paramsErr("withdrawals and beacon root not supported in V1")
|
return engine.STATUS_INVALID, paramsErr("withdrawals and beacon root not supported in V1")
|
||||||
case !api.checkFork(payloadAttributes.Timestamp, forks.Paris, forks.Shanghai):
|
case !api.checkFork(payloadAttributes.Timestamp, forks.Paris, forks.Shanghai):
|
||||||
|
|
@ -51,6 +53,8 @@ func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV1(update engine.Forkchoice
|
||||||
func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV2(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
|
func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV2(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
|
||||||
if params != nil {
|
if params != nil {
|
||||||
switch {
|
switch {
|
||||||
|
case params.ProposerPubkey != nil:
|
||||||
|
return engine.STATUS_INVALID, attributesErr("unexpected proposer pubkey")
|
||||||
case params.BeaconRoot != nil:
|
case params.BeaconRoot != nil:
|
||||||
return engine.STATUS_INVALID, attributesErr("unexpected beacon root")
|
return engine.STATUS_INVALID, attributesErr("unexpected beacon root")
|
||||||
case api.checkFork(params.Timestamp, forks.Paris) && params.Withdrawals != nil:
|
case api.checkFork(params.Timestamp, forks.Paris) && params.Withdrawals != nil:
|
||||||
|
|
@ -69,6 +73,8 @@ func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV2(update engine.Forkchoice
|
||||||
func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV3(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
|
func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV3(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
|
||||||
if params != nil {
|
if params != nil {
|
||||||
switch {
|
switch {
|
||||||
|
case params.ProposerPubkey != nil:
|
||||||
|
return engine.STATUS_INVALID, attributesErr("unexpected proposer pubkey")
|
||||||
case params.Withdrawals == nil:
|
case params.Withdrawals == nil:
|
||||||
return engine.STATUS_INVALID, attributesErr("missing withdrawals")
|
return engine.STATUS_INVALID, attributesErr("missing withdrawals")
|
||||||
case params.BeaconRoot == nil:
|
case params.BeaconRoot == nil:
|
||||||
|
|
@ -84,13 +90,35 @@ func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV3(update engine.Forkchoice
|
||||||
return api.forkchoiceUpdated(update, params, engine.PayloadV3, true)
|
return api.forkchoiceUpdated(update, params, engine.PayloadV3, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ForkchoiceUpdatedWithWitnessV3P11 is analogous to ForkchoiceUpdatedV3P11, only it
|
||||||
|
// generates an execution witness too if block building was requested.
|
||||||
|
func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV3P11(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
|
||||||
|
if params != nil {
|
||||||
|
switch {
|
||||||
|
case params.Withdrawals == nil:
|
||||||
|
return engine.STATUS_INVALID, attributesErr("missing withdrawals")
|
||||||
|
case params.BeaconRoot == nil:
|
||||||
|
return engine.STATUS_INVALID, attributesErr("missing beacon root")
|
||||||
|
case params.ProposerPubkey == nil:
|
||||||
|
return engine.STATUS_INVALID, attributesErr("missing proposer pubkey")
|
||||||
|
case !api.checkFork(params.Timestamp, forks.Prague1):
|
||||||
|
return engine.STATUS_INVALID, unsupportedForkErr("fcuV3P11 must only be called for prague1 payloads")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO(matt): the spec requires that fcu is applied when called on a valid
|
||||||
|
// hash, even if params are wrong. To do this we need to split up
|
||||||
|
// forkchoiceUpdate into a function that only updates the head and then a
|
||||||
|
// function that kicks off block construction.
|
||||||
|
return api.forkchoiceUpdated(update, params, engine.PayloadV3P11, true)
|
||||||
|
}
|
||||||
|
|
||||||
// NewPayloadWithWitnessV1 is analogous to NewPayloadV1, only it also generates
|
// NewPayloadWithWitnessV1 is analogous to NewPayloadV1, only it also generates
|
||||||
// and returns a stateless witness after running the payload.
|
// and returns a stateless witness after running the payload.
|
||||||
func (api *ConsensusAPI) NewPayloadWithWitnessV1(params engine.ExecutableData) (engine.PayloadStatusV1, error) {
|
func (api *ConsensusAPI) NewPayloadWithWitnessV1(params engine.ExecutableData) (engine.PayloadStatusV1, error) {
|
||||||
if params.Withdrawals != nil {
|
if params.Withdrawals != nil {
|
||||||
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("withdrawals not supported in V1"))
|
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("withdrawals not supported in V1"))
|
||||||
}
|
}
|
||||||
return api.newPayload(params, nil, nil, nil, true)
|
return api.newPayload(params, nil, nil, nil, true, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPayloadWithWitnessV2 is analogous to NewPayloadV2, only it also generates
|
// NewPayloadWithWitnessV2 is analogous to NewPayloadV2, only it also generates
|
||||||
|
|
@ -112,7 +140,7 @@ func (api *ConsensusAPI) NewPayloadWithWitnessV2(params engine.ExecutableData) (
|
||||||
case params.BlobGasUsed != nil:
|
case params.BlobGasUsed != nil:
|
||||||
return invalidStatus, paramsErr("non-nil blobGasUsed pre-cancun")
|
return invalidStatus, paramsErr("non-nil blobGasUsed pre-cancun")
|
||||||
}
|
}
|
||||||
return api.newPayload(params, nil, nil, nil, true)
|
return api.newPayload(params, nil, nil, nil, true, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPayloadWithWitnessV3 is analogous to NewPayloadV3, only it also generates
|
// NewPayloadWithWitnessV3 is analogous to NewPayloadV3, only it also generates
|
||||||
|
|
@ -132,7 +160,7 @@ func (api *ConsensusAPI) NewPayloadWithWitnessV3(params engine.ExecutableData, v
|
||||||
case !api.checkFork(params.Timestamp, forks.Cancun):
|
case !api.checkFork(params.Timestamp, forks.Cancun):
|
||||||
return invalidStatus, unsupportedForkErr("newPayloadV3 must only be called for cancun payloads")
|
return invalidStatus, unsupportedForkErr("newPayloadV3 must only be called for cancun payloads")
|
||||||
}
|
}
|
||||||
return api.newPayload(params, versionedHashes, beaconRoot, nil, true)
|
return api.newPayload(params, versionedHashes, beaconRoot, nil, true, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPayloadWithWitnessV4 is analogous to NewPayloadV4, only it also generates
|
// NewPayloadWithWitnessV4 is analogous to NewPayloadV4, only it also generates
|
||||||
|
|
@ -158,7 +186,35 @@ func (api *ConsensusAPI) NewPayloadWithWitnessV4(params engine.ExecutableData, v
|
||||||
if err := validateRequests(requests); err != nil {
|
if err := validateRequests(requests); err != nil {
|
||||||
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(err)
|
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(err)
|
||||||
}
|
}
|
||||||
return api.newPayload(params, versionedHashes, beaconRoot, requests, true)
|
return api.newPayload(params, versionedHashes, beaconRoot, requests, true, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPayloadWithWitnessV4P11 is analogous to NewPayloadV4P11, only it also generates
|
||||||
|
// and returns a stateless witness after running the payload.
|
||||||
|
func (api *ConsensusAPI) NewPayloadWithWitnessV4P11(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, executionRequests []hexutil.Bytes, proposerPubkey *common.Pubkey) (engine.PayloadStatusV1, error) {
|
||||||
|
switch {
|
||||||
|
case params.Withdrawals == nil:
|
||||||
|
return invalidStatus, paramsErr("nil withdrawals post-shanghai")
|
||||||
|
case params.ExcessBlobGas == nil:
|
||||||
|
return invalidStatus, paramsErr("nil excessBlobGas post-cancun")
|
||||||
|
case params.BlobGasUsed == nil:
|
||||||
|
return invalidStatus, paramsErr("nil blobGasUsed post-cancun")
|
||||||
|
case versionedHashes == nil:
|
||||||
|
return invalidStatus, paramsErr("nil versionedHashes post-cancun")
|
||||||
|
case beaconRoot == nil:
|
||||||
|
return invalidStatus, paramsErr("nil beaconRoot post-cancun")
|
||||||
|
case executionRequests == nil:
|
||||||
|
return invalidStatus, paramsErr("nil executionRequests post-prague")
|
||||||
|
case proposerPubkey == nil:
|
||||||
|
return invalidStatus, paramsErr("nil proposerPubkey post-prague1")
|
||||||
|
case !api.checkFork(params.Timestamp, forks.Prague1):
|
||||||
|
return invalidStatus, unsupportedForkErr("newPayloadV4P11 must only be called for prague1 payloads")
|
||||||
|
}
|
||||||
|
requests := convertRequests(executionRequests)
|
||||||
|
if err := validateRequests(requests); err != nil {
|
||||||
|
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(err)
|
||||||
|
}
|
||||||
|
return api.newPayload(params, versionedHashes, beaconRoot, requests, true, proposerPubkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecuteStatelessPayloadV1 is analogous to NewPayloadV1, only it operates in
|
// ExecuteStatelessPayloadV1 is analogous to NewPayloadV1, only it operates in
|
||||||
|
|
@ -167,7 +223,7 @@ func (api *ConsensusAPI) ExecuteStatelessPayloadV1(params engine.ExecutableData,
|
||||||
if params.Withdrawals != nil {
|
if params.Withdrawals != nil {
|
||||||
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("withdrawals not supported in V1"))
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("withdrawals not supported in V1"))
|
||||||
}
|
}
|
||||||
return api.executeStatelessPayload(params, nil, nil, nil, opaqueWitness)
|
return api.executeStatelessPayload(params, nil, nil, nil, opaqueWitness, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecuteStatelessPayloadV2 is analogous to NewPayloadV2, only it operates in
|
// ExecuteStatelessPayloadV2 is analogous to NewPayloadV2, only it operates in
|
||||||
|
|
@ -189,7 +245,7 @@ func (api *ConsensusAPI) ExecuteStatelessPayloadV2(params engine.ExecutableData,
|
||||||
case params.BlobGasUsed != nil:
|
case params.BlobGasUsed != nil:
|
||||||
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("non-nil blobGasUsed pre-cancun")
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("non-nil blobGasUsed pre-cancun")
|
||||||
}
|
}
|
||||||
return api.executeStatelessPayload(params, nil, nil, nil, opaqueWitness)
|
return api.executeStatelessPayload(params, nil, nil, nil, opaqueWitness, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecuteStatelessPayloadV3 is analogous to NewPayloadV3, only it operates in
|
// ExecuteStatelessPayloadV3 is analogous to NewPayloadV3, only it operates in
|
||||||
|
|
@ -207,9 +263,9 @@ func (api *ConsensusAPI) ExecuteStatelessPayloadV3(params engine.ExecutableData,
|
||||||
case beaconRoot == nil:
|
case beaconRoot == nil:
|
||||||
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("nil beaconRoot post-cancun")
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("nil beaconRoot post-cancun")
|
||||||
case !api.checkFork(params.Timestamp, forks.Cancun):
|
case !api.checkFork(params.Timestamp, forks.Cancun):
|
||||||
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, unsupportedForkErr("newPayloadV3 must only be called for cancun payloads")
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, unsupportedForkErr("executeStatelessPayloadV3 must only be called for cancun payloads")
|
||||||
}
|
}
|
||||||
return api.executeStatelessPayload(params, versionedHashes, beaconRoot, nil, opaqueWitness)
|
return api.executeStatelessPayload(params, versionedHashes, beaconRoot, nil, opaqueWitness, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecuteStatelessPayloadV4 is analogous to NewPayloadV4, only it operates in
|
// ExecuteStatelessPayloadV4 is analogous to NewPayloadV4, only it operates in
|
||||||
|
|
@ -229,18 +285,46 @@ func (api *ConsensusAPI) ExecuteStatelessPayloadV4(params engine.ExecutableData,
|
||||||
case executionRequests == nil:
|
case executionRequests == nil:
|
||||||
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("nil executionRequests post-prague")
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("nil executionRequests post-prague")
|
||||||
case !api.checkFork(params.Timestamp, forks.Prague):
|
case !api.checkFork(params.Timestamp, forks.Prague):
|
||||||
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, unsupportedForkErr("newPayloadV3 must only be called for cancun payloads")
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, unsupportedForkErr("executeStatelessPayloadV4 must only be called for prague payloads")
|
||||||
}
|
}
|
||||||
requests := convertRequests(executionRequests)
|
requests := convertRequests(executionRequests)
|
||||||
if err := validateRequests(requests); err != nil {
|
if err := validateRequests(requests); err != nil {
|
||||||
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(err)
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(err)
|
||||||
}
|
}
|
||||||
return api.executeStatelessPayload(params, versionedHashes, beaconRoot, requests, opaqueWitness)
|
return api.executeStatelessPayload(params, versionedHashes, beaconRoot, requests, opaqueWitness, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *ConsensusAPI) executeStatelessPayload(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte, opaqueWitness hexutil.Bytes) (engine.StatelessPayloadStatusV1, error) {
|
// ExecuteStatelessPayloadV4P11 is analogous to NewPayloadV4P11, only it operates in
|
||||||
|
// a stateless mode on top of a provided witness instead of the local database.
|
||||||
|
func (api *ConsensusAPI) ExecuteStatelessPayloadV4P11(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, executionRequests []hexutil.Bytes, opaqueWitness hexutil.Bytes, proposerPubkey *common.Pubkey) (engine.StatelessPayloadStatusV1, error) {
|
||||||
|
switch {
|
||||||
|
case params.Withdrawals == nil:
|
||||||
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("nil withdrawals post-shanghai")
|
||||||
|
case params.ExcessBlobGas == nil:
|
||||||
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("nil excessBlobGas post-cancun")
|
||||||
|
case params.BlobGasUsed == nil:
|
||||||
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("nil blobGasUsed post-cancun")
|
||||||
|
case versionedHashes == nil:
|
||||||
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("nil versionedHashes post-cancun")
|
||||||
|
case beaconRoot == nil:
|
||||||
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("nil beaconRoot post-cancun")
|
||||||
|
case executionRequests == nil:
|
||||||
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("nil executionRequests post-prague")
|
||||||
|
case proposerPubkey == nil:
|
||||||
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("nil proposerPubkey post-prague1")
|
||||||
|
case !api.checkFork(params.Timestamp, forks.Prague1):
|
||||||
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, unsupportedForkErr("executeStatelessPayloadV4P11 must only be called for prague1 payloads")
|
||||||
|
}
|
||||||
|
requests := convertRequests(executionRequests)
|
||||||
|
if err := validateRequests(requests); err != nil {
|
||||||
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(err)
|
||||||
|
}
|
||||||
|
return api.executeStatelessPayload(params, versionedHashes, beaconRoot, requests, opaqueWitness, proposerPubkey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *ConsensusAPI) executeStatelessPayload(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte, opaqueWitness hexutil.Bytes, proposerPubkey *common.Pubkey) (engine.StatelessPayloadStatusV1, error) {
|
||||||
log.Trace("Engine API request received", "method", "ExecuteStatelessPayload", "number", params.Number, "hash", params.BlockHash)
|
log.Trace("Engine API request received", "method", "ExecuteStatelessPayload", "number", params.Number, "hash", params.BlockHash)
|
||||||
block, err := engine.ExecutableDataToBlockNoHash(params, versionedHashes, beaconRoot, requests)
|
block, err := engine.ExecutableDataToBlockNoHash(params, versionedHashes, beaconRoot, requests, proposerPubkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bgu := "nil"
|
bgu := "nil"
|
||||||
if params.BlobGasUsed != nil {
|
if params.BlobGasUsed != nil {
|
||||||
|
|
@ -268,6 +352,7 @@ func (api *ConsensusAPI) executeStatelessPayload(params engine.ExecutableData, v
|
||||||
"len(params.Transactions)", len(params.Transactions),
|
"len(params.Transactions)", len(params.Transactions),
|
||||||
"len(params.Withdrawals)", len(params.Withdrawals),
|
"len(params.Withdrawals)", len(params.Withdrawals),
|
||||||
"beaconRoot", beaconRoot,
|
"beaconRoot", beaconRoot,
|
||||||
|
"parentProposerPubkey", proposerPubkey,
|
||||||
"len(requests)", len(requests),
|
"len(requests)", len(requests),
|
||||||
"error", err)
|
"error", err)
|
||||||
errorMsg := err.Error()
|
errorMsg := err.Error()
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ var FullNodeGPO = gasprice.Config{
|
||||||
IgnorePrice: gasprice.DefaultIgnorePrice,
|
IgnorePrice: gasprice.DefaultIgnorePrice,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defaults contains default settings for use on the Ethereum main net.
|
// Defaults contains default settings for use on the Ethereum and Berachain main net.
|
||||||
var Defaults = Config{
|
var Defaults = Config{
|
||||||
HistoryMode: history.KeepAll,
|
HistoryMode: history.KeepAll,
|
||||||
SyncMode: SnapSync,
|
SyncMode: SnapSync,
|
||||||
|
|
|
||||||
|
|
@ -984,9 +984,11 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
msg = args.ToMessage(blockContext.BaseFee, true, true)
|
isPrague1 = api.backend.ChainConfig().IsPrague1(blockContext.BlockNumber, blockContext.Time)
|
||||||
tx = args.ToTransaction(types.LegacyTxType)
|
distributorAddress = api.backend.ChainConfig().Berachain.Prague1.PoLDistributorAddress
|
||||||
traceConfig *TraceConfig
|
msg = args.ToMessage(blockContext.BaseFee, true, true, isPrague1, distributorAddress)
|
||||||
|
tx = args.ToTransaction(types.LegacyTxType, isPrague1, distributorAddress)
|
||||||
|
traceConfig *TraceConfig
|
||||||
)
|
)
|
||||||
// Lower the basefee to 0 to avoid breaking EVM
|
// Lower the basefee to 0 to avoid breaking EVM
|
||||||
// invariants (basefee < feecap).
|
// invariants (basefee < feecap).
|
||||||
|
|
|
||||||
|
|
@ -318,7 +318,7 @@ func (t *Transaction) MaxFeePerGas(ctx context.Context) *hexutil.Big {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
switch tx.Type() {
|
switch tx.Type() {
|
||||||
case types.DynamicFeeTxType, types.BlobTxType, types.SetCodeTxType:
|
case types.DynamicFeeTxType, types.BlobTxType, types.SetCodeTxType, types.PoLTxType:
|
||||||
return (*hexutil.Big)(tx.GasFeeCap())
|
return (*hexutil.Big)(tx.GasFeeCap())
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -331,7 +331,7 @@ func (t *Transaction) MaxPriorityFeePerGas(ctx context.Context) *hexutil.Big {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
switch tx.Type() {
|
switch tx.Type() {
|
||||||
case types.DynamicFeeTxType, types.BlobTxType, types.SetCodeTxType:
|
case types.DynamicFeeTxType, types.BlobTxType, types.SetCodeTxType, types.PoLTxType:
|
||||||
return (*hexutil.Big)(tx.GasTipCap())
|
return (*hexutil.Big)(tx.GasTipCap())
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,14 @@ func Env() Environment {
|
||||||
isPR := os.Getenv("GITHUB_HEAD_REF") != ""
|
isPR := os.Getenv("GITHUB_HEAD_REF") != ""
|
||||||
tag := ""
|
tag := ""
|
||||||
branch := ""
|
branch := ""
|
||||||
|
if reftype == "" {
|
||||||
|
gref := os.Getenv("GITHUB_REF")
|
||||||
|
if strings.HasPrefix(gref, "refs/heads/") {
|
||||||
|
reftype = "branch"
|
||||||
|
} else if strings.HasPrefix(gref, "refs/tags/") {
|
||||||
|
reftype = "tag"
|
||||||
|
}
|
||||||
|
}
|
||||||
switch {
|
switch {
|
||||||
case isPR:
|
case isPR:
|
||||||
branch = os.Getenv("GITHUB_BASE_REF")
|
branch = os.Getenv("GITHUB_BASE_REF")
|
||||||
|
|
@ -106,6 +114,18 @@ func Env() Environment {
|
||||||
case reftype == "tag":
|
case reftype == "tag":
|
||||||
tag = os.Getenv("GITHUB_REF_NAME")
|
tag = os.Getenv("GITHUB_REF_NAME")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fallback: If tag or branch is still empty, derive from GITHUB_REF.
|
||||||
|
if tag == "" && branch == "" {
|
||||||
|
if gref := os.Getenv("GITHUB_REF"); gref != "" {
|
||||||
|
if strings.HasPrefix(gref, "refs/tags/") {
|
||||||
|
tag = strings.TrimPrefix(gref, "refs/tags/")
|
||||||
|
} else if strings.HasPrefix(gref, "refs/heads/") {
|
||||||
|
branch = strings.TrimPrefix(gref, "refs/heads/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Environment{
|
return Environment{
|
||||||
CI: true,
|
CI: true,
|
||||||
Name: "github-actions",
|
Name: "github-actions",
|
||||||
|
|
@ -126,7 +146,7 @@ func Env() Environment {
|
||||||
|
|
||||||
// LocalEnv returns build environment metadata gathered from git.
|
// LocalEnv returns build environment metadata gathered from git.
|
||||||
func LocalEnv() Environment {
|
func LocalEnv() Environment {
|
||||||
env := applyEnvFlags(Environment{Name: "local", Repo: "ethereum/go-ethereum"})
|
env := applyEnvFlags(Environment{Name: "local", Repo: "berachain/bera-geth"})
|
||||||
|
|
||||||
head := readGitFile("HEAD")
|
head := readGitFile("HEAD")
|
||||||
if fields := strings.Fields(head); len(fields) == 2 {
|
if fields := strings.Fields(head); len(fields) == 2 {
|
||||||
|
|
|
||||||
|
|
@ -696,7 +696,7 @@ func applyMessage(ctx context.Context, b Backend, args TransactionArgs, state *s
|
||||||
if err := args.CallDefaults(gp.Gas(), blockContext.BaseFee, b.ChainConfig().ChainID); err != nil {
|
if err := args.CallDefaults(gp.Gas(), blockContext.BaseFee, b.ChainConfig().ChainID); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
msg := args.ToMessage(header.BaseFee, skipChecks, skipChecks)
|
msg := args.ToMessage(header.BaseFee, skipChecks, skipChecks, b.ChainConfig().IsPrague1(header.Number, header.Time), b.ChainConfig().Berachain.Prague1.PoLDistributorAddress)
|
||||||
// Lower the basefee to 0 to avoid breaking EVM
|
// Lower the basefee to 0 to avoid breaking EVM
|
||||||
// invariants (basefee < feecap).
|
// invariants (basefee < feecap).
|
||||||
if msg.GasPrice.Sign() == 0 {
|
if msg.GasPrice.Sign() == 0 {
|
||||||
|
|
@ -839,7 +839,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
|
||||||
if err := args.CallDefaults(gasCap, header.BaseFee, b.ChainConfig().ChainID); err != nil {
|
if err := args.CallDefaults(gasCap, header.BaseFee, b.ChainConfig().ChainID); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
call := args.ToMessage(header.BaseFee, true, true)
|
call := args.ToMessage(header.BaseFee, true, true, b.ChainConfig().IsPrague1(header.Number, header.Time), b.ChainConfig().Berachain.Prague1.PoLDistributorAddress)
|
||||||
|
|
||||||
// Run the gas estimation and wrap any revertals into a custom return
|
// Run the gas estimation and wrap any revertals into a custom return
|
||||||
estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap)
|
estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap)
|
||||||
|
|
@ -904,6 +904,9 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} {
|
||||||
if head.RequestsHash != nil {
|
if head.RequestsHash != nil {
|
||||||
result["requestsHash"] = head.RequestsHash
|
result["requestsHash"] = head.RequestsHash
|
||||||
}
|
}
|
||||||
|
if head.ParentProposerPubkey != nil {
|
||||||
|
result["parentProposerPubkey"] = head.ParentProposerPubkey
|
||||||
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1057,6 +1060,14 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
|
||||||
result.GasPrice = (*hexutil.Big)(tx.GasFeeCap())
|
result.GasPrice = (*hexutil.Big)(tx.GasFeeCap())
|
||||||
}
|
}
|
||||||
result.AuthorizationList = tx.SetCodeAuthorizations()
|
result.AuthorizationList = tx.SetCodeAuthorizations()
|
||||||
|
|
||||||
|
case types.PoLTxType:
|
||||||
|
al := tx.AccessList()
|
||||||
|
result.Accesses = &al
|
||||||
|
result.ChainID = (*hexutil.Big)(tx.ChainId())
|
||||||
|
result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap())
|
||||||
|
result.GasTipCap = (*hexutil.Big)(tx.GasTipCap())
|
||||||
|
result.MaxFeePerBlobGas = (*hexutil.Big)(tx.BlobGasFeeCap())
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
@ -1217,7 +1228,9 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
|
||||||
statedb := db.Copy()
|
statedb := db.Copy()
|
||||||
// Set the accesslist to the last al
|
// Set the accesslist to the last al
|
||||||
args.AccessList = &accessList
|
args.AccessList = &accessList
|
||||||
msg := args.ToMessage(header.BaseFee, true, true)
|
isPrague1 := b.ChainConfig().IsPrague1(header.Number, header.Time)
|
||||||
|
distributorAddress := b.ChainConfig().Berachain.Prague1.PoLDistributorAddress
|
||||||
|
msg := args.ToMessage(header.BaseFee, true, true, isPrague1, distributorAddress)
|
||||||
|
|
||||||
// Apply the transaction with the access list tracer
|
// Apply the transaction with the access list tracer
|
||||||
tracer := logger.NewAccessListTracer(accessList, addressesToExclude)
|
tracer := logger.NewAccessListTracer(accessList, addressesToExclude)
|
||||||
|
|
@ -1234,7 +1247,15 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
|
||||||
}
|
}
|
||||||
res, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit))
|
res, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.ToTransaction(types.LegacyTxType).Hash(), err)
|
return nil, 0, nil, fmt.Errorf(
|
||||||
|
"failed to apply transaction: %v err: %v",
|
||||||
|
args.ToTransaction(
|
||||||
|
types.LegacyTxType,
|
||||||
|
b.ChainConfig().IsPrague1(header.Number, header.Time),
|
||||||
|
b.ChainConfig().Berachain.Prague1.PoLDistributorAddress,
|
||||||
|
).Hash(),
|
||||||
|
err,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if tracer.Equal(prevTracer) {
|
if tracer.Equal(prevTracer) {
|
||||||
return accessList, res.UsedGas, res.Err, nil
|
return accessList, res.UsedGas, res.Err, nil
|
||||||
|
|
@ -1503,7 +1524,13 @@ func (api *TransactionAPI) SendTransaction(ctx context.Context, args Transaction
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
// Assemble the transaction and sign with the wallet
|
// Assemble the transaction and sign with the wallet
|
||||||
tx := args.ToTransaction(types.LegacyTxType)
|
header := api.b.CurrentHeader()
|
||||||
|
|
||||||
|
tx := args.ToTransaction(
|
||||||
|
types.LegacyTxType,
|
||||||
|
api.b.ChainConfig().IsPrague1(header.Number, header.Time),
|
||||||
|
api.b.ChainConfig().Berachain.Prague1.PoLDistributorAddress,
|
||||||
|
)
|
||||||
|
|
||||||
signed, err := wallet.SignTx(account, tx, api.b.ChainConfig().ChainID)
|
signed, err := wallet.SignTx(account, tx, api.b.ChainConfig().ChainID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -1523,7 +1550,12 @@ func (api *TransactionAPI) FillTransaction(ctx context.Context, args Transaction
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Assemble the transaction and obtain rlp
|
// Assemble the transaction and obtain rlp
|
||||||
tx := args.ToTransaction(types.LegacyTxType)
|
header := api.b.CurrentHeader()
|
||||||
|
tx := args.ToTransaction(
|
||||||
|
types.LegacyTxType,
|
||||||
|
api.b.ChainConfig().IsPrague1(header.Number, header.Time),
|
||||||
|
api.b.ChainConfig().Berachain.Prague1.PoLDistributorAddress,
|
||||||
|
)
|
||||||
data, err := tx.MarshalBinary()
|
data, err := tx.MarshalBinary()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -1591,7 +1623,12 @@ func (api *TransactionAPI) SignTransaction(ctx context.Context, args Transaction
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Before actually sign the transaction, ensure the transaction fee is reasonable.
|
// Before actually sign the transaction, ensure the transaction fee is reasonable.
|
||||||
tx := args.ToTransaction(types.LegacyTxType)
|
header := api.b.CurrentHeader()
|
||||||
|
tx := args.ToTransaction(
|
||||||
|
types.LegacyTxType,
|
||||||
|
api.b.ChainConfig().IsPrague1(header.Number, header.Time),
|
||||||
|
api.b.ChainConfig().Berachain.Prague1.PoLDistributorAddress,
|
||||||
|
)
|
||||||
if err := checkTxFee(tx.GasPrice(), tx.Gas(), api.b.RPCTxFeeCap()); err != nil {
|
if err := checkTxFee(tx.GasPrice(), tx.Gas(), api.b.RPCTxFeeCap()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1645,7 +1682,12 @@ func (api *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs,
|
||||||
if err := sendArgs.setDefaults(ctx, api.b, false); err != nil {
|
if err := sendArgs.setDefaults(ctx, api.b, false); err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
matchTx := sendArgs.ToTransaction(types.LegacyTxType)
|
header := api.b.CurrentHeader()
|
||||||
|
matchTx := sendArgs.ToTransaction(
|
||||||
|
types.LegacyTxType,
|
||||||
|
api.b.ChainConfig().IsPrague1(header.Number, header.Time),
|
||||||
|
api.b.ChainConfig().Berachain.Prague1.PoLDistributorAddress,
|
||||||
|
)
|
||||||
|
|
||||||
// Before replacing the old transaction, ensure the _new_ transaction fee is reasonable.
|
// Before replacing the old transaction, ensure the _new_ transaction fee is reasonable.
|
||||||
price := matchTx.GasPrice()
|
price := matchTx.GasPrice()
|
||||||
|
|
@ -1675,7 +1717,14 @@ func (api *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs,
|
||||||
if gasLimit != nil && *gasLimit != 0 {
|
if gasLimit != nil && *gasLimit != 0 {
|
||||||
sendArgs.Gas = gasLimit
|
sendArgs.Gas = gasLimit
|
||||||
}
|
}
|
||||||
signedTx, err := api.sign(sendArgs.from(), sendArgs.ToTransaction(types.LegacyTxType))
|
header := api.b.CurrentHeader()
|
||||||
|
signedTx, err := api.sign(
|
||||||
|
sendArgs.from(), sendArgs.ToTransaction(
|
||||||
|
types.LegacyTxType,
|
||||||
|
api.b.ChainConfig().IsPrague1(header.Number, header.Time),
|
||||||
|
api.b.ChainConfig().Berachain.Prague1.PoLDistributorAddress,
|
||||||
|
),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1217,6 +1217,15 @@ func TestCall(t *testing.T) {
|
||||||
},
|
},
|
||||||
expectErr: errors.New(`block override "withdrawals" is not supported for this RPC method`),
|
expectErr: errors.New(`block override "withdrawals" is not supported for this RPC method`),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "unsupported block override proposerPubkey",
|
||||||
|
blockNumber: rpc.LatestBlockNumber,
|
||||||
|
call: TransactionArgs{},
|
||||||
|
blockOverrides: override.BlockOverrides{
|
||||||
|
ProposerPubkey: &common.Pubkey{},
|
||||||
|
},
|
||||||
|
expectErr: errors.New(`block override "proposerPubkey" is not supported for this RPC method`),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range testSuite {
|
for _, tc := range testSuite {
|
||||||
result, err := api.Call(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides)
|
result, err := api.Call(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides)
|
||||||
|
|
|
||||||
|
|
@ -121,16 +121,17 @@ func (diff *StateOverride) Apply(statedb *state.StateDB, precompiles vm.Precompi
|
||||||
|
|
||||||
// BlockOverrides is a set of header fields to override.
|
// BlockOverrides is a set of header fields to override.
|
||||||
type BlockOverrides struct {
|
type BlockOverrides struct {
|
||||||
Number *hexutil.Big
|
Number *hexutil.Big
|
||||||
Difficulty *hexutil.Big // No-op if we're simulating post-merge calls.
|
Difficulty *hexutil.Big // No-op if we're simulating post-merge calls.
|
||||||
Time *hexutil.Uint64
|
Time *hexutil.Uint64
|
||||||
GasLimit *hexutil.Uint64
|
GasLimit *hexutil.Uint64
|
||||||
FeeRecipient *common.Address
|
FeeRecipient *common.Address
|
||||||
PrevRandao *common.Hash
|
PrevRandao *common.Hash
|
||||||
BaseFeePerGas *hexutil.Big
|
BaseFeePerGas *hexutil.Big
|
||||||
BlobBaseFee *hexutil.Big
|
BlobBaseFee *hexutil.Big
|
||||||
BeaconRoot *common.Hash
|
BeaconRoot *common.Hash
|
||||||
Withdrawals *types.Withdrawals
|
Withdrawals *types.Withdrawals
|
||||||
|
ProposerPubkey *common.Pubkey
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply overrides the given header fields into the given block context.
|
// Apply overrides the given header fields into the given block context.
|
||||||
|
|
@ -144,6 +145,9 @@ func (o *BlockOverrides) Apply(blockCtx *vm.BlockContext) error {
|
||||||
if o.Withdrawals != nil {
|
if o.Withdrawals != nil {
|
||||||
return errors.New(`block override "withdrawals" is not supported for this RPC method`)
|
return errors.New(`block override "withdrawals" is not supported for this RPC method`)
|
||||||
}
|
}
|
||||||
|
if o.ProposerPubkey != nil {
|
||||||
|
return errors.New(`block override "proposerPubkey" is not supported for this RPC method`)
|
||||||
|
}
|
||||||
if o.Number != nil {
|
if o.Number != nil {
|
||||||
blockCtx.BlockNumber = o.Number.ToInt()
|
blockCtx.BlockNumber = o.Number.ToInt()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -199,6 +199,37 @@ func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]*simBlo
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Berachain: Pre-compute expected PoL tx hash when in Prague1.
|
||||||
|
isPrague1 := sim.chainConfig.IsPrague1(result.Number(), result.Time())
|
||||||
|
var expectedPoLHash common.Hash
|
||||||
|
if isPrague1 {
|
||||||
|
polTx, err := types.NewPoLTx(
|
||||||
|
sim.chainConfig.ChainID,
|
||||||
|
sim.chainConfig.Berachain.Prague1.PoLDistributorAddress,
|
||||||
|
new(big.Int).Sub(result.Number(), big.NewInt(1)),
|
||||||
|
params.PoLTxGasLimit,
|
||||||
|
result.BaseFee(),
|
||||||
|
result.ProposerPubkey(),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create expected PoL tx: %w", err)
|
||||||
|
}
|
||||||
|
expectedPoLHash = polTx.Hash()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Berachain: validate the PoL tx is only the first tx in the block.
|
||||||
|
for i, tx := range result.Transactions() {
|
||||||
|
switch {
|
||||||
|
case isPrague1 && i == 0:
|
||||||
|
if tx.Hash() != expectedPoLHash {
|
||||||
|
return nil, fmt.Errorf("PoL tx hash mismatch: have %v, want %v", tx.Hash(), expectedPoLHash)
|
||||||
|
}
|
||||||
|
case tx.Type() == types.PoLTxType:
|
||||||
|
return nil, fmt.Errorf("invalid block: tx at index %d is a PoL tx", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
headers[bi] = result.Header()
|
headers[bi] = result.Header()
|
||||||
results[bi] = &simBlockResult{fullTx: sim.fullTx, chainConfig: sim.chainConfig, Block: result, Calls: callResults, senders: senders}
|
results[bi] = &simBlockResult{fullTx: sim.fullTx, chainConfig: sim.chainConfig, Block: result, Calls: callResults, senders: senders}
|
||||||
parent = result.Header()
|
parent = result.Header()
|
||||||
|
|
@ -279,15 +310,17 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
tx = call.ToTransaction(types.DynamicFeeTxType)
|
isPrague1 = sim.chainConfig.IsPrague1(header.Number, header.Time)
|
||||||
txHash = tx.Hash()
|
distributorAddress = sim.chainConfig.Berachain.Prague1.PoLDistributorAddress
|
||||||
|
tx = call.ToTransaction(types.DynamicFeeTxType, isPrague1, distributorAddress)
|
||||||
|
txHash = tx.Hash()
|
||||||
)
|
)
|
||||||
txes[i] = tx
|
txes[i] = tx
|
||||||
senders[txHash] = call.from()
|
senders[txHash] = call.from()
|
||||||
tracer.reset(txHash, uint(i))
|
tracer.reset(txHash, uint(i))
|
||||||
sim.state.SetTxContext(txHash, i)
|
sim.state.SetTxContext(txHash, i)
|
||||||
// EoA check is always skipped, even in validation mode.
|
// EoA check is always skipped, even in validation mode.
|
||||||
msg := call.ToMessage(header.BaseFee, !sim.validate, true)
|
msg := call.ToMessage(header.BaseFee, !sim.validate, true, isPrague1, distributorAddress)
|
||||||
result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp)
|
result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
txErr := txValidationError(err)
|
txErr := txValidationError(err)
|
||||||
|
|
@ -484,15 +517,24 @@ func (sim *simulator) makeHeaders(blocks []simBlock) ([]*types.Header, error) {
|
||||||
parentBeaconRoot = overrides.BeaconRoot
|
parentBeaconRoot = overrides.BeaconRoot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var parentProposerPubkey *common.Pubkey
|
||||||
|
if sim.chainConfig.IsPrague1(overrides.Number.ToInt(), (uint64)(*overrides.Time)) {
|
||||||
|
parentProposerPubkey = new(common.Pubkey)
|
||||||
|
if overrides.ProposerPubkey == nil {
|
||||||
|
return nil, errors.New("proposer pubkey override is required for post Prague1 blocks")
|
||||||
|
}
|
||||||
|
*parentProposerPubkey = *overrides.ProposerPubkey
|
||||||
|
}
|
||||||
header = overrides.MakeHeader(&types.Header{
|
header = overrides.MakeHeader(&types.Header{
|
||||||
UncleHash: types.EmptyUncleHash,
|
UncleHash: types.EmptyUncleHash,
|
||||||
ReceiptHash: types.EmptyReceiptsHash,
|
ReceiptHash: types.EmptyReceiptsHash,
|
||||||
TxHash: types.EmptyTxsHash,
|
TxHash: types.EmptyTxsHash,
|
||||||
Coinbase: header.Coinbase,
|
Coinbase: header.Coinbase,
|
||||||
Difficulty: header.Difficulty,
|
Difficulty: header.Difficulty,
|
||||||
GasLimit: header.GasLimit,
|
GasLimit: header.GasLimit,
|
||||||
WithdrawalsHash: withdrawalsHash,
|
WithdrawalsHash: withdrawalsHash,
|
||||||
ParentBeaconRoot: parentBeaconRoot,
|
ParentBeaconRoot: parentBeaconRoot,
|
||||||
|
ParentProposerPubkey: parentProposerPubkey,
|
||||||
})
|
})
|
||||||
res[bi] = header
|
res[bi] = header
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -414,7 +414,7 @@ func (args *TransactionArgs) CallDefaults(globalGasCap uint64, baseFee *big.Int,
|
||||||
// core evm. This method is used in calls and traces that do not require a real
|
// core evm. This method is used in calls and traces that do not require a real
|
||||||
// live transaction.
|
// live transaction.
|
||||||
// Assumes that fields are not nil, i.e. setDefaults or CallDefaults has been called.
|
// Assumes that fields are not nil, i.e. setDefaults or CallDefaults has been called.
|
||||||
func (args *TransactionArgs) ToMessage(baseFee *big.Int, skipNonceCheck, skipEoACheck bool) *core.Message {
|
func (args *TransactionArgs) ToMessage(baseFee *big.Int, skipNonceCheck, skipEoACheck, isPrague1 bool, distributorAddress common.Address) *core.Message {
|
||||||
var (
|
var (
|
||||||
gasPrice *big.Int
|
gasPrice *big.Int
|
||||||
gasFeeCap *big.Int
|
gasFeeCap *big.Int
|
||||||
|
|
@ -463,14 +463,17 @@ func (args *TransactionArgs) ToMessage(baseFee *big.Int, skipNonceCheck, skipEoA
|
||||||
SetCodeAuthorizations: args.AuthorizationList,
|
SetCodeAuthorizations: args.AuthorizationList,
|
||||||
SkipNonceChecks: skipNonceCheck,
|
SkipNonceChecks: skipNonceCheck,
|
||||||
SkipFromEOACheck: skipEoACheck,
|
SkipFromEOACheck: skipEoACheck,
|
||||||
|
IsPoLTx: isPrague1 && types.IsPoLDistribution(args.To, args.data(), distributorAddress),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToTransaction converts the arguments to a transaction.
|
// ToTransaction converts the arguments to a transaction.
|
||||||
// This assumes that setDefaults has been called.
|
// This assumes that setDefaults has been called.
|
||||||
func (args *TransactionArgs) ToTransaction(defaultType int) *types.Transaction {
|
func (args *TransactionArgs) ToTransaction(defaultType int, isPrague1 bool, distributorAddress common.Address) *types.Transaction {
|
||||||
usedType := types.LegacyTxType
|
usedType := types.LegacyTxType
|
||||||
switch {
|
switch {
|
||||||
|
case isPrague1 && types.IsPoLDistribution(args.To, args.data(), distributorAddress):
|
||||||
|
usedType = types.PoLTxType
|
||||||
case args.AuthorizationList != nil || defaultType == types.SetCodeTxType:
|
case args.AuthorizationList != nil || defaultType == types.SetCodeTxType:
|
||||||
usedType = types.SetCodeTxType
|
usedType = types.SetCodeTxType
|
||||||
case args.BlobHashes != nil || defaultType == types.BlobTxType:
|
case args.BlobHashes != nil || defaultType == types.BlobTxType:
|
||||||
|
|
@ -486,6 +489,20 @@ func (args *TransactionArgs) ToTransaction(defaultType int) *types.Transaction {
|
||||||
}
|
}
|
||||||
var data types.TxData
|
var data types.TxData
|
||||||
switch usedType {
|
switch usedType {
|
||||||
|
case types.PoLTxType:
|
||||||
|
gasPrice := (*big.Int)(args.GasPrice)
|
||||||
|
if args.MaxFeePerGas != nil || defaultType == types.DynamicFeeTxType {
|
||||||
|
gasPrice = (*big.Int)(args.MaxFeePerGas)
|
||||||
|
}
|
||||||
|
data = &types.PoLTx{
|
||||||
|
ChainID: (*big.Int)(args.ChainID),
|
||||||
|
From: args.from(),
|
||||||
|
To: *args.To,
|
||||||
|
Nonce: uint64(*args.Nonce),
|
||||||
|
GasLimit: uint64(*args.Gas),
|
||||||
|
GasPrice: gasPrice,
|
||||||
|
Data: args.data(),
|
||||||
|
}
|
||||||
case types.SetCodeTxType:
|
case types.SetCodeTxType:
|
||||||
al := types.AccessList{}
|
al := types.AccessList{}
|
||||||
if args.AccessList != nil {
|
if args.AccessList != nil {
|
||||||
|
|
|
||||||
|
|
@ -57,8 +57,8 @@ func WithCommit(gitCommit, gitDate string) string {
|
||||||
// Archive holds the textual version string used for Geth archives. e.g.
|
// Archive holds the textual version string used for Geth archives. e.g.
|
||||||
// "1.8.11-dea1ce05" for stable releases, or "1.8.13-unstable-21c059b6" for unstable
|
// "1.8.11-dea1ce05" for stable releases, or "1.8.13-unstable-21c059b6" for unstable
|
||||||
// releases.
|
// releases.
|
||||||
func Archive(gitCommit string) string {
|
func Archive(tag, gitCommit string) string {
|
||||||
vsn := Semantic
|
vsn := tag
|
||||||
if version.Meta != "stable" {
|
if version.Meta != "stable" {
|
||||||
vsn += "-" + version.Meta
|
vsn += "-" + version.Meta
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,11 @@ func (miner *Miner) BuildPayload(args *BuildPayloadArgs, witness bool) (*Payload
|
||||||
|
|
||||||
// getPending retrieves the pending block based on the current head block.
|
// getPending retrieves the pending block based on the current head block.
|
||||||
// The result might be nil if pending generation is failed.
|
// The result might be nil if pending generation is failed.
|
||||||
|
//
|
||||||
|
// Berachain: Note that the correct PoL tx is not included in the pending block as the
|
||||||
|
// parent proposer pubkey of the pending block is not made available here.
|
||||||
|
//
|
||||||
|
// TODO(BRIP-4): Include parent proposer pubkey as soon as it is made available by CL.
|
||||||
func (miner *Miner) getPending() *newPayloadResult {
|
func (miner *Miner) getPending() *newPayloadResult {
|
||||||
header := miner.chain.CurrentHeader()
|
header := miner.chain.CurrentHeader()
|
||||||
miner.pendingMu.Lock()
|
miner.pendingMu.Lock()
|
||||||
|
|
@ -156,14 +161,15 @@ func (miner *Miner) getPending() *newPayloadResult {
|
||||||
withdrawal = []*types.Withdrawal{}
|
withdrawal = []*types.Withdrawal{}
|
||||||
}
|
}
|
||||||
ret := miner.generateWork(&generateParams{
|
ret := miner.generateWork(&generateParams{
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
forceTime: false,
|
forceTime: false,
|
||||||
parentHash: header.Hash(),
|
parentHash: header.Hash(),
|
||||||
coinbase: miner.config.PendingFeeRecipient,
|
coinbase: miner.config.PendingFeeRecipient,
|
||||||
random: common.Hash{},
|
random: common.Hash{},
|
||||||
withdrawals: withdrawal,
|
withdrawals: withdrawal,
|
||||||
beaconRoot: nil,
|
beaconRoot: nil,
|
||||||
noTxs: false,
|
proposerPubkey: &common.Pubkey{},
|
||||||
|
noTxs: false,
|
||||||
}, false) // we will never make a witness for a pending block
|
}, false) // we will never make a witness for a pending block
|
||||||
if ret.err != nil {
|
if ret.err != nil {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -37,13 +37,14 @@ import (
|
||||||
// Check engine-api specification for more details.
|
// Check engine-api specification for more details.
|
||||||
// https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#payloadattributesv3
|
// https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#payloadattributesv3
|
||||||
type BuildPayloadArgs struct {
|
type BuildPayloadArgs struct {
|
||||||
Parent common.Hash // The parent block to build payload on top
|
Parent common.Hash // The parent block to build payload on top
|
||||||
Timestamp uint64 // The provided timestamp of generated payload
|
Timestamp uint64 // The provided timestamp of generated payload
|
||||||
FeeRecipient common.Address // The provided recipient address for collecting transaction fee
|
FeeRecipient common.Address // The provided recipient address for collecting transaction fee
|
||||||
Random common.Hash // The provided randomness value
|
Random common.Hash // The provided randomness value
|
||||||
Withdrawals types.Withdrawals // The provided withdrawals
|
Withdrawals types.Withdrawals // The provided withdrawals
|
||||||
BeaconRoot *common.Hash // The provided beaconRoot (Cancun)
|
BeaconRoot *common.Hash // The provided beaconRoot (Cancun)
|
||||||
Version engine.PayloadVersion // Versioning byte for payload id calculation.
|
ProposerPubkey *common.Pubkey // Berachain BRIP-0004: The provided proposer pubkey (Prague1)
|
||||||
|
Version engine.PayloadVersion // Versioning byte for payload id calculation.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Id computes an 8-byte identifier by hashing the components of the payload arguments.
|
// Id computes an 8-byte identifier by hashing the components of the payload arguments.
|
||||||
|
|
@ -57,6 +58,9 @@ func (args *BuildPayloadArgs) Id() engine.PayloadID {
|
||||||
if args.BeaconRoot != nil {
|
if args.BeaconRoot != nil {
|
||||||
hasher.Write(args.BeaconRoot[:])
|
hasher.Write(args.BeaconRoot[:])
|
||||||
}
|
}
|
||||||
|
if args.ProposerPubkey != nil {
|
||||||
|
hasher.Write(args.ProposerPubkey[:])
|
||||||
|
}
|
||||||
var out engine.PayloadID
|
var out engine.PayloadID
|
||||||
copy(out[:], hasher.Sum(nil)[:8])
|
copy(out[:], hasher.Sum(nil)[:8])
|
||||||
out[0] = byte(args.Version)
|
out[0] = byte(args.Version)
|
||||||
|
|
@ -211,14 +215,15 @@ func (miner *Miner) buildPayload(args *BuildPayloadArgs, witness bool) (*Payload
|
||||||
// enough to run. The empty payload can at least make sure there is something
|
// enough to run. The empty payload can at least make sure there is something
|
||||||
// to deliver for not missing slot.
|
// to deliver for not missing slot.
|
||||||
emptyParams := &generateParams{
|
emptyParams := &generateParams{
|
||||||
timestamp: args.Timestamp,
|
timestamp: args.Timestamp,
|
||||||
forceTime: true,
|
forceTime: true,
|
||||||
parentHash: args.Parent,
|
parentHash: args.Parent,
|
||||||
coinbase: args.FeeRecipient,
|
coinbase: args.FeeRecipient,
|
||||||
random: args.Random,
|
random: args.Random,
|
||||||
withdrawals: args.Withdrawals,
|
withdrawals: args.Withdrawals,
|
||||||
beaconRoot: args.BeaconRoot,
|
beaconRoot: args.BeaconRoot,
|
||||||
noTxs: true,
|
proposerPubkey: args.ProposerPubkey,
|
||||||
|
noTxs: true,
|
||||||
}
|
}
|
||||||
empty := miner.generateWork(emptyParams, witness)
|
empty := miner.generateWork(emptyParams, witness)
|
||||||
if empty.err != nil {
|
if empty.err != nil {
|
||||||
|
|
@ -235,20 +240,24 @@ func (miner *Miner) buildPayload(args *BuildPayloadArgs, witness bool) (*Payload
|
||||||
timer := time.NewTimer(0)
|
timer := time.NewTimer(0)
|
||||||
defer timer.Stop()
|
defer timer.Stop()
|
||||||
|
|
||||||
// Setup the timer for terminating the process if SECONDS_PER_SLOT (12s in
|
// Setup the timer for terminating the process if SECONDS_PER_SLOT (2s in
|
||||||
// the Mainnet configuration) have passed since the point in time identified
|
// the Berachain configuration) have passed since the point in time identified
|
||||||
// by the timestamp parameter.
|
// by the timestamp parameter.
|
||||||
endTimer := time.NewTimer(time.Second * 12)
|
//
|
||||||
|
// TODO(Berachain): Using 4s for now to handle cases where block time exceeds 2s. To be
|
||||||
|
// verified further after stable block time is in effect.
|
||||||
|
endTimer := time.NewTimer(time.Second * 4)
|
||||||
|
|
||||||
fullParams := &generateParams{
|
fullParams := &generateParams{
|
||||||
timestamp: args.Timestamp,
|
timestamp: args.Timestamp,
|
||||||
forceTime: true,
|
forceTime: true,
|
||||||
parentHash: args.Parent,
|
parentHash: args.Parent,
|
||||||
coinbase: args.FeeRecipient,
|
coinbase: args.FeeRecipient,
|
||||||
random: args.Random,
|
random: args.Random,
|
||||||
withdrawals: args.Withdrawals,
|
withdrawals: args.Withdrawals,
|
||||||
beaconRoot: args.BeaconRoot,
|
beaconRoot: args.BeaconRoot,
|
||||||
noTxs: false,
|
proposerPubkey: args.ProposerPubkey,
|
||||||
|
noTxs: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
|
|
||||||
|
|
@ -94,14 +94,15 @@ type newPayloadResult struct {
|
||||||
|
|
||||||
// generateParams wraps various settings for generating sealing task.
|
// generateParams wraps various settings for generating sealing task.
|
||||||
type generateParams struct {
|
type generateParams struct {
|
||||||
timestamp uint64 // The timestamp for sealing task
|
timestamp uint64 // The timestamp for sealing task
|
||||||
forceTime bool // Flag whether the given timestamp is immutable or not
|
forceTime bool // Flag whether the given timestamp is immutable or not
|
||||||
parentHash common.Hash // Parent block hash, empty means the latest chain head
|
parentHash common.Hash // Parent block hash, empty means the latest chain head
|
||||||
coinbase common.Address // The fee recipient address for including transaction
|
coinbase common.Address // The fee recipient address for including transaction
|
||||||
random common.Hash // The randomness generated by beacon chain, empty before the merge
|
random common.Hash // The randomness generated by beacon chain, empty before the merge
|
||||||
withdrawals types.Withdrawals // List of withdrawals to include in block (shanghai field)
|
withdrawals types.Withdrawals // List of withdrawals to include in block (shanghai field)
|
||||||
beaconRoot *common.Hash // The beacon root (cancun field).
|
beaconRoot *common.Hash // The beacon root (cancun field).
|
||||||
noTxs bool // Flag whether an empty block without any transaction is expected
|
proposerPubkey *common.Pubkey // Berachain: The proposer pubkey (prague1 field).
|
||||||
|
noTxs bool // Flag whether an empty block without any transaction is expected
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateWork generates a sealing block based on the given parameters.
|
// generateWork generates a sealing block based on the given parameters.
|
||||||
|
|
@ -242,6 +243,10 @@ func (miner *Miner) prepareWork(genParams *generateParams, witness bool) (*envir
|
||||||
header.ExcessBlobGas = &excessBlobGas
|
header.ExcessBlobGas = &excessBlobGas
|
||||||
header.ParentBeaconRoot = genParams.beaconRoot
|
header.ParentBeaconRoot = genParams.beaconRoot
|
||||||
}
|
}
|
||||||
|
// Berachain: Apply BRIP-0004.
|
||||||
|
if miner.chainConfig.IsPrague1(header.Number, header.Time) {
|
||||||
|
header.ParentProposerPubkey = genParams.proposerPubkey
|
||||||
|
}
|
||||||
// Could potentially happen if starting to mine in an odd state.
|
// Could potentially happen if starting to mine in an odd state.
|
||||||
// Note genParams.coinbase can be different with header.Coinbase
|
// Note genParams.coinbase can be different with header.Coinbase
|
||||||
// since clique algorithm can modify the coinbase field in header.
|
// since clique algorithm can modify the coinbase field in header.
|
||||||
|
|
@ -331,13 +336,23 @@ func (miner *Miner) commitBlobTransaction(env *environment, tx *types.Transactio
|
||||||
// applyTransaction runs the transaction. If execution fails, state and gas pool are reverted.
|
// applyTransaction runs the transaction. If execution fails, state and gas pool are reverted.
|
||||||
func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (*types.Receipt, error) {
|
func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (*types.Receipt, error) {
|
||||||
var (
|
var (
|
||||||
snap = env.state.Snapshot()
|
gasPool = env.gasPool
|
||||||
gp = env.gasPool.Gas()
|
blockGasUsed = &env.header.GasUsed
|
||||||
|
snap = env.state.Snapshot()
|
||||||
|
gasBefore uint64
|
||||||
)
|
)
|
||||||
receipt, err := core.ApplyTransaction(env.evm, env.gasPool, env.state, env.header, tx, &env.header.GasUsed)
|
// Berachain: PoL tx does not consume gas.
|
||||||
|
if tx.Type() == types.PoLTxType {
|
||||||
|
gasPool = nil
|
||||||
|
blockGasUsed = new(uint64)
|
||||||
|
}
|
||||||
|
if gasPool != nil {
|
||||||
|
gasBefore = gasPool.Gas()
|
||||||
|
}
|
||||||
|
receipt, err := core.ApplyTransaction(env.evm, env.gasPool, env.state, env.header, tx, blockGasUsed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
env.state.RevertToSnapshot(snap)
|
env.state.RevertToSnapshot(snap)
|
||||||
env.gasPool.SetGas(gp)
|
env.gasPool.SetGas(gasBefore)
|
||||||
}
|
}
|
||||||
return receipt, err
|
return receipt, err
|
||||||
}
|
}
|
||||||
|
|
@ -484,6 +499,29 @@ func (miner *Miner) fillTransactions(interrupt *atomic.Int32, env *environment)
|
||||||
prio := miner.prio
|
prio := miner.prio
|
||||||
miner.confMu.RUnlock()
|
miner.confMu.RUnlock()
|
||||||
|
|
||||||
|
// Berachain: Post-Prague1, add PoL tx to the block according to BRIP-0004.
|
||||||
|
if miner.chainConfig.IsPrague1(env.header.Number, env.header.Time) {
|
||||||
|
tx, err := types.NewPoLTx(
|
||||||
|
miner.chainConfig.ChainID,
|
||||||
|
miner.chainConfig.Berachain.Prague1.PoLDistributorAddress,
|
||||||
|
new(big.Int).Sub(env.header.Number, big.NewInt(1)),
|
||||||
|
params.PoLTxGasLimit,
|
||||||
|
env.header.BaseFee,
|
||||||
|
env.header.ParentProposerPubkey,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create PoL tx: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start executing the PoL transaction, outside of miner commitTransactions loop.
|
||||||
|
// env.tcount must be at 0 at this point.
|
||||||
|
env.state.SetTxContext(tx.Hash(), env.tcount)
|
||||||
|
if err = miner.commitTransaction(env, tx); err != nil {
|
||||||
|
log.Trace("Failed to commit PoL transaction", "hash", tx.Hash(), "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Retrieve the pending transactions pre-filtered by the 1559/4844 dynamic fees
|
// Retrieve the pending transactions pre-filtered by the 1559/4844 dynamic fees
|
||||||
filter := txpool.PendingFilter{
|
filter := txpool.PendingFilter{
|
||||||
MinTip: uint256.MustFromBig(tip),
|
MinTip: uint256.MustFromBig(tip),
|
||||||
|
|
|
||||||
166
params/config.go
166
params/config.go
|
|
@ -32,6 +32,10 @@ var (
|
||||||
HoleskyGenesisHash = common.HexToHash("0xb5f7f912443c940f21fd611f12828d75b534364ed9e95ca4e307729a4661bde4")
|
HoleskyGenesisHash = common.HexToHash("0xb5f7f912443c940f21fd611f12828d75b534364ed9e95ca4e307729a4661bde4")
|
||||||
SepoliaGenesisHash = common.HexToHash("0x25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9")
|
SepoliaGenesisHash = common.HexToHash("0x25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9")
|
||||||
HoodiGenesisHash = common.HexToHash("0xbbe312868b376a3001692a646dd2d7d1e4406380dfd86b98aa8a34d1557c971b")
|
HoodiGenesisHash = common.HexToHash("0xbbe312868b376a3001692a646dd2d7d1e4406380dfd86b98aa8a34d1557c971b")
|
||||||
|
|
||||||
|
// Berachain
|
||||||
|
BerachainGenesisHash = common.HexToHash("0xd57819422128da1c44339fc7956662378c17e2213e669b427ac91cd11dfcfb38")
|
||||||
|
BepoliaGenesisHash = common.HexToHash("0x0207661de38f0e54ba91c8286096e72486784c79dc6a9681fc486b38335c042f")
|
||||||
)
|
)
|
||||||
|
|
||||||
func newUint64(val uint64) *uint64 { return &val }
|
func newUint64(val uint64) *uint64 { return &val }
|
||||||
|
|
@ -158,6 +162,80 @@ var (
|
||||||
Prague: DefaultPragueBlobConfig,
|
Prague: DefaultPragueBlobConfig,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
// BerachainChainConfig is the chain parameters to run a node on the Berachain network.
|
||||||
|
BerachainChainConfig = &ChainConfig{
|
||||||
|
ChainID: big.NewInt(80094),
|
||||||
|
HomesteadBlock: big.NewInt(0),
|
||||||
|
DAOForkBlock: big.NewInt(0),
|
||||||
|
DAOForkSupport: true,
|
||||||
|
EIP150Block: big.NewInt(0),
|
||||||
|
EIP155Block: big.NewInt(0),
|
||||||
|
EIP158Block: big.NewInt(0),
|
||||||
|
ByzantiumBlock: big.NewInt(0),
|
||||||
|
ConstantinopleBlock: big.NewInt(0),
|
||||||
|
PetersburgBlock: big.NewInt(0),
|
||||||
|
IstanbulBlock: big.NewInt(0),
|
||||||
|
MuirGlacierBlock: big.NewInt(0),
|
||||||
|
BerlinBlock: big.NewInt(0),
|
||||||
|
LondonBlock: big.NewInt(0),
|
||||||
|
ArrowGlacierBlock: big.NewInt(0),
|
||||||
|
GrayGlacierBlock: big.NewInt(0),
|
||||||
|
TerminalTotalDifficulty: big.NewInt(0),
|
||||||
|
MergeNetsplitBlock: big.NewInt(0),
|
||||||
|
ShanghaiTime: newUint64(0),
|
||||||
|
CancunTime: newUint64(0),
|
||||||
|
PragueTime: newUint64(1749056400),
|
||||||
|
DepositContractAddress: common.HexToAddress("0x4242424242424242424242424242424242424242"),
|
||||||
|
Ethash: new(EthashConfig),
|
||||||
|
BlobScheduleConfig: &BlobScheduleConfig{
|
||||||
|
Cancun: DefaultCancunBlobConfig,
|
||||||
|
Prague: DefaultBerachainPragueBlobConfig,
|
||||||
|
},
|
||||||
|
Berachain: BerachainConfig{
|
||||||
|
Prague1: Prague1Config{
|
||||||
|
Time: newUint64(999999999999999),
|
||||||
|
MinimumBaseFeeWei: 1000000000, // 1 gwei
|
||||||
|
BaseFeeChangeDenominator: 48, // 6x increase from the default
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// BepoliaChainConfig contains the chain parameters to run a node on the Bepolia test network.
|
||||||
|
BepoliaChainConfig = &ChainConfig{
|
||||||
|
ChainID: big.NewInt(80069),
|
||||||
|
HomesteadBlock: big.NewInt(0),
|
||||||
|
DAOForkBlock: big.NewInt(0),
|
||||||
|
DAOForkSupport: true,
|
||||||
|
EIP150Block: big.NewInt(0),
|
||||||
|
EIP155Block: big.NewInt(0),
|
||||||
|
EIP158Block: big.NewInt(0),
|
||||||
|
ByzantiumBlock: big.NewInt(0),
|
||||||
|
ConstantinopleBlock: big.NewInt(0),
|
||||||
|
PetersburgBlock: big.NewInt(0),
|
||||||
|
IstanbulBlock: big.NewInt(0),
|
||||||
|
MuirGlacierBlock: big.NewInt(0),
|
||||||
|
BerlinBlock: big.NewInt(0),
|
||||||
|
LondonBlock: big.NewInt(0),
|
||||||
|
ArrowGlacierBlock: big.NewInt(0),
|
||||||
|
GrayGlacierBlock: big.NewInt(0),
|
||||||
|
TerminalTotalDifficulty: big.NewInt(0),
|
||||||
|
MergeNetsplitBlock: big.NewInt(0),
|
||||||
|
ShanghaiTime: newUint64(0),
|
||||||
|
CancunTime: newUint64(0),
|
||||||
|
PragueTime: newUint64(1746633600),
|
||||||
|
DepositContractAddress: common.HexToAddress("0x4242424242424242424242424242424242424242"),
|
||||||
|
Ethash: new(EthashConfig),
|
||||||
|
BlobScheduleConfig: &BlobScheduleConfig{
|
||||||
|
Cancun: DefaultCancunBlobConfig,
|
||||||
|
Prague: DefaultBerachainPragueBlobConfig,
|
||||||
|
},
|
||||||
|
Berachain: BerachainConfig{
|
||||||
|
Prague1: Prague1Config{
|
||||||
|
Time: newUint64(999999999999999),
|
||||||
|
MinimumBaseFeeWei: 1000000000, // 1 gwei
|
||||||
|
BaseFeeChangeDenominator: 48, // 6x increase from the default
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
// AllEthashProtocolChanges contains every protocol change (EIPs) introduced
|
// AllEthashProtocolChanges contains every protocol change (EIPs) introduced
|
||||||
// and accepted by the Ethereum core developers into the Ethash consensus.
|
// and accepted by the Ethereum core developers into the Ethash consensus.
|
||||||
AllEthashProtocolChanges = &ChainConfig{
|
AllEthashProtocolChanges = &ChainConfig{
|
||||||
|
|
@ -353,6 +431,13 @@ var (
|
||||||
Max: 9,
|
Max: 9,
|
||||||
UpdateFraction: 5007716,
|
UpdateFraction: 5007716,
|
||||||
}
|
}
|
||||||
|
// DefaultBerachainPragueBlobConfig is the default blob configuration for the Prague fork
|
||||||
|
// on Berachain networks.
|
||||||
|
DefaultBerachainPragueBlobConfig = &BlobConfig{
|
||||||
|
Target: 3,
|
||||||
|
Max: 6,
|
||||||
|
UpdateFraction: 3338477,
|
||||||
|
}
|
||||||
// DefaultOsakaBlobConfig is the default blob configuration for the Osaka fork.
|
// DefaultOsakaBlobConfig is the default blob configuration for the Osaka fork.
|
||||||
DefaultOsakaBlobConfig = &BlobConfig{
|
DefaultOsakaBlobConfig = &BlobConfig{
|
||||||
Target: 6,
|
Target: 6,
|
||||||
|
|
@ -440,6 +525,48 @@ type ChainConfig struct {
|
||||||
Ethash *EthashConfig `json:"ethash,omitempty"`
|
Ethash *EthashConfig `json:"ethash,omitempty"`
|
||||||
Clique *CliqueConfig `json:"clique,omitempty"`
|
Clique *CliqueConfig `json:"clique,omitempty"`
|
||||||
BlobScheduleConfig *BlobScheduleConfig `json:"blobSchedule,omitempty"`
|
BlobScheduleConfig *BlobScheduleConfig `json:"blobSchedule,omitempty"`
|
||||||
|
|
||||||
|
// Berachain config
|
||||||
|
Berachain BerachainConfig `json:"berachain,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BerachainConfig is the berachain config.
|
||||||
|
type BerachainConfig struct {
|
||||||
|
// Prague1 fork values.
|
||||||
|
Prague1 Prague1Config `json:"prague1,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements the stringer interface.
|
||||||
|
func (o *BerachainConfig) String() string {
|
||||||
|
banner := "berachain"
|
||||||
|
if o.Prague1.Time != nil {
|
||||||
|
banner += fmt.Sprintf("(%s)", o.Prague1)
|
||||||
|
}
|
||||||
|
return banner
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prague1Config is the config values for the Prague1 fork on Berachain.
|
||||||
|
type Prague1Config struct {
|
||||||
|
// Time is the time of the Prague1 fork.
|
||||||
|
Time *uint64 `json:"time,omitempty"` // Prague1 switch time (0 = already on prague1, nil = no fork)
|
||||||
|
// BaseFeeChangeDenominator is the base fee change denominator.
|
||||||
|
BaseFeeChangeDenominator uint64 `json:"baseFeeChangeDenominator,omitempty"`
|
||||||
|
// MinimumBaseFeeWei is the minimum base fee in wei.
|
||||||
|
MinimumBaseFeeWei uint64 `json:"minimumBaseFeeWei,omitempty"`
|
||||||
|
// PoLDistributorAddress is the address of the PoL distributor.
|
||||||
|
PoLDistributorAddress common.Address `json:"polDistributorAddress,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements the stringer interface.
|
||||||
|
func (c Prague1Config) String() string {
|
||||||
|
banner := "prague1"
|
||||||
|
if c.Time != nil {
|
||||||
|
banner += fmt.Sprintf(
|
||||||
|
"(time: %v, baseFeeChangeDenominator: %v, minimumBaseFeeWei: %v, polDistributorAddress: %v)",
|
||||||
|
*c.Time, c.BaseFeeChangeDenominator, c.MinimumBaseFeeWei, c.PoLDistributorAddress,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return banner
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthashConfig is the consensus engine configs for proof-of-work based sealing.
|
// EthashConfig is the consensus engine configs for proof-of-work based sealing.
|
||||||
|
|
@ -530,6 +657,9 @@ func (c *ChainConfig) Description() string {
|
||||||
if c.PragueTime != nil {
|
if c.PragueTime != nil {
|
||||||
banner += fmt.Sprintf(" - Prague: @%-10v\n", *c.PragueTime)
|
banner += fmt.Sprintf(" - Prague: @%-10v\n", *c.PragueTime)
|
||||||
}
|
}
|
||||||
|
if c.Berachain.Prague1.Time != nil {
|
||||||
|
banner += fmt.Sprintf(" - Prague1: @%-10v\n", *c.Berachain.Prague1.Time)
|
||||||
|
}
|
||||||
if c.OsakaTime != nil {
|
if c.OsakaTime != nil {
|
||||||
banner += fmt.Sprintf(" - Osaka: @%-10v\n", *c.OsakaTime)
|
banner += fmt.Sprintf(" - Osaka: @%-10v\n", *c.OsakaTime)
|
||||||
}
|
}
|
||||||
|
|
@ -669,6 +799,12 @@ func (c *ChainConfig) IsPrague(num *big.Int, time uint64) bool {
|
||||||
return c.IsLondon(num) && isTimestampForked(c.PragueTime, time)
|
return c.IsLondon(num) && isTimestampForked(c.PragueTime, time)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsPrague1 returns whether time is either equal to the Prague1 fork time or greater.
|
||||||
|
// NOTE: Prague1 is a Berachain fork and must be on Ethereum's Prague fork.
|
||||||
|
func (c *ChainConfig) IsPrague1(num *big.Int, time uint64) bool {
|
||||||
|
return c.IsPrague(num, time) && isTimestampForked(c.Berachain.Prague1.Time, time)
|
||||||
|
}
|
||||||
|
|
||||||
// IsOsaka returns whether time is either equal to the Osaka fork time or greater.
|
// IsOsaka returns whether time is either equal to the Osaka fork time or greater.
|
||||||
func (c *ChainConfig) IsOsaka(num *big.Int, time uint64) bool {
|
func (c *ChainConfig) IsOsaka(num *big.Int, time uint64) bool {
|
||||||
return c.IsLondon(num) && isTimestampForked(c.OsakaTime, time)
|
return c.IsLondon(num) && isTimestampForked(c.OsakaTime, time)
|
||||||
|
|
@ -777,6 +913,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error {
|
||||||
{name: "shanghaiTime", timestamp: c.ShanghaiTime},
|
{name: "shanghaiTime", timestamp: c.ShanghaiTime},
|
||||||
{name: "cancunTime", timestamp: c.CancunTime, optional: true},
|
{name: "cancunTime", timestamp: c.CancunTime, optional: true},
|
||||||
{name: "pragueTime", timestamp: c.PragueTime, optional: true},
|
{name: "pragueTime", timestamp: c.PragueTime, optional: true},
|
||||||
|
{name: "prague1Time", timestamp: c.Berachain.Prague1.Time, optional: true},
|
||||||
{name: "osakaTime", timestamp: c.OsakaTime, optional: true},
|
{name: "osakaTime", timestamp: c.OsakaTime, optional: true},
|
||||||
{name: "verkleTime", timestamp: c.VerkleTime, optional: true},
|
{name: "verkleTime", timestamp: c.VerkleTime, optional: true},
|
||||||
{name: "bpo1", timestamp: c.BPO1Time, optional: true},
|
{name: "bpo1", timestamp: c.BPO1Time, optional: true},
|
||||||
|
|
@ -932,6 +1069,9 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int,
|
||||||
if isForkTimestampIncompatible(c.PragueTime, newcfg.PragueTime, headTimestamp) {
|
if isForkTimestampIncompatible(c.PragueTime, newcfg.PragueTime, headTimestamp) {
|
||||||
return newTimestampCompatError("Prague fork timestamp", c.PragueTime, newcfg.PragueTime)
|
return newTimestampCompatError("Prague fork timestamp", c.PragueTime, newcfg.PragueTime)
|
||||||
}
|
}
|
||||||
|
if isForkTimestampIncompatible(c.Berachain.Prague1.Time, newcfg.Berachain.Prague1.Time, headTimestamp) {
|
||||||
|
return newTimestampCompatError("Prague1 fork timestamp", c.Berachain.Prague1.Time, newcfg.Berachain.Prague1.Time)
|
||||||
|
}
|
||||||
if isForkTimestampIncompatible(c.OsakaTime, newcfg.OsakaTime, headTimestamp) {
|
if isForkTimestampIncompatible(c.OsakaTime, newcfg.OsakaTime, headTimestamp) {
|
||||||
return newTimestampCompatError("Osaka fork timestamp", c.OsakaTime, newcfg.OsakaTime)
|
return newTimestampCompatError("Osaka fork timestamp", c.OsakaTime, newcfg.OsakaTime)
|
||||||
}
|
}
|
||||||
|
|
@ -957,7 +1097,12 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int,
|
||||||
}
|
}
|
||||||
|
|
||||||
// BaseFeeChangeDenominator bounds the amount the base fee can change between blocks.
|
// BaseFeeChangeDenominator bounds the amount the base fee can change between blocks.
|
||||||
func (c *ChainConfig) BaseFeeChangeDenominator() uint64 {
|
func (c *ChainConfig) BaseFeeChangeDenominator(num *big.Int, time uint64) uint64 {
|
||||||
|
// Starting at the Prague1 fork, we use the Berachain base fee change denominator.
|
||||||
|
if c.IsPrague1(num, time) {
|
||||||
|
return c.Berachain.Prague1.BaseFeeChangeDenominator
|
||||||
|
}
|
||||||
|
|
||||||
return DefaultBaseFeeChangeDenominator
|
return DefaultBaseFeeChangeDenominator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -974,6 +1119,8 @@ func (c *ChainConfig) LatestFork(time uint64) forks.Fork {
|
||||||
switch {
|
switch {
|
||||||
case c.IsOsaka(london, time):
|
case c.IsOsaka(london, time):
|
||||||
return forks.Osaka
|
return forks.Osaka
|
||||||
|
case c.IsPrague1(london, time):
|
||||||
|
return forks.Prague1
|
||||||
case c.IsPrague(london, time):
|
case c.IsPrague(london, time):
|
||||||
return forks.Prague
|
return forks.Prague
|
||||||
case c.IsCancun(london, time):
|
case c.IsCancun(london, time):
|
||||||
|
|
@ -991,6 +1138,8 @@ func (c *ChainConfig) Timestamp(fork forks.Fork) *uint64 {
|
||||||
switch {
|
switch {
|
||||||
case fork == forks.Osaka:
|
case fork == forks.Osaka:
|
||||||
return c.OsakaTime
|
return c.OsakaTime
|
||||||
|
case fork == forks.Prague1:
|
||||||
|
return c.Berachain.Prague1.Time
|
||||||
case fork == forks.Prague:
|
case fork == forks.Prague:
|
||||||
return c.PragueTime
|
return c.PragueTime
|
||||||
case fork == forks.Cancun:
|
case fork == forks.Cancun:
|
||||||
|
|
@ -1137,13 +1286,13 @@ func (err *ConfigCompatError) Error() string {
|
||||||
// Rules is a one time interface meaning that it shouldn't be used in between transition
|
// Rules is a one time interface meaning that it shouldn't be used in between transition
|
||||||
// phases.
|
// phases.
|
||||||
type Rules struct {
|
type Rules struct {
|
||||||
ChainID *big.Int
|
ChainID *big.Int
|
||||||
IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool
|
IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool
|
||||||
IsEIP2929, IsEIP4762 bool
|
IsEIP2929, IsEIP4762 bool
|
||||||
IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool
|
IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool
|
||||||
IsBerlin, IsLondon bool
|
IsBerlin, IsLondon bool
|
||||||
IsMerge, IsShanghai, IsCancun, IsPrague, IsOsaka bool
|
IsMerge, IsShanghai, IsCancun, IsPrague, IsPrague1, IsOsaka bool
|
||||||
IsVerkle bool
|
IsVerkle bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rules ensures c's ChainID is not nil.
|
// Rules ensures c's ChainID is not nil.
|
||||||
|
|
@ -1172,6 +1321,7 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules
|
||||||
IsShanghai: isMerge && c.IsShanghai(num, timestamp),
|
IsShanghai: isMerge && c.IsShanghai(num, timestamp),
|
||||||
IsCancun: isMerge && c.IsCancun(num, timestamp),
|
IsCancun: isMerge && c.IsCancun(num, timestamp),
|
||||||
IsPrague: isMerge && c.IsPrague(num, timestamp),
|
IsPrague: isMerge && c.IsPrague(num, timestamp),
|
||||||
|
IsPrague1: isMerge && c.IsPrague1(num, timestamp),
|
||||||
IsOsaka: isMerge && c.IsOsaka(num, timestamp),
|
IsOsaka: isMerge && c.IsOsaka(num, timestamp),
|
||||||
IsVerkle: isVerkle,
|
IsVerkle: isVerkle,
|
||||||
IsEIP4762: isVerkle,
|
IsEIP4762: isVerkle,
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ const (
|
||||||
Shanghai
|
Shanghai
|
||||||
Cancun
|
Cancun
|
||||||
Prague
|
Prague
|
||||||
|
Prague1
|
||||||
Osaka
|
Osaka
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -71,5 +72,6 @@ var forkToString = map[Fork]string{
|
||||||
Shanghai: "Shanghai",
|
Shanghai: "Shanghai",
|
||||||
Cancun: "Cancun",
|
Cancun: "Cancun",
|
||||||
Prague: "Prague",
|
Prague: "Prague",
|
||||||
|
Prague1: "Prague1",
|
||||||
Osaka: "Osaka",
|
Osaka: "Osaka",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -201,7 +201,7 @@ var (
|
||||||
|
|
||||||
// System contracts.
|
// System contracts.
|
||||||
var (
|
var (
|
||||||
// SystemAddress is where the system-transaction is sent from as per EIP-4788
|
// SystemAddress is where the system-transaction is sent from as per EIP-4788 and BRIP-0004.
|
||||||
SystemAddress = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe")
|
SystemAddress = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe")
|
||||||
|
|
||||||
// EIP-4788 - Beacon block root in the EVM
|
// EIP-4788 - Beacon block root in the EVM
|
||||||
|
|
@ -219,4 +219,7 @@ var (
|
||||||
// EIP-7251 - Increase the MAX_EFFECTIVE_BALANCE
|
// EIP-7251 - Increase the MAX_EFFECTIVE_BALANCE
|
||||||
ConsolidationQueueAddress = common.HexToAddress("0x0000BBdDc7CE488642fb579F8B00f3a590007251")
|
ConsolidationQueueAddress = common.HexToAddress("0x0000BBdDc7CE488642fb579F8B00f3a590007251")
|
||||||
ConsolidationQueueCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd")
|
ConsolidationQueueCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd")
|
||||||
|
|
||||||
|
// BRIP-0004 - PoL Distributor
|
||||||
|
PoLTxGasLimit uint64 = 30_000_000
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,7 @@ type btHeader struct {
|
||||||
BlobGasUsed *uint64
|
BlobGasUsed *uint64
|
||||||
ExcessBlobGas *uint64
|
ExcessBlobGas *uint64
|
||||||
ParentBeaconBlockRoot *common.Hash
|
ParentBeaconBlockRoot *common.Hash
|
||||||
|
ParentProposerPubkey *common.Pubkey
|
||||||
}
|
}
|
||||||
|
|
||||||
type btHeaderMarshaling struct {
|
type btHeaderMarshaling struct {
|
||||||
|
|
@ -336,6 +337,9 @@ func validateHeader(h *btHeader, h2 *types.Header) error {
|
||||||
if !reflect.DeepEqual(h.ParentBeaconBlockRoot, h2.ParentBeaconRoot) {
|
if !reflect.DeepEqual(h.ParentBeaconBlockRoot, h2.ParentBeaconRoot) {
|
||||||
return fmt.Errorf("parentBeaconBlockRoot: want: %v have: %v", h.ParentBeaconBlockRoot, h2.ParentBeaconRoot)
|
return fmt.Errorf("parentBeaconBlockRoot: want: %v have: %v", h.ParentBeaconBlockRoot, h2.ParentBeaconRoot)
|
||||||
}
|
}
|
||||||
|
if !reflect.DeepEqual(h.ParentProposerPubkey, h2.ParentProposerPubkey) {
|
||||||
|
return fmt.Errorf("parentProposerPubkey: want: %v have: %v", h.ParentProposerPubkey, h2.ParentProposerPubkey)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ func (b btHeader) MarshalJSON() ([]byte, error) {
|
||||||
BlobGasUsed *math.HexOrDecimal64
|
BlobGasUsed *math.HexOrDecimal64
|
||||||
ExcessBlobGas *math.HexOrDecimal64
|
ExcessBlobGas *math.HexOrDecimal64
|
||||||
ParentBeaconBlockRoot *common.Hash
|
ParentBeaconBlockRoot *common.Hash
|
||||||
|
ParentProposerPubkey *common.Pubkey
|
||||||
}
|
}
|
||||||
var enc btHeader
|
var enc btHeader
|
||||||
enc.Bloom = b.Bloom
|
enc.Bloom = b.Bloom
|
||||||
|
|
@ -61,6 +62,7 @@ func (b btHeader) MarshalJSON() ([]byte, error) {
|
||||||
enc.BlobGasUsed = (*math.HexOrDecimal64)(b.BlobGasUsed)
|
enc.BlobGasUsed = (*math.HexOrDecimal64)(b.BlobGasUsed)
|
||||||
enc.ExcessBlobGas = (*math.HexOrDecimal64)(b.ExcessBlobGas)
|
enc.ExcessBlobGas = (*math.HexOrDecimal64)(b.ExcessBlobGas)
|
||||||
enc.ParentBeaconBlockRoot = b.ParentBeaconBlockRoot
|
enc.ParentBeaconBlockRoot = b.ParentBeaconBlockRoot
|
||||||
|
enc.ParentProposerPubkey = b.ParentProposerPubkey
|
||||||
return json.Marshal(&enc)
|
return json.Marshal(&enc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,6 +90,7 @@ func (b *btHeader) UnmarshalJSON(input []byte) error {
|
||||||
BlobGasUsed *math.HexOrDecimal64
|
BlobGasUsed *math.HexOrDecimal64
|
||||||
ExcessBlobGas *math.HexOrDecimal64
|
ExcessBlobGas *math.HexOrDecimal64
|
||||||
ParentBeaconBlockRoot *common.Hash
|
ParentBeaconBlockRoot *common.Hash
|
||||||
|
ParentProposerPubkey *common.Pubkey
|
||||||
}
|
}
|
||||||
var dec btHeader
|
var dec btHeader
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
|
@ -156,5 +159,8 @@ func (b *btHeader) UnmarshalJSON(input []byte) error {
|
||||||
if dec.ParentBeaconBlockRoot != nil {
|
if dec.ParentBeaconBlockRoot != nil {
|
||||||
b.ParentBeaconBlockRoot = dec.ParentBeaconBlockRoot
|
b.ParentBeaconBlockRoot = dec.ParentBeaconBlockRoot
|
||||||
}
|
}
|
||||||
|
if dec.ParentProposerPubkey != nil {
|
||||||
|
b.ParentProposerPubkey = dec.ParentProposerPubkey
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue