mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-19 19:30:44 +00:00
Merge branch 'master' into simulate/fix-revert-err-code
This commit is contained in:
commit
ce4530a6e1
360 changed files with 20346 additions and 7663 deletions
|
|
@ -122,6 +122,27 @@ jobs:
|
||||||
LINUX_SIGNING_KEY: ${{ secrets.LINUX_SIGNING_KEY }}
|
LINUX_SIGNING_KEY: ${{ secrets.LINUX_SIGNING_KEY }}
|
||||||
AZURE_BLOBSTORE_TOKEN: ${{ secrets.AZURE_BLOBSTORE_TOKEN }}
|
AZURE_BLOBSTORE_TOKEN: ${{ secrets.AZURE_BLOBSTORE_TOKEN }}
|
||||||
|
|
||||||
|
keeper:
|
||||||
|
name: Keeper Build
|
||||||
|
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: |
|
||||||
|
apt-get update
|
||||||
|
apt-get -yq --no-install-suggests --no-install-recommends install gcc-multilib
|
||||||
|
|
||||||
|
- name: Build (amd64)
|
||||||
|
run: |
|
||||||
|
go run build/ci.go keeper -dlgo
|
||||||
|
|
||||||
windows:
|
windows:
|
||||||
name: Windows Build
|
name: Windows Build
|
||||||
runs-on: "win-11"
|
runs-on: "win-11"
|
||||||
|
|
|
||||||
41
.github/workflows/go.yml
vendored
41
.github/workflows/go.yml
vendored
|
|
@ -34,6 +34,47 @@ 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
|
||||||
|
|
||||||
|
keeper:
|
||||||
|
name: Keeper Builds
|
||||||
|
needs: test
|
||||||
|
runs-on: [self-hosted-ghr, size-l-x64]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: '1.25'
|
||||||
|
cache: false
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: go run build/ci.go keeper
|
||||||
|
|
||||||
|
test-32bit:
|
||||||
|
name: "32bit tests"
|
||||||
|
needs: test
|
||||||
|
runs-on: [self-hosted-ghr, size-l-x64]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: false
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: '1.25'
|
||||||
|
cache: false
|
||||||
|
|
||||||
|
- name: Install cross toolchain
|
||||||
|
run: |
|
||||||
|
apt-get update
|
||||||
|
apt-get -yq --no-install-suggests --no-install-recommends install gcc-multilib
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: go run build/ci.go test -arch 386 -short -p 8
|
||||||
|
|
||||||
test:
|
test:
|
||||||
name: Test
|
name: Test
|
||||||
needs: lint
|
needs: lint
|
||||||
|
|
|
||||||
60
.github/workflows/validate_pr.yml
vendored
60
.github/workflows/validate_pr.yml
vendored
|
|
@ -8,10 +8,54 @@ jobs:
|
||||||
validate-pr:
|
validate-pr:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
- name: Check for Spam PR
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const prTitle = context.payload.pull_request.title;
|
||||||
|
const spamRegex = /^(feat|chore|fix)(\(.*\))?\s*:/i;
|
||||||
|
|
||||||
|
if (spamRegex.test(prTitle)) {
|
||||||
|
// Leave a comment explaining why
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: context.payload.pull_request.number,
|
||||||
|
body: `## PR Closed as Spam
|
||||||
|
|
||||||
|
This PR was automatically closed because the title format \`feat:\`, \`fix:\`, or \`chore:\` is commonly associated with spam contributions.
|
||||||
|
|
||||||
|
If this is a legitimate contribution, please:
|
||||||
|
1. Review our contribution guidelines
|
||||||
|
2. Use the correct PR title format: \`directory, ...: description\`
|
||||||
|
3. Open a new PR with the proper title format
|
||||||
|
|
||||||
|
Thank you for your understanding.`
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close the PR
|
||||||
|
await github.rest.pulls.update({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
pull_number: context.payload.pull_request.number,
|
||||||
|
state: 'closed'
|
||||||
|
});
|
||||||
|
|
||||||
|
core.setFailed('PR closed as spam due to suspicious title format');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('✅ PR passed spam check');
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Check PR Title Format
|
- name: Check PR Title Format
|
||||||
uses: actions/github-script@v7
|
uses: actions/github-script@v7
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
const prTitle = context.payload.pull_request.title;
|
const prTitle = context.payload.pull_request.title;
|
||||||
const titleRegex = /^([\w\s,{}/.]+): .+/;
|
const titleRegex = /^([\w\s,{}/.]+): .+/;
|
||||||
|
|
||||||
|
|
@ -19,5 +63,21 @@ jobs:
|
||||||
core.setFailed(`PR title "${prTitle}" does not match required format: directory, ...: description`);
|
core.setFailed(`PR title "${prTitle}" does not match required format: directory, ...: description`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const match = prTitle.match(titleRegex);
|
||||||
|
const dirPart = match[1];
|
||||||
|
const directories = dirPart.split(',').map(d => d.trim());
|
||||||
|
const missingDirs = [];
|
||||||
|
for (const dir of directories) {
|
||||||
|
const fullPath = path.join(process.env.GITHUB_WORKSPACE, dir);
|
||||||
|
if (!fs.existsSync(fullPath)) {
|
||||||
|
missingDirs.push(dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missingDirs.length > 0) {
|
||||||
|
core.setFailed(`The following directories in the PR title do not exist: ${missingDirs.join(', ')}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
console.log('✅ PR title format is valid');
|
console.log('✅ PR title format is valid');
|
||||||
|
|
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -55,4 +55,5 @@ 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
|
||||||
|
cmd/keeper/keeper
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ Audit reports are published in the `docs` folder: https://github.com/ethereum/go
|
||||||
|
|
||||||
To find out how to disclose a vulnerability in Ethereum visit [https://bounty.ethereum.org](https://bounty.ethereum.org) or email bounty@ethereum.org. Please read the [disclosure page](https://github.com/ethereum/go-ethereum/security/advisories?state=published) for more information about publicly disclosed security vulnerabilities.
|
To find out how to disclose a vulnerability in Ethereum visit [https://bounty.ethereum.org](https://bounty.ethereum.org) or email bounty@ethereum.org. Please read the [disclosure page](https://github.com/ethereum/go-ethereum/security/advisories?state=published) for more information about publicly disclosed security vulnerabilities.
|
||||||
|
|
||||||
Use the built-in `geth version-check` feature to check whether the software is affected by any known vulnerability. This command will fetch the latest [`vulnerabilities.json`](https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities.json) file which contains known security vulnerabilities concerning `geth`, and cross-check the data against its own version number.
|
|
||||||
|
|
||||||
The following key may be used to communicate sensitive information to developers.
|
The following key may be used to communicate sensitive information to developers.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -158,10 +158,10 @@ func testLinkCase(tcInput linkTestCaseInput) error {
|
||||||
overrideAddrs = make(map[rune]common.Address)
|
overrideAddrs = make(map[rune]common.Address)
|
||||||
)
|
)
|
||||||
// generate deterministic addresses for the override set.
|
// generate deterministic addresses for the override set.
|
||||||
rand.Seed(42)
|
rng := rand.New(rand.NewSource(42))
|
||||||
for contract := range tcInput.overrides {
|
for contract := range tcInput.overrides {
|
||||||
var addr common.Address
|
var addr common.Address
|
||||||
rand.Read(addr[:])
|
rng.Read(addr[:])
|
||||||
overrideAddrs[contract] = addr
|
overrideAddrs[contract] = addr
|
||||||
overridesAddrs[addr] = struct{}{}
|
overridesAddrs[addr] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -144,10 +144,9 @@ func TestWaitDeployedCornerCases(t *testing.T) {
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
defer close(done)
|
defer close(done)
|
||||||
want := errors.New("context canceled")
|
|
||||||
_, err := bind.WaitDeployed(ctx, backend.Client(), tx.Hash())
|
_, err := bind.WaitDeployed(ctx, backend.Client(), tx.Hash())
|
||||||
if err == nil || errors.Is(want, err) {
|
if !errors.Is(err, context.Canceled) {
|
||||||
t.Errorf("error mismatch: want %v, got %v", want, err)
|
t.Errorf("error mismatch: want %v, got %v", context.Canceled, err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ import (
|
||||||
"github.com/ethereum/go-ethereum"
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto/keccak"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"golang.org/x/crypto/sha3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Account represents an Ethereum account located at a specific location defined
|
// Account represents an Ethereum account located at a specific location defined
|
||||||
|
|
@ -196,7 +196,7 @@ func TextHash(data []byte) []byte {
|
||||||
// This gives context to the signed message and prevents signing of transactions.
|
// This gives context to the signed message and prevents signing of transactions.
|
||||||
func TextAndHash(data []byte) ([]byte, string) {
|
func TextAndHash(data []byte) ([]byte, string) {
|
||||||
msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data)
|
msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data)
|
||||||
hasher := sha3.NewLegacyKeccak256()
|
hasher := keccak.NewLegacyKeccak256()
|
||||||
hasher.Write([]byte(msg))
|
hasher.Write([]byte(msg))
|
||||||
return hasher.Sum(nil), msg
|
return hasher.Sum(nil), msg
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -418,6 +418,7 @@ func (ks *KeyStore) Export(a accounts.Account, passphrase, newPassphrase string)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
defer zeroKey(key.PrivateKey)
|
||||||
var N, P int
|
var N, P int
|
||||||
if store, ok := ks.storage.(*keyStorePassphrase); ok {
|
if store, ok := ks.storage.(*keyStorePassphrase); ok {
|
||||||
N, P = store.scryptN, store.scryptP
|
N, P = store.scryptN, store.scryptP
|
||||||
|
|
@ -477,6 +478,7 @@ func (ks *KeyStore) Update(a accounts.Account, passphrase, newPassphrase string)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer zeroKey(key.PrivateKey)
|
||||||
return ks.storage.StoreKey(a.URL.Path, key, newPassphrase)
|
return ks.storage.StoreKey(a.URL.Path, key, newPassphrase)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,9 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error
|
||||||
*/
|
*/
|
||||||
passBytes := []byte(password)
|
passBytes := []byte(password)
|
||||||
derivedKey := pbkdf2.Key(passBytes, passBytes, 2000, 16, sha256.New)
|
derivedKey := pbkdf2.Key(passBytes, passBytes, 2000, 16, sha256.New)
|
||||||
|
if len(cipherText)%aes.BlockSize != 0 {
|
||||||
|
return nil, errors.New("ciphertext must be a multiple of block size")
|
||||||
|
}
|
||||||
plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
|
plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -300,6 +300,10 @@ func (s *SecureChannelSession) decryptAPDU(data []byte) ([]byte, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(data) == 0 || len(data)%aes.BlockSize != 0 {
|
||||||
|
return nil, fmt.Errorf("invalid ciphertext length: %d", len(data))
|
||||||
|
}
|
||||||
|
|
||||||
ret := make([]byte, len(data))
|
ret := make([]byte, len(data))
|
||||||
|
|
||||||
crypter := cipher.NewCBCDecrypter(a, s.iv)
|
crypter := cipher.NewCBCDecrypter(a, s.iv)
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,14 @@ const refreshCycle = time.Second
|
||||||
// trashing.
|
// trashing.
|
||||||
const refreshThrottling = 500 * time.Millisecond
|
const refreshThrottling = 500 * time.Millisecond
|
||||||
|
|
||||||
|
const (
|
||||||
|
// deviceUsagePage identifies Ledger devices by HID usage page (0xffa0) on Windows and macOS.
|
||||||
|
// See: https://github.com/LedgerHQ/ledger-live/blob/05a2980e838955a11a1418da638ef8ac3df4fb74/libs/ledgerjs/packages/hw-transport-node-hid-noevents/src/TransportNodeHid.ts
|
||||||
|
deviceUsagePage = 0xffa0
|
||||||
|
// deviceInterface identifies Ledger devices by USB interface number (0) on Linux.
|
||||||
|
deviceInterface = 0
|
||||||
|
)
|
||||||
|
|
||||||
// Hub is a accounts.Backend that can find and handle generic USB hardware wallets.
|
// Hub is a accounts.Backend that can find and handle generic USB hardware wallets.
|
||||||
type Hub struct {
|
type Hub struct {
|
||||||
scheme string // Protocol scheme prefixing account and wallet URLs.
|
scheme string // Protocol scheme prefixing account and wallet URLs.
|
||||||
|
|
@ -82,6 +90,7 @@ func NewLedgerHub() (*Hub, error) {
|
||||||
0x0005, /* Ledger Nano S Plus */
|
0x0005, /* Ledger Nano S Plus */
|
||||||
0x0006, /* Ledger Nano FTS */
|
0x0006, /* Ledger Nano FTS */
|
||||||
0x0007, /* Ledger Flex */
|
0x0007, /* Ledger Flex */
|
||||||
|
0x0008, /* Ledger Nano Gen5 */
|
||||||
|
|
||||||
0x0000, /* WebUSB Ledger Blue */
|
0x0000, /* WebUSB Ledger Blue */
|
||||||
0x1000, /* WebUSB Ledger Nano S */
|
0x1000, /* WebUSB Ledger Nano S */
|
||||||
|
|
@ -89,7 +98,8 @@ func NewLedgerHub() (*Hub, error) {
|
||||||
0x5000, /* WebUSB Ledger Nano S Plus */
|
0x5000, /* WebUSB Ledger Nano S Plus */
|
||||||
0x6000, /* WebUSB Ledger Nano FTS */
|
0x6000, /* WebUSB Ledger Nano FTS */
|
||||||
0x7000, /* WebUSB Ledger Flex */
|
0x7000, /* WebUSB Ledger Flex */
|
||||||
}, 0xffa0, 0, newLedgerDriver)
|
0x8000, /* WebUSB Ledger Nano Gen5 */
|
||||||
|
}, deviceUsagePage, deviceInterface, newLedgerDriver)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTrezorHubWithHID creates a new hardware wallet manager for Trezor devices.
|
// NewTrezorHubWithHID creates a new hardware wallet manager for Trezor devices.
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,7 @@ func (w *ledgerDriver) SignTypedMessage(path accounts.DerivationPath, domainHash
|
||||||
return nil, accounts.ErrWalletClosed
|
return nil, accounts.ErrWalletClosed
|
||||||
}
|
}
|
||||||
// Ensure the wallet is capable of signing the given transaction
|
// Ensure the wallet is capable of signing the given transaction
|
||||||
if w.version[0] < 1 && w.version[1] < 5 {
|
if w.version[0] < 1 || (w.version[0] == 1 && w.version[1] < 5) {
|
||||||
//lint:ignore ST1005 brand name displayed on the console
|
//lint:ignore ST1005 brand name displayed on the console
|
||||||
return nil, fmt.Errorf("Ledger version >= 1.5.0 required for EIP-712 signing (found version v%d.%d.%d)", w.version[0], w.version[1], w.version[2])
|
return nil, fmt.Errorf("Ledger version >= 1.5.0 required for EIP-712 signing (found version v%d.%d.%d)", w.version[0], w.version[1], w.version[2])
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -632,7 +632,7 @@ func (w *wallet) SignTx(account accounts.Account, tx *types.Transaction, chainID
|
||||||
// data is not supported for Ledger wallets, so this method will always return
|
// data is not supported for Ledger wallets, so this method will always return
|
||||||
// an error.
|
// an error.
|
||||||
func (w *wallet) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) {
|
func (w *wallet) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) {
|
||||||
return w.SignText(account, accounts.TextHash(text))
|
return w.SignText(account, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignTxWithPassphrase implements accounts.Wallet, attempting to sign the given
|
// SignTxWithPassphrase implements accounts.Wallet, attempting to sign the given
|
||||||
|
|
|
||||||
|
|
@ -36,4 +36,4 @@ for:
|
||||||
- go run build/ci.go archive -arch %GETH_ARCH% -type zip -signer WINDOWS_SIGNING_KEY -upload gethstore/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
|
- go run build/ci.go nsis -arch %GETH_ARCH% -signer WINDOWS_SIGNING_KEY -upload gethstore/builds
|
||||||
test_script:
|
test_script:
|
||||||
- go run build/ci.go test -dlgo -arch %GETH_ARCH% -cc %GETH_CC% -short -skip-spectests
|
- go run build/ci.go test -dlgo -arch %GETH_ARCH% -cc %GETH_CC% -short
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,16 @@ func (ec *engineClient) callNewPayload(fork string, event types.ChainHeadEvent)
|
||||||
params = []any{execData}
|
params = []any{execData}
|
||||||
)
|
)
|
||||||
switch fork {
|
switch fork {
|
||||||
case "electra":
|
case "altair", "bellatrix":
|
||||||
|
method = "engine_newPayloadV1"
|
||||||
|
case "capella":
|
||||||
|
method = "engine_newPayloadV2"
|
||||||
|
case "deneb":
|
||||||
|
method = "engine_newPayloadV3"
|
||||||
|
parentBeaconRoot := event.BeaconHead.ParentRoot
|
||||||
|
blobHashes := collectBlobHashes(event.Block)
|
||||||
|
params = append(params, blobHashes, parentBeaconRoot)
|
||||||
|
default: // electra, fulu and above
|
||||||
method = "engine_newPayloadV4"
|
method = "engine_newPayloadV4"
|
||||||
parentBeaconRoot := event.BeaconHead.ParentRoot
|
parentBeaconRoot := event.BeaconHead.ParentRoot
|
||||||
blobHashes := collectBlobHashes(event.Block)
|
blobHashes := collectBlobHashes(event.Block)
|
||||||
|
|
@ -110,15 +119,6 @@ func (ec *engineClient) callNewPayload(fork string, event types.ChainHeadEvent)
|
||||||
hexRequests[i] = hexutil.Bytes(event.ExecRequests[i])
|
hexRequests[i] = hexutil.Bytes(event.ExecRequests[i])
|
||||||
}
|
}
|
||||||
params = append(params, blobHashes, parentBeaconRoot, hexRequests)
|
params = append(params, blobHashes, parentBeaconRoot, hexRequests)
|
||||||
case "deneb":
|
|
||||||
method = "engine_newPayloadV3"
|
|
||||||
parentBeaconRoot := event.BeaconHead.ParentRoot
|
|
||||||
blobHashes := collectBlobHashes(event.Block)
|
|
||||||
params = append(params, blobHashes, parentBeaconRoot)
|
|
||||||
case "capella":
|
|
||||||
method = "engine_newPayloadV2"
|
|
||||||
default:
|
|
||||||
method = "engine_newPayloadV1"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(ec.rootCtx, time.Second*5)
|
ctx, cancel := context.WithTimeout(ec.rootCtx, time.Second*5)
|
||||||
|
|
@ -145,12 +145,12 @@ func (ec *engineClient) callForkchoiceUpdated(fork string, event types.ChainHead
|
||||||
|
|
||||||
var method string
|
var method string
|
||||||
switch fork {
|
switch fork {
|
||||||
case "deneb", "electra":
|
case "altair", "bellatrix":
|
||||||
method = "engine_forkchoiceUpdatedV3"
|
method = "engine_forkchoiceUpdatedV1"
|
||||||
case "capella":
|
case "capella":
|
||||||
method = "engine_forkchoiceUpdatedV2"
|
method = "engine_forkchoiceUpdatedV2"
|
||||||
default:
|
default: // deneb, electra, fulu and above
|
||||||
method = "engine_forkchoiceUpdatedV1"
|
method = "engine_forkchoiceUpdatedV3"
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(ec.rootCtx, time.Second*5)
|
ctx, cancel := context.WithTimeout(ec.rootCtx, time.Second*5)
|
||||||
|
|
|
||||||
|
|
@ -17,24 +17,23 @@ var _ = (*executableDataMarshaling)(nil)
|
||||||
// MarshalJSON marshals as JSON.
|
// MarshalJSON marshals as JSON.
|
||||||
func (e ExecutableData) MarshalJSON() ([]byte, error) {
|
func (e ExecutableData) MarshalJSON() ([]byte, error) {
|
||||||
type ExecutableData struct {
|
type ExecutableData struct {
|
||||||
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
||||||
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
|
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
|
||||||
StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
|
StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
|
||||||
ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
|
ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
|
||||||
LogsBloom hexutil.Bytes `json:"logsBloom" gencodec:"required"`
|
LogsBloom hexutil.Bytes `json:"logsBloom" gencodec:"required"`
|
||||||
Random common.Hash `json:"prevRandao" gencodec:"required"`
|
Random common.Hash `json:"prevRandao" gencodec:"required"`
|
||||||
Number hexutil.Uint64 `json:"blockNumber" gencodec:"required"`
|
Number hexutil.Uint64 `json:"blockNumber" 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"`
|
||||||
Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
||||||
ExtraData hexutil.Bytes `json:"extraData" gencodec:"required"`
|
ExtraData hexutil.Bytes `json:"extraData" gencodec:"required"`
|
||||||
BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"`
|
BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"`
|
||||||
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
|
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
|
||||||
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
|
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
|
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
|
||||||
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
|
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
|
||||||
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
|
|
||||||
}
|
}
|
||||||
var enc ExecutableData
|
var enc ExecutableData
|
||||||
enc.ParentHash = e.ParentHash
|
enc.ParentHash = e.ParentHash
|
||||||
|
|
@ -59,31 +58,29 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
|
||||||
enc.Withdrawals = e.Withdrawals
|
enc.Withdrawals = e.Withdrawals
|
||||||
enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed)
|
enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed)
|
||||||
enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas)
|
enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas)
|
||||||
enc.ExecutionWitness = e.ExecutionWitness
|
|
||||||
return json.Marshal(&enc)
|
return json.Marshal(&enc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON unmarshals from JSON.
|
// UnmarshalJSON unmarshals from JSON.
|
||||||
func (e *ExecutableData) UnmarshalJSON(input []byte) error {
|
func (e *ExecutableData) UnmarshalJSON(input []byte) error {
|
||||||
type ExecutableData struct {
|
type ExecutableData struct {
|
||||||
ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
|
ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
|
||||||
FeeRecipient *common.Address `json:"feeRecipient" gencodec:"required"`
|
FeeRecipient *common.Address `json:"feeRecipient" gencodec:"required"`
|
||||||
StateRoot *common.Hash `json:"stateRoot" gencodec:"required"`
|
StateRoot *common.Hash `json:"stateRoot" gencodec:"required"`
|
||||||
ReceiptsRoot *common.Hash `json:"receiptsRoot" gencodec:"required"`
|
ReceiptsRoot *common.Hash `json:"receiptsRoot" gencodec:"required"`
|
||||||
LogsBloom *hexutil.Bytes `json:"logsBloom" gencodec:"required"`
|
LogsBloom *hexutil.Bytes `json:"logsBloom" gencodec:"required"`
|
||||||
Random *common.Hash `json:"prevRandao" gencodec:"required"`
|
Random *common.Hash `json:"prevRandao" gencodec:"required"`
|
||||||
Number *hexutil.Uint64 `json:"blockNumber" gencodec:"required"`
|
Number *hexutil.Uint64 `json:"blockNumber" 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"`
|
||||||
Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
||||||
ExtraData *hexutil.Bytes `json:"extraData" gencodec:"required"`
|
ExtraData *hexutil.Bytes `json:"extraData" gencodec:"required"`
|
||||||
BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"`
|
BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"`
|
||||||
BlockHash *common.Hash `json:"blockHash" gencodec:"required"`
|
BlockHash *common.Hash `json:"blockHash" gencodec:"required"`
|
||||||
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
|
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
|
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
|
||||||
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
|
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
|
||||||
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
|
|
||||||
}
|
}
|
||||||
var dec ExecutableData
|
var dec ExecutableData
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
|
@ -157,8 +154,5 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
|
||||||
if dec.ExcessBlobGas != nil {
|
if dec.ExcessBlobGas != nil {
|
||||||
e.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas)
|
e.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas)
|
||||||
}
|
}
|
||||||
if dec.ExecutionWitness != nil {
|
|
||||||
e.ExecutionWitness = dec.ExecutionWitness
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,24 +73,23 @@ type payloadAttributesMarshaling struct {
|
||||||
|
|
||||||
// ExecutableData is the data necessary to execute an EL payload.
|
// ExecutableData is the data necessary to execute an EL payload.
|
||||||
type ExecutableData struct {
|
type ExecutableData struct {
|
||||||
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
||||||
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
|
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
|
||||||
StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
|
StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
|
||||||
ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
|
ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
|
||||||
LogsBloom []byte `json:"logsBloom" gencodec:"required"`
|
LogsBloom []byte `json:"logsBloom" gencodec:"required"`
|
||||||
Random common.Hash `json:"prevRandao" gencodec:"required"`
|
Random common.Hash `json:"prevRandao" gencodec:"required"`
|
||||||
Number uint64 `json:"blockNumber" gencodec:"required"`
|
Number uint64 `json:"blockNumber" gencodec:"required"`
|
||||||
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
|
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
|
||||||
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
|
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
|
||||||
Timestamp uint64 `json:"timestamp" gencodec:"required"`
|
Timestamp uint64 `json:"timestamp" gencodec:"required"`
|
||||||
ExtraData []byte `json:"extraData" gencodec:"required"`
|
ExtraData []byte `json:"extraData" gencodec:"required"`
|
||||||
BaseFeePerGas *big.Int `json:"baseFeePerGas" gencodec:"required"`
|
BaseFeePerGas *big.Int `json:"baseFeePerGas" gencodec:"required"`
|
||||||
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
|
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
|
||||||
Transactions [][]byte `json:"transactions" gencodec:"required"`
|
Transactions [][]byte `json:"transactions" gencodec:"required"`
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
BlobGasUsed *uint64 `json:"blobGasUsed"`
|
BlobGasUsed *uint64 `json:"blobGasUsed"`
|
||||||
ExcessBlobGas *uint64 `json:"excessBlobGas"`
|
ExcessBlobGas *uint64 `json:"excessBlobGas"`
|
||||||
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSON type overrides for executableData.
|
// JSON type overrides for executableData.
|
||||||
|
|
@ -316,8 +315,7 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H
|
||||||
RequestsHash: requestsHash,
|
RequestsHash: requestsHash,
|
||||||
}
|
}
|
||||||
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}),
|
||||||
WithWitness(data.ExecutionWitness),
|
|
||||||
nil
|
nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -325,24 +323,23 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H
|
||||||
// fields from the given block. It assumes the given block is post-merge block.
|
// fields from the given block. It assumes the given block is post-merge block.
|
||||||
func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.BlobTxSidecar, requests [][]byte) *ExecutionPayloadEnvelope {
|
func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.BlobTxSidecar, requests [][]byte) *ExecutionPayloadEnvelope {
|
||||||
data := &ExecutableData{
|
data := &ExecutableData{
|
||||||
BlockHash: block.Hash(),
|
BlockHash: block.Hash(),
|
||||||
ParentHash: block.ParentHash(),
|
ParentHash: block.ParentHash(),
|
||||||
FeeRecipient: block.Coinbase(),
|
FeeRecipient: block.Coinbase(),
|
||||||
StateRoot: block.Root(),
|
StateRoot: block.Root(),
|
||||||
Number: block.NumberU64(),
|
Number: block.NumberU64(),
|
||||||
GasLimit: block.GasLimit(),
|
GasLimit: block.GasLimit(),
|
||||||
GasUsed: block.GasUsed(),
|
GasUsed: block.GasUsed(),
|
||||||
BaseFeePerGas: block.BaseFee(),
|
BaseFeePerGas: block.BaseFee(),
|
||||||
Timestamp: block.Time(),
|
Timestamp: block.Time(),
|
||||||
ReceiptsRoot: block.ReceiptHash(),
|
ReceiptsRoot: block.ReceiptHash(),
|
||||||
LogsBloom: block.Bloom().Bytes(),
|
LogsBloom: block.Bloom().Bytes(),
|
||||||
Transactions: encodeTransactions(block.Transactions()),
|
Transactions: encodeTransactions(block.Transactions()),
|
||||||
Random: block.MixDigest(),
|
Random: block.MixDigest(),
|
||||||
ExtraData: block.Extra(),
|
ExtraData: block.Extra(),
|
||||||
Withdrawals: block.Withdrawals(),
|
Withdrawals: block.Withdrawals(),
|
||||||
BlobGasUsed: block.BlobGasUsed(),
|
BlobGasUsed: block.BlobGasUsed(),
|
||||||
ExcessBlobGas: block.ExcessBlobGas(),
|
ExcessBlobGas: block.ExcessBlobGas(),
|
||||||
ExecutionWitness: block.ExecutionWitness(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add blobs.
|
// Add blobs.
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,10 @@ func newCanonicalStore[T any](db ethdb.Iteratee, keyPrefix []byte) (*canonicalSt
|
||||||
|
|
||||||
// databaseKey returns the database key belonging to the given period.
|
// databaseKey returns the database key belonging to the given period.
|
||||||
func (cs *canonicalStore[T]) databaseKey(period uint64) []byte {
|
func (cs *canonicalStore[T]) databaseKey(period uint64) []byte {
|
||||||
return binary.BigEndian.AppendUint64(append([]byte{}, cs.keyPrefix...), period)
|
key := make([]byte, len(cs.keyPrefix)+8)
|
||||||
|
copy(key, cs.keyPrefix)
|
||||||
|
binary.BigEndian.PutUint64(key[len(cs.keyPrefix):], period)
|
||||||
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
// add adds the given item to the database. It also ensures that the range remains
|
// add adds the given item to the database. It also ensures that the range remains
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,7 @@ func (s *HeadSync) Process(requester request.Requester, events []request.Event)
|
||||||
delete(s.serverHeads, event.Server)
|
delete(s.serverHeads, event.Server)
|
||||||
delete(s.unvalidatedOptimistic, event.Server)
|
delete(s.unvalidatedOptimistic, event.Server)
|
||||||
delete(s.unvalidatedFinality, event.Server)
|
delete(s.unvalidatedFinality, event.Server)
|
||||||
|
delete(s.reqFinalityEpoch, event.Server)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
0x1bbf958008172591b6cbdb3d8d52e26998258e83d4bdb9eec10969d84519a6bd
|
0xbb7a7f3c40d8ea0b450f91587db65d0f1c079669277e01a0426c8911702a863a
|
||||||
|
|
@ -1 +1 @@
|
||||||
0x2fe39a39b6f7cbd549e0f74d259de6db486005a65bd3bd92840dd6ce21d6f4c8
|
0x2af778d703186526a1b6304b423f338f11556206f618643c3f7fa0d7b1ef5c9b
|
||||||
|
|
@ -1 +1 @@
|
||||||
0x86686b2b366e24134e0e3969a9c5f3759f92e5d2b04785b42e22cc7d468c2107
|
0x48a89c9ea7ba19de2931797974cf8722344ab231c0edada278b108ef74125478
|
||||||
|
|
@ -38,7 +38,7 @@ import (
|
||||||
// across signing different data structures.
|
// across signing different data structures.
|
||||||
const syncCommitteeDomain = 7
|
const syncCommitteeDomain = 7
|
||||||
|
|
||||||
var knownForks = []string{"GENESIS", "ALTAIR", "BELLATRIX", "CAPELLA", "DENEB"}
|
var knownForks = []string{"GENESIS", "ALTAIR", "BELLATRIX", "CAPELLA", "DENEB", "ELECTRA", "FULU"}
|
||||||
|
|
||||||
// ClientConfig contains beacon light client configuration.
|
// ClientConfig contains beacon light client configuration.
|
||||||
type ClientConfig struct {
|
type ClientConfig struct {
|
||||||
|
|
@ -103,11 +103,16 @@ func (c *ChainConfig) LoadForks(file []byte) error {
|
||||||
epochs["GENESIS"] = 0
|
epochs["GENESIS"] = 0
|
||||||
|
|
||||||
for key, value := range config {
|
for key, value := range config {
|
||||||
|
if value == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if strings.HasSuffix(key, "_FORK_VERSION") {
|
if strings.HasSuffix(key, "_FORK_VERSION") {
|
||||||
name := key[:len(key)-len("_FORK_VERSION")]
|
name := key[:len(key)-len("_FORK_VERSION")]
|
||||||
switch version := value.(type) {
|
switch version := value.(type) {
|
||||||
case int:
|
case int:
|
||||||
versions[name] = new(big.Int).SetUint64(uint64(version)).FillBytes(make([]byte, 4))
|
versions[name] = new(big.Int).SetUint64(uint64(version)).FillBytes(make([]byte, 4))
|
||||||
|
case int64:
|
||||||
|
versions[name] = new(big.Int).SetUint64(uint64(version)).FillBytes(make([]byte, 4))
|
||||||
case uint64:
|
case uint64:
|
||||||
versions[name] = new(big.Int).SetUint64(version).FillBytes(make([]byte, 4))
|
versions[name] = new(big.Int).SetUint64(version).FillBytes(make([]byte, 4))
|
||||||
case string:
|
case string:
|
||||||
|
|
@ -125,6 +130,8 @@ func (c *ChainConfig) LoadForks(file []byte) error {
|
||||||
switch epoch := value.(type) {
|
switch epoch := value.(type) {
|
||||||
case int:
|
case int:
|
||||||
epochs[name] = uint64(epoch)
|
epochs[name] = uint64(epoch)
|
||||||
|
case int64:
|
||||||
|
epochs[name] = uint64(epoch)
|
||||||
case uint64:
|
case uint64:
|
||||||
epochs[name] = epoch
|
epochs[name] = epoch
|
||||||
case string:
|
case string:
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,9 @@ ALTAIR_FORK_EPOCH: 1
|
||||||
EIP7928_FORK_VERSION: 0xb0000038
|
EIP7928_FORK_VERSION: 0xb0000038
|
||||||
EIP7928_FORK_EPOCH: 18446744073709551615
|
EIP7928_FORK_EPOCH: 18446744073709551615
|
||||||
|
|
||||||
|
EIP7XXX_FORK_VERSION:
|
||||||
|
EIP7XXX_FORK_EPOCH:
|
||||||
|
|
||||||
BLOB_SCHEDULE: []
|
BLOB_SCHEDULE: []
|
||||||
`
|
`
|
||||||
c := &ChainConfig{}
|
c := &ChainConfig{}
|
||||||
|
|
|
||||||
|
|
@ -40,36 +40,39 @@ var (
|
||||||
GenesisTime: 1606824023,
|
GenesisTime: 1606824023,
|
||||||
Checkpoint: common.HexToHash(checkpointMainnet),
|
Checkpoint: common.HexToHash(checkpointMainnet),
|
||||||
}).
|
}).
|
||||||
AddFork("GENESIS", 0, []byte{0, 0, 0, 0}).
|
AddFork("GENESIS", 0, common.FromHex("0x00000000")).
|
||||||
AddFork("ALTAIR", 74240, []byte{1, 0, 0, 0}).
|
AddFork("ALTAIR", 74240, common.FromHex("0x01000000")).
|
||||||
AddFork("BELLATRIX", 144896, []byte{2, 0, 0, 0}).
|
AddFork("BELLATRIX", 144896, common.FromHex("0x02000000")).
|
||||||
AddFork("CAPELLA", 194048, []byte{3, 0, 0, 0}).
|
AddFork("CAPELLA", 194048, common.FromHex("0x03000000")).
|
||||||
AddFork("DENEB", 269568, []byte{4, 0, 0, 0}).
|
AddFork("DENEB", 269568, common.FromHex("0x04000000")).
|
||||||
AddFork("ELECTRA", 364032, []byte{5, 0, 0, 0})
|
AddFork("ELECTRA", 364032, common.FromHex("0x05000000")).
|
||||||
|
AddFork("FULU", 411392, common.FromHex("0x06000000"))
|
||||||
|
|
||||||
SepoliaLightConfig = (&ChainConfig{
|
SepoliaLightConfig = (&ChainConfig{
|
||||||
GenesisValidatorsRoot: common.HexToHash("0xd8ea171f3c94aea21ebc42a1ed61052acf3f9209c00e4efbaaddac09ed9b8078"),
|
GenesisValidatorsRoot: common.HexToHash("0xd8ea171f3c94aea21ebc42a1ed61052acf3f9209c00e4efbaaddac09ed9b8078"),
|
||||||
GenesisTime: 1655733600,
|
GenesisTime: 1655733600,
|
||||||
Checkpoint: common.HexToHash(checkpointSepolia),
|
Checkpoint: common.HexToHash(checkpointSepolia),
|
||||||
}).
|
}).
|
||||||
AddFork("GENESIS", 0, []byte{144, 0, 0, 105}).
|
AddFork("GENESIS", 0, common.FromHex("0x90000069")).
|
||||||
AddFork("ALTAIR", 50, []byte{144, 0, 0, 112}).
|
AddFork("ALTAIR", 50, common.FromHex("0x90000070")).
|
||||||
AddFork("BELLATRIX", 100, []byte{144, 0, 0, 113}).
|
AddFork("BELLATRIX", 100, common.FromHex("0x90000071")).
|
||||||
AddFork("CAPELLA", 56832, []byte{144, 0, 0, 114}).
|
AddFork("CAPELLA", 56832, common.FromHex("0x90000072")).
|
||||||
AddFork("DENEB", 132608, []byte{144, 0, 0, 115}).
|
AddFork("DENEB", 132608, common.FromHex("0x90000073")).
|
||||||
AddFork("ELECTRA", 222464, []byte{144, 0, 0, 116})
|
AddFork("ELECTRA", 222464, common.FromHex("0x90000074")).
|
||||||
|
AddFork("FULU", 272640, common.FromHex("0x90000075"))
|
||||||
|
|
||||||
HoleskyLightConfig = (&ChainConfig{
|
HoleskyLightConfig = (&ChainConfig{
|
||||||
GenesisValidatorsRoot: common.HexToHash("0x9143aa7c615a7f7115e2b6aac319c03529df8242ae705fba9df39b79c59fa8b1"),
|
GenesisValidatorsRoot: common.HexToHash("0x9143aa7c615a7f7115e2b6aac319c03529df8242ae705fba9df39b79c59fa8b1"),
|
||||||
GenesisTime: 1695902400,
|
GenesisTime: 1695902400,
|
||||||
Checkpoint: common.HexToHash(checkpointHolesky),
|
Checkpoint: common.HexToHash(checkpointHolesky),
|
||||||
}).
|
}).
|
||||||
AddFork("GENESIS", 0, []byte{1, 1, 112, 0}).
|
AddFork("GENESIS", 0, common.FromHex("0x01017000")).
|
||||||
AddFork("ALTAIR", 0, []byte{2, 1, 112, 0}).
|
AddFork("ALTAIR", 0, common.FromHex("0x02017000")).
|
||||||
AddFork("BELLATRIX", 0, []byte{3, 1, 112, 0}).
|
AddFork("BELLATRIX", 0, common.FromHex("0x03017000")).
|
||||||
AddFork("CAPELLA", 256, []byte{4, 1, 112, 0}).
|
AddFork("CAPELLA", 256, common.FromHex("0x04017000")).
|
||||||
AddFork("DENEB", 29696, []byte{5, 1, 112, 0}).
|
AddFork("DENEB", 29696, common.FromHex("0x05017000")).
|
||||||
AddFork("ELECTRA", 115968, []byte{6, 1, 112, 0})
|
AddFork("ELECTRA", 115968, common.FromHex("0x06017000")).
|
||||||
|
AddFork("FULU", 165120, common.FromHex("0x07017000"))
|
||||||
|
|
||||||
HoodiLightConfig = (&ChainConfig{
|
HoodiLightConfig = (&ChainConfig{
|
||||||
GenesisValidatorsRoot: common.HexToHash("0x212f13fc4df078b6cb7db228f1c8307566dcecf900867401a92023d7ba99cb5f"),
|
GenesisValidatorsRoot: common.HexToHash("0x212f13fc4df078b6cb7db228f1c8307566dcecf900867401a92023d7ba99cb5f"),
|
||||||
|
|
@ -82,5 +85,5 @@ var (
|
||||||
AddFork("CAPELLA", 0, common.FromHex("0x40000910")).
|
AddFork("CAPELLA", 0, common.FromHex("0x40000910")).
|
||||||
AddFork("DENEB", 0, common.FromHex("0x50000910")).
|
AddFork("DENEB", 0, common.FromHex("0x50000910")).
|
||||||
AddFork("ELECTRA", 2048, common.FromHex("0x60000910")).
|
AddFork("ELECTRA", 2048, common.FromHex("0x60000910")).
|
||||||
AddFork("FULU", 18446744073709551615, common.FromHex("0x70000910"))
|
AddFork("FULU", 50688, common.FromHex("0x70000910"))
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ func BlockFromJSON(forkName string, data []byte) (*BeaconBlock, error) {
|
||||||
obj = new(capella.BeaconBlock)
|
obj = new(capella.BeaconBlock)
|
||||||
case "deneb":
|
case "deneb":
|
||||||
obj = new(deneb.BeaconBlock)
|
obj = new(deneb.BeaconBlock)
|
||||||
case "electra":
|
case "electra", "fulu":
|
||||||
obj = new(electra.BeaconBlock)
|
obj = new(electra.BeaconBlock)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported fork: %s", forkName)
|
return nil, fmt.Errorf("unsupported fork: %s", forkName)
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ func ExecutionHeaderFromJSON(forkName string, data []byte) (*ExecutionHeader, er
|
||||||
switch forkName {
|
switch forkName {
|
||||||
case "capella":
|
case "capella":
|
||||||
obj = new(capella.ExecutionPayloadHeader)
|
obj = new(capella.ExecutionPayloadHeader)
|
||||||
case "deneb", "electra": // note: the payload type was not changed in electra
|
case "deneb", "electra", "fulu": // note: the payload type was not changed in electra/fulu
|
||||||
obj = new(deneb.ExecutionPayloadHeader)
|
obj = new(deneb.ExecutionPayloadHeader)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported fork: %s", forkName)
|
return nil, fmt.Errorf("unsupported fork: %s", forkName)
|
||||||
|
|
|
||||||
145
build/ci.go
145
build/ci.go
|
|
@ -31,6 +31,9 @@ Available commands are:
|
||||||
install [ -arch architecture ] [ -cc compiler ] [ packages... ] -- builds packages and executables
|
install [ -arch architecture ] [ -cc compiler ] [ packages... ] -- builds packages and executables
|
||||||
test [ -coverage ] [ packages... ] -- runs the tests
|
test [ -coverage ] [ packages... ] -- runs the tests
|
||||||
|
|
||||||
|
keeper [ -dlgo ]
|
||||||
|
keeper-archive [ -signer key-envvar ] [ -signify key-envvar ] [ -upload dest ]
|
||||||
|
|
||||||
archive [ -arch architecture ] [ -type zip|tar ] [ -signer key-envvar ] [ -signify key-envvar ] [ -upload dest ] -- archives build artifacts
|
archive [ -arch architecture ] [ -type zip|tar ] [ -signer key-envvar ] [ -signify key-envvar ] [ -upload dest ] -- archives build artifacts
|
||||||
importkeys -- imports signing keys from env
|
importkeys -- imports signing keys from env
|
||||||
debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package
|
debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package
|
||||||
|
|
@ -86,6 +89,42 @@ var (
|
||||||
executablePath("clef"),
|
executablePath("clef"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keeper build targets with their configurations
|
||||||
|
keeperTargets = []struct {
|
||||||
|
Name string
|
||||||
|
GOOS string
|
||||||
|
GOARCH string
|
||||||
|
CC string
|
||||||
|
Tags string
|
||||||
|
Env map[string]string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "ziren",
|
||||||
|
GOOS: "linux",
|
||||||
|
GOARCH: "mipsle",
|
||||||
|
// enable when cgo works
|
||||||
|
// CC: "mipsel-linux-gnu-gcc",
|
||||||
|
Tags: "ziren",
|
||||||
|
Env: map[string]string{"GOMIPS": "softfloat", "CGO_ENABLED": "0"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "wasm-js",
|
||||||
|
GOOS: "js",
|
||||||
|
GOARCH: "wasm",
|
||||||
|
Tags: "example",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "wasm-wasi",
|
||||||
|
GOOS: "wasip1",
|
||||||
|
GOARCH: "wasm",
|
||||||
|
Tags: "example",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "example",
|
||||||
|
Tags: "example",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
// A debian package is created for all executables listed here.
|
// A debian package is created for all executables listed here.
|
||||||
debExecutables = []debExecutable{
|
debExecutables = []debExecutable{
|
||||||
{
|
{
|
||||||
|
|
@ -178,6 +217,10 @@ func main() {
|
||||||
doPurge(os.Args[2:])
|
doPurge(os.Args[2:])
|
||||||
case "sanitycheck":
|
case "sanitycheck":
|
||||||
doSanityCheck()
|
doSanityCheck()
|
||||||
|
case "keeper":
|
||||||
|
doInstallKeeper(os.Args[2:])
|
||||||
|
case "keeper-archive":
|
||||||
|
doKeeperArchive(os.Args[2:])
|
||||||
default:
|
default:
|
||||||
log.Fatal("unknown command ", os.Args[1])
|
log.Fatal("unknown command ", os.Args[1])
|
||||||
}
|
}
|
||||||
|
|
@ -212,9 +255,6 @@ func doInstall(cmdline []string) {
|
||||||
// Configure the build.
|
// Configure the build.
|
||||||
gobuild := tc.Go("build", buildFlags(env, *staticlink, buildTags)...)
|
gobuild := tc.Go("build", buildFlags(env, *staticlink, buildTags)...)
|
||||||
|
|
||||||
// We use -trimpath to avoid leaking local paths into the built executables.
|
|
||||||
gobuild.Args = append(gobuild.Args, "-trimpath")
|
|
||||||
|
|
||||||
// Show packages during build.
|
// Show packages during build.
|
||||||
gobuild.Args = append(gobuild.Args, "-v")
|
gobuild.Args = append(gobuild.Args, "-v")
|
||||||
|
|
||||||
|
|
@ -234,6 +274,43 @@ func doInstall(cmdline []string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// doInstallKeeper builds keeper binaries for all supported targets.
|
||||||
|
func doInstallKeeper(cmdline []string) {
|
||||||
|
var dlgo = flag.Bool("dlgo", false, "Download Go and build with it")
|
||||||
|
|
||||||
|
flag.CommandLine.Parse(cmdline)
|
||||||
|
env := build.Env()
|
||||||
|
|
||||||
|
// Configure the toolchain.
|
||||||
|
tc := build.GoToolchain{}
|
||||||
|
if *dlgo {
|
||||||
|
csdb := download.MustLoadChecksums("build/checksums.txt")
|
||||||
|
tc.Root = build.DownloadGo(csdb)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, target := range keeperTargets {
|
||||||
|
log.Printf("Building keeper-%s", target.Name)
|
||||||
|
|
||||||
|
// Configure the build.
|
||||||
|
tc.GOARCH = target.GOARCH
|
||||||
|
tc.GOOS = target.GOOS
|
||||||
|
tc.CC = target.CC
|
||||||
|
gobuild := tc.Go("build", buildFlags(env, true, []string{target.Tags})...)
|
||||||
|
gobuild.Dir = "./cmd/keeper"
|
||||||
|
gobuild.Args = append(gobuild.Args, "-v")
|
||||||
|
|
||||||
|
for key, value := range target.Env {
|
||||||
|
gobuild.Env = append(gobuild.Env, key+"="+value)
|
||||||
|
}
|
||||||
|
outputName := fmt.Sprintf("keeper-%s", target.Name)
|
||||||
|
|
||||||
|
args := slices.Clone(gobuild.Args)
|
||||||
|
args = append(args, "-o", executablePath(outputName))
|
||||||
|
args = append(args, ".")
|
||||||
|
build.MustRun(&exec.Cmd{Path: gobuild.Path, Args: args, Env: gobuild.Env})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// buildFlags returns the go tool flags for building.
|
// buildFlags returns the go tool flags for building.
|
||||||
func buildFlags(env build.Environment, staticLinking bool, buildTags []string) (flags []string) {
|
func buildFlags(env build.Environment, staticLinking bool, buildTags []string) (flags []string) {
|
||||||
var ld []string
|
var ld []string
|
||||||
|
|
@ -266,12 +343,18 @@ func buildFlags(env build.Environment, staticLinking bool, buildTags []string) (
|
||||||
}
|
}
|
||||||
ld = append(ld, "-extldflags", "'"+strings.Join(extld, " ")+"'")
|
ld = append(ld, "-extldflags", "'"+strings.Join(extld, " ")+"'")
|
||||||
}
|
}
|
||||||
|
// TODO(gballet): revisit after the input api has been defined
|
||||||
|
if runtime.GOARCH == "wasm" {
|
||||||
|
ld = append(ld, "-gcflags=all=-d=softfloat")
|
||||||
|
}
|
||||||
if len(ld) > 0 {
|
if len(ld) > 0 {
|
||||||
flags = append(flags, "-ldflags", strings.Join(ld, " "))
|
flags = append(flags, "-ldflags", strings.Join(ld, " "))
|
||||||
}
|
}
|
||||||
if len(buildTags) > 0 {
|
if len(buildTags) > 0 {
|
||||||
flags = append(flags, "-tags", strings.Join(buildTags, ","))
|
flags = append(flags, "-tags", strings.Join(buildTags, ","))
|
||||||
}
|
}
|
||||||
|
// We use -trimpath to avoid leaking local paths into the built executables.
|
||||||
|
flags = append(flags, "-trimpath")
|
||||||
return flags
|
return flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -281,16 +364,15 @@ func buildFlags(env build.Environment, staticLinking bool, buildTags []string) (
|
||||||
|
|
||||||
func doTest(cmdline []string) {
|
func doTest(cmdline []string) {
|
||||||
var (
|
var (
|
||||||
dlgo = flag.Bool("dlgo", false, "Download Go and build with it")
|
dlgo = flag.Bool("dlgo", false, "Download Go and build with it")
|
||||||
arch = flag.String("arch", "", "Run tests for given architecture")
|
arch = flag.String("arch", "", "Run tests for given architecture")
|
||||||
cc = flag.String("cc", "", "Sets C compiler binary")
|
cc = flag.String("cc", "", "Sets C compiler binary")
|
||||||
coverage = flag.Bool("coverage", false, "Whether to record code coverage")
|
coverage = flag.Bool("coverage", false, "Whether to record code coverage")
|
||||||
verbose = flag.Bool("v", false, "Whether to log verbosely")
|
verbose = flag.Bool("v", false, "Whether to log verbosely")
|
||||||
race = flag.Bool("race", false, "Execute the race detector")
|
race = flag.Bool("race", false, "Execute the race detector")
|
||||||
short = flag.Bool("short", false, "Pass the 'short'-flag to go test")
|
short = flag.Bool("short", false, "Pass the 'short'-flag to go test")
|
||||||
cachedir = flag.String("cachedir", "./build/cache", "directory for caching downloads")
|
cachedir = flag.String("cachedir", "./build/cache", "directory for caching downloads")
|
||||||
skipspectests = flag.Bool("skip-spectests", false, "Skip downloading execution-spec-tests fixtures")
|
threads = flag.Int("p", 1, "Number of CPU threads to use for testing")
|
||||||
threads = flag.Int("p", 1, "Number of CPU threads to use for testing")
|
|
||||||
)
|
)
|
||||||
flag.CommandLine.Parse(cmdline)
|
flag.CommandLine.Parse(cmdline)
|
||||||
|
|
||||||
|
|
@ -298,7 +380,7 @@ func doTest(cmdline []string) {
|
||||||
csdb := download.MustLoadChecksums("build/checksums.txt")
|
csdb := download.MustLoadChecksums("build/checksums.txt")
|
||||||
|
|
||||||
// Get test fixtures.
|
// Get test fixtures.
|
||||||
if !*skipspectests {
|
if !*short {
|
||||||
downloadSpecTestFixtures(csdb, *cachedir)
|
downloadSpecTestFixtures(csdb, *cachedir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -380,9 +462,14 @@ func doCheckGenerate() {
|
||||||
)
|
)
|
||||||
pathList := []string{filepath.Join(protocPath, "bin"), protocGenGoPath, os.Getenv("PATH")}
|
pathList := []string{filepath.Join(protocPath, "bin"), protocGenGoPath, os.Getenv("PATH")}
|
||||||
|
|
||||||
|
excludes := []string{"tests/testdata", "build/cache", ".git"}
|
||||||
|
for i := range excludes {
|
||||||
|
excludes[i] = filepath.FromSlash(excludes[i])
|
||||||
|
}
|
||||||
|
|
||||||
for _, mod := range goModules {
|
for _, mod := range goModules {
|
||||||
// Compute the origin hashes of all the files
|
// Compute the origin hashes of all the files
|
||||||
hashes, err := build.HashFolder(mod, []string{"tests/testdata", "build/cache", ".git"})
|
hashes, err := build.HashFolder(mod, excludes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error computing hashes", "err", err)
|
log.Fatal("Error computing hashes", "err", err)
|
||||||
}
|
}
|
||||||
|
|
@ -392,7 +479,7 @@ func doCheckGenerate() {
|
||||||
c.Dir = mod
|
c.Dir = mod
|
||||||
build.MustRun(c)
|
build.MustRun(c)
|
||||||
// Check if generate file hashes have changed
|
// Check if generate file hashes have changed
|
||||||
generated, err := build.HashFolder(mod, []string{"tests/testdata", "build/cache", ".git"})
|
generated, err := build.HashFolder(mod, excludes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error re-computing hashes: %v", err)
|
log.Fatalf("Error re-computing hashes: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -630,6 +717,32 @@ func doArchive(cmdline []string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func doKeeperArchive(cmdline []string) {
|
||||||
|
var (
|
||||||
|
signer = flag.String("signer", "", `Environment variable holding the signing key (e.g. LINUX_SIGNING_KEY)`)
|
||||||
|
signify = flag.String("signify", "", `Environment variable holding the signify key (e.g. LINUX_SIGNIFY_KEY)`)
|
||||||
|
upload = flag.String("upload", "", `Destination to upload the archives (usually "gethstore/builds")`)
|
||||||
|
)
|
||||||
|
flag.CommandLine.Parse(cmdline)
|
||||||
|
|
||||||
|
var (
|
||||||
|
env = build.Env()
|
||||||
|
vsn = version.Archive(env.Commit)
|
||||||
|
keeper = "keeper-" + vsn + ".tar.gz"
|
||||||
|
)
|
||||||
|
maybeSkipArchive(env)
|
||||||
|
files := []string{"COPYING"}
|
||||||
|
for _, target := range keeperTargets {
|
||||||
|
files = append(files, executablePath(fmt.Sprintf("keeper-%s", target.Name)))
|
||||||
|
}
|
||||||
|
if err := build.WriteArchive(keeper, files); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := archiveUpload(keeper, *upload, *signer, *signify); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func archiveBasename(arch string, archiveVersion string) string {
|
func archiveBasename(arch string, archiveVersion string) string {
|
||||||
platform := runtime.GOOS + "-" + arch
|
platform := runtime.GOOS + "-" + arch
|
||||||
if arch == "arm" {
|
if arch == "arm" {
|
||||||
|
|
|
||||||
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
|
|
||||||
|
|
@ -121,7 +121,7 @@ with our test chain. The chain files are located in `./cmd/devp2p/internal/ethte
|
||||||
--nat=none \
|
--nat=none \
|
||||||
--networkid 3503995874084926 \
|
--networkid 3503995874084926 \
|
||||||
--verbosity 5 \
|
--verbosity 5 \
|
||||||
--authrpc.jwtsecret 0x7365637265747365637265747365637265747365637265747365637265747365
|
--authrpc.jwtsecret jwt.secret
|
||||||
|
|
||||||
Note that the tests also require access to the engine API.
|
Note that the tests also require access to the engine API.
|
||||||
The test suite can now be executed using the devp2p tool.
|
The test suite can now be executed using the devp2p tool.
|
||||||
|
|
@ -130,7 +130,7 @@ The test suite can now be executed using the devp2p tool.
|
||||||
--chain internal/ethtest/testdata \
|
--chain internal/ethtest/testdata \
|
||||||
--node enode://.... \
|
--node enode://.... \
|
||||||
--engineapi http://127.0.0.1:8551 \
|
--engineapi http://127.0.0.1:8551 \
|
||||||
--jwtsecret 0x7365637265747365637265747365637265747365637265747365637265747365
|
--jwtsecret $(cat jwt.secret)
|
||||||
|
|
||||||
Repeat the above process (re-initialising the node) in order to run the Eth Protocol test suite again.
|
Repeat the above process (re-initialising the node) in order to run the Eth Protocol test suite again.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -143,9 +143,6 @@ type testParams struct {
|
||||||
|
|
||||||
func cliTestParams(ctx *cli.Context) *testParams {
|
func cliTestParams(ctx *cli.Context) *testParams {
|
||||||
nodeStr := ctx.String(testNodeFlag.Name)
|
nodeStr := ctx.String(testNodeFlag.Name)
|
||||||
if nodeStr == "" {
|
|
||||||
exit(fmt.Errorf("missing -%s", testNodeFlag.Name))
|
|
||||||
}
|
|
||||||
node, err := parseNode(nodeStr)
|
node, err := parseNode(nodeStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit(err)
|
exit(err)
|
||||||
|
|
@ -156,14 +153,5 @@ func cliTestParams(ctx *cli.Context) *testParams {
|
||||||
jwt: ctx.String(testNodeJWTFlag.Name),
|
jwt: ctx.String(testNodeJWTFlag.Name),
|
||||||
chainDir: ctx.String(testChainDirFlag.Name),
|
chainDir: ctx.String(testChainDirFlag.Name),
|
||||||
}
|
}
|
||||||
if p.engineAPI == "" {
|
|
||||||
exit(fmt.Errorf("missing -%s", testNodeEngineFlag.Name))
|
|
||||||
}
|
|
||||||
if p.jwt == "" {
|
|
||||||
exit(fmt.Errorf("missing -%s", testNodeJWTFlag.Name))
|
|
||||||
}
|
|
||||||
if p.chainDir == "" {
|
|
||||||
exit(fmt.Errorf("missing -%s", testChainDirFlag.Name))
|
|
||||||
}
|
|
||||||
return &p
|
return &p
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,26 +39,29 @@ var (
|
||||||
}
|
}
|
||||||
|
|
||||||
// for eth/snap tests
|
// for eth/snap tests
|
||||||
testChainDirFlag = &cli.StringFlag{
|
testChainDirFlag = &cli.PathFlag{
|
||||||
Name: "chain",
|
Name: "chain",
|
||||||
Usage: "Test chain directory (required)",
|
Usage: "Test chain directory (required)",
|
||||||
Category: flags.TestingCategory,
|
Category: flags.TestingCategory,
|
||||||
|
Required: true,
|
||||||
}
|
}
|
||||||
testNodeFlag = &cli.StringFlag{
|
testNodeFlag = &cli.StringFlag{
|
||||||
Name: "node",
|
Name: "node",
|
||||||
Usage: "Peer-to-Peer endpoint (ENR) of the test node (required)",
|
Usage: "Peer-to-Peer endpoint (ENR) of the test node (required)",
|
||||||
Category: flags.TestingCategory,
|
Category: flags.TestingCategory,
|
||||||
|
Required: true,
|
||||||
}
|
}
|
||||||
testNodeJWTFlag = &cli.StringFlag{
|
testNodeJWTFlag = &cli.StringFlag{
|
||||||
Name: "jwtsecret",
|
Name: "jwtsecret",
|
||||||
Usage: "JWT secret for the engine API of the test node (required)",
|
Usage: "JWT secret for the engine API of the test node (required)",
|
||||||
Category: flags.TestingCategory,
|
Category: flags.TestingCategory,
|
||||||
Value: "0x7365637265747365637265747365637265747365637265747365637265747365",
|
Required: true,
|
||||||
}
|
}
|
||||||
testNodeEngineFlag = &cli.StringFlag{
|
testNodeEngineFlag = &cli.StringFlag{
|
||||||
Name: "engineapi",
|
Name: "engineapi",
|
||||||
Usage: "Engine API endpoint of the test node (required)",
|
Usage: "Engine API endpoint of the test node (required)",
|
||||||
Category: flags.TestingCategory,
|
Category: flags.TestingCategory,
|
||||||
|
Required: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
// These two are specific to the discovery tests.
|
// These two are specific to the discovery tests.
|
||||||
|
|
|
||||||
|
|
@ -17,16 +17,18 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/tests"
|
"github.com/ethereum/go-ethereum/tests"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
@ -34,33 +36,52 @@ import (
|
||||||
var blockTestCommand = &cli.Command{
|
var blockTestCommand = &cli.Command{
|
||||||
Action: blockTestCmd,
|
Action: blockTestCmd,
|
||||||
Name: "blocktest",
|
Name: "blocktest",
|
||||||
Usage: "Executes the given blockchain tests",
|
Usage: "Executes the given blockchain tests. Filenames can be fed via standard input (batch mode) or as an argument (one-off execution).",
|
||||||
ArgsUsage: "<path>",
|
ArgsUsage: "<path>",
|
||||||
Flags: slices.Concat([]cli.Flag{
|
Flags: slices.Concat([]cli.Flag{
|
||||||
DumpFlag,
|
DumpFlag,
|
||||||
HumanReadableFlag,
|
HumanReadableFlag,
|
||||||
RunFlag,
|
RunFlag,
|
||||||
WitnessCrossCheckFlag,
|
WitnessCrossCheckFlag,
|
||||||
|
FuzzFlag,
|
||||||
}, traceFlags),
|
}, traceFlags),
|
||||||
}
|
}
|
||||||
|
|
||||||
func blockTestCmd(ctx *cli.Context) error {
|
func blockTestCmd(ctx *cli.Context) error {
|
||||||
path := ctx.Args().First()
|
path := ctx.Args().First()
|
||||||
if len(path) == 0 {
|
|
||||||
return errors.New("path argument required")
|
// If path is provided, run the tests at that path.
|
||||||
|
if len(path) != 0 {
|
||||||
|
var (
|
||||||
|
collected = collectFiles(path)
|
||||||
|
results []testResult
|
||||||
|
)
|
||||||
|
for _, fname := range collected {
|
||||||
|
r, err := runBlockTest(ctx, fname)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
results = append(results, r...)
|
||||||
|
}
|
||||||
|
report(ctx, results)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
var (
|
// Otherwise, read filenames from stdin and execute back-to-back.
|
||||||
collected = collectFiles(path)
|
scanner := bufio.NewScanner(os.Stdin)
|
||||||
results []testResult
|
for scanner.Scan() {
|
||||||
)
|
fname := scanner.Text()
|
||||||
for _, fname := range collected {
|
if len(fname) == 0 {
|
||||||
r, err := runBlockTest(ctx, fname)
|
return nil
|
||||||
|
}
|
||||||
|
results, err := runBlockTest(ctx, fname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
results = append(results, r...)
|
// During fuzzing, we report the result after every block
|
||||||
|
if !ctx.IsSet(FuzzFlag.Name) {
|
||||||
|
report(ctx, results)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
report(ctx, results)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,6 +100,11 @@ func runBlockTest(ctx *cli.Context, fname string) ([]testResult, error) {
|
||||||
}
|
}
|
||||||
tracer := tracerFromFlags(ctx)
|
tracer := tracerFromFlags(ctx)
|
||||||
|
|
||||||
|
// Suppress INFO logs during fuzzing
|
||||||
|
if ctx.IsSet(FuzzFlag.Name) {
|
||||||
|
log.SetDefault(log.NewLogger(log.DiscardHandler()))
|
||||||
|
}
|
||||||
|
|
||||||
// Pull out keys to sort and ensure tests are run in order.
|
// Pull out keys to sort and ensure tests are run in order.
|
||||||
keys := slices.Sorted(maps.Keys(tests))
|
keys := slices.Sorted(maps.Keys(tests))
|
||||||
|
|
||||||
|
|
@ -88,16 +114,35 @@ func runBlockTest(ctx *cli.Context, fname string) ([]testResult, error) {
|
||||||
if !re.MatchString(name) {
|
if !re.MatchString(name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
test := tests[name]
|
||||||
result := &testResult{Name: name, Pass: true}
|
result := &testResult{Name: name, Pass: true}
|
||||||
if err := tests[name].Run(false, rawdb.PathScheme, ctx.Bool(WitnessCrossCheckFlag.Name), tracer, func(res error, chain *core.BlockChain) {
|
var finalRoot *common.Hash
|
||||||
|
if err := test.Run(false, rawdb.PathScheme, ctx.Bool(WitnessCrossCheckFlag.Name), tracer, func(res error, chain *core.BlockChain) {
|
||||||
if ctx.Bool(DumpFlag.Name) {
|
if ctx.Bool(DumpFlag.Name) {
|
||||||
if s, _ := chain.State(); s != nil {
|
if s, _ := chain.State(); s != nil {
|
||||||
result.State = dump(s)
|
result.State = dump(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Capture final state root for end marker
|
||||||
|
if chain != nil {
|
||||||
|
root := chain.CurrentBlock().Root
|
||||||
|
finalRoot = &root
|
||||||
|
}
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
result.Pass, result.Error = false, err.Error()
|
result.Pass, result.Error = false, err.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Always assign fork (regardless of pass/fail or tracer)
|
||||||
|
result.Fork = test.Network()
|
||||||
|
// Assign root if test succeeded
|
||||||
|
if result.Pass && finalRoot != nil {
|
||||||
|
result.Root = finalRoot
|
||||||
|
}
|
||||||
|
|
||||||
|
// When fuzzing, write results after every block
|
||||||
|
if ctx.IsSet(FuzzFlag.Name) {
|
||||||
|
report(ctx, []testResult{*result})
|
||||||
|
}
|
||||||
results = append(results, *result)
|
results = append(results, *result)
|
||||||
}
|
}
|
||||||
return results, nil
|
return results, nil
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package t8ntool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
stdmath "math"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -32,6 +33,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto/keccak"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
@ -39,12 +41,12 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/ethereum/go-ethereum/triedb"
|
"github.com/ethereum/go-ethereum/triedb"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
"golang.org/x/crypto/sha3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Prestate struct {
|
type Prestate struct {
|
||||||
Env stEnv `json:"env"`
|
Env stEnv `json:"env"`
|
||||||
Pre types.GenesisAlloc `json:"pre"`
|
Pre types.GenesisAlloc `json:"pre"`
|
||||||
|
TreeLeaves map[common.Hash]hexutil.Bytes `json:"vkt,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:generate go run github.com/fjl/gencodec -type ExecutionResult -field-override executionResultMarshaling -out gen_execresult.go
|
//go:generate go run github.com/fjl/gencodec -type ExecutionResult -field-override executionResultMarshaling -out gen_execresult.go
|
||||||
|
|
@ -142,7 +144,8 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre)
|
isEIP4762 = chainConfig.IsVerkle(big.NewInt(int64(pre.Env.Number)), pre.Env.Timestamp)
|
||||||
|
statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre, isEIP4762)
|
||||||
signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp)
|
signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp)
|
||||||
gaspool = new(core.GasPool)
|
gaspool = new(core.GasPool)
|
||||||
blockHash = common.Hash{0x13, 0x37}
|
blockHash = common.Hash{0x13, 0x37}
|
||||||
|
|
@ -301,6 +304,10 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
// Amount is in gwei, turn into wei
|
// Amount is in gwei, turn into wei
|
||||||
amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei))
|
amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei))
|
||||||
statedb.AddBalance(w.Address, uint256.MustFromBig(amount), tracing.BalanceIncreaseWithdrawal)
|
statedb.AddBalance(w.Address, uint256.MustFromBig(amount), tracing.BalanceIncreaseWithdrawal)
|
||||||
|
|
||||||
|
if isEIP4762 {
|
||||||
|
statedb.AccessEvents().AddAccount(w.Address, true, stdmath.MaxUint64)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gather the execution-layer triggered requests.
|
// Gather the execution-layer triggered requests.
|
||||||
|
|
@ -361,8 +368,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
execRs.Requests = requests
|
execRs.Requests = requests
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-create statedb instance with new root upon the updated database
|
// Re-create statedb instance with new root for MPT mode
|
||||||
// for accessing latest states.
|
|
||||||
statedb, err = state.New(root, statedb.Database())
|
statedb, err = state.New(root, statedb.Database())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not reopen state: %v", err))
|
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not reopen state: %v", err))
|
||||||
|
|
@ -371,12 +377,17 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
return statedb, execRs, body, nil
|
return statedb, execRs, body, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB {
|
func MakePreState(db ethdb.Database, accounts types.GenesisAlloc, isBintrie bool) *state.StateDB {
|
||||||
tdb := triedb.NewDatabase(db, &triedb.Config{Preimages: true})
|
tdb := triedb.NewDatabase(db, &triedb.Config{Preimages: true, IsVerkle: isBintrie})
|
||||||
sdb := state.NewDatabase(tdb, nil)
|
sdb := state.NewDatabase(tdb, nil)
|
||||||
statedb, err := state.New(types.EmptyRootHash, sdb)
|
|
||||||
|
root := types.EmptyRootHash
|
||||||
|
if isBintrie {
|
||||||
|
root = types.EmptyBinaryHash
|
||||||
|
}
|
||||||
|
statedb, err := state.New(root, sdb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("failed to create initial state: %v", err))
|
panic(fmt.Errorf("failed to create initial statedb: %v", err))
|
||||||
}
|
}
|
||||||
for addr, a := range accounts {
|
for addr, a := range accounts {
|
||||||
statedb.SetCode(addr, a.Code, tracing.CodeChangeUnspecified)
|
statedb.SetCode(addr, a.Code, tracing.CodeChangeUnspecified)
|
||||||
|
|
@ -387,10 +398,15 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Commit and re-open to start with a clean state.
|
// Commit and re-open to start with a clean state.
|
||||||
root, err := statedb.Commit(0, false, false)
|
root, err = statedb.Commit(0, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("failed to commit initial state: %v", err))
|
panic(fmt.Errorf("failed to commit initial state: %v", err))
|
||||||
}
|
}
|
||||||
|
// If bintrie mode started, check if conversion happened
|
||||||
|
if isBintrie {
|
||||||
|
return statedb
|
||||||
|
}
|
||||||
|
// For MPT mode, reopen the state with the committed root
|
||||||
statedb, err = state.New(root, sdb)
|
statedb, err = state.New(root, sdb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("failed to reopen state after commit: %v", err))
|
panic(fmt.Errorf("failed to reopen state after commit: %v", err))
|
||||||
|
|
@ -398,8 +414,8 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB
|
||||||
return statedb
|
return statedb
|
||||||
}
|
}
|
||||||
|
|
||||||
func rlpHash(x interface{}) (h common.Hash) {
|
func rlpHash(x any) (h common.Hash) {
|
||||||
hw := sha3.NewLegacyKeccak256()
|
hw := keccak.NewLegacyKeccak256()
|
||||||
rlp.Encode(hw, x)
|
rlp.Encode(hw, x)
|
||||||
hw.Sum(h[:0])
|
hw.Sum(h[:0])
|
||||||
return h
|
return h
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,14 @@ var (
|
||||||
"\t<file> - into the file <file> ",
|
"\t<file> - into the file <file> ",
|
||||||
Value: "block.json",
|
Value: "block.json",
|
||||||
}
|
}
|
||||||
|
OutputBTFlag = &cli.StringFlag{
|
||||||
|
Name: "output.vkt",
|
||||||
|
Usage: "Determines where to put the `BT` of the post-state.\n" +
|
||||||
|
"\t`stdout` - into the stdout output\n" +
|
||||||
|
"\t`stderr` - into the stderr output\n" +
|
||||||
|
"\t<file> - into the file <file> ",
|
||||||
|
Value: "vkt.json",
|
||||||
|
}
|
||||||
InputAllocFlag = &cli.StringFlag{
|
InputAllocFlag = &cli.StringFlag{
|
||||||
Name: "input.alloc",
|
Name: "input.alloc",
|
||||||
Usage: "`stdin` or file name of where to find the prestate alloc to use.",
|
Usage: "`stdin` or file name of where to find the prestate alloc to use.",
|
||||||
|
|
@ -123,6 +131,11 @@ var (
|
||||||
Usage: "`stdin` or file name of where to find the transactions list in RLP form.",
|
Usage: "`stdin` or file name of where to find the transactions list in RLP form.",
|
||||||
Value: "txs.rlp",
|
Value: "txs.rlp",
|
||||||
}
|
}
|
||||||
|
// TODO(@CPerezz): rename `Name` of the file in a follow-up PR (relays on EEST -> https://github.com/ethereum/execution-spec-tests/tree/verkle/main)
|
||||||
|
InputBTFlag = &cli.StringFlag{
|
||||||
|
Name: "input.vkt",
|
||||||
|
Usage: "`stdin` or file name of where to find the prestate BT.",
|
||||||
|
}
|
||||||
SealCliqueFlag = &cli.StringFlag{
|
SealCliqueFlag = &cli.StringFlag{
|
||||||
Name: "seal.clique",
|
Name: "seal.clique",
|
||||||
Usage: "Seal block with Clique. `stdin` or file name of where to find the Clique sealing data.",
|
Usage: "Seal block with Clique. `stdin` or file name of where to find the Clique sealing data.",
|
||||||
|
|
|
||||||
|
|
@ -28,15 +28,22 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
|
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/tests"
|
"github.com/ethereum/go-ethereum/tests"
|
||||||
|
"github.com/ethereum/go-ethereum/trie/bintrie"
|
||||||
|
"github.com/ethereum/go-ethereum/triedb"
|
||||||
|
"github.com/ethereum/go-ethereum/triedb/database"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -75,10 +82,11 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type input struct {
|
type input struct {
|
||||||
Alloc types.GenesisAlloc `json:"alloc,omitempty"`
|
Alloc types.GenesisAlloc `json:"alloc,omitempty"`
|
||||||
Env *stEnv `json:"env,omitempty"`
|
Env *stEnv `json:"env,omitempty"`
|
||||||
Txs []*txWithKey `json:"txs,omitempty"`
|
BT map[common.Hash]hexutil.Bytes `json:"vkt,omitempty"`
|
||||||
TxRlp string `json:"txsRlp,omitempty"`
|
Txs []*txWithKey `json:"txs,omitempty"`
|
||||||
|
TxRlp string `json:"txsRlp,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func Transition(ctx *cli.Context) error {
|
func Transition(ctx *cli.Context) error {
|
||||||
|
|
@ -90,16 +98,16 @@ func Transition(ctx *cli.Context) error {
|
||||||
// stdin input or in files.
|
// stdin input or in files.
|
||||||
// Check if anything needs to be read from stdin
|
// Check if anything needs to be read from stdin
|
||||||
var (
|
var (
|
||||||
prestate Prestate
|
prestate Prestate
|
||||||
txIt txIterator // txs to apply
|
txIt txIterator // txs to apply
|
||||||
allocStr = ctx.String(InputAllocFlag.Name)
|
allocStr = ctx.String(InputAllocFlag.Name)
|
||||||
|
btStr = ctx.String(InputBTFlag.Name)
|
||||||
envStr = ctx.String(InputEnvFlag.Name)
|
envStr = ctx.String(InputEnvFlag.Name)
|
||||||
txStr = ctx.String(InputTxsFlag.Name)
|
txStr = ctx.String(InputTxsFlag.Name)
|
||||||
inputData = &input{}
|
inputData = &input{}
|
||||||
)
|
)
|
||||||
// Figure out the prestate alloc
|
// Figure out the prestate alloc
|
||||||
if allocStr == stdinSelector || envStr == stdinSelector || txStr == stdinSelector {
|
if allocStr == stdinSelector || btStr == stdinSelector || envStr == stdinSelector || txStr == stdinSelector {
|
||||||
decoder := json.NewDecoder(os.Stdin)
|
decoder := json.NewDecoder(os.Stdin)
|
||||||
if err := decoder.Decode(inputData); err != nil {
|
if err := decoder.Decode(inputData); err != nil {
|
||||||
return NewError(ErrorJson, fmt.Errorf("failed unmarshalling stdin: %v", err))
|
return NewError(ErrorJson, fmt.Errorf("failed unmarshalling stdin: %v", err))
|
||||||
|
|
@ -112,6 +120,13 @@ func Transition(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
prestate.Pre = inputData.Alloc
|
prestate.Pre = inputData.Alloc
|
||||||
|
|
||||||
|
if btStr != stdinSelector && btStr != "" {
|
||||||
|
if err := readFile(btStr, "BT", &inputData.BT); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prestate.TreeLeaves = inputData.BT
|
||||||
|
|
||||||
// Set the block environment
|
// Set the block environment
|
||||||
if envStr != stdinSelector {
|
if envStr != stdinSelector {
|
||||||
var env stEnv
|
var env stEnv
|
||||||
|
|
@ -182,9 +197,21 @@ func Transition(ctx *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Dump the execution result
|
// Dump the execution result
|
||||||
collector := make(Alloc)
|
var (
|
||||||
s.DumpToCollector(collector, nil)
|
collector = make(Alloc)
|
||||||
return dispatchOutput(ctx, baseDir, result, collector, body)
|
btleaves map[common.Hash]hexutil.Bytes
|
||||||
|
)
|
||||||
|
isBinary := chainConfig.IsVerkle(big.NewInt(int64(prestate.Env.Number)), prestate.Env.Timestamp)
|
||||||
|
if !isBinary {
|
||||||
|
s.DumpToCollector(collector, nil)
|
||||||
|
} else {
|
||||||
|
btleaves = make(map[common.Hash]hexutil.Bytes)
|
||||||
|
if err := s.DumpBinTrieLeaves(btleaves); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dispatchOutput(ctx, baseDir, result, collector, body, btleaves)
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyLondonChecks(env *stEnv, chainConfig *params.ChainConfig) error {
|
func applyLondonChecks(env *stEnv, chainConfig *params.ChainConfig) error {
|
||||||
|
|
@ -306,7 +333,7 @@ func saveFile(baseDir, filename string, data interface{}) error {
|
||||||
|
|
||||||
// dispatchOutput writes the output data to either stderr or stdout, or to the specified
|
// dispatchOutput writes the output data to either stderr or stdout, or to the specified
|
||||||
// files
|
// files
|
||||||
func dispatchOutput(ctx *cli.Context, baseDir string, result *ExecutionResult, alloc Alloc, body hexutil.Bytes) error {
|
func dispatchOutput(ctx *cli.Context, baseDir string, result *ExecutionResult, alloc Alloc, body hexutil.Bytes, bt map[common.Hash]hexutil.Bytes) error {
|
||||||
stdOutObject := make(map[string]interface{})
|
stdOutObject := make(map[string]interface{})
|
||||||
stdErrObject := make(map[string]interface{})
|
stdErrObject := make(map[string]interface{})
|
||||||
dispatch := func(baseDir, fName, name string, obj interface{}) error {
|
dispatch := func(baseDir, fName, name string, obj interface{}) error {
|
||||||
|
|
@ -333,6 +360,13 @@ func dispatchOutput(ctx *cli.Context, baseDir string, result *ExecutionResult, a
|
||||||
if err := dispatch(baseDir, ctx.String(OutputBodyFlag.Name), "body", body); err != nil {
|
if err := dispatch(baseDir, ctx.String(OutputBodyFlag.Name), "body", body); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// Only write bt output if we actually have binary trie leaves
|
||||||
|
if bt != nil {
|
||||||
|
if err := dispatch(baseDir, ctx.String(OutputBTFlag.Name), "vkt", bt); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(stdOutObject) > 0 {
|
if len(stdOutObject) > 0 {
|
||||||
b, err := json.MarshalIndent(stdOutObject, "", " ")
|
b, err := json.MarshalIndent(stdOutObject, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -351,3 +385,168 @@ func dispatchOutput(ctx *cli.Context, baseDir string, result *ExecutionResult, a
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BinKey computes the tree key given an address and an optional slot number.
|
||||||
|
func BinKey(ctx *cli.Context) error {
|
||||||
|
if ctx.Args().Len() == 0 || ctx.Args().Len() > 2 {
|
||||||
|
return errors.New("invalid number of arguments: expecting an address and an optional slot number")
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := hexutil.Decode(ctx.Args().Get(0))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error decoding address: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.Args().Len() == 2 {
|
||||||
|
slot, err := hexutil.Decode(ctx.Args().Get(1))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error decoding slot: %w", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("%#x\n", bintrie.GetBinaryTreeKeyStorageSlot(common.BytesToAddress(addr), slot))
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%#x\n", bintrie.GetBinaryTreeKeyBasicData(common.BytesToAddress(addr)))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BinKeys computes a set of tree keys given a genesis alloc.
|
||||||
|
func BinKeys(ctx *cli.Context) error {
|
||||||
|
var allocStr = ctx.String(InputAllocFlag.Name)
|
||||||
|
var alloc core.GenesisAlloc
|
||||||
|
// Figure out the prestate alloc
|
||||||
|
if allocStr == stdinSelector {
|
||||||
|
decoder := json.NewDecoder(os.Stdin)
|
||||||
|
if err := decoder.Decode(&alloc); err != nil {
|
||||||
|
return NewError(ErrorJson, fmt.Errorf("failed unmarshaling stdin: %v", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if allocStr != stdinSelector {
|
||||||
|
if err := readFile(allocStr, "alloc", &alloc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
db := triedb.NewDatabase(rawdb.NewMemoryDatabase(), triedb.VerkleDefaults)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
bt, err := genBinTrieFromAlloc(alloc, db)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error generating bt: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
collector := make(map[common.Hash]hexutil.Bytes)
|
||||||
|
it, err := bt.NodeIterator(nil)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
for it.Next(true) {
|
||||||
|
if it.Leaf() {
|
||||||
|
collector[common.BytesToHash(it.LeafKey())] = it.LeafBlob()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := json.MarshalIndent(collector, "", "")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error outputting tree: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(output))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BinTrieRoot computes the root of a Binary Trie from a genesis alloc.
|
||||||
|
func BinTrieRoot(ctx *cli.Context) error {
|
||||||
|
var allocStr = ctx.String(InputAllocFlag.Name)
|
||||||
|
var alloc core.GenesisAlloc
|
||||||
|
if allocStr == stdinSelector {
|
||||||
|
decoder := json.NewDecoder(os.Stdin)
|
||||||
|
if err := decoder.Decode(&alloc); err != nil {
|
||||||
|
return NewError(ErrorJson, fmt.Errorf("failed unmarshaling stdin: %v", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if allocStr != stdinSelector {
|
||||||
|
if err := readFile(allocStr, "alloc", &alloc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
db := triedb.NewDatabase(rawdb.NewMemoryDatabase(), triedb.VerkleDefaults)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
bt, err := genBinTrieFromAlloc(alloc, db)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error generating bt: %w", err)
|
||||||
|
}
|
||||||
|
fmt.Println(bt.Hash().Hex())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(@CPerezz): Should this go to `bintrie` module?
|
||||||
|
func genBinTrieFromAlloc(alloc core.GenesisAlloc, db database.NodeDatabase) (*bintrie.BinaryTrie, error) {
|
||||||
|
bt, err := bintrie.NewBinaryTrie(types.EmptyBinaryHash, db)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for addr, acc := range alloc {
|
||||||
|
for slot, value := range acc.Storage {
|
||||||
|
err := bt.UpdateStorage(addr, slot.Bytes(), value.Big().Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error inserting storage: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
account := &types.StateAccount{
|
||||||
|
Balance: uint256.MustFromBig(acc.Balance),
|
||||||
|
Nonce: acc.Nonce,
|
||||||
|
CodeHash: crypto.Keccak256Hash(acc.Code).Bytes(),
|
||||||
|
Root: common.Hash{},
|
||||||
|
}
|
||||||
|
err := bt.UpdateAccount(addr, account, len(acc.Code))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error inserting account: %w", err)
|
||||||
|
}
|
||||||
|
err = bt.UpdateContractCode(addr, common.BytesToHash(account.CodeHash), acc.Code)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error inserting code: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BinaryCodeChunkKey computes the tree key of a code-chunk for a given address.
|
||||||
|
func BinaryCodeChunkKey(ctx *cli.Context) error {
|
||||||
|
if ctx.Args().Len() == 0 || ctx.Args().Len() > 2 {
|
||||||
|
return errors.New("invalid number of arguments: expecting an address and an code-chunk number")
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := hexutil.Decode(ctx.Args().Get(0))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error decoding address: %w", err)
|
||||||
|
}
|
||||||
|
chunkNumberBytes, err := hexutil.Decode(ctx.Args().Get(1))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error decoding chunk number: %w", err)
|
||||||
|
}
|
||||||
|
var chunkNumber uint256.Int
|
||||||
|
chunkNumber.SetBytes(chunkNumberBytes)
|
||||||
|
|
||||||
|
fmt.Printf("%#x\n", bintrie.GetBinaryTreeKeyCodeChunk(common.BytesToAddress(addr), &chunkNumber))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BinaryCodeChunkCode returns the code chunkification for a given code.
|
||||||
|
func BinaryCodeChunkCode(ctx *cli.Context) error {
|
||||||
|
if ctx.Args().Len() == 0 || ctx.Args().Len() > 1 {
|
||||||
|
return errors.New("invalid number of arguments: expecting a bytecode")
|
||||||
|
}
|
||||||
|
|
||||||
|
bytecode, err := hexutil.Decode(ctx.Args().Get(0))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error decoding address: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
chunkedCode := bintrie.ChunkifyCode(bytecode)
|
||||||
|
fmt.Printf("%#x\n", chunkedCode)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,11 @@ var (
|
||||||
Usage: "benchmark the execution",
|
Usage: "benchmark the execution",
|
||||||
Category: flags.VMCategory,
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
|
FuzzFlag = &cli.BoolFlag{
|
||||||
|
Name: "fuzz",
|
||||||
|
Usage: "adapts output format for fuzzing",
|
||||||
|
Category: flags.VMCategory,
|
||||||
|
}
|
||||||
WitnessCrossCheckFlag = &cli.BoolFlag{
|
WitnessCrossCheckFlag = &cli.BoolFlag{
|
||||||
Name: "cross-check",
|
Name: "cross-check",
|
||||||
Aliases: []string{"xc"},
|
Aliases: []string{"xc"},
|
||||||
|
|
@ -146,16 +151,63 @@ var (
|
||||||
t8ntool.TraceEnableCallFramesFlag,
|
t8ntool.TraceEnableCallFramesFlag,
|
||||||
t8ntool.OutputBasedir,
|
t8ntool.OutputBasedir,
|
||||||
t8ntool.OutputAllocFlag,
|
t8ntool.OutputAllocFlag,
|
||||||
|
t8ntool.OutputBTFlag,
|
||||||
t8ntool.OutputResultFlag,
|
t8ntool.OutputResultFlag,
|
||||||
t8ntool.OutputBodyFlag,
|
t8ntool.OutputBodyFlag,
|
||||||
t8ntool.InputAllocFlag,
|
t8ntool.InputAllocFlag,
|
||||||
t8ntool.InputEnvFlag,
|
t8ntool.InputEnvFlag,
|
||||||
|
t8ntool.InputBTFlag,
|
||||||
t8ntool.InputTxsFlag,
|
t8ntool.InputTxsFlag,
|
||||||
t8ntool.ForknameFlag,
|
t8ntool.ForknameFlag,
|
||||||
t8ntool.ChainIDFlag,
|
t8ntool.ChainIDFlag,
|
||||||
t8ntool.RewardFlag,
|
t8ntool.RewardFlag,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
verkleCommand = &cli.Command{
|
||||||
|
Name: "verkle",
|
||||||
|
Aliases: []string{"vkt"},
|
||||||
|
Usage: "Binary Trie helpers",
|
||||||
|
Subcommands: []*cli.Command{
|
||||||
|
{
|
||||||
|
Name: "tree-keys",
|
||||||
|
Aliases: []string{"v"},
|
||||||
|
Usage: "compute a set of binary trie keys, given their source addresses and optional slot numbers",
|
||||||
|
Action: t8ntool.BinKeys,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
t8ntool.InputAllocFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "single-key",
|
||||||
|
Aliases: []string{"vk"},
|
||||||
|
Usage: "compute the binary trie key given an address and optional slot number",
|
||||||
|
Action: t8ntool.BinKey,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "code-chunk-key",
|
||||||
|
Aliases: []string{"vck"},
|
||||||
|
Usage: "compute the binary trie key given an address and chunk number",
|
||||||
|
Action: t8ntool.BinaryCodeChunkKey,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "chunkify-code",
|
||||||
|
Aliases: []string{"vcc"},
|
||||||
|
Usage: "chunkify a given bytecode for a binary trie",
|
||||||
|
Action: t8ntool.BinaryCodeChunkCode,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "state-root",
|
||||||
|
Aliases: []string{"vsr"},
|
||||||
|
Usage: "compute the state-root of a binary trie for the given alloc",
|
||||||
|
Action: t8ntool.BinTrieRoot,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
t8ntool.InputAllocFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
transactionCommand = &cli.Command{
|
transactionCommand = &cli.Command{
|
||||||
Name: "transaction",
|
Name: "transaction",
|
||||||
Aliases: []string{"t9n"},
|
Aliases: []string{"t9n"},
|
||||||
|
|
@ -210,6 +262,7 @@ func init() {
|
||||||
stateTransitionCommand,
|
stateTransitionCommand,
|
||||||
transactionCommand,
|
transactionCommand,
|
||||||
blockBuilderCommand,
|
blockBuilderCommand,
|
||||||
|
verkleCommand,
|
||||||
}
|
}
|
||||||
app.Before = func(ctx *cli.Context) error {
|
app.Before = func(ctx *cli.Context) error {
|
||||||
flags.MigrateGlobalFlags(ctx)
|
flags.MigrateGlobalFlags(ctx)
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,7 @@ if one is set. Otherwise it prints the genesis from the datadir.`,
|
||||||
utils.CacheNoPrefetchFlag,
|
utils.CacheNoPrefetchFlag,
|
||||||
utils.CachePreimagesFlag,
|
utils.CachePreimagesFlag,
|
||||||
utils.NoCompactionFlag,
|
utils.NoCompactionFlag,
|
||||||
|
utils.LogSlowBlockFlag,
|
||||||
utils.MetricsEnabledFlag,
|
utils.MetricsEnabledFlag,
|
||||||
utils.MetricsEnabledExpensiveFlag,
|
utils.MetricsEnabledExpensiveFlag,
|
||||||
utils.MetricsHTTPFlag,
|
utils.MetricsHTTPFlag,
|
||||||
|
|
@ -119,6 +120,8 @@ if one is set. Otherwise it prints the genesis from the datadir.`,
|
||||||
utils.LogNoHistoryFlag,
|
utils.LogNoHistoryFlag,
|
||||||
utils.LogExportCheckpointsFlag,
|
utils.LogExportCheckpointsFlag,
|
||||||
utils.StateHistoryFlag,
|
utils.StateHistoryFlag,
|
||||||
|
utils.TrienodeHistoryFlag,
|
||||||
|
utils.TrienodeHistoryFullValueCheckpointFlag,
|
||||||
}, utils.DatabaseFlags, debug.Flags),
|
}, utils.DatabaseFlags, debug.Flags),
|
||||||
Before: func(ctx *cli.Context) error {
|
Before: func(ctx *cli.Context) error {
|
||||||
flags.MigrateGlobalFlags(ctx)
|
flags.MigrateGlobalFlags(ctx)
|
||||||
|
|
@ -295,7 +298,7 @@ func initGenesis(ctx *cli.Context) error {
|
||||||
triedb := utils.MakeTrieDatabase(ctx, stack, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false, genesis.IsVerkle())
|
triedb := utils.MakeTrieDatabase(ctx, stack, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false, genesis.IsVerkle())
|
||||||
defer triedb.Close()
|
defer triedb.Close()
|
||||||
|
|
||||||
_, hash, compatErr, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides)
|
_, hash, compatErr, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Failed to write genesis block: %v", err)
|
utils.Fatalf("Failed to write genesis block: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/beacon/blsync"
|
"github.com/ethereum/go-ethereum/beacon/blsync"
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth/catalyst"
|
"github.com/ethereum/go-ethereum/eth/catalyst"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
|
|
@ -273,11 +272,11 @@ func makeFullNode(ctx *cli.Context) *node.Node {
|
||||||
// Configure synchronization override service
|
// Configure synchronization override service
|
||||||
var synctarget common.Hash
|
var synctarget common.Hash
|
||||||
if ctx.IsSet(utils.SyncTargetFlag.Name) {
|
if ctx.IsSet(utils.SyncTargetFlag.Name) {
|
||||||
hex := hexutil.MustDecode(ctx.String(utils.SyncTargetFlag.Name))
|
target := ctx.String(utils.SyncTargetFlag.Name)
|
||||||
if len(hex) != common.HashLength {
|
if !common.IsHexHash(target) {
|
||||||
utils.Fatalf("invalid sync target length: have %d, want %d", len(hex), common.HashLength)
|
utils.Fatalf("sync target hash is not a valid hex hash: %s", target)
|
||||||
}
|
}
|
||||||
synctarget = common.BytesToHash(hex)
|
synctarget = common.HexToHash(target)
|
||||||
}
|
}
|
||||||
utils.RegisterSyncOverrideService(stack, eth, synctarget, ctx.Bool(utils.ExitWhenSyncedFlag.Name))
|
utils.RegisterSyncOverrideService(stack, eth, synctarget, ctx.Bool(utils.ExitWhenSyncedFlag.Name))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,9 @@ const (
|
||||||
// child g gets a temporary data directory.
|
// child g gets a temporary data directory.
|
||||||
func runMinimalGeth(t *testing.T, args ...string) *testgeth {
|
func runMinimalGeth(t *testing.T, args ...string) *testgeth {
|
||||||
// --holesky to make the 'writing genesis to disk' faster (no accounts)
|
// --holesky to make the 'writing genesis to disk' faster (no accounts)
|
||||||
|
// --networkid=1337 to avoid cache bump
|
||||||
// --syncmode=full to avoid allocating fast sync bloom
|
// --syncmode=full to avoid allocating fast sync bloom
|
||||||
allArgs := []string{"--holesky", "--authrpc.port", "0", "--syncmode=full", "--port", "0",
|
allArgs := []string{"--holesky", "--networkid", "1337", "--authrpc.port", "0", "--syncmode=full", "--port", "0",
|
||||||
"--nat", "none", "--nodiscover", "--maxpeers", "0", "--cache", "64",
|
"--nat", "none", "--nodiscover", "--maxpeers", "0", "--cache", "64",
|
||||||
"--datadir.minfreedisk", "0"}
|
"--datadir.minfreedisk", "0"}
|
||||||
return runGeth(t, append(allArgs, args...)...)
|
return runGeth(t, append(allArgs, args...)...)
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/ethereum/go-ethereum/triedb"
|
"github.com/ethereum/go-ethereum/triedb"
|
||||||
"github.com/olekukonko/tablewriter"
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -760,7 +759,7 @@ func showMetaData(ctx *cli.Context) error {
|
||||||
data = append(data, []string{"headHeader.Root", fmt.Sprintf("%v", h.Root)})
|
data = append(data, []string{"headHeader.Root", fmt.Sprintf("%v", h.Root)})
|
||||||
data = append(data, []string{"headHeader.Number", fmt.Sprintf("%d (%#x)", h.Number, h.Number)})
|
data = append(data, []string{"headHeader.Number", fmt.Sprintf("%d (%#x)", h.Number, h.Number)})
|
||||||
}
|
}
|
||||||
table := tablewriter.NewWriter(os.Stdout)
|
table := rawdb.NewTableWriter(os.Stdout)
|
||||||
table.SetHeader([]string{"Field", "Value"})
|
table.SetHeader([]string{"Field", "Value"})
|
||||||
table.AppendBulk(data)
|
table.AppendBulk(data)
|
||||||
table.Render()
|
table.Render()
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ var (
|
||||||
utils.OverrideBPO1,
|
utils.OverrideBPO1,
|
||||||
utils.OverrideBPO2,
|
utils.OverrideBPO2,
|
||||||
utils.OverrideVerkle,
|
utils.OverrideVerkle,
|
||||||
|
utils.OverrideGenesisFlag,
|
||||||
utils.EnablePersonal, // deprecated
|
utils.EnablePersonal, // deprecated
|
||||||
utils.TxPoolLocalsFlag,
|
utils.TxPoolLocalsFlag,
|
||||||
utils.TxPoolNoLocalsFlag,
|
utils.TxPoolNoLocalsFlag,
|
||||||
|
|
@ -93,6 +94,8 @@ var (
|
||||||
utils.LogNoHistoryFlag,
|
utils.LogNoHistoryFlag,
|
||||||
utils.LogExportCheckpointsFlag,
|
utils.LogExportCheckpointsFlag,
|
||||||
utils.StateHistoryFlag,
|
utils.StateHistoryFlag,
|
||||||
|
utils.TrienodeHistoryFlag,
|
||||||
|
utils.TrienodeHistoryFullValueCheckpointFlag,
|
||||||
utils.LightKDFFlag,
|
utils.LightKDFFlag,
|
||||||
utils.EthRequiredBlocksFlag,
|
utils.EthRequiredBlocksFlag,
|
||||||
utils.LegacyWhitelistFlag, // deprecated
|
utils.LegacyWhitelistFlag, // deprecated
|
||||||
|
|
@ -117,6 +120,7 @@ var (
|
||||||
utils.MinerGasPriceFlag,
|
utils.MinerGasPriceFlag,
|
||||||
utils.MinerEtherbaseFlag, // deprecated
|
utils.MinerEtherbaseFlag, // deprecated
|
||||||
utils.MinerExtraDataFlag,
|
utils.MinerExtraDataFlag,
|
||||||
|
utils.MinerMaxBlobsFlag,
|
||||||
utils.MinerRecommitIntervalFlag,
|
utils.MinerRecommitIntervalFlag,
|
||||||
utils.MinerPendingFeeRecipientFlag,
|
utils.MinerPendingFeeRecipientFlag,
|
||||||
utils.MinerNewPayloadTimeoutFlag, // deprecated
|
utils.MinerNewPayloadTimeoutFlag, // deprecated
|
||||||
|
|
@ -155,6 +159,7 @@ var (
|
||||||
utils.BeaconGenesisTimeFlag,
|
utils.BeaconGenesisTimeFlag,
|
||||||
utils.BeaconCheckpointFlag,
|
utils.BeaconCheckpointFlag,
|
||||||
utils.BeaconCheckpointFileFlag,
|
utils.BeaconCheckpointFileFlag,
|
||||||
|
utils.LogSlowBlockFlag,
|
||||||
}, utils.NetworkFlags, utils.DatabaseFlags)
|
}, utils.NetworkFlags, utils.DatabaseFlags)
|
||||||
|
|
||||||
rpcFlags = []cli.Flag{
|
rpcFlags = []cli.Flag{
|
||||||
|
|
@ -190,6 +195,7 @@ var (
|
||||||
utils.BatchResponseMaxSize,
|
utils.BatchResponseMaxSize,
|
||||||
utils.RPCTxSyncDefaultTimeoutFlag,
|
utils.RPCTxSyncDefaultTimeoutFlag,
|
||||||
utils.RPCTxSyncMaxTimeoutFlag,
|
utils.RPCTxSyncMaxTimeoutFlag,
|
||||||
|
utils.RPCGlobalRangeLimitFlag,
|
||||||
}
|
}
|
||||||
|
|
||||||
metricsFlags = []cli.Flag{
|
metricsFlags = []cli.Flag{
|
||||||
|
|
@ -238,7 +244,6 @@ func init() {
|
||||||
javascriptCommand,
|
javascriptCommand,
|
||||||
// See misccmd.go:
|
// See misccmd.go:
|
||||||
versionCommand,
|
versionCommand,
|
||||||
versionCheckCommand,
|
|
||||||
licenseCommand,
|
licenseCommand,
|
||||||
// See config.go
|
// See config.go
|
||||||
dumpConfigCommand,
|
dumpConfigCommand,
|
||||||
|
|
@ -248,8 +253,6 @@ func init() {
|
||||||
utils.ShowDeprecated,
|
utils.ShowDeprecated,
|
||||||
// See snapshot.go
|
// See snapshot.go
|
||||||
snapshotCommand,
|
snapshotCommand,
|
||||||
// See verkle.go
|
|
||||||
verkleCommand,
|
|
||||||
}
|
}
|
||||||
if logTestCommand != nil {
|
if logTestCommand != nil {
|
||||||
app.Commands = append(app.Commands, logTestCommand)
|
app.Commands = append(app.Commands, logTestCommand)
|
||||||
|
|
|
||||||
|
|
@ -27,16 +27,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
VersionCheckUrlFlag = &cli.StringFlag{
|
|
||||||
Name: "check.url",
|
|
||||||
Usage: "URL to use when checking vulnerabilities",
|
|
||||||
Value: "https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities.json",
|
|
||||||
}
|
|
||||||
VersionCheckVersionFlag = &cli.StringFlag{
|
|
||||||
Name: "check.version",
|
|
||||||
Usage: "Version to check",
|
|
||||||
Value: version.ClientName(clientIdentifier),
|
|
||||||
}
|
|
||||||
versionCommand = &cli.Command{
|
versionCommand = &cli.Command{
|
||||||
Action: printVersion,
|
Action: printVersion,
|
||||||
Name: "version",
|
Name: "version",
|
||||||
|
|
@ -44,20 +34,6 @@ var (
|
||||||
ArgsUsage: " ",
|
ArgsUsage: " ",
|
||||||
Description: `
|
Description: `
|
||||||
The output of this command is supposed to be machine-readable.
|
The output of this command is supposed to be machine-readable.
|
||||||
`,
|
|
||||||
}
|
|
||||||
versionCheckCommand = &cli.Command{
|
|
||||||
Action: versionCheck,
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
VersionCheckUrlFlag,
|
|
||||||
VersionCheckVersionFlag,
|
|
||||||
},
|
|
||||||
Name: "version-check",
|
|
||||||
Usage: "Checks (online) for known Geth security vulnerabilities",
|
|
||||||
ArgsUsage: "<versionstring (optional)>",
|
|
||||||
Description: `
|
|
||||||
The version-check command fetches vulnerability-information from https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities.json,
|
|
||||||
and displays information about any security vulnerabilities that affect the currently executing version.
|
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
licenseCommand = &cli.Command{
|
licenseCommand = &cli.Command{
|
||||||
|
|
|
||||||
|
|
@ -639,11 +639,11 @@ func snapshotExportPreimages(ctx *cli.Context) error {
|
||||||
|
|
||||||
var root common.Hash
|
var root common.Hash
|
||||||
if ctx.NArg() > 1 {
|
if ctx.NArg() > 1 {
|
||||||
rootBytes := common.FromHex(ctx.Args().Get(1))
|
hash := ctx.Args().Get(1)
|
||||||
if len(rootBytes) != common.HashLength {
|
if !common.IsHexHash(hash) {
|
||||||
return fmt.Errorf("invalid hash: %s", ctx.Args().Get(1))
|
return fmt.Errorf("invalid hash: %s", ctx.Args().Get(1))
|
||||||
}
|
}
|
||||||
root = common.BytesToHash(rootBytes)
|
root = common.HexToHash(hash)
|
||||||
} else {
|
} else {
|
||||||
headBlock := rawdb.ReadHeadBlock(chaindb)
|
headBlock := rawdb.ReadHeadBlock(chaindb)
|
||||||
if headBlock == nil {
|
if headBlock == nil {
|
||||||
|
|
|
||||||
202
cmd/geth/testdata/vcheck/data.json
vendored
202
cmd/geth/testdata/vcheck/data.json
vendored
|
|
@ -1,202 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"name": "CorruptedDAG",
|
|
||||||
"uid": "GETH-2020-01",
|
|
||||||
"summary": "Mining nodes will generate erroneous PoW on epochs > `385`.",
|
|
||||||
"description": "A mining flaw could cause miners to erroneously calculate PoW, due to an index overflow, if DAG size is exceeding the maximum 32 bit unsigned value.\n\nThis occurred on the ETC chain on 2020-11-06. This is likely to trigger for ETH mainnet around block `11550000`/epoch `385`, slated to occur early January 2021.\n\nThis issue is relevant only for miners, non-mining nodes are unaffected, since non-mining nodes use a smaller verification cache instead of a full DAG.",
|
|
||||||
"links": [
|
|
||||||
"https://github.com/ethereum/go-ethereum/pull/21793",
|
|
||||||
"https://blog.ethereum.org/2020/11/12/geth-security-release",
|
|
||||||
"https://github.com/ethereum/go-ethereum/commit/567d41d9363706b4b13ce0903804e8acf214af49",
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-v592-xf75-856p"
|
|
||||||
],
|
|
||||||
"introduced": "v1.6.0",
|
|
||||||
"fixed": "v1.9.24",
|
|
||||||
"published": "2020-11-12",
|
|
||||||
"severity": "Medium",
|
|
||||||
"CVE": "CVE-2020-26240",
|
|
||||||
"check": "Geth\\/v1\\.(6|7|8)\\..*|Geth\\/v1\\.9\\.\\d-.*|Geth\\/v1\\.9\\.1.*|Geth\\/v1\\.9\\.2(0|1|2|3)-.*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Denial of service due to Go CVE-2020-28362",
|
|
||||||
"uid": "GETH-2020-02",
|
|
||||||
"summary": "A denial-of-service issue can be used to crash Geth nodes during block processing, due to an underlying bug in Go (CVE-2020-28362) versions < `1.15.5`, or `<1.14.12`",
|
|
||||||
"description": "The DoS issue can be used to crash all Geth nodes during block processing, the effects of which would be that a major part of the Ethereum network went offline.\n\nOutside of Go-Ethereum, the issue is most likely relevant for all forks of Geth (such as TurboGeth or ETC’s core-geth) which is built with versions of Go which contains the vulnerability.",
|
|
||||||
"links": [
|
|
||||||
"https://blog.ethereum.org/2020/11/12/geth-security-release",
|
|
||||||
"https://groups.google.com/g/golang-announce/c/NpBGTTmKzpM",
|
|
||||||
"https://github.com/golang/go/issues/42552",
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-m6gx-rhvj-fh52"
|
|
||||||
],
|
|
||||||
"introduced": "v0.0.0",
|
|
||||||
"fixed": "v1.9.24",
|
|
||||||
"published": "2020-11-12",
|
|
||||||
"severity": "Critical",
|
|
||||||
"CVE": "CVE-2020-28362",
|
|
||||||
"check": "Geth.*\\/go1\\.(11(.*)|12(.*)|13(.*)|14|14\\.(\\d|10|11|)|15|15\\.[0-4])$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ShallowCopy",
|
|
||||||
"uid": "GETH-2020-03",
|
|
||||||
"summary": "A consensus flaw in Geth, related to `datacopy` precompile",
|
|
||||||
"description": "Geth erroneously performed a 'shallow' copy when the precompiled `datacopy` (at `0x00...04`) was invoked. An attacker could deploy a contract that uses the shallow copy to corrupt the contents of the `RETURNDATA`, thus causing a consensus failure.",
|
|
||||||
"links": [
|
|
||||||
"https://blog.ethereum.org/2020/11/12/geth-security-release",
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-69v6-xc2j-r2jf"
|
|
||||||
],
|
|
||||||
"introduced": "v1.9.7",
|
|
||||||
"fixed": "v1.9.17",
|
|
||||||
"published": "2020-11-12",
|
|
||||||
"severity": "Critical",
|
|
||||||
"CVE": "CVE-2020-26241",
|
|
||||||
"check": "Geth\\/v1\\.9\\.(7|8|9|10|11|12|13|14|15|16).*$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Geth DoS via MULMOD",
|
|
||||||
"uid": "GETH-2020-04",
|
|
||||||
"summary": "A denial-of-service issue can be used to crash Geth nodes during block processing",
|
|
||||||
"description": "Affected versions suffer from a vulnerability which can be exploited through the `MULMOD` operation, by specifying a modulo of `0`: `mulmod(a,b,0)`, causing a `panic` in the underlying library. \nThe crash was in the `uint256` library, where a buffer [underflowed](https://github.com/holiman/uint256/blob/4ce82e695c10ddad57215bdbeafb68b8c5df2c30/uint256.go#L442).\n\n\tif `d == 0`, `dLen` remains `0`\n\nand https://github.com/holiman/uint256/blob/4ce82e695c10ddad57215bdbeafb68b8c5df2c30/uint256.go#L451 will try to access index `[-1]`.\n\nThe `uint256` library was first merged in this [commit](https://github.com/ethereum/go-ethereum/commit/cf6674539c589f80031f3371a71c6a80addbe454), on 2020-06-08. \nExploiting this vulnerabilty would cause all vulnerable nodes to drop off the network. \n\nThe issue was brought to our attention through a [bug report](https://github.com/ethereum/go-ethereum/issues/21367), showing a `panic` occurring on sync from genesis on the Ropsten network.\n \nIt was estimated that the least obvious way to fix this would be to merge the fix into `uint256`, make a new release of that library and then update the geth-dependency.\n",
|
|
||||||
"links": [
|
|
||||||
"https://blog.ethereum.org/2020/11/12/geth-security-release",
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-jm5c-rv3w-w83m",
|
|
||||||
"https://github.com/holiman/uint256/releases/tag/v1.1.1",
|
|
||||||
"https://github.com/holiman/uint256/pull/80",
|
|
||||||
"https://github.com/ethereum/go-ethereum/pull/21368"
|
|
||||||
],
|
|
||||||
"introduced": "v1.9.16",
|
|
||||||
"fixed": "v1.9.18",
|
|
||||||
"published": "2020-11-12",
|
|
||||||
"severity": "Critical",
|
|
||||||
"CVE": "CVE-2020-26242",
|
|
||||||
"check": "Geth\\/v1\\.9.(16|17).*$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "LES Server DoS via GetProofsV2",
|
|
||||||
"uid": "GETH-2020-05",
|
|
||||||
"summary": "A DoS vulnerability can make a LES server crash.",
|
|
||||||
"description": "A DoS vulnerability can make a LES server crash via malicious GetProofsV2 request from a connected LES client.\n\nThe vulnerability was patched in #21896.\n\nThis vulnerability only concern users explicitly running geth as a light server",
|
|
||||||
"links": [
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-r33q-22hv-j29q",
|
|
||||||
"https://github.com/ethereum/go-ethereum/pull/21896"
|
|
||||||
],
|
|
||||||
"introduced": "v1.8.0",
|
|
||||||
"fixed": "v1.9.25",
|
|
||||||
"published": "2020-12-10",
|
|
||||||
"severity": "Medium",
|
|
||||||
"CVE": "CVE-2020-26264",
|
|
||||||
"check": "(Geth\\/v1\\.8\\.*)|(Geth\\/v1\\.9\\.\\d-.*)|(Geth\\/v1\\.9\\.1\\d-.*)|(Geth\\/v1\\.9\\.(20|21|22|23|24)-.*)$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "SELFDESTRUCT-recreate consensus flaw",
|
|
||||||
"uid": "GETH-2020-06",
|
|
||||||
"introduced": "v1.9.4",
|
|
||||||
"fixed": "v1.9.20",
|
|
||||||
"summary": "A consensus-vulnerability in Geth could cause a chain split, where vulnerable versions refuse to accept the canonical chain.",
|
|
||||||
"description": "A flaw was repoted at 2020-08-11 by John Youngseok Yang (Software Platform Lab), where a particular sequence of transactions could cause a consensus failure.\n\n- Tx 1:\n - `sender` invokes `caller`.\n - `caller` invokes `0xaa`. `0xaa` has 3 wei, does a self-destruct-to-self\n - `caller` does a `1 wei` -call to `0xaa`, who thereby has 1 wei (the code in `0xaa` still executed, since the tx is still ongoing, but doesn't redo the selfdestruct, it takes a different path if callvalue is non-zero)\n\n-Tx 2:\n - `sender` does a 5-wei call to 0xaa. No exec (since no code). \n\nIn geth, the result would be that `0xaa` had `6 wei`, whereas OE reported (correctly) `5` wei. Furthermore, in geth, if the second tx was not executed, the `0xaa` would be destructed, resulting in `0 wei`. Thus obviously wrong. \n\nIt was determined that the root cause was this [commit](https://github.com/ethereum/go-ethereum/commit/223b950944f494a5b4e0957fd9f92c48b09037ad) from [this PR](https://github.com/ethereum/go-ethereum/pull/19953). The semantics of `createObject` was subtly changd, into returning a non-nil object (with `deleted=true`) where it previously did not if the account had been destructed. This return value caused the new object to inherit the old `balance`.\n",
|
|
||||||
"links": [
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-xw37-57qp-9mm4"
|
|
||||||
],
|
|
||||||
"published": "2020-12-10",
|
|
||||||
"severity": "High",
|
|
||||||
"CVE": "CVE-2020-26265",
|
|
||||||
"check": "(Geth\\/v1\\.9\\.(4|5|6|7|8|9)-.*)|(Geth\\/v1\\.9\\.1\\d-.*)$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Not ready for London upgrade",
|
|
||||||
"uid": "GETH-2021-01",
|
|
||||||
"summary": "The client is not ready for the 'London' technical upgrade, and will deviate from the canonical chain when the London upgrade occurs (at block '12965000' around August 4, 2021.",
|
|
||||||
"description": "At (or around) August 4, Ethereum will undergo a technical upgrade called 'London'. Clients not upgraded will fail to progress on the canonical chain.",
|
|
||||||
"links": [
|
|
||||||
"https://github.com/ethereum/eth1.0-specs/blob/master/network-upgrades/mainnet-upgrades/london.md",
|
|
||||||
"https://notes.ethereum.org/@timbeiko/ropsten-postmortem"
|
|
||||||
],
|
|
||||||
"introduced": "v1.10.1",
|
|
||||||
"fixed": "v1.10.6",
|
|
||||||
"published": "2021-07-22",
|
|
||||||
"severity": "High",
|
|
||||||
"check": "(Geth\\/v1\\.10\\.(1|2|3|4|5)-.*)$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "RETURNDATA corruption via datacopy",
|
|
||||||
"uid": "GETH-2021-02",
|
|
||||||
"summary": "A consensus-flaw in the Geth EVM could cause a node to deviate from the canonical chain.",
|
|
||||||
"description": "A memory-corruption bug within the EVM can cause a consensus error, where vulnerable nodes obtain a different `stateRoot` when processing a maliciously crafted transaction. This, in turn, would lead to the chain being split: mainnet splitting in two forks.\n\nAll Geth versions supporting the London hard fork are vulnerable (the bug is older than London), so all users should update.\n\nThis bug was exploited on Mainnet at block 13107518.\n\nCredits for the discovery go to @guidovranken (working for Sentnl during an audit of the Telos EVM) and reported via bounty@ethereum.org.",
|
|
||||||
"links": [
|
|
||||||
"https://github.com/ethereum/go-ethereum/blob/master/docs/postmortems/2021-08-22-split-postmortem.md",
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-9856-9gg9-qcmq",
|
|
||||||
"https://github.com/ethereum/go-ethereum/releases/tag/v1.10.8"
|
|
||||||
],
|
|
||||||
"introduced": "v1.10.0",
|
|
||||||
"fixed": "v1.10.8",
|
|
||||||
"published": "2021-08-24",
|
|
||||||
"severity": "High",
|
|
||||||
"CVE": "CVE-2021-39137",
|
|
||||||
"check": "(Geth\\/v1\\.10\\.(0|1|2|3|4|5|6|7)-.*)$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "DoS via malicious `snap/1` request",
|
|
||||||
"uid": "GETH-2021-03",
|
|
||||||
"summary": "A vulnerable node is susceptible to crash when processing a maliciously crafted message from a peer, via the snap/1 protocol. The crash can be triggered by sending a malicious snap/1 GetTrieNodes package.",
|
|
||||||
"description": "The `snap/1` protocol handler contains two vulnerabilities related to the `GetTrieNodes` packet, which can be exploited to crash the node. Full details are available at the Github security [advisory](https://github.com/ethereum/go-ethereum/security/advisories/GHSA-59hh-656j-3p7v)",
|
|
||||||
"links": [
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-59hh-656j-3p7v",
|
|
||||||
"https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities",
|
|
||||||
"https://github.com/ethereum/go-ethereum/pull/23657"
|
|
||||||
],
|
|
||||||
"introduced": "v1.10.0",
|
|
||||||
"fixed": "v1.10.9",
|
|
||||||
"published": "2021-10-24",
|
|
||||||
"severity": "Medium",
|
|
||||||
"CVE": "CVE-2021-41173",
|
|
||||||
"check": "(Geth\\/v1\\.10\\.(0|1|2|3|4|5|6|7|8)-.*)$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "DoS via malicious p2p message",
|
|
||||||
"uid": "GETH-2022-01",
|
|
||||||
"summary": "A vulnerable node can crash via p2p messages sent from an attacker node, if running with non-default log options.",
|
|
||||||
"description": "A vulnerable node, if configured to use high verbosity logging, can be made to crash when handling specially crafted p2p messages sent from an attacker node. Full details are available at the Github security [advisory](https://github.com/ethereum/go-ethereum/security/advisories/GHSA-wjxw-gh3m-7pm5)",
|
|
||||||
"links": [
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-wjxw-gh3m-7pm5",
|
|
||||||
"https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities",
|
|
||||||
"https://github.com/ethereum/go-ethereum/pull/24507"
|
|
||||||
],
|
|
||||||
"introduced": "v1.10.0",
|
|
||||||
"fixed": "v1.10.17",
|
|
||||||
"published": "2022-05-11",
|
|
||||||
"severity": "Low",
|
|
||||||
"CVE": "CVE-2022-29177",
|
|
||||||
"check": "(Geth\\/v1\\.10\\.(0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16)-.*)$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "DoS via malicious p2p message",
|
|
||||||
"uid": "GETH-2023-01",
|
|
||||||
"summary": "A vulnerable node can be made to consume unbounded amounts of memory when handling specially crafted p2p messages sent from an attacker node.",
|
|
||||||
"description": "The p2p handler spawned a new goroutine to respond to ping requests. By flooding a node with ping requests, an unbounded number of goroutines can be created, leading to resource exhaustion and potentially crash due to OOM.",
|
|
||||||
"links": [
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-ppjg-v974-84cm",
|
|
||||||
"https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities"
|
|
||||||
],
|
|
||||||
"introduced": "v1.10.0",
|
|
||||||
"fixed": "v1.12.1",
|
|
||||||
"published": "2023-09-06",
|
|
||||||
"severity": "High",
|
|
||||||
"CVE": "CVE-2023-40591",
|
|
||||||
"check": "(Geth\\/v1\\.(10|11)\\..*)|(Geth\\/v1\\.12\\.0-.*)$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "DoS via malicious p2p message",
|
|
||||||
"uid": "GETH-2024-01",
|
|
||||||
"summary": "A vulnerable node can be made to consume very large amounts of memory when handling specially crafted p2p messages sent from an attacker node.",
|
|
||||||
"description": "A vulnerable node can be made to consume very large amounts of memory when handling specially crafted p2p messages sent from an attacker node. Full details will be available at the Github security [advisory](https://github.com/ethereum/go-ethereum/security/advisories/GHSA-4xc9-8hmq-j652)",
|
|
||||||
"links": [
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-4xc9-8hmq-j652",
|
|
||||||
"https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities"
|
|
||||||
],
|
|
||||||
"introduced": "v1.10.0",
|
|
||||||
"fixed": "v1.13.15",
|
|
||||||
"published": "2024-05-06",
|
|
||||||
"severity": "High",
|
|
||||||
"CVE": "CVE-2024-32972",
|
|
||||||
"check": "(Geth\\/v1\\.(10|11|12)\\..*)|(Geth\\/v1\\.13\\.\\d-.*)|(Geth\\/v1\\.13\\.1(0|1|2|3|4)-.*)$"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
untrusted comment: signature from minisign secret key
|
|
||||||
RUQkliYstQBOKHklFEYCUjepz81dyUuDmIAxjAvXa+icjGuKcjtVfV06G7qfOMSpplS5EcntU12n+AnGNyuOM8zIctaIWcfG2w0=
|
|
||||||
trusted comment: timestamp:1752094689 file:data.json hashed
|
|
||||||
u2e4wo4HBTU6viQTSY/NVBHoWoPFJnnTvLZS0FYl3JdvSOYi6+qpbEsDhAIFqq/n8VmlS/fPqqf7vKCNiAgjAA==
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
untrusted comment: signature from minisign secret key
|
|
||||||
RWQkliYstQBOKNoyq2O98hPmeVJQ6ShQLM58+4n0gkY0y0trFMDAsHuN/l4IyHfh8dDQ1ry0+IuZVrf/i8M/P3YFzFfAymDYCQ0=
|
|
||||||
trusted comment: timestamp:1752094703 file:data.json
|
|
||||||
cNyq3ZGlqo785HtWODb9ejWqF0HhSeXuLGXzC7z1IhnDrBObWBJngYd3qBG1dQcYlHQ+bgB/On5mSyMFn4UoCQ==
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
untrusted comment: Here's a comment
|
|
||||||
RWQkliYstQBOKNoyq2O98hPmeVJQ6ShQLM58+4n0gkY0y0trFMDAsHuN/l4IyHfh8dDQ1ry0+IuZVrf/i8M/P3YFzFfAymDYCQ0=
|
|
||||||
trusted comment: Here's a trusted comment
|
|
||||||
dL7lO8sqFFCOXJO/u8SgoDk2nlXGWPRDbOTJkChMbmtUp9PB7sG831basXkZ/0CQ/l/vG7AbPyMNEVZyJn5NCg==
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
untrusted comment: One more (untrusted™) comment
|
|
||||||
RWQkliYstQBOKNoyq2O98hPmeVJQ6ShQLM58+4n0gkY0y0trFMDAsHuN/l4IyHfh8dDQ1ry0+IuZVrf/i8M/P3YFzFfAymDYCQ0=
|
|
||||||
trusted comment: Here's a trusted comment
|
|
||||||
dL7lO8sqFFCOXJO/u8SgoDk2nlXGWPRDbOTJkChMbmtUp9PB7sG831basXkZ/0CQ/l/vG7AbPyMNEVZyJn5NCg==
|
|
||||||
2
cmd/geth/testdata/vcheck/minisign.pub
vendored
2
cmd/geth/testdata/vcheck/minisign.pub
vendored
|
|
@ -1,2 +0,0 @@
|
||||||
untrusted comment: minisign public key 284E00B52C269624
|
|
||||||
RWQkliYstQBOKOdtClfgC3IypIPX6TAmoEi7beZ4gyR3wsaezvqOMWsp
|
|
||||||
2
cmd/geth/testdata/vcheck/minisign.sec
vendored
2
cmd/geth/testdata/vcheck/minisign.sec
vendored
|
|
@ -1,2 +0,0 @@
|
||||||
untrusted comment: minisign encrypted secret key
|
|
||||||
RWRTY0Iyz8kmPMKrqk6DCtlO9a33akKiaOQG1aLolqDxs52qvPoAAAACAAAAAAAAAEAAAAAArEiggdvyn6+WzTprirLtgiYQoU+ihz/HyGgjhuF+Pz2ddMduyCO+xjCHeq+vgVVW039fbsI8hW6LRGJZLBKV5/jdxCXAVVQE7qTQ6xpEdO0z8Z731/pV1hlspQXG2PNd16NMtwd9dWw=
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
untrusted comment: verify with signifykey.pub
|
|
||||||
RWSKLNhZb0KdARbMcGN40hbHzKQYZDgDOFhEUT1YpzMnqre/mbKJ8td/HVlG03Am1YCszATiI0DbnljjTy4iNHYwqBfzrFUqUg0=
|
|
||||||
2
cmd/geth/testdata/vcheck/signifykey.pub
vendored
2
cmd/geth/testdata/vcheck/signifykey.pub
vendored
|
|
@ -1,2 +0,0 @@
|
||||||
untrusted comment: signify public key
|
|
||||||
RWSKLNhZb0KdATtRT7mZC/bybI3t3+Hv/O2i3ye04Dq9fnT9slpZ1a2/
|
|
||||||
2
cmd/geth/testdata/vcheck/signifykey.sec
vendored
2
cmd/geth/testdata/vcheck/signifykey.sec
vendored
|
|
@ -1,2 +0,0 @@
|
||||||
untrusted comment: signify secret key
|
|
||||||
RWRCSwAAACpLQDLawSQCtI7eAVIvaiHzjTsTyJsfV5aKLNhZb0KdAWeICXJGa93/bHAcsY6jUh9I8RdEcDWEoGxmaXZC+IdVBPxDpkix9fBRGEUdKWHi3dOfqME0YRzErWI5AVg3cRw=
|
|
||||||
202
cmd/geth/testdata/vcheck/vulnerabilities.json
vendored
202
cmd/geth/testdata/vcheck/vulnerabilities.json
vendored
|
|
@ -1,202 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"name": "CorruptedDAG",
|
|
||||||
"uid": "GETH-2020-01",
|
|
||||||
"summary": "Mining nodes will generate erroneous PoW on epochs > `385`.",
|
|
||||||
"description": "A mining flaw could cause miners to erroneously calculate PoW, due to an index overflow, if DAG size is exceeding the maximum 32 bit unsigned value.\n\nThis occurred on the ETC chain on 2020-11-06. This is likely to trigger for ETH mainnet around block `11550000`/epoch `385`, slated to occur early January 2021.\n\nThis issue is relevant only for miners, non-mining nodes are unaffected, since non-mining nodes use a smaller verification cache instead of a full DAG.",
|
|
||||||
"links": [
|
|
||||||
"https://github.com/ethereum/go-ethereum/pull/21793",
|
|
||||||
"https://blog.ethereum.org/2020/11/12/geth-security-release",
|
|
||||||
"https://github.com/ethereum/go-ethereum/commit/567d41d9363706b4b13ce0903804e8acf214af49",
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-v592-xf75-856p"
|
|
||||||
],
|
|
||||||
"introduced": "v1.6.0",
|
|
||||||
"fixed": "v1.9.24",
|
|
||||||
"published": "2020-11-12",
|
|
||||||
"severity": "Medium",
|
|
||||||
"CVE": "CVE-2020-26240",
|
|
||||||
"check": "Geth\\/v1\\.(6|7|8)\\..*|Geth\\/v1\\.9\\.\\d-.*|Geth\\/v1\\.9\\.1.*|Geth\\/v1\\.9\\.2(0|1|2|3)-.*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Denial of service due to Go CVE-2020-28362",
|
|
||||||
"uid": "GETH-2020-02",
|
|
||||||
"summary": "A denial-of-service issue can be used to crash Geth nodes during block processing, due to an underlying bug in Go (CVE-2020-28362) versions < `1.15.5`, or `<1.14.12`",
|
|
||||||
"description": "The DoS issue can be used to crash all Geth nodes during block processing, the effects of which would be that a major part of the Ethereum network went offline.\n\nOutside of Go-Ethereum, the issue is most likely relevant for all forks of Geth (such as TurboGeth or ETC’s core-geth) which is built with versions of Go which contains the vulnerability.",
|
|
||||||
"links": [
|
|
||||||
"https://blog.ethereum.org/2020/11/12/geth-security-release",
|
|
||||||
"https://groups.google.com/g/golang-announce/c/NpBGTTmKzpM",
|
|
||||||
"https://github.com/golang/go/issues/42552",
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-m6gx-rhvj-fh52"
|
|
||||||
],
|
|
||||||
"introduced": "v0.0.0",
|
|
||||||
"fixed": "v1.9.24",
|
|
||||||
"published": "2020-11-12",
|
|
||||||
"severity": "Critical",
|
|
||||||
"CVE": "CVE-2020-28362",
|
|
||||||
"check": "Geth.*\\/go1\\.(11(.*)|12(.*)|13(.*)|14|14\\.(\\d|10|11|)|15|15\\.[0-4])$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ShallowCopy",
|
|
||||||
"uid": "GETH-2020-03",
|
|
||||||
"summary": "A consensus flaw in Geth, related to `datacopy` precompile",
|
|
||||||
"description": "Geth erroneously performed a 'shallow' copy when the precompiled `datacopy` (at `0x00...04`) was invoked. An attacker could deploy a contract that uses the shallow copy to corrupt the contents of the `RETURNDATA`, thus causing a consensus failure.",
|
|
||||||
"links": [
|
|
||||||
"https://blog.ethereum.org/2020/11/12/geth-security-release",
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-69v6-xc2j-r2jf"
|
|
||||||
],
|
|
||||||
"introduced": "v1.9.7",
|
|
||||||
"fixed": "v1.9.17",
|
|
||||||
"published": "2020-11-12",
|
|
||||||
"severity": "Critical",
|
|
||||||
"CVE": "CVE-2020-26241",
|
|
||||||
"check": "Geth\\/v1\\.9\\.(7|8|9|10|11|12|13|14|15|16).*$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Geth DoS via MULMOD",
|
|
||||||
"uid": "GETH-2020-04",
|
|
||||||
"summary": "A denial-of-service issue can be used to crash Geth nodes during block processing",
|
|
||||||
"description": "Affected versions suffer from a vulnerability which can be exploited through the `MULMOD` operation, by specifying a modulo of `0`: `mulmod(a,b,0)`, causing a `panic` in the underlying library. \nThe crash was in the `uint256` library, where a buffer [underflowed](https://github.com/holiman/uint256/blob/4ce82e695c10ddad57215bdbeafb68b8c5df2c30/uint256.go#L442).\n\n\tif `d == 0`, `dLen` remains `0`\n\nand https://github.com/holiman/uint256/blob/4ce82e695c10ddad57215bdbeafb68b8c5df2c30/uint256.go#L451 will try to access index `[-1]`.\n\nThe `uint256` library was first merged in this [commit](https://github.com/ethereum/go-ethereum/commit/cf6674539c589f80031f3371a71c6a80addbe454), on 2020-06-08. \nExploiting this vulnerabilty would cause all vulnerable nodes to drop off the network. \n\nThe issue was brought to our attention through a [bug report](https://github.com/ethereum/go-ethereum/issues/21367), showing a `panic` occurring on sync from genesis on the Ropsten network.\n \nIt was estimated that the least obvious way to fix this would be to merge the fix into `uint256`, make a new release of that library and then update the geth-dependency.\n",
|
|
||||||
"links": [
|
|
||||||
"https://blog.ethereum.org/2020/11/12/geth-security-release",
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-jm5c-rv3w-w83m",
|
|
||||||
"https://github.com/holiman/uint256/releases/tag/v1.1.1",
|
|
||||||
"https://github.com/holiman/uint256/pull/80",
|
|
||||||
"https://github.com/ethereum/go-ethereum/pull/21368"
|
|
||||||
],
|
|
||||||
"introduced": "v1.9.16",
|
|
||||||
"fixed": "v1.9.18",
|
|
||||||
"published": "2020-11-12",
|
|
||||||
"severity": "Critical",
|
|
||||||
"CVE": "CVE-2020-26242",
|
|
||||||
"check": "Geth\\/v1\\.9.(16|17).*$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "LES Server DoS via GetProofsV2",
|
|
||||||
"uid": "GETH-2020-05",
|
|
||||||
"summary": "A DoS vulnerability can make a LES server crash.",
|
|
||||||
"description": "A DoS vulnerability can make a LES server crash via malicious GetProofsV2 request from a connected LES client.\n\nThe vulnerability was patched in #21896.\n\nThis vulnerability only concern users explicitly running geth as a light server",
|
|
||||||
"links": [
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-r33q-22hv-j29q",
|
|
||||||
"https://github.com/ethereum/go-ethereum/pull/21896"
|
|
||||||
],
|
|
||||||
"introduced": "v1.8.0",
|
|
||||||
"fixed": "v1.9.25",
|
|
||||||
"published": "2020-12-10",
|
|
||||||
"severity": "Medium",
|
|
||||||
"CVE": "CVE-2020-26264",
|
|
||||||
"check": "(Geth\\/v1\\.8\\.*)|(Geth\\/v1\\.9\\.\\d-.*)|(Geth\\/v1\\.9\\.1\\d-.*)|(Geth\\/v1\\.9\\.(20|21|22|23|24)-.*)$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "SELFDESTRUCT-recreate consensus flaw",
|
|
||||||
"uid": "GETH-2020-06",
|
|
||||||
"introduced": "v1.9.4",
|
|
||||||
"fixed": "v1.9.20",
|
|
||||||
"summary": "A consensus-vulnerability in Geth could cause a chain split, where vulnerable versions refuse to accept the canonical chain.",
|
|
||||||
"description": "A flaw was repoted at 2020-08-11 by John Youngseok Yang (Software Platform Lab), where a particular sequence of transactions could cause a consensus failure.\n\n- Tx 1:\n - `sender` invokes `caller`.\n - `caller` invokes `0xaa`. `0xaa` has 3 wei, does a self-destruct-to-self\n - `caller` does a `1 wei` -call to `0xaa`, who thereby has 1 wei (the code in `0xaa` still executed, since the tx is still ongoing, but doesn't redo the selfdestruct, it takes a different path if callvalue is non-zero)\n\n-Tx 2:\n - `sender` does a 5-wei call to 0xaa. No exec (since no code). \n\nIn geth, the result would be that `0xaa` had `6 wei`, whereas OE reported (correctly) `5` wei. Furthermore, in geth, if the second tx was not executed, the `0xaa` would be destructed, resulting in `0 wei`. Thus obviously wrong. \n\nIt was determined that the root cause was this [commit](https://github.com/ethereum/go-ethereum/commit/223b950944f494a5b4e0957fd9f92c48b09037ad) from [this PR](https://github.com/ethereum/go-ethereum/pull/19953). The semantics of `createObject` was subtly changd, into returning a non-nil object (with `deleted=true`) where it previously did not if the account had been destructed. This return value caused the new object to inherit the old `balance`.\n",
|
|
||||||
"links": [
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-xw37-57qp-9mm4"
|
|
||||||
],
|
|
||||||
"published": "2020-12-10",
|
|
||||||
"severity": "High",
|
|
||||||
"CVE": "CVE-2020-26265",
|
|
||||||
"check": "(Geth\\/v1\\.9\\.(4|5|6|7|8|9)-.*)|(Geth\\/v1\\.9\\.1\\d-.*)$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Not ready for London upgrade",
|
|
||||||
"uid": "GETH-2021-01",
|
|
||||||
"summary": "The client is not ready for the 'London' technical upgrade, and will deviate from the canonical chain when the London upgrade occurs (at block '12965000' around August 4, 2021.",
|
|
||||||
"description": "At (or around) August 4, Ethereum will undergo a technical upgrade called 'London'. Clients not upgraded will fail to progress on the canonical chain.",
|
|
||||||
"links": [
|
|
||||||
"https://github.com/ethereum/eth1.0-specs/blob/master/network-upgrades/mainnet-upgrades/london.md",
|
|
||||||
"https://notes.ethereum.org/@timbeiko/ropsten-postmortem"
|
|
||||||
],
|
|
||||||
"introduced": "v1.10.1",
|
|
||||||
"fixed": "v1.10.6",
|
|
||||||
"published": "2021-07-22",
|
|
||||||
"severity": "High",
|
|
||||||
"check": "(Geth\\/v1\\.10\\.(1|2|3|4|5)-.*)$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "RETURNDATA corruption via datacopy",
|
|
||||||
"uid": "GETH-2021-02",
|
|
||||||
"summary": "A consensus-flaw in the Geth EVM could cause a node to deviate from the canonical chain.",
|
|
||||||
"description": "A memory-corruption bug within the EVM can cause a consensus error, where vulnerable nodes obtain a different `stateRoot` when processing a maliciously crafted transaction. This, in turn, would lead to the chain being split: mainnet splitting in two forks.\n\nAll Geth versions supporting the London hard fork are vulnerable (the bug is older than London), so all users should update.\n\nThis bug was exploited on Mainnet at block 13107518.\n\nCredits for the discovery go to @guidovranken (working for Sentnl during an audit of the Telos EVM) and reported via bounty@ethereum.org.",
|
|
||||||
"links": [
|
|
||||||
"https://github.com/ethereum/go-ethereum/blob/master/docs/postmortems/2021-08-22-split-postmortem.md",
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-9856-9gg9-qcmq",
|
|
||||||
"https://github.com/ethereum/go-ethereum/releases/tag/v1.10.8"
|
|
||||||
],
|
|
||||||
"introduced": "v1.10.0",
|
|
||||||
"fixed": "v1.10.8",
|
|
||||||
"published": "2021-08-24",
|
|
||||||
"severity": "High",
|
|
||||||
"CVE": "CVE-2021-39137",
|
|
||||||
"check": "(Geth\\/v1\\.10\\.(0|1|2|3|4|5|6|7)-.*)$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "DoS via malicious `snap/1` request",
|
|
||||||
"uid": "GETH-2021-03",
|
|
||||||
"summary": "A vulnerable node is susceptible to crash when processing a maliciously crafted message from a peer, via the snap/1 protocol. The crash can be triggered by sending a malicious snap/1 GetTrieNodes package.",
|
|
||||||
"description": "The `snap/1` protocol handler contains two vulnerabilities related to the `GetTrieNodes` packet, which can be exploited to crash the node. Full details are available at the Github security [advisory](https://github.com/ethereum/go-ethereum/security/advisories/GHSA-59hh-656j-3p7v)",
|
|
||||||
"links": [
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-59hh-656j-3p7v",
|
|
||||||
"https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities",
|
|
||||||
"https://github.com/ethereum/go-ethereum/pull/23657"
|
|
||||||
],
|
|
||||||
"introduced": "v1.10.0",
|
|
||||||
"fixed": "v1.10.9",
|
|
||||||
"published": "2021-10-24",
|
|
||||||
"severity": "Medium",
|
|
||||||
"CVE": "CVE-2021-41173",
|
|
||||||
"check": "(Geth\\/v1\\.10\\.(0|1|2|3|4|5|6|7|8)-.*)$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "DoS via malicious p2p message",
|
|
||||||
"uid": "GETH-2022-01",
|
|
||||||
"summary": "A vulnerable node can crash via p2p messages sent from an attacker node, if running with non-default log options.",
|
|
||||||
"description": "A vulnerable node, if configured to use high verbosity logging, can be made to crash when handling specially crafted p2p messages sent from an attacker node. Full details are available at the Github security [advisory](https://github.com/ethereum/go-ethereum/security/advisories/GHSA-wjxw-gh3m-7pm5)",
|
|
||||||
"links": [
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-wjxw-gh3m-7pm5",
|
|
||||||
"https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities",
|
|
||||||
"https://github.com/ethereum/go-ethereum/pull/24507"
|
|
||||||
],
|
|
||||||
"introduced": "v1.10.0",
|
|
||||||
"fixed": "v1.10.17",
|
|
||||||
"published": "2022-05-11",
|
|
||||||
"severity": "Low",
|
|
||||||
"CVE": "CVE-2022-29177",
|
|
||||||
"check": "(Geth\\/v1\\.10\\.(0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16)-.*)$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "DoS via malicious p2p message",
|
|
||||||
"uid": "GETH-2023-01",
|
|
||||||
"summary": "A vulnerable node can be made to consume unbounded amounts of memory when handling specially crafted p2p messages sent from an attacker node.",
|
|
||||||
"description": "The p2p handler spawned a new goroutine to respond to ping requests. By flooding a node with ping requests, an unbounded number of goroutines can be created, leading to resource exhaustion and potentially crash due to OOM.",
|
|
||||||
"links": [
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-ppjg-v974-84cm",
|
|
||||||
"https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities"
|
|
||||||
],
|
|
||||||
"introduced": "v1.10.0",
|
|
||||||
"fixed": "v1.12.1",
|
|
||||||
"published": "2023-09-06",
|
|
||||||
"severity": "High",
|
|
||||||
"CVE": "CVE-2023-40591",
|
|
||||||
"check": "(Geth\\/v1\\.(10|11)\\..*)|(Geth\\/v1\\.12\\.0-.*)$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "DoS via malicious p2p message",
|
|
||||||
"uid": "GETH-2024-01",
|
|
||||||
"summary": "A vulnerable node can be made to consume very large amounts of memory when handling specially crafted p2p messages sent from an attacker node.",
|
|
||||||
"description": "A vulnerable node can be made to consume very large amounts of memory when handling specially crafted p2p messages sent from an attacker node. Full details will be available at the Github security [advisory](https://github.com/ethereum/go-ethereum/security/advisories/GHSA-4xc9-8hmq-j652)",
|
|
||||||
"links": [
|
|
||||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-4xc9-8hmq-j652",
|
|
||||||
"https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities"
|
|
||||||
],
|
|
||||||
"introduced": "v1.10.0",
|
|
||||||
"fixed": "v1.13.15",
|
|
||||||
"published": "2024-05-06",
|
|
||||||
"severity": "High",
|
|
||||||
"CVE": "CVE-2024-32972",
|
|
||||||
"check": "(Geth\\/v1\\.(10|11|12)\\..*)|(Geth\\/v1\\.13\\.\\d-.*)|(Geth\\/v1\\.13\\.1(0|1|2|3|4)-.*)$"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
@ -1,214 +0,0 @@
|
||||||
// Copyright 2022 The go-ethereum Authors
|
|
||||||
// This file is part of go-ethereum.
|
|
||||||
//
|
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// go-ethereum 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 General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/hex"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"slices"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/ethereum/go-verkle"
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
zero [32]byte
|
|
||||||
|
|
||||||
verkleCommand = &cli.Command{
|
|
||||||
Name: "verkle",
|
|
||||||
Usage: "A set of experimental verkle tree management commands",
|
|
||||||
Description: "",
|
|
||||||
Subcommands: []*cli.Command{
|
|
||||||
{
|
|
||||||
Name: "verify",
|
|
||||||
Usage: "verify the conversion of a MPT into a verkle tree",
|
|
||||||
ArgsUsage: "<root>",
|
|
||||||
Action: verifyVerkle,
|
|
||||||
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
|
|
||||||
Description: `
|
|
||||||
geth verkle verify <state-root>
|
|
||||||
This command takes a root commitment and attempts to rebuild the tree.
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "dump",
|
|
||||||
Usage: "Dump a verkle tree to a DOT file",
|
|
||||||
ArgsUsage: "<root> <key1> [<key 2> ...]",
|
|
||||||
Action: expandVerkle,
|
|
||||||
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
|
|
||||||
Description: `
|
|
||||||
geth verkle dump <state-root> <key 1> [<key 2> ...]
|
|
||||||
This command will produce a dot file representing the tree, rooted at <root>.
|
|
||||||
in which key1, key2, ... are expanded.
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// recurse into each child to ensure they can be loaded from the db. The tree isn't rebuilt
|
|
||||||
// (only its nodes are loaded) so there is no need to flush them, the garbage collector should
|
|
||||||
// take care of that for us.
|
|
||||||
func checkChildren(root verkle.VerkleNode, resolver verkle.NodeResolverFn) error {
|
|
||||||
switch node := root.(type) {
|
|
||||||
case *verkle.InternalNode:
|
|
||||||
for i, child := range node.Children() {
|
|
||||||
childC := child.Commit().Bytes()
|
|
||||||
|
|
||||||
childS, err := resolver(childC[:])
|
|
||||||
if bytes.Equal(childC[:], zero[:]) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not find child %x in db: %w", childC, err)
|
|
||||||
}
|
|
||||||
// depth is set to 0, the tree isn't rebuilt so it's not a problem
|
|
||||||
childN, err := verkle.ParseNode(childS, 0)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("decode error child %x in db: %w", child.Commitment().Bytes(), err)
|
|
||||||
}
|
|
||||||
if err := checkChildren(childN, resolver); err != nil {
|
|
||||||
return fmt.Errorf("%x%w", i, err) // write the path to the erroring node
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case *verkle.LeafNode:
|
|
||||||
// sanity check: ensure at least one value is non-zero
|
|
||||||
|
|
||||||
for i := 0; i < verkle.NodeWidth; i++ {
|
|
||||||
if len(node.Value(i)) != 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errors.New("both balance and nonce are 0")
|
|
||||||
case verkle.Empty:
|
|
||||||
// nothing to do
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unsupported type encountered %v", root)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func verifyVerkle(ctx *cli.Context) error {
|
|
||||||
stack, _ := makeConfigNode(ctx)
|
|
||||||
defer stack.Close()
|
|
||||||
|
|
||||||
chaindb := utils.MakeChainDatabase(ctx, stack, true)
|
|
||||||
defer chaindb.Close()
|
|
||||||
headBlock := rawdb.ReadHeadBlock(chaindb)
|
|
||||||
if headBlock == nil {
|
|
||||||
log.Error("Failed to load head block")
|
|
||||||
return errors.New("no head block")
|
|
||||||
}
|
|
||||||
if ctx.NArg() > 1 {
|
|
||||||
log.Error("Too many arguments given")
|
|
||||||
return errors.New("too many arguments")
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
rootC common.Hash
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
if ctx.NArg() == 1 {
|
|
||||||
rootC, err = parseRoot(ctx.Args().First())
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Failed to resolve state root", "error", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Info("Rebuilding the tree", "root", rootC)
|
|
||||||
} else {
|
|
||||||
rootC = headBlock.Root()
|
|
||||||
log.Info("Rebuilding the tree", "root", rootC, "number", headBlock.NumberU64())
|
|
||||||
}
|
|
||||||
|
|
||||||
serializedRoot, err := chaindb.Get(rootC[:])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
root, err := verkle.ParseNode(serializedRoot, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := checkChildren(root, chaindb.Get); err != nil {
|
|
||||||
log.Error("Could not rebuild the tree from the database", "err", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("Tree was rebuilt from the database")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func expandVerkle(ctx *cli.Context) error {
|
|
||||||
stack, _ := makeConfigNode(ctx)
|
|
||||||
defer stack.Close()
|
|
||||||
|
|
||||||
chaindb := utils.MakeChainDatabase(ctx, stack, true)
|
|
||||||
defer chaindb.Close()
|
|
||||||
var (
|
|
||||||
rootC common.Hash
|
|
||||||
keylist [][]byte
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
if ctx.NArg() >= 2 {
|
|
||||||
rootC, err = parseRoot(ctx.Args().First())
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Failed to resolve state root", "error", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
keylist = make([][]byte, 0, ctx.Args().Len()-1)
|
|
||||||
args := ctx.Args().Slice()
|
|
||||||
for i := range args[1:] {
|
|
||||||
key, err := hex.DecodeString(args[i+1])
|
|
||||||
log.Info("decoded key", "arg", args[i+1], "key", key)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error decoding key #%d: %w", i+1, err)
|
|
||||||
}
|
|
||||||
keylist = append(keylist, key)
|
|
||||||
}
|
|
||||||
log.Info("Rebuilding the tree", "root", rootC)
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("usage: %s root key1 [key 2...]", ctx.App.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
serializedRoot, err := chaindb.Get(rootC[:])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
root, err := verkle.ParseNode(serializedRoot, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, key := range keylist {
|
|
||||||
log.Info("Reading key", "index", i, "key", key)
|
|
||||||
root.Get(key, chaindb.Get)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.WriteFile("dump.dot", []byte(verkle.ToDot(root)), 0600); err != nil {
|
|
||||||
log.Error("Failed to dump file", "err", err)
|
|
||||||
} else {
|
|
||||||
log.Info("Tree was dumped to file", "file", "dump.dot")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,170 +0,0 @@
|
||||||
// Copyright 2020 The go-ethereum Authors
|
|
||||||
// This file is part of go-ethereum.
|
|
||||||
//
|
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// go-ethereum 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 General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/jedisct1/go-minisign"
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
var gethPubKeys []string = []string{
|
|
||||||
//@holiman, minisign public key FB1D084D39BAEC24
|
|
||||||
"RWQk7Lo5TQgd+wxBNZM+Zoy+7UhhMHaWKzqoes9tvSbFLJYZhNTbrIjx",
|
|
||||||
//minisign public key 138B1CA303E51687
|
|
||||||
"RWSHFuUDoxyLEzjszuWZI1xStS66QTyXFFZG18uDfO26CuCsbckX1e9J",
|
|
||||||
//minisign public key FD9813B2D2098484
|
|
||||||
"RWSEhAnSshOY/b+GmaiDkObbCWefsAoavjoLcPjBo1xn71yuOH5I+Lts",
|
|
||||||
}
|
|
||||||
|
|
||||||
type vulnJson struct {
|
|
||||||
Name string
|
|
||||||
Uid string
|
|
||||||
Summary string
|
|
||||||
Description string
|
|
||||||
Links []string
|
|
||||||
Introduced string
|
|
||||||
Fixed string
|
|
||||||
Published string
|
|
||||||
Severity string
|
|
||||||
Check string
|
|
||||||
CVE string
|
|
||||||
}
|
|
||||||
|
|
||||||
func versionCheck(ctx *cli.Context) error {
|
|
||||||
url := ctx.String(VersionCheckUrlFlag.Name)
|
|
||||||
version := ctx.String(VersionCheckVersionFlag.Name)
|
|
||||||
log.Info("Checking vulnerabilities", "version", version, "url", url)
|
|
||||||
return checkCurrent(url, version)
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkCurrent(url, current string) error {
|
|
||||||
var (
|
|
||||||
data []byte
|
|
||||||
sig []byte
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
if data, err = fetch(url); err != nil {
|
|
||||||
return fmt.Errorf("could not retrieve data: %w", err)
|
|
||||||
}
|
|
||||||
if sig, err = fetch(fmt.Sprintf("%v.minisig", url)); err != nil {
|
|
||||||
return fmt.Errorf("could not retrieve signature: %w", err)
|
|
||||||
}
|
|
||||||
if err = verifySignature(gethPubKeys, data, sig); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var vulns []vulnJson
|
|
||||||
if err = json.Unmarshal(data, &vulns); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
allOk := true
|
|
||||||
for _, vuln := range vulns {
|
|
||||||
r, err := regexp.Compile(vuln.Check)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if r.MatchString(current) {
|
|
||||||
allOk = false
|
|
||||||
fmt.Printf("## Vulnerable to %v (%v)\n\n", vuln.Uid, vuln.Name)
|
|
||||||
fmt.Printf("Severity: %v\n", vuln.Severity)
|
|
||||||
fmt.Printf("Summary : %v\n", vuln.Summary)
|
|
||||||
fmt.Printf("Fixed in: %v\n", vuln.Fixed)
|
|
||||||
if len(vuln.CVE) > 0 {
|
|
||||||
fmt.Printf("CVE: %v\n", vuln.CVE)
|
|
||||||
}
|
|
||||||
if len(vuln.Links) > 0 {
|
|
||||||
fmt.Printf("References:\n")
|
|
||||||
for _, ref := range vuln.Links {
|
|
||||||
fmt.Printf("\t- %v\n", ref)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if allOk {
|
|
||||||
fmt.Println("No vulnerabilities found")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch makes an HTTP request to the given url and returns the response body
|
|
||||||
func fetch(url string) ([]byte, error) {
|
|
||||||
if filep := strings.TrimPrefix(url, "file://"); filep != url {
|
|
||||||
return os.ReadFile(filep)
|
|
||||||
}
|
|
||||||
res, err := http.Get(url)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
body, err := io.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return body, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// verifySignature checks that the sigData is a valid signature of the given
|
|
||||||
// data, for pubkey GethPubkey
|
|
||||||
func verifySignature(pubkeys []string, data, sigdata []byte) error {
|
|
||||||
sig, err := minisign.DecodeSignature(string(sigdata))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// find the used key
|
|
||||||
var key *minisign.PublicKey
|
|
||||||
for _, pubkey := range pubkeys {
|
|
||||||
pub, err := minisign.NewPublicKey(pubkey)
|
|
||||||
if err != nil {
|
|
||||||
// our pubkeys should be parseable
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if pub.KeyId != sig.KeyId {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
key = &pub
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if key == nil {
|
|
||||||
log.Info("Signing key not trusted", "keyid", keyID(sig.KeyId), "error", err)
|
|
||||||
return errors.New("signature could not be verified")
|
|
||||||
}
|
|
||||||
if ok, err := key.Verify(data, sig); !ok || err != nil {
|
|
||||||
log.Info("Verification failed error", "keyid", keyID(key.KeyId), "error", err)
|
|
||||||
return errors.New("signature could not be verified")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// keyID turns a binary minisign key ID into a hex string.
|
|
||||||
// Note: key IDs are printed in reverse byte order.
|
|
||||||
func keyID(id [8]byte) string {
|
|
||||||
var rev [8]byte
|
|
||||||
for i := range id {
|
|
||||||
rev[len(rev)-1-i] = id[i]
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%X", rev)
|
|
||||||
}
|
|
||||||
|
|
@ -1,189 +0,0 @@
|
||||||
// Copyright 2020 The go-ethereum Authors
|
|
||||||
// This file is part of go-ethereum.
|
|
||||||
//
|
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// go-ethereum 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 General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/jedisct1/go-minisign"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestVerification(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
// Signatures generated with `minisign`. Legacy format, not pre-hashed file.
|
|
||||||
t.Run("minisig-legacy", func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
// For this test, the pubkey is in testdata/vcheck/minisign.pub
|
|
||||||
// (the privkey is `minisign.sec`, if we want to expand this test. Password 'test' )
|
|
||||||
// 1. `minisign -S -l -s ./minisign.sec -m data.json -x ./minisig-sigs/vulnerabilities.json.minisig.1 -c "signature from minisign secret key"`
|
|
||||||
// 2. `minisign -S -l -s ./minisign.sec -m vulnerabilities.json -x ./minisig-sigs/vulnerabilities.json.minisig.2 -c "Here's a comment" -t "Here's a trusted comment"`
|
|
||||||
// 3. minisign -S -l -s ./minisign.sec -m vulnerabilities.json -x ./minisig-sigs/vulnerabilities.json.minisig.3 -c "One more (untrusted™) comment" -t "Here's a trusted comment"
|
|
||||||
pub := "RWQkliYstQBOKOdtClfgC3IypIPX6TAmoEi7beZ4gyR3wsaezvqOMWsp"
|
|
||||||
testVerification(t, pub, "./testdata/vcheck/minisig-sigs/")
|
|
||||||
})
|
|
||||||
t.Run("minisig-new", func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
// For this test, the pubkey is in testdata/vcheck/minisign.pub
|
|
||||||
// (the privkey is `minisign.sec`, if we want to expand this test. Password 'test' )
|
|
||||||
// `minisign -S -s ./minisign.sec -m data.json -x ./minisig-sigs-new/data.json.minisig`
|
|
||||||
pub := "RWQkliYstQBOKOdtClfgC3IypIPX6TAmoEi7beZ4gyR3wsaezvqOMWsp"
|
|
||||||
testVerification(t, pub, "./testdata/vcheck/minisig-sigs-new/")
|
|
||||||
})
|
|
||||||
// Signatures generated with `signify-openbsd`
|
|
||||||
t.Run("signify-openbsd", func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
t.Skip("This currently fails, minisign expects 4 lines of data, signify provides only 2")
|
|
||||||
// For this test, the pubkey is in testdata/vcheck/signifykey.pub
|
|
||||||
// (the privkey is `signifykey.sec`, if we want to expand this test. Password 'test' )
|
|
||||||
// `signify -S -s signifykey.sec -m data.json -x ./signify-sigs/data.json.sig`
|
|
||||||
pub := "RWSKLNhZb0KdATtRT7mZC/bybI3t3+Hv/O2i3ye04Dq9fnT9slpZ1a2/"
|
|
||||||
testVerification(t, pub, "./testdata/vcheck/signify-sigs/")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func testVerification(t *testing.T, pubkey, sigdir string) {
|
|
||||||
// Data to verify
|
|
||||||
data, err := os.ReadFile("./testdata/vcheck/data.json")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
// Signatures, with and without comments, both trusted and untrusted
|
|
||||||
files, err := os.ReadDir(sigdir)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if len(files) == 0 {
|
|
||||||
t.Fatal("Missing tests")
|
|
||||||
}
|
|
||||||
for _, f := range files {
|
|
||||||
sig, err := os.ReadFile(filepath.Join(sigdir, f.Name()))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
err = verifySignature([]string{pubkey}, data, sig)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func versionUint(v string) int {
|
|
||||||
mustInt := func(s string) int {
|
|
||||||
a, err := strconv.Atoi(s)
|
|
||||||
if err != nil {
|
|
||||||
panic(v)
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
components := strings.Split(strings.TrimPrefix(v, "v"), ".")
|
|
||||||
a := mustInt(components[0])
|
|
||||||
b := mustInt(components[1])
|
|
||||||
c := mustInt(components[2])
|
|
||||||
return a*100*100 + b*100 + c
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestMatching can be used to check that the regexps are correct
|
|
||||||
func TestMatching(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
data, _ := os.ReadFile("./testdata/vcheck/vulnerabilities.json")
|
|
||||||
var vulns []vulnJson
|
|
||||||
if err := json.Unmarshal(data, &vulns); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
check := func(version string) {
|
|
||||||
vFull := fmt.Sprintf("Geth/%v-unstable-15339cf1-20201204/linux-amd64/go1.15.4", version)
|
|
||||||
for _, vuln := range vulns {
|
|
||||||
r, err := regexp.Compile(vuln.Check)
|
|
||||||
vulnIntro := versionUint(vuln.Introduced)
|
|
||||||
vulnFixed := versionUint(vuln.Fixed)
|
|
||||||
current := versionUint(version)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if vuln.Name == "Denial of service due to Go CVE-2020-28362" {
|
|
||||||
// this one is not tied to geth-versions
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if vulnIntro <= current && vulnFixed > current {
|
|
||||||
// Should be vulnerable
|
|
||||||
if !r.MatchString(vFull) {
|
|
||||||
t.Errorf("Should be vulnerable, version %v, intro: %v, fixed: %v %v %v",
|
|
||||||
version, vuln.Introduced, vuln.Fixed, vuln.Name, vuln.Check)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if r.MatchString(vFull) {
|
|
||||||
t.Errorf("Should not be flagged vulnerable, version %v, intro: %v, fixed: %v %v %d %d %d",
|
|
||||||
version, vuln.Introduced, vuln.Fixed, vuln.Name, vulnIntro, current, vulnFixed)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for major := 1; major < 2; major++ {
|
|
||||||
for minor := 0; minor < 30; minor++ {
|
|
||||||
for patch := 0; patch < 30; patch++ {
|
|
||||||
vShort := fmt.Sprintf("v%d.%d.%d", major, minor, patch)
|
|
||||||
check(vShort)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGethPubKeysParseable(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
for _, pubkey := range gethPubKeys {
|
|
||||||
_, err := minisign.NewPublicKey(pubkey)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Should be parseable")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestKeyID(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
type args struct {
|
|
||||||
id [8]byte
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{"@holiman key", args{id: extractKeyId(gethPubKeys[0])}, "FB1D084D39BAEC24"},
|
|
||||||
{"second key", args{id: extractKeyId(gethPubKeys[1])}, "138B1CA303E51687"},
|
|
||||||
{"third key", args{id: extractKeyId(gethPubKeys[2])}, "FD9813B2D2098484"},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
if got := keyID(tt.args.id); got != tt.want {
|
|
||||||
t.Errorf("keyID() = %v, want %v", got, tt.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func extractKeyId(pubkey string) [8]byte {
|
|
||||||
p, _ := minisign.NewPublicKey(pubkey)
|
|
||||||
return p.KeyId
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2025 The go-ethereum Authors
|
// Copyright 2026 The go-ethereum Authors
|
||||||
// This file is part of the go-ethereum library.
|
// This file is part of the go-ethereum library.
|
||||||
//
|
//
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
|
@ -14,20 +14,23 @@
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//go:build !tinygo
|
//go:build wasm
|
||||||
// +build !tinygo
|
// +build wasm
|
||||||
|
|
||||||
package rawdb
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/olekukonko/tablewriter"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Re-export the real tablewriter types and functions
|
//go:wasmimport geth_io len
|
||||||
type Table = tablewriter.Table
|
func hintLen() uint32
|
||||||
|
|
||||||
func newTableWriter(w io.Writer) *Table {
|
//go:wasmimport geth_io read
|
||||||
return tablewriter.NewWriter(w)
|
func hintRead(data unsafe.Pointer)
|
||||||
|
|
||||||
|
func getInput() []byte {
|
||||||
|
data := make([]byte, hintLen())
|
||||||
|
hintRead(unsafe.Pointer(&data[0]))
|
||||||
|
return data
|
||||||
}
|
}
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
zkruntime "github.com/zkMIPS/zkMIPS/crates/go-runtime/zkm_runtime"
|
zkruntime "github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// getInput reads the input payload from the zkVM runtime environment.
|
// getInput reads the input payload from the zkVM runtime environment.
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ module github.com/ethereum/go-ethereum/cmd/keeper
|
||||||
go 1.24.0
|
go 1.24.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6
|
||||||
github.com/ethereum/go-ethereum v0.0.0-00010101000000-000000000000
|
github.com/ethereum/go-ethereum v0.0.0-00010101000000-000000000000
|
||||||
github.com/zkMIPS/zkMIPS/crates/go-runtime/zkm_runtime v0.0.0-20250915074013-fbc07aa2c6f5
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|
@ -12,15 +12,13 @@ require (
|
||||||
github.com/VictoriaMetrics/fastcache v1.13.0 // indirect
|
github.com/VictoriaMetrics/fastcache v1.13.0 // indirect
|
||||||
github.com/bits-and-blooms/bitset v1.20.0 // indirect
|
github.com/bits-and-blooms/bitset v1.20.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/consensys/gnark-crypto v0.18.0 // indirect
|
github.com/consensys/gnark-crypto v0.18.1 // indirect
|
||||||
github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect
|
github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect
|
||||||
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect
|
|
||||||
github.com/deckarep/golang-set/v2 v2.6.0 // indirect
|
github.com/deckarep/golang-set/v2 v2.6.0 // indirect
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
||||||
github.com/emicklei/dot v1.6.2 // indirect
|
github.com/emicklei/dot v1.6.2 // indirect
|
||||||
github.com/ethereum/c-kzg-4844/v2 v2.1.3 // indirect
|
github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect
|
||||||
github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab // indirect
|
github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab // indirect
|
||||||
github.com/ethereum/go-verkle v0.2.2 // indirect
|
|
||||||
github.com/ferranbt/fastssz v0.1.4 // indirect
|
github.com/ferranbt/fastssz v0.1.4 // indirect
|
||||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||||
github.com/gofrs/flock v0.12.1 // indirect
|
github.com/gofrs/flock v0.12.1 // indirect
|
||||||
|
|
@ -28,22 +26,16 @@ require (
|
||||||
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
|
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
|
||||||
github.com/holiman/uint256 v1.3.2 // indirect
|
github.com/holiman/uint256 v1.3.2 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
|
||||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
||||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
|
||||||
github.com/rivo/uniseg v0.2.0 // indirect
|
|
||||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
|
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
|
||||||
github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe // indirect
|
github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe // indirect
|
||||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||||
golang.org/x/crypto v0.36.0 // indirect
|
golang.org/x/crypto v0.36.0 // indirect
|
||||||
golang.org/x/sync v0.12.0 // indirect
|
golang.org/x/sync v0.12.0 // indirect
|
||||||
golang.org/x/sys v0.36.0 // indirect
|
golang.org/x/sys v0.39.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace (
|
replace github.com/ethereum/go-ethereum => ../../
|
||||||
github.com/ethereum/go-ethereum => ../../
|
|
||||||
github.com/zkMIPS/zkMIPS/crates/go-runtime/zkm_runtime => github.com/weilzkm/zkMIPS/crates/go-runtime/zkvm_runtime v0.0.0-20250915074013-fbc07aa2c6f5
|
|
||||||
)
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
|
github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
|
||||||
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||||
|
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 h1:1zYrtlhrZ6/b6SAjLSfKzWtdgqK0U+HtH/VcBWh1BaU=
|
||||||
|
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI=
|
||||||
github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
|
github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
|
||||||
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
|
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
|
||||||
github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0=
|
github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0=
|
||||||
|
|
@ -24,12 +26,10 @@ github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwP
|
||||||
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
|
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
|
||||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
|
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
|
||||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
|
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
|
||||||
github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0=
|
github.com/consensys/gnark-crypto v0.18.1 h1:RyLV6UhPRoYYzaFnPQA4qK3DyuDgkTgskDdoGqFt3fI=
|
||||||
github.com/consensys/gnark-crypto v0.18.0/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c=
|
github.com/consensys/gnark-crypto v0.18.1/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c=
|
||||||
github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg=
|
github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg=
|
||||||
github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI=
|
github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI=
|
||||||
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg=
|
|
||||||
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM=
|
github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM=
|
||||||
|
|
@ -40,12 +40,10 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
|
||||||
github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A=
|
github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A=
|
||||||
github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s=
|
github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s=
|
||||||
github.com/ethereum/c-kzg-4844/v2 v2.1.3 h1:DQ21UU0VSsuGy8+pcMJHDS0CV1bKmJmxsJYK8l3MiLU=
|
github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s=
|
||||||
github.com/ethereum/c-kzg-4844/v2 v2.1.3/go.mod h1:fyNcYI/yAuLWJxf4uzVtS8VDKeoAaRM8G/+ADz/pRdA=
|
github.com/ethereum/c-kzg-4844/v2 v2.1.5/go.mod h1:u59hRTTah4Co6i9fDWtiCjTrblJv0UwsqZKCc0GfgUs=
|
||||||
github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab h1:rvv6MJhy07IMfEKuARQ9TKojGqLVNxQajaXEp/BoqSk=
|
github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab h1:rvv6MJhy07IMfEKuARQ9TKojGqLVNxQajaXEp/BoqSk=
|
||||||
github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab/go.mod h1:IuLm4IsPipXKF7CW5Lzf68PIbZ5yl7FFd74l/E0o9A8=
|
github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab/go.mod h1:IuLm4IsPipXKF7CW5Lzf68PIbZ5yl7FFd74l/E0o9A8=
|
||||||
github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8=
|
|
||||||
github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk=
|
|
||||||
github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY=
|
github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY=
|
||||||
github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg=
|
github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg=
|
||||||
github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps=
|
github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps=
|
||||||
|
|
@ -65,8 +63,8 @@ github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZ
|
||||||
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
|
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
|
||||||
github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA=
|
github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA=
|
||||||
github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
||||||
github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4=
|
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||||
github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
|
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
|
|
@ -78,17 +76,12 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4=
|
github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4=
|
||||||
github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c=
|
github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c=
|
||||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
|
||||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
|
||||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||||
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
|
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
|
||||||
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
|
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
|
||||||
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
||||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
|
||||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
|
@ -103,22 +96,18 @@ github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJf
|
||||||
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
|
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
|
||||||
github.com/prysmaticlabs/gohashtree v0.0.4-beta h1:H/EbCuXPeTV3lpKeXGPpEV9gsUpkqOOVnWapUyeWro4=
|
github.com/prysmaticlabs/gohashtree v0.0.4-beta h1:H/EbCuXPeTV3lpKeXGPpEV9gsUpkqOOVnWapUyeWro4=
|
||||||
github.com/prysmaticlabs/gohashtree v0.0.4-beta/go.mod h1:BFdtALS+Ffhg3lGQIHv9HDWuHS8cTvHZzrHWxwOtGOs=
|
github.com/prysmaticlabs/gohashtree v0.0.4-beta/go.mod h1:BFdtALS+Ffhg3lGQIHv9HDWuHS8cTvHZzrHWxwOtGOs=
|
||||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
|
||||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
|
||||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU=
|
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU=
|
||||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe h1:nbdqkIGOGfUAD54q1s2YBcBz/WcsxCO9HUQ4aGV5hUw=
|
github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe h1:nbdqkIGOGfUAD54q1s2YBcBz/WcsxCO9HUQ4aGV5hUw=
|
||||||
github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
|
github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
|
||||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||||
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
||||||
github.com/weilzkm/zkMIPS/crates/go-runtime/zkvm_runtime v0.0.0-20250915074013-fbc07aa2c6f5 h1:MxKlbmI7Dta6O6Nsc9OAer/rOltjoL11CVLMqCiYnxU=
|
|
||||||
github.com/weilzkm/zkMIPS/crates/go-runtime/zkvm_runtime v0.0.0-20250915074013-fbc07aa2c6f5/go.mod h1:zk/SUgiiVz2U1ufZ+yM2MHPbD93W25KH5zK3qAxXbT4=
|
|
||||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME=
|
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME=
|
||||||
|
|
@ -129,8 +118,8 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,8 @@
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//go:build !example && !ziren
|
//go:build !example && !ziren && !wasm
|
||||||
|
// +build !example,!ziren,!wasm
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
|
@ -311,7 +312,7 @@ func ImportHistory(chain *core.BlockChain, dir string, network string) error {
|
||||||
return fmt.Errorf("error reading receipts %d: %w", it.Number(), err)
|
return fmt.Errorf("error reading receipts %d: %w", it.Number(), err)
|
||||||
}
|
}
|
||||||
encReceipts := types.EncodeBlockReceiptLists([]types.Receipts{receipts})
|
encReceipts := types.EncodeBlockReceiptLists([]types.Receipts{receipts})
|
||||||
if _, err := chain.InsertReceiptChain([]*types.Block{block}, encReceipts, 2^64-1); err != nil {
|
if _, err := chain.InsertReceiptChain([]*types.Block{block}, encReceipts, math.MaxUint64); err != nil {
|
||||||
return fmt.Errorf("error inserting body %d: %w", it.Number(), err)
|
return fmt.Errorf("error inserting body %d: %w", it.Number(), err)
|
||||||
}
|
}
|
||||||
imported += 1
|
imported += 1
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ package utils
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -115,7 +114,7 @@ var (
|
||||||
Usage: "Root directory for era1 history (default = inside ancient/chain)",
|
Usage: "Root directory for era1 history (default = inside ancient/chain)",
|
||||||
Category: flags.EthCategory,
|
Category: flags.EthCategory,
|
||||||
}
|
}
|
||||||
MinFreeDiskSpaceFlag = &flags.DirectoryFlag{
|
MinFreeDiskSpaceFlag = &cli.IntFlag{
|
||||||
Name: "datadir.minfreedisk",
|
Name: "datadir.minfreedisk",
|
||||||
Usage: "Minimum free disk space in MB, once reached triggers auto shut down (default = --cache.gc converted to MB, 0 = disabled)",
|
Usage: "Minimum free disk space in MB, once reached triggers auto shut down (default = --cache.gc converted to MB, 0 = disabled)",
|
||||||
Category: flags.EthCategory,
|
Category: flags.EthCategory,
|
||||||
|
|
@ -138,7 +137,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)(For testnets: use --sepolia, --holesky, --hoodi instead)",
|
||||||
Value: ethconfig.Defaults.NetworkId,
|
Value: ethconfig.Defaults.NetworkId,
|
||||||
Category: flags.EthCategory,
|
Category: flags.EthCategory,
|
||||||
}
|
}
|
||||||
|
|
@ -262,6 +261,11 @@ var (
|
||||||
Usage: "Manually specify the Verkle fork timestamp, overriding the bundled setting",
|
Usage: "Manually specify the Verkle fork timestamp, overriding the bundled setting",
|
||||||
Category: flags.EthCategory,
|
Category: flags.EthCategory,
|
||||||
}
|
}
|
||||||
|
OverrideGenesisFlag = &cli.StringFlag{
|
||||||
|
Name: "override.genesis",
|
||||||
|
Usage: "Load genesis block and configuration from file at this path",
|
||||||
|
Category: flags.EthCategory,
|
||||||
|
}
|
||||||
SyncModeFlag = &cli.StringFlag{
|
SyncModeFlag = &cli.StringFlag{
|
||||||
Name: "syncmode",
|
Name: "syncmode",
|
||||||
Usage: `Blockchain sync mode ("snap" or "full")`,
|
Usage: `Blockchain sync mode ("snap" or "full")`,
|
||||||
|
|
@ -291,6 +295,18 @@ var (
|
||||||
Value: ethconfig.Defaults.StateHistory,
|
Value: ethconfig.Defaults.StateHistory,
|
||||||
Category: flags.StateCategory,
|
Category: flags.StateCategory,
|
||||||
}
|
}
|
||||||
|
TrienodeHistoryFlag = &cli.Int64Flag{
|
||||||
|
Name: "history.trienode",
|
||||||
|
Usage: "Number of recent blocks to retain trienode history for, only relevant in state.scheme=path (default/negative = disabled, 0 = entire chain)",
|
||||||
|
Value: ethconfig.Defaults.TrienodeHistory,
|
||||||
|
Category: flags.StateCategory,
|
||||||
|
}
|
||||||
|
TrienodeHistoryFullValueCheckpointFlag = &cli.UintFlag{
|
||||||
|
Name: "history.trienode.full-value-checkpoint",
|
||||||
|
Usage: "The frequency of full-value encoding. Every n-th node is stored in full-value format; all other nodes are stored as diffs relative to their predecessor",
|
||||||
|
Value: uint(ethconfig.Defaults.NodeFullValueCheckpoint),
|
||||||
|
Category: flags.StateCategory,
|
||||||
|
}
|
||||||
TransactionHistoryFlag = &cli.Uint64Flag{
|
TransactionHistoryFlag = &cli.Uint64Flag{
|
||||||
Name: "history.transactions",
|
Name: "history.transactions",
|
||||||
Usage: "Number of recent blocks to maintain transactions index for (default = about one year, 0 = entire chain)",
|
Usage: "Number of recent blocks to maintain transactions index for (default = about one year, 0 = entire chain)",
|
||||||
|
|
@ -549,6 +565,11 @@ var (
|
||||||
Usage: "0x prefixed public address for the pending block producer (not used for actual block production)",
|
Usage: "0x prefixed public address for the pending block producer (not used for actual block production)",
|
||||||
Category: flags.MinerCategory,
|
Category: flags.MinerCategory,
|
||||||
}
|
}
|
||||||
|
MinerMaxBlobsFlag = &cli.IntFlag{
|
||||||
|
Name: "miner.maxblobs",
|
||||||
|
Usage: "Maximum number of blobs per block (falls back to protocol maximum if unspecified)",
|
||||||
|
Category: flags.MinerCategory,
|
||||||
|
}
|
||||||
|
|
||||||
// Account settings
|
// Account settings
|
||||||
PasswordFileFlag = &cli.PathFlag{
|
PasswordFileFlag = &cli.PathFlag{
|
||||||
|
|
@ -627,6 +648,12 @@ var (
|
||||||
Value: ethconfig.Defaults.TxSyncMaxTimeout,
|
Value: ethconfig.Defaults.TxSyncMaxTimeout,
|
||||||
Category: flags.APICategory,
|
Category: flags.APICategory,
|
||||||
}
|
}
|
||||||
|
RPCGlobalRangeLimitFlag = &cli.Uint64Flag{
|
||||||
|
Name: "rpc.rangelimit",
|
||||||
|
Usage: "Maximum block range (end - begin) allowed for range queries (0 = unlimited)",
|
||||||
|
Value: ethconfig.Defaults.RangeLimit,
|
||||||
|
Category: flags.APICategory,
|
||||||
|
}
|
||||||
// Authenticated RPC HTTP settings
|
// Authenticated RPC HTTP settings
|
||||||
AuthListenFlag = &cli.StringFlag{
|
AuthListenFlag = &cli.StringFlag{
|
||||||
Name: "authrpc.addr",
|
Name: "authrpc.addr",
|
||||||
|
|
@ -663,6 +690,12 @@ var (
|
||||||
Usage: "Disables db compaction after import",
|
Usage: "Disables db compaction after import",
|
||||||
Category: flags.LoggingCategory,
|
Category: flags.LoggingCategory,
|
||||||
}
|
}
|
||||||
|
LogSlowBlockFlag = &cli.DurationFlag{
|
||||||
|
Name: "debug.logslowblock",
|
||||||
|
Usage: "Block execution time threshold beyond which detailed statistics will be logged (0 logs all blocks, negative means disable)",
|
||||||
|
Value: ethconfig.Defaults.SlowBlockThreshold,
|
||||||
|
Category: flags.LoggingCategory,
|
||||||
|
}
|
||||||
|
|
||||||
// MISC settings
|
// MISC settings
|
||||||
SyncTargetFlag = &cli.StringFlag{
|
SyncTargetFlag = &cli.StringFlag{
|
||||||
|
|
@ -855,14 +888,14 @@ var (
|
||||||
Aliases: []string{"discv4"},
|
Aliases: []string{"discv4"},
|
||||||
Usage: "Enables the V4 discovery mechanism",
|
Usage: "Enables the V4 discovery mechanism",
|
||||||
Category: flags.NetworkingCategory,
|
Category: flags.NetworkingCategory,
|
||||||
Value: true,
|
Value: node.DefaultConfig.P2P.DiscoveryV4,
|
||||||
}
|
}
|
||||||
DiscoveryV5Flag = &cli.BoolFlag{
|
DiscoveryV5Flag = &cli.BoolFlag{
|
||||||
Name: "discovery.v5",
|
Name: "discovery.v5",
|
||||||
Aliases: []string{"discv5"},
|
Aliases: []string{"discv5"},
|
||||||
Usage: "Enables the V5 discovery mechanism",
|
Usage: "Enables the V5 discovery mechanism",
|
||||||
Category: flags.NetworkingCategory,
|
Category: flags.NetworkingCategory,
|
||||||
Value: true,
|
Value: node.DefaultConfig.P2P.DiscoveryV5,
|
||||||
}
|
}
|
||||||
NetrestrictFlag = &cli.StringFlag{
|
NetrestrictFlag = &cli.StringFlag{
|
||||||
Name: "netrestrict",
|
Name: "netrestrict",
|
||||||
|
|
@ -1336,15 +1369,10 @@ func setEtherbase(ctx *cli.Context, cfg *ethconfig.Config) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
addr := ctx.String(MinerPendingFeeRecipientFlag.Name)
|
addr := ctx.String(MinerPendingFeeRecipientFlag.Name)
|
||||||
if strings.HasPrefix(addr, "0x") || strings.HasPrefix(addr, "0X") {
|
if !common.IsHexAddress(addr) {
|
||||||
addr = addr[2:]
|
|
||||||
}
|
|
||||||
b, err := hex.DecodeString(addr)
|
|
||||||
if err != nil || len(b) != common.AddressLength {
|
|
||||||
Fatalf("-%s: invalid pending block producer address %q", MinerPendingFeeRecipientFlag.Name, addr)
|
Fatalf("-%s: invalid pending block producer address %q", MinerPendingFeeRecipientFlag.Name, addr)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
cfg.Miner.PendingFeeRecipient = common.BytesToAddress(b)
|
cfg.Miner.PendingFeeRecipient = common.HexToAddress(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
|
func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
|
||||||
|
|
@ -1364,13 +1392,17 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
|
||||||
cfg.MaxPendingPeers = ctx.Int(MaxPendingPeersFlag.Name)
|
cfg.MaxPendingPeers = ctx.Int(MaxPendingPeersFlag.Name)
|
||||||
}
|
}
|
||||||
if ctx.IsSet(NoDiscoverFlag.Name) {
|
if ctx.IsSet(NoDiscoverFlag.Name) {
|
||||||
cfg.NoDiscovery = true
|
cfg.NoDiscovery = ctx.Bool(NoDiscoverFlag.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
flags.CheckExclusive(ctx, DiscoveryV4Flag, NoDiscoverFlag)
|
flags.CheckExclusive(ctx, DiscoveryV4Flag, NoDiscoverFlag)
|
||||||
flags.CheckExclusive(ctx, DiscoveryV5Flag, NoDiscoverFlag)
|
flags.CheckExclusive(ctx, DiscoveryV5Flag, NoDiscoverFlag)
|
||||||
cfg.DiscoveryV4 = ctx.Bool(DiscoveryV4Flag.Name)
|
if ctx.IsSet(DiscoveryV4Flag.Name) {
|
||||||
cfg.DiscoveryV5 = ctx.Bool(DiscoveryV5Flag.Name)
|
cfg.DiscoveryV4 = ctx.Bool(DiscoveryV4Flag.Name)
|
||||||
|
}
|
||||||
|
if ctx.IsSet(DiscoveryV5Flag.Name) {
|
||||||
|
cfg.DiscoveryV5 = ctx.Bool(DiscoveryV5Flag.Name)
|
||||||
|
}
|
||||||
|
|
||||||
if netrestrict := ctx.String(NetrestrictFlag.Name); netrestrict != "" {
|
if netrestrict := ctx.String(NetrestrictFlag.Name); netrestrict != "" {
|
||||||
list, err := netutil.ParseNetlist(netrestrict)
|
list, err := netutil.ParseNetlist(netrestrict)
|
||||||
|
|
@ -1416,7 +1448,7 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) {
|
||||||
cfg.KeyStoreDir = ctx.String(KeyStoreDirFlag.Name)
|
cfg.KeyStoreDir = ctx.String(KeyStoreDirFlag.Name)
|
||||||
}
|
}
|
||||||
if ctx.IsSet(DeveloperFlag.Name) {
|
if ctx.IsSet(DeveloperFlag.Name) {
|
||||||
cfg.UseLightweightKDF = true
|
cfg.UseLightweightKDF = ctx.Bool(DeveloperFlag.Name)
|
||||||
}
|
}
|
||||||
if ctx.IsSet(LightKDFFlag.Name) {
|
if ctx.IsSet(LightKDFFlag.Name) {
|
||||||
cfg.UseLightweightKDF = ctx.Bool(LightKDFFlag.Name)
|
cfg.UseLightweightKDF = ctx.Bool(LightKDFFlag.Name)
|
||||||
|
|
@ -1572,6 +1604,9 @@ func setMiner(ctx *cli.Context, cfg *miner.Config) {
|
||||||
log.Warn("The flag --miner.newpayload-timeout is deprecated and will be removed, please use --miner.recommit")
|
log.Warn("The flag --miner.newpayload-timeout is deprecated and will be removed, please use --miner.recommit")
|
||||||
cfg.Recommit = ctx.Duration(MinerNewPayloadTimeoutFlag.Name)
|
cfg.Recommit = ctx.Duration(MinerNewPayloadTimeoutFlag.Name)
|
||||||
}
|
}
|
||||||
|
if ctx.IsSet(MinerMaxBlobsFlag.Name) {
|
||||||
|
cfg.MaxBlobsPerBlock = ctx.Int(MinerMaxBlobsFlag.Name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setRequiredBlocks(ctx *cli.Context, cfg *ethconfig.Config) {
|
func setRequiredBlocks(ctx *cli.Context, cfg *ethconfig.Config) {
|
||||||
|
|
@ -1604,8 +1639,8 @@ func setRequiredBlocks(ctx *cli.Context, cfg *ethconfig.Config) {
|
||||||
|
|
||||||
// SetEthConfig applies eth-related command line flags to the config.
|
// SetEthConfig applies eth-related command line flags to the config.
|
||||||
func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
// Avoid conflicting network flags, don't allow network id override on preset networks
|
// Avoid conflicting network flags
|
||||||
flags.CheckExclusive(ctx, MainnetFlag, DeveloperFlag, SepoliaFlag, HoleskyFlag, HoodiFlag, NetworkIdFlag)
|
flags.CheckExclusive(ctx, MainnetFlag, DeveloperFlag, SepoliaFlag, HoleskyFlag, HoodiFlag, OverrideGenesisFlag)
|
||||||
flags.CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer
|
flags.CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer
|
||||||
|
|
||||||
// Set configurations from CLI flags
|
// Set configurations from CLI flags
|
||||||
|
|
@ -1652,9 +1687,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.IsSet(NetworkIdFlag.Name) {
|
|
||||||
cfg.NetworkId = ctx.Uint64(NetworkIdFlag.Name)
|
|
||||||
}
|
|
||||||
if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheDatabaseFlag.Name) {
|
if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheDatabaseFlag.Name) {
|
||||||
cfg.DatabaseCache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheDatabaseFlag.Name) / 100
|
cfg.DatabaseCache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheDatabaseFlag.Name) / 100
|
||||||
}
|
}
|
||||||
|
|
@ -1675,8 +1707,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
if ctx.IsSet(CacheNoPrefetchFlag.Name) {
|
if ctx.IsSet(CacheNoPrefetchFlag.Name) {
|
||||||
cfg.NoPrefetch = ctx.Bool(CacheNoPrefetchFlag.Name)
|
cfg.NoPrefetch = ctx.Bool(CacheNoPrefetchFlag.Name)
|
||||||
}
|
}
|
||||||
// Read the value from the flag no matter if it's set or not.
|
if ctx.IsSet(CachePreimagesFlag.Name) {
|
||||||
cfg.Preimages = ctx.Bool(CachePreimagesFlag.Name)
|
cfg.Preimages = ctx.Bool(CachePreimagesFlag.Name)
|
||||||
|
}
|
||||||
if cfg.NoPruning && !cfg.Preimages {
|
if cfg.NoPruning && !cfg.Preimages {
|
||||||
cfg.Preimages = true
|
cfg.Preimages = true
|
||||||
log.Info("Enabling recording of key preimages since archive mode is used")
|
log.Info("Enabling recording of key preimages since archive mode is used")
|
||||||
|
|
@ -1684,6 +1717,12 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
if ctx.IsSet(StateHistoryFlag.Name) {
|
if ctx.IsSet(StateHistoryFlag.Name) {
|
||||||
cfg.StateHistory = ctx.Uint64(StateHistoryFlag.Name)
|
cfg.StateHistory = ctx.Uint64(StateHistoryFlag.Name)
|
||||||
}
|
}
|
||||||
|
if ctx.IsSet(TrienodeHistoryFlag.Name) {
|
||||||
|
cfg.TrienodeHistory = ctx.Int64(TrienodeHistoryFlag.Name)
|
||||||
|
}
|
||||||
|
if ctx.IsSet(TrienodeHistoryFullValueCheckpointFlag.Name) {
|
||||||
|
cfg.NodeFullValueCheckpoint = uint32(ctx.Uint(TrienodeHistoryFullValueCheckpointFlag.Name))
|
||||||
|
}
|
||||||
if ctx.IsSet(StateSchemeFlag.Name) {
|
if ctx.IsSet(StateSchemeFlag.Name) {
|
||||||
cfg.StateScheme = ctx.String(StateSchemeFlag.Name)
|
cfg.StateScheme = ctx.String(StateSchemeFlag.Name)
|
||||||
}
|
}
|
||||||
|
|
@ -1709,7 +1748,10 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
cfg.LogHistory = ctx.Uint64(LogHistoryFlag.Name)
|
cfg.LogHistory = ctx.Uint64(LogHistoryFlag.Name)
|
||||||
}
|
}
|
||||||
if ctx.IsSet(LogNoHistoryFlag.Name) {
|
if ctx.IsSet(LogNoHistoryFlag.Name) {
|
||||||
cfg.LogNoHistory = true
|
cfg.LogNoHistory = ctx.Bool(LogNoHistoryFlag.Name)
|
||||||
|
}
|
||||||
|
if ctx.IsSet(LogSlowBlockFlag.Name) {
|
||||||
|
cfg.SlowBlockThreshold = ctx.Duration(LogSlowBlockFlag.Name)
|
||||||
}
|
}
|
||||||
if ctx.IsSet(LogExportCheckpointsFlag.Name) {
|
if ctx.IsSet(LogExportCheckpointsFlag.Name) {
|
||||||
cfg.LogExportCheckpoints = ctx.String(LogExportCheckpointsFlag.Name)
|
cfg.LogExportCheckpoints = ctx.String(LogExportCheckpointsFlag.Name)
|
||||||
|
|
@ -1735,6 +1777,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
if ctx.IsSet(RPCTxSyncMaxTimeoutFlag.Name) {
|
if ctx.IsSet(RPCTxSyncMaxTimeoutFlag.Name) {
|
||||||
cfg.TxSyncMaxTimeout = ctx.Duration(RPCTxSyncMaxTimeoutFlag.Name)
|
cfg.TxSyncMaxTimeout = ctx.Duration(RPCTxSyncMaxTimeoutFlag.Name)
|
||||||
}
|
}
|
||||||
|
if ctx.IsSet(RPCGlobalRangeLimitFlag.Name) {
|
||||||
|
cfg.RangeLimit = ctx.Uint64(RPCGlobalRangeLimitFlag.Name)
|
||||||
|
}
|
||||||
if !ctx.Bool(SnapshotFlag.Name) || cfg.SnapshotCache == 0 {
|
if !ctx.Bool(SnapshotFlag.Name) || cfg.SnapshotCache == 0 {
|
||||||
// If snap-sync is requested, this flag is also required
|
// If snap-sync is requested, this flag is also required
|
||||||
if cfg.SyncMode == ethconfig.SnapSync {
|
if cfg.SyncMode == ethconfig.SnapSync {
|
||||||
|
|
@ -1891,11 +1936,31 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
if !ctx.IsSet(MinerGasPriceFlag.Name) {
|
if !ctx.IsSet(MinerGasPriceFlag.Name) {
|
||||||
cfg.Miner.GasPrice = big.NewInt(1)
|
cfg.Miner.GasPrice = big.NewInt(1)
|
||||||
}
|
}
|
||||||
|
case ctx.String(OverrideGenesisFlag.Name) != "":
|
||||||
|
f, err := os.Open(ctx.String(OverrideGenesisFlag.Name))
|
||||||
|
if err != nil {
|
||||||
|
Fatalf("Failed to read genesis file: %v", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
genesis := new(core.Genesis)
|
||||||
|
if err := json.NewDecoder(f).Decode(genesis); err != nil {
|
||||||
|
Fatalf("Invalid genesis file: %v", err)
|
||||||
|
}
|
||||||
|
cfg.Genesis = genesis
|
||||||
default:
|
default:
|
||||||
if cfg.NetworkId == 1 {
|
if ctx.Uint64(NetworkIdFlag.Name) == 1 {
|
||||||
SetDNSDiscoveryDefaults(cfg, params.MainnetGenesisHash)
|
SetDNSDiscoveryDefaults(cfg, params.MainnetGenesisHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ctx.IsSet(NetworkIdFlag.Name) {
|
||||||
|
// Typically it's best to automatically set the network ID to the chainID,
|
||||||
|
// by not passing the --networkid flag at all. Emit a warning when set
|
||||||
|
// explicitly in case overriding the network ID is not the user's intention.
|
||||||
|
id := ctx.Uint64(NetworkIdFlag.Name)
|
||||||
|
log.Warn("Setting network ID with command-line flag", "id", id)
|
||||||
|
cfg.NetworkId = id
|
||||||
|
}
|
||||||
// Set any dangling config values
|
// Set any dangling config values
|
||||||
if ctx.String(CryptoKZGFlag.Name) != "gokzg" && ctx.String(CryptoKZGFlag.Name) != "ckzg" {
|
if ctx.String(CryptoKZGFlag.Name) != "gokzg" && ctx.String(CryptoKZGFlag.Name) != "ckzg" {
|
||||||
Fatalf("--%s flag must be 'gokzg' or 'ckzg'", CryptoKZGFlag.Name)
|
Fatalf("--%s flag must be 'gokzg' or 'ckzg'", CryptoKZGFlag.Name)
|
||||||
|
|
@ -2059,6 +2124,7 @@ func RegisterFilterAPI(stack *node.Node, backend ethapi.Backend, ethcfg *ethconf
|
||||||
filterSystem := filters.NewFilterSystem(backend, filters.Config{
|
filterSystem := filters.NewFilterSystem(backend, filters.Config{
|
||||||
LogCacheSize: ethcfg.FilterLogCacheSize,
|
LogCacheSize: ethcfg.FilterLogCacheSize,
|
||||||
LogQueryLimit: ethcfg.LogQueryLimit,
|
LogQueryLimit: ethcfg.LogQueryLimit,
|
||||||
|
RangeLimit: ethcfg.RangeLimit,
|
||||||
})
|
})
|
||||||
stack.RegisterAPIs([]rpc.API{{
|
stack.RegisterAPIs([]rpc.API{{
|
||||||
Namespace: "eth",
|
Namespace: "eth",
|
||||||
|
|
@ -2261,15 +2327,18 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
|
||||||
Fatalf("%v", err)
|
Fatalf("%v", err)
|
||||||
}
|
}
|
||||||
options := &core.BlockChainConfig{
|
options := &core.BlockChainConfig{
|
||||||
TrieCleanLimit: ethconfig.Defaults.TrieCleanCache,
|
TrieCleanLimit: ethconfig.Defaults.TrieCleanCache,
|
||||||
NoPrefetch: ctx.Bool(CacheNoPrefetchFlag.Name),
|
NoPrefetch: ctx.Bool(CacheNoPrefetchFlag.Name),
|
||||||
TrieDirtyLimit: ethconfig.Defaults.TrieDirtyCache,
|
TrieDirtyLimit: ethconfig.Defaults.TrieDirtyCache,
|
||||||
ArchiveMode: ctx.String(GCModeFlag.Name) == "archive",
|
ArchiveMode: ctx.String(GCModeFlag.Name) == "archive",
|
||||||
TrieTimeLimit: ethconfig.Defaults.TrieTimeout,
|
TrieTimeLimit: ethconfig.Defaults.TrieTimeout,
|
||||||
SnapshotLimit: ethconfig.Defaults.SnapshotCache,
|
SnapshotLimit: ethconfig.Defaults.SnapshotCache,
|
||||||
Preimages: ctx.Bool(CachePreimagesFlag.Name),
|
Preimages: ctx.Bool(CachePreimagesFlag.Name),
|
||||||
StateScheme: scheme,
|
StateScheme: scheme,
|
||||||
StateHistory: ctx.Uint64(StateHistoryFlag.Name),
|
StateHistory: ctx.Uint64(StateHistoryFlag.Name),
|
||||||
|
TrienodeHistory: ctx.Int64(TrienodeHistoryFlag.Name),
|
||||||
|
NodeFullValueCheckpoint: uint32(ctx.Uint(TrienodeHistoryFullValueCheckpointFlag.Name)),
|
||||||
|
|
||||||
// Disable transaction indexing/unindexing.
|
// Disable transaction indexing/unindexing.
|
||||||
TxLookupLimit: -1,
|
TxLookupLimit: -1,
|
||||||
|
|
||||||
|
|
@ -2281,6 +2350,13 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
|
||||||
|
|
||||||
// Enable state size tracking if enabled
|
// Enable state size tracking if enabled
|
||||||
StateSizeTracking: ctx.Bool(StateSizeTrackingFlag.Name),
|
StateSizeTracking: ctx.Bool(StateSizeTrackingFlag.Name),
|
||||||
|
|
||||||
|
// Configure the slow block statistic logger (disabled by default)
|
||||||
|
SlowBlockThreshold: ethconfig.Defaults.SlowBlockThreshold,
|
||||||
|
}
|
||||||
|
// Only enable slow block logging if the flag was explicitly set
|
||||||
|
if ctx.IsSet(LogSlowBlockFlag.Name) {
|
||||||
|
options.SlowBlockThreshold = ctx.Duration(LogSlowBlockFlag.Name)
|
||||||
}
|
}
|
||||||
if options.ArchiveMode && !options.Preimages {
|
if options.ArchiveMode && !options.Preimages {
|
||||||
options.Preimages = true
|
options.Preimages = true
|
||||||
|
|
|
||||||
|
|
@ -34,4 +34,5 @@ the following commands (in this directory) against a synced mainnet node:
|
||||||
> go run . filtergen --queries queries/filter_queries_mainnet.json http://host:8545
|
> go run . filtergen --queries queries/filter_queries_mainnet.json http://host:8545
|
||||||
> go run . historygen --history-tests queries/history_mainnet.json http://host:8545
|
> go run . historygen --history-tests queries/history_mainnet.json http://host:8545
|
||||||
> go run . tracegen --trace-tests queries/trace_mainnet.json --trace-start 4000000 --trace-end 4000100 http://host:8545
|
> go run . tracegen --trace-tests queries/trace_mainnet.json --trace-start 4000000 --trace-end 4000100 http://host:8545
|
||||||
|
> go run . proofgen --proof-tests queries/proof_mainnet.json --proof-states 3000 http://host:8545
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ func init() {
|
||||||
historyGenerateCommand,
|
historyGenerateCommand,
|
||||||
filterGenerateCommand,
|
filterGenerateCommand,
|
||||||
traceGenerateCommand,
|
traceGenerateCommand,
|
||||||
|
proofGenerateCommand,
|
||||||
filterPerfCommand,
|
filterPerfCommand,
|
||||||
filterFuzzCommand,
|
filterFuzzCommand,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
105
cmd/workload/prooftest.go
Normal file
105
cmd/workload/prooftest.go
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
// Copyright 2025 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/utesting"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// proofTest is the content of a state-proof test.
|
||||||
|
type proofTest struct {
|
||||||
|
BlockNumbers []uint64 `json:"blockNumbers"`
|
||||||
|
Addresses [][]common.Address `json:"addresses"`
|
||||||
|
StorageKeys [][][]string `json:"storageKeys"`
|
||||||
|
Results [][]common.Hash `json:"results"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type proofTestSuite struct {
|
||||||
|
cfg testConfig
|
||||||
|
tests proofTest
|
||||||
|
invalidDir string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newProofTestSuite(cfg testConfig, ctx *cli.Context) *proofTestSuite {
|
||||||
|
s := &proofTestSuite{
|
||||||
|
cfg: cfg,
|
||||||
|
invalidDir: ctx.String(proofTestInvalidOutputFlag.Name),
|
||||||
|
}
|
||||||
|
if err := s.loadTests(); err != nil {
|
||||||
|
exit(err)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *proofTestSuite) loadTests() error {
|
||||||
|
file, err := s.cfg.fsys.Open(s.cfg.proofTestFile)
|
||||||
|
if err != nil {
|
||||||
|
// If not found in embedded FS, try to load it from disk
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
file, err = os.OpenFile(s.cfg.proofTestFile, os.O_RDONLY, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't open proofTestFile: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
if err := json.NewDecoder(file).Decode(&s.tests); err != nil {
|
||||||
|
return fmt.Errorf("invalid JSON in %s: %v", s.cfg.proofTestFile, err)
|
||||||
|
}
|
||||||
|
if len(s.tests.BlockNumbers) == 0 {
|
||||||
|
return fmt.Errorf("proofTestFile %s has no test data", s.cfg.proofTestFile)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *proofTestSuite) allTests() []workloadTest {
|
||||||
|
return []workloadTest{
|
||||||
|
newArchiveWorkloadTest("Proof/GetProof", s.getProof),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *proofTestSuite) getProof(t *utesting.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
for i, blockNumber := range s.tests.BlockNumbers {
|
||||||
|
for j := 0; j < len(s.tests.Addresses[i]); j++ {
|
||||||
|
res, err := s.cfg.client.Geth.GetProof(ctx, s.tests.Addresses[i][j], s.tests.StorageKeys[i][j], big.NewInt(int64(blockNumber)))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("State proving fails, blockNumber: %d, address: %x, keys: %v, err: %v\n", blockNumber, s.tests.Addresses[i][j], strings.Join(s.tests.StorageKeys[i][j], " "), err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
blob, err := json.Marshal(res)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("State proving fails: error %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if crypto.Keccak256Hash(blob) != s.tests.Results[i][j] {
|
||||||
|
t.Errorf("State proof mismatch, %d, number: %d, address: %x, keys: %v: invalid result", i, blockNumber, s.tests.Addresses[i][j], strings.Join(s.tests.StorageKeys[i][j], " "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
355
cmd/workload/prooftestgen.go
Normal file
355
cmd/workload/prooftestgen.go
Normal file
|
|
@ -0,0 +1,355 @@
|
||||||
|
// Copyright 2025 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/tracers/native"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/flags"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/testrand"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
proofGenerateCommand = &cli.Command{
|
||||||
|
Name: "proofgen",
|
||||||
|
Usage: "Generates tests for state proof verification",
|
||||||
|
ArgsUsage: "<RPC endpoint URL>",
|
||||||
|
Action: generateProofTests,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
proofTestFileFlag,
|
||||||
|
proofTestResultOutputFlag,
|
||||||
|
proofTestStatesFlag,
|
||||||
|
proofTestStartBlockFlag,
|
||||||
|
proofTestEndBlockFlag,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
proofTestFileFlag = &cli.StringFlag{
|
||||||
|
Name: "proof-tests",
|
||||||
|
Usage: "JSON file containing proof test queries",
|
||||||
|
Value: "proof_tests.json",
|
||||||
|
Category: flags.TestingCategory,
|
||||||
|
}
|
||||||
|
proofTestResultOutputFlag = &cli.StringFlag{
|
||||||
|
Name: "proof-output",
|
||||||
|
Usage: "Folder containing detailed trace output files",
|
||||||
|
Value: "",
|
||||||
|
Category: flags.TestingCategory,
|
||||||
|
}
|
||||||
|
proofTestStatesFlag = &cli.Int64Flag{
|
||||||
|
Name: "proof-states",
|
||||||
|
Usage: "Number of states to generate proof against",
|
||||||
|
Value: 10000,
|
||||||
|
Category: flags.TestingCategory,
|
||||||
|
}
|
||||||
|
proofTestInvalidOutputFlag = &cli.StringFlag{
|
||||||
|
Name: "proof-invalid",
|
||||||
|
Usage: "Folder containing the mismatched state proof output files",
|
||||||
|
Value: "",
|
||||||
|
Category: flags.TestingCategory,
|
||||||
|
}
|
||||||
|
proofTestStartBlockFlag = &cli.Uint64Flag{
|
||||||
|
Name: "proof-start",
|
||||||
|
Usage: "The number of starting block for proof verification (included)",
|
||||||
|
Category: flags.TestingCategory,
|
||||||
|
}
|
||||||
|
proofTestEndBlockFlag = &cli.Uint64Flag{
|
||||||
|
Name: "proof-end",
|
||||||
|
Usage: "The number of ending block for proof verification (excluded)",
|
||||||
|
Category: flags.TestingCategory,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type proofGenerator func(cli *client, startBlock uint64, endBlock uint64, number int) ([]uint64, [][]common.Address, [][][]string, error)
|
||||||
|
|
||||||
|
func genAccountProof(cli *client, startBlock uint64, endBlock uint64, number int) ([]uint64, [][]common.Address, [][][]string, error) {
|
||||||
|
var (
|
||||||
|
blockNumbers []uint64
|
||||||
|
accountAddresses [][]common.Address
|
||||||
|
storageKeys [][][]string
|
||||||
|
nAccounts int
|
||||||
|
ctx = context.Background()
|
||||||
|
start = time.Now()
|
||||||
|
)
|
||||||
|
chainID, err := cli.Eth.ChainID(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
signer := types.LatestSignerForChainID(chainID)
|
||||||
|
|
||||||
|
for {
|
||||||
|
if nAccounts >= number {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
blockNumber := uint64(rand.Intn(int(endBlock-startBlock))) + startBlock
|
||||||
|
|
||||||
|
block, err := cli.Eth.BlockByNumber(context.Background(), big.NewInt(int64(blockNumber)))
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
addresses []common.Address
|
||||||
|
keys [][]string
|
||||||
|
gather = func(address common.Address) {
|
||||||
|
addresses = append(addresses, address)
|
||||||
|
keys = append(keys, nil)
|
||||||
|
nAccounts++
|
||||||
|
}
|
||||||
|
)
|
||||||
|
for _, tx := range block.Transactions() {
|
||||||
|
if nAccounts >= number {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
sender, err := signer.Sender(tx)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to resolve the sender address", "hash", tx.Hash(), "err", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
gather(sender)
|
||||||
|
|
||||||
|
if tx.To() != nil {
|
||||||
|
gather(*tx.To())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blockNumbers = append(blockNumbers, blockNumber)
|
||||||
|
accountAddresses = append(accountAddresses, addresses)
|
||||||
|
storageKeys = append(storageKeys, keys)
|
||||||
|
}
|
||||||
|
log.Info("Generated tests for account proof", "blocks", len(blockNumbers), "accounts", nAccounts, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||||
|
return blockNumbers, accountAddresses, storageKeys, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func genNonExistentAccountProof(cli *client, startBlock uint64, endBlock uint64, number int) ([]uint64, [][]common.Address, [][][]string, error) {
|
||||||
|
var (
|
||||||
|
blockNumbers []uint64
|
||||||
|
accountAddresses [][]common.Address
|
||||||
|
storageKeys [][][]string
|
||||||
|
total int
|
||||||
|
)
|
||||||
|
for i := 0; i < number/5; i++ {
|
||||||
|
var (
|
||||||
|
addresses []common.Address
|
||||||
|
keys [][]string
|
||||||
|
blockNumber = uint64(rand.Intn(int(endBlock-startBlock))) + startBlock
|
||||||
|
)
|
||||||
|
for j := 0; j < 5; j++ {
|
||||||
|
addresses = append(addresses, testrand.Address())
|
||||||
|
keys = append(keys, nil)
|
||||||
|
}
|
||||||
|
total += len(addresses)
|
||||||
|
blockNumbers = append(blockNumbers, blockNumber)
|
||||||
|
accountAddresses = append(accountAddresses, addresses)
|
||||||
|
storageKeys = append(storageKeys, keys)
|
||||||
|
}
|
||||||
|
log.Info("Generated tests for non-existing account proof", "blocks", len(blockNumbers), "accounts", total)
|
||||||
|
return blockNumbers, accountAddresses, storageKeys, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func genStorageProof(cli *client, startBlock uint64, endBlock uint64, number int) ([]uint64, [][]common.Address, [][][]string, error) {
|
||||||
|
var (
|
||||||
|
blockNumbers []uint64
|
||||||
|
accountAddresses [][]common.Address
|
||||||
|
storageKeys [][][]string
|
||||||
|
|
||||||
|
nAccounts int
|
||||||
|
nStorages int
|
||||||
|
start = time.Now()
|
||||||
|
)
|
||||||
|
for {
|
||||||
|
if nAccounts+nStorages >= number {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
blockNumber := uint64(rand.Intn(int(endBlock-startBlock))) + startBlock
|
||||||
|
|
||||||
|
block, err := cli.Eth.BlockByNumber(context.Background(), big.NewInt(int64(blockNumber)))
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
addresses []common.Address
|
||||||
|
slots [][]string
|
||||||
|
tracer = "prestateTracer"
|
||||||
|
configBlob, _ = json.Marshal(native.PrestateTracerConfig{
|
||||||
|
DiffMode: false,
|
||||||
|
DisableCode: true,
|
||||||
|
DisableStorage: false,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
for _, tx := range block.Transactions() {
|
||||||
|
if nAccounts+nStorages >= number {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if tx.To() == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ret, err := cli.Geth.TraceTransaction(context.Background(), tx.Hash(), &tracers.TraceConfig{
|
||||||
|
Tracer: &tracer,
|
||||||
|
TracerConfig: configBlob,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to trace the transaction", "blockNumber", blockNumber, "hash", tx.Hash(), "err", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
blob, err := json.Marshal(ret)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to marshal data", "err", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var accounts map[common.Address]*types.Account
|
||||||
|
if err := json.Unmarshal(blob, &accounts); err != nil {
|
||||||
|
log.Error("Failed to decode trace result", "blockNumber", blockNumber, "hash", tx.Hash(), "err", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for addr, account := range accounts {
|
||||||
|
if len(account.Storage) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addresses = append(addresses, addr)
|
||||||
|
nAccounts += 1
|
||||||
|
|
||||||
|
var keys []string
|
||||||
|
for k := range account.Storage {
|
||||||
|
keys = append(keys, k.Hex())
|
||||||
|
}
|
||||||
|
nStorages += len(keys)
|
||||||
|
|
||||||
|
var emptyKeys []string
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
emptyKeys = append(emptyKeys, testrand.Hash().Hex())
|
||||||
|
}
|
||||||
|
nStorages += len(emptyKeys)
|
||||||
|
|
||||||
|
slots = append(slots, append(keys, emptyKeys...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blockNumbers = append(blockNumbers, blockNumber)
|
||||||
|
accountAddresses = append(accountAddresses, addresses)
|
||||||
|
storageKeys = append(storageKeys, slots)
|
||||||
|
}
|
||||||
|
log.Info("Generated tests for storage proof", "blocks", len(blockNumbers), "accounts", nAccounts, "storages", nStorages, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||||
|
return blockNumbers, accountAddresses, storageKeys, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func genProofRequests(cli *client, startBlock, endBlock uint64, states int) (*proofTest, error) {
|
||||||
|
var (
|
||||||
|
blockNumbers []uint64
|
||||||
|
accountAddresses [][]common.Address
|
||||||
|
storageKeys [][][]string
|
||||||
|
)
|
||||||
|
ratio := []float64{0.2, 0.1, 0.7}
|
||||||
|
for i, fn := range []proofGenerator{genAccountProof, genNonExistentAccountProof, genStorageProof} {
|
||||||
|
numbers, addresses, keys, err := fn(cli, startBlock, endBlock, int(float64(states)*ratio[i]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
blockNumbers = append(blockNumbers, numbers...)
|
||||||
|
accountAddresses = append(accountAddresses, addresses...)
|
||||||
|
storageKeys = append(storageKeys, keys...)
|
||||||
|
}
|
||||||
|
return &proofTest{
|
||||||
|
BlockNumbers: blockNumbers,
|
||||||
|
Addresses: accountAddresses,
|
||||||
|
StorageKeys: storageKeys,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateProofTests(clictx *cli.Context) error {
|
||||||
|
var (
|
||||||
|
client = makeClient(clictx)
|
||||||
|
ctx = context.Background()
|
||||||
|
states = clictx.Int(proofTestStatesFlag.Name)
|
||||||
|
outputFile = clictx.String(proofTestFileFlag.Name)
|
||||||
|
outputDir = clictx.String(proofTestResultOutputFlag.Name)
|
||||||
|
startBlock = clictx.Uint64(proofTestStartBlockFlag.Name)
|
||||||
|
endBlock = clictx.Uint64(proofTestEndBlockFlag.Name)
|
||||||
|
)
|
||||||
|
head, err := client.Eth.BlockNumber(ctx)
|
||||||
|
if err != nil {
|
||||||
|
exit(err)
|
||||||
|
}
|
||||||
|
if startBlock > head || endBlock > head {
|
||||||
|
return fmt.Errorf("chain is out of proof range, head %d, start: %d, limit: %d", head, startBlock, endBlock)
|
||||||
|
}
|
||||||
|
if endBlock == 0 {
|
||||||
|
endBlock = head
|
||||||
|
}
|
||||||
|
log.Info("Generating proof states", "startBlock", startBlock, "endBlock", endBlock, "states", states)
|
||||||
|
|
||||||
|
test, err := genProofRequests(client, startBlock, endBlock, states)
|
||||||
|
if err != nil {
|
||||||
|
exit(err)
|
||||||
|
}
|
||||||
|
for i, blockNumber := range test.BlockNumbers {
|
||||||
|
var hashes []common.Hash
|
||||||
|
for j := 0; j < len(test.Addresses[i]); j++ {
|
||||||
|
res, err := client.Geth.GetProof(ctx, test.Addresses[i][j], test.StorageKeys[i][j], big.NewInt(int64(blockNumber)))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to prove the state", "number", blockNumber, "address", test.Addresses[i][j], "slots", len(test.StorageKeys[i][j]), "err", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
blob, err := json.Marshal(res)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
hashes = append(hashes, crypto.Keccak256Hash(blob))
|
||||||
|
|
||||||
|
writeStateProof(outputDir, blockNumber, test.Addresses[i][j], res)
|
||||||
|
}
|
||||||
|
test.Results = append(test.Results, hashes)
|
||||||
|
}
|
||||||
|
writeJSON(outputFile, test)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeStateProof(dir string, blockNumber uint64, address common.Address, result any) {
|
||||||
|
if dir == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Ensure the directory exists
|
||||||
|
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
|
||||||
|
exit(fmt.Errorf("failed to create directories: %w", err))
|
||||||
|
}
|
||||||
|
fname := fmt.Sprintf("%d-%x", blockNumber, address)
|
||||||
|
name := filepath.Join(dir, fname)
|
||||||
|
file, err := os.Create(name)
|
||||||
|
if err != nil {
|
||||||
|
exit(fmt.Errorf("error creating %s: %v", name, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
data, _ := json.MarshalIndent(result, "", " ")
|
||||||
|
_, err = file.Write(data)
|
||||||
|
if err != nil {
|
||||||
|
exit(fmt.Errorf("error writing %s: %v", name, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -50,7 +50,9 @@ var (
|
||||||
filterQueryFileFlag,
|
filterQueryFileFlag,
|
||||||
historyTestFileFlag,
|
historyTestFileFlag,
|
||||||
traceTestFileFlag,
|
traceTestFileFlag,
|
||||||
|
proofTestFileFlag,
|
||||||
traceTestInvalidOutputFlag,
|
traceTestInvalidOutputFlag,
|
||||||
|
proofTestInvalidOutputFlag,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
testPatternFlag = &cli.StringFlag{
|
testPatternFlag = &cli.StringFlag{
|
||||||
|
|
@ -95,6 +97,7 @@ type testConfig struct {
|
||||||
historyTestFile string
|
historyTestFile string
|
||||||
historyPruneBlock *uint64
|
historyPruneBlock *uint64
|
||||||
traceTestFile string
|
traceTestFile string
|
||||||
|
proofTestFile string
|
||||||
}
|
}
|
||||||
|
|
||||||
var errPrunedHistory = errors.New("attempt to access pruned history")
|
var errPrunedHistory = errors.New("attempt to access pruned history")
|
||||||
|
|
@ -145,6 +148,12 @@ func testConfigFromCLI(ctx *cli.Context) (cfg testConfig) {
|
||||||
} else {
|
} else {
|
||||||
cfg.traceTestFile = "queries/trace_mainnet.json"
|
cfg.traceTestFile = "queries/trace_mainnet.json"
|
||||||
}
|
}
|
||||||
|
if ctx.IsSet(proofTestFileFlag.Name) {
|
||||||
|
cfg.proofTestFile = ctx.String(proofTestFileFlag.Name)
|
||||||
|
} else {
|
||||||
|
cfg.proofTestFile = "queries/proof_mainnet.json"
|
||||||
|
}
|
||||||
|
|
||||||
cfg.historyPruneBlock = new(uint64)
|
cfg.historyPruneBlock = new(uint64)
|
||||||
*cfg.historyPruneBlock = history.PrunePoints[params.MainnetGenesisHash].BlockNumber
|
*cfg.historyPruneBlock = history.PrunePoints[params.MainnetGenesisHash].BlockNumber
|
||||||
case ctx.Bool(testSepoliaFlag.Name):
|
case ctx.Bool(testSepoliaFlag.Name):
|
||||||
|
|
@ -164,6 +173,12 @@ func testConfigFromCLI(ctx *cli.Context) (cfg testConfig) {
|
||||||
} else {
|
} else {
|
||||||
cfg.traceTestFile = "queries/trace_sepolia.json"
|
cfg.traceTestFile = "queries/trace_sepolia.json"
|
||||||
}
|
}
|
||||||
|
if ctx.IsSet(proofTestFileFlag.Name) {
|
||||||
|
cfg.proofTestFile = ctx.String(proofTestFileFlag.Name)
|
||||||
|
} else {
|
||||||
|
cfg.proofTestFile = "queries/proof_sepolia.json"
|
||||||
|
}
|
||||||
|
|
||||||
cfg.historyPruneBlock = new(uint64)
|
cfg.historyPruneBlock = new(uint64)
|
||||||
*cfg.historyPruneBlock = history.PrunePoints[params.SepoliaGenesisHash].BlockNumber
|
*cfg.historyPruneBlock = history.PrunePoints[params.SepoliaGenesisHash].BlockNumber
|
||||||
default:
|
default:
|
||||||
|
|
@ -171,6 +186,7 @@ func testConfigFromCLI(ctx *cli.Context) (cfg testConfig) {
|
||||||
cfg.filterQueryFile = ctx.String(filterQueryFileFlag.Name)
|
cfg.filterQueryFile = ctx.String(filterQueryFileFlag.Name)
|
||||||
cfg.historyTestFile = ctx.String(historyTestFileFlag.Name)
|
cfg.historyTestFile = ctx.String(historyTestFileFlag.Name)
|
||||||
cfg.traceTestFile = ctx.String(traceTestFileFlag.Name)
|
cfg.traceTestFile = ctx.String(traceTestFileFlag.Name)
|
||||||
|
cfg.proofTestFile = ctx.String(proofTestFileFlag.Name)
|
||||||
}
|
}
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
|
@ -222,11 +238,13 @@ func runTestCmd(ctx *cli.Context) error {
|
||||||
filterSuite := newFilterTestSuite(cfg)
|
filterSuite := newFilterTestSuite(cfg)
|
||||||
historySuite := newHistoryTestSuite(cfg)
|
historySuite := newHistoryTestSuite(cfg)
|
||||||
traceSuite := newTraceTestSuite(cfg, ctx)
|
traceSuite := newTraceTestSuite(cfg, ctx)
|
||||||
|
proofSuite := newProofTestSuite(cfg, ctx)
|
||||||
|
|
||||||
// Filter test cases.
|
// Filter test cases.
|
||||||
tests := filterSuite.allTests()
|
tests := filterSuite.allTests()
|
||||||
tests = append(tests, historySuite.allTests()...)
|
tests = append(tests, historySuite.allTests()...)
|
||||||
tests = append(tests, traceSuite.allTests()...)
|
tests = append(tests, traceSuite.allTests()...)
|
||||||
|
tests = append(tests, proofSuite.allTests()...)
|
||||||
|
|
||||||
utests := filterTests(tests, ctx.String(testPatternFlag.Name), func(t workloadTest) bool {
|
utests := filterTests(tests, ctx.String(testPatternFlag.Name), func(t workloadTest) bool {
|
||||||
if t.Slow && !ctx.Bool(testSlowFlag.Name) {
|
if t.Slow && !ctx.Bool(testSlowFlag.Name) {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
package bitutil
|
package bitutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/subtle"
|
||||||
"runtime"
|
"runtime"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
@ -17,46 +18,16 @@ const supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "amd64" |
|
||||||
|
|
||||||
// XORBytes xors the bytes in a and b. The destination is assumed to have enough
|
// XORBytes xors the bytes in a and b. The destination is assumed to have enough
|
||||||
// space. Returns the number of bytes xor'd.
|
// space. Returns the number of bytes xor'd.
|
||||||
|
//
|
||||||
|
// If dst does not have length at least n,
|
||||||
|
// XORBytes panics without writing anything to dst.
|
||||||
|
//
|
||||||
|
// dst and x or y may overlap exactly or not at all,
|
||||||
|
// otherwise XORBytes may panic.
|
||||||
|
//
|
||||||
|
// Deprecated: use crypto/subtle.XORBytes
|
||||||
func XORBytes(dst, a, b []byte) int {
|
func XORBytes(dst, a, b []byte) int {
|
||||||
if supportsUnaligned {
|
return subtle.XORBytes(dst, a, b)
|
||||||
return fastXORBytes(dst, a, b)
|
|
||||||
}
|
|
||||||
return safeXORBytes(dst, a, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// fastXORBytes xors in bulk. It only works on architectures that support
|
|
||||||
// unaligned read/writes.
|
|
||||||
func fastXORBytes(dst, a, b []byte) int {
|
|
||||||
n := len(a)
|
|
||||||
if len(b) < n {
|
|
||||||
n = len(b)
|
|
||||||
}
|
|
||||||
w := n / wordSize
|
|
||||||
if w > 0 {
|
|
||||||
dw := *(*[]uintptr)(unsafe.Pointer(&dst))
|
|
||||||
aw := *(*[]uintptr)(unsafe.Pointer(&a))
|
|
||||||
bw := *(*[]uintptr)(unsafe.Pointer(&b))
|
|
||||||
for i := 0; i < w; i++ {
|
|
||||||
dw[i] = aw[i] ^ bw[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i := n - n%wordSize; i < n; i++ {
|
|
||||||
dst[i] = a[i] ^ b[i]
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
// safeXORBytes xors one by one. It works on all architectures, independent if
|
|
||||||
// it supports unaligned read/writes or not.
|
|
||||||
func safeXORBytes(dst, a, b []byte) int {
|
|
||||||
n := len(a)
|
|
||||||
if len(b) < n {
|
|
||||||
n = len(b)
|
|
||||||
}
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
dst[i] = a[i] ^ b[i]
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ANDBytes ands the bytes in a and b. The destination is assumed to have enough
|
// ANDBytes ands the bytes in a and b. The destination is assumed to have enough
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ func TestXOR(t *testing.T) {
|
||||||
d2 := make([]byte, 1023+alignD)[alignD:]
|
d2 := make([]byte, 1023+alignD)[alignD:]
|
||||||
|
|
||||||
XORBytes(d1, p, q)
|
XORBytes(d1, p, q)
|
||||||
safeXORBytes(d2, p, q)
|
naiveXOR(d2, p, q)
|
||||||
if !bytes.Equal(d1, d2) {
|
if !bytes.Equal(d1, d2) {
|
||||||
t.Error("not equal", d1, d2)
|
t.Error("not equal", d1, d2)
|
||||||
}
|
}
|
||||||
|
|
@ -38,6 +38,18 @@ func TestXOR(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// naiveXOR xors bytes one by one.
|
||||||
|
func naiveXOR(dst, a, b []byte) int {
|
||||||
|
n := len(a)
|
||||||
|
if len(b) < n {
|
||||||
|
n = len(b)
|
||||||
|
}
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
dst[i] = a[i] ^ b[i]
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
// Tests that bitwise AND works for various alignments.
|
// Tests that bitwise AND works for various alignments.
|
||||||
func TestAND(t *testing.T) {
|
func TestAND(t *testing.T) {
|
||||||
for alignP := 0; alignP < 2; alignP++ {
|
for alignP := 0; alignP < 2; alignP++ {
|
||||||
|
|
@ -134,7 +146,7 @@ func benchmarkBaseXOR(b *testing.B, size int) {
|
||||||
p, q := make([]byte, size), make([]byte, size)
|
p, q := make([]byte, size), make([]byte, size)
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
safeXORBytes(p, p, q)
|
naiveXOR(p, p, q)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ func (t PrettyAge) String() string {
|
||||||
result, prec := "", 0
|
result, prec := "", 0
|
||||||
|
|
||||||
for _, unit := range ageUnits {
|
for _, unit := range ageUnits {
|
||||||
if diff > unit.Size {
|
if diff >= unit.Size {
|
||||||
result = fmt.Sprintf("%s%d%s", result, diff/unit.Size, unit.Symbol)
|
result = fmt.Sprintf("%s%d%s", result, diff/unit.Size, unit.Symbol)
|
||||||
diff %= unit.Size
|
diff %= unit.Size
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
@ -24,10 +26,7 @@ import (
|
||||||
// FileExist checks if a file exists at filePath.
|
// FileExist checks if a file exists at filePath.
|
||||||
func FileExist(filePath string) bool {
|
func FileExist(filePath string) bool {
|
||||||
_, err := os.Stat(filePath)
|
_, err := os.Stat(filePath)
|
||||||
if err != nil && os.IsNotExist(err) {
|
return !errors.Is(err, fs.ErrNotExist)
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AbsolutePath returns datadir + filename, or filename if it is absolute.
|
// AbsolutePath returns datadir + filename, or filename if it is absolute.
|
||||||
|
|
@ -37,3 +36,14 @@ func AbsolutePath(datadir string, filename string) string {
|
||||||
}
|
}
|
||||||
return filepath.Join(datadir, filename)
|
return filepath.Join(datadir, filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsNonEmptyDir checks if a directory exists and is non-empty.
|
||||||
|
func IsNonEmptyDir(dir string) bool {
|
||||||
|
f, err := os.Open(dir)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
names, _ := f.Readdirnames(1)
|
||||||
|
return len(names) > 0
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,13 +26,13 @@ type StorageSize float64
|
||||||
|
|
||||||
// String implements the stringer interface.
|
// String implements the stringer interface.
|
||||||
func (s StorageSize) String() string {
|
func (s StorageSize) String() string {
|
||||||
if s > 1099511627776 {
|
if s >= 1099511627776 {
|
||||||
return fmt.Sprintf("%.2f TiB", s/1099511627776)
|
return fmt.Sprintf("%.2f TiB", s/1099511627776)
|
||||||
} else if s > 1073741824 {
|
} else if s >= 1073741824 {
|
||||||
return fmt.Sprintf("%.2f GiB", s/1073741824)
|
return fmt.Sprintf("%.2f GiB", s/1073741824)
|
||||||
} else if s > 1048576 {
|
} else if s >= 1048576 {
|
||||||
return fmt.Sprintf("%.2f MiB", s/1048576)
|
return fmt.Sprintf("%.2f MiB", s/1048576)
|
||||||
} else if s > 1024 {
|
} else if s >= 1024 {
|
||||||
return fmt.Sprintf("%.2f KiB", s/1024)
|
return fmt.Sprintf("%.2f KiB", s/1024)
|
||||||
} else {
|
} else {
|
||||||
return fmt.Sprintf("%.2f B", s)
|
return fmt.Sprintf("%.2f B", s)
|
||||||
|
|
@ -42,13 +42,13 @@ func (s StorageSize) String() string {
|
||||||
// TerminalString implements log.TerminalStringer, formatting a string for console
|
// TerminalString implements log.TerminalStringer, formatting a string for console
|
||||||
// output during logging.
|
// output during logging.
|
||||||
func (s StorageSize) TerminalString() string {
|
func (s StorageSize) TerminalString() string {
|
||||||
if s > 1099511627776 {
|
if s >= 1099511627776 {
|
||||||
return fmt.Sprintf("%.2fTiB", s/1099511627776)
|
return fmt.Sprintf("%.2fTiB", s/1099511627776)
|
||||||
} else if s > 1073741824 {
|
} else if s >= 1073741824 {
|
||||||
return fmt.Sprintf("%.2fGiB", s/1073741824)
|
return fmt.Sprintf("%.2fGiB", s/1073741824)
|
||||||
} else if s > 1048576 {
|
} else if s >= 1048576 {
|
||||||
return fmt.Sprintf("%.2fMiB", s/1048576)
|
return fmt.Sprintf("%.2fMiB", s/1048576)
|
||||||
} else if s > 1024 {
|
} else if s >= 1024 {
|
||||||
return fmt.Sprintf("%.2fKiB", s/1024)
|
return fmt.Sprintf("%.2fKiB", s/1024)
|
||||||
} else {
|
} else {
|
||||||
return fmt.Sprintf("%.2fB", s)
|
return fmt.Sprintf("%.2fB", s)
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"golang.org/x/crypto/sha3"
|
"github.com/ethereum/go-ethereum/crypto/keccak"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Lengths of hashes and addresses in bytes.
|
// Lengths of hashes and addresses in bytes.
|
||||||
|
|
@ -71,6 +71,15 @@ func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) }
|
||||||
// If b is larger than len(h), b will be cropped from the left.
|
// If b is larger than len(h), b will be cropped from the left.
|
||||||
func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) }
|
func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) }
|
||||||
|
|
||||||
|
// IsHexHash verifies whether a string can represent a valid hex-encoded
|
||||||
|
// Ethereum hash or not.
|
||||||
|
func IsHexHash(s string) bool {
|
||||||
|
if has0xPrefix(s) {
|
||||||
|
s = s[2:]
|
||||||
|
}
|
||||||
|
return len(s) == 2*HashLength && isHex(s)
|
||||||
|
}
|
||||||
|
|
||||||
// Cmp compares two hashes.
|
// Cmp compares two hashes.
|
||||||
func (h Hash) Cmp(other Hash) int {
|
func (h Hash) Cmp(other Hash) int {
|
||||||
return bytes.Compare(h[:], other[:])
|
return bytes.Compare(h[:], other[:])
|
||||||
|
|
@ -262,7 +271,7 @@ func (a *Address) checksumHex() []byte {
|
||||||
buf := a.hex()
|
buf := a.hex()
|
||||||
|
|
||||||
// compute checksum
|
// compute checksum
|
||||||
sha := sha3.NewLegacyKeccak256()
|
sha := keccak.NewLegacyKeccak256()
|
||||||
sha.Write(buf[2:])
|
sha.Write(buf[2:])
|
||||||
hash := sha.Sum(nil)
|
hash := sha.Sum(nil)
|
||||||
for i := 2; i < len(buf); i++ {
|
for i := 2; i < len(buf); i++ {
|
||||||
|
|
|
||||||
|
|
@ -258,11 +258,11 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa
|
||||||
if !cancun {
|
if !cancun {
|
||||||
switch {
|
switch {
|
||||||
case header.ExcessBlobGas != nil:
|
case header.ExcessBlobGas != nil:
|
||||||
return fmt.Errorf("invalid excessBlobGas: have %d, expected nil", header.ExcessBlobGas)
|
return fmt.Errorf("invalid excessBlobGas: have %d, expected nil", *header.ExcessBlobGas)
|
||||||
case header.BlobGasUsed != nil:
|
case header.BlobGasUsed != nil:
|
||||||
return fmt.Errorf("invalid blobGasUsed: have %d, expected nil", header.BlobGasUsed)
|
return fmt.Errorf("invalid blobGasUsed: have %d, expected nil", *header.BlobGasUsed)
|
||||||
case header.ParentBeaconRoot != nil:
|
case header.ParentBeaconRoot != nil:
|
||||||
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot)
|
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", *header.ParentBeaconRoot)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if header.ParentBeaconRoot == nil {
|
if header.ParentBeaconRoot == nil {
|
||||||
|
|
@ -365,46 +365,7 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
|
||||||
header.Root = state.IntermediateRoot(true)
|
header.Root = state.IntermediateRoot(true)
|
||||||
|
|
||||||
// Assemble the final block.
|
// Assemble the final block.
|
||||||
block := types.NewBlock(header, body, receipts, trie.NewStackTrie(nil))
|
return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)), nil
|
||||||
|
|
||||||
// Create the block witness and attach to block.
|
|
||||||
// This step needs to happen as late as possible to catch all access events.
|
|
||||||
if chain.Config().IsVerkle(header.Number, header.Time) {
|
|
||||||
keys := state.AccessEvents().Keys()
|
|
||||||
|
|
||||||
// Open the pre-tree to prove the pre-state against
|
|
||||||
parent := chain.GetHeaderByNumber(header.Number.Uint64() - 1)
|
|
||||||
if parent == nil {
|
|
||||||
return nil, fmt.Errorf("nil parent header for block %d", header.Number)
|
|
||||||
}
|
|
||||||
preTrie, err := state.Database().OpenTrie(parent.Root)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error opening pre-state tree root: %w", err)
|
|
||||||
}
|
|
||||||
postTrie := state.GetTrie()
|
|
||||||
if postTrie == nil {
|
|
||||||
return nil, errors.New("post-state tree is not available")
|
|
||||||
}
|
|
||||||
vktPreTrie, okpre := preTrie.(*trie.VerkleTrie)
|
|
||||||
vktPostTrie, okpost := postTrie.(*trie.VerkleTrie)
|
|
||||||
|
|
||||||
// The witness is only attached iff both parent and current block are
|
|
||||||
// using verkle tree.
|
|
||||||
if okpre && okpost {
|
|
||||||
if len(keys) > 0 {
|
|
||||||
verkleProof, stateDiff, err := vktPreTrie.Proof(vktPostTrie, keys)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error generating verkle proof for block %d: %w", header.Number, err)
|
|
||||||
}
|
|
||||||
block = block.WithWitness(&types.ExecutionWitness{
|
|
||||||
StateDiff: stateDiff,
|
|
||||||
VerkleProof: verkleProof,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return block, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seal generates a new sealing request for the given input block and pushes
|
// Seal generates a new sealing request for the given input block and pushes
|
||||||
|
|
|
||||||
|
|
@ -37,12 +37,12 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto/keccak"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"golang.org/x/crypto/sha3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -305,11 +305,11 @@ func (c *Clique) verifyHeader(chain consensus.ChainHeaderReader, header *types.H
|
||||||
// Verify the non-existence of cancun-specific header fields
|
// Verify the non-existence of cancun-specific header fields
|
||||||
switch {
|
switch {
|
||||||
case header.ExcessBlobGas != nil:
|
case header.ExcessBlobGas != nil:
|
||||||
return fmt.Errorf("invalid excessBlobGas: have %d, expected nil", header.ExcessBlobGas)
|
return fmt.Errorf("invalid excessBlobGas: have %d, expected nil", *header.ExcessBlobGas)
|
||||||
case header.BlobGasUsed != nil:
|
case header.BlobGasUsed != nil:
|
||||||
return fmt.Errorf("invalid blobGasUsed: have %d, expected nil", header.BlobGasUsed)
|
return fmt.Errorf("invalid blobGasUsed: have %d, expected nil", *header.BlobGasUsed)
|
||||||
case header.ParentBeaconRoot != nil:
|
case header.ParentBeaconRoot != nil:
|
||||||
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot)
|
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", *header.ParentBeaconRoot)
|
||||||
}
|
}
|
||||||
// All basic checks passed, verify cascading fields
|
// All basic checks passed, verify cascading fields
|
||||||
return c.verifyCascadingFields(chain, header, parents)
|
return c.verifyCascadingFields(chain, header, parents)
|
||||||
|
|
@ -642,7 +642,7 @@ func (c *Clique) Close() error {
|
||||||
|
|
||||||
// SealHash returns the hash of a block prior to it being sealed.
|
// SealHash returns the hash of a block prior to it being sealed.
|
||||||
func SealHash(header *types.Header) (hash common.Hash) {
|
func SealHash(header *types.Header) (hash common.Hash) {
|
||||||
hasher := sha3.NewLegacyKeccak256()
|
hasher := keccak.NewLegacyKeccak256()
|
||||||
encodeSigHeader(hasher, header)
|
encodeSigHeader(hasher, header)
|
||||||
hasher.(crypto.KeccakState).Read(hash[:])
|
hasher.(crypto.KeccakState).Read(hash[:])
|
||||||
return hash
|
return hash
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,11 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto/keccak"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
"golang.org/x/crypto/sha3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ethash proof-of-work protocol constants.
|
// Ethash proof-of-work protocol constants.
|
||||||
|
|
@ -278,11 +278,11 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa
|
||||||
// Verify the non-existence of cancun-specific header fields
|
// Verify the non-existence of cancun-specific header fields
|
||||||
switch {
|
switch {
|
||||||
case header.ExcessBlobGas != nil:
|
case header.ExcessBlobGas != nil:
|
||||||
return fmt.Errorf("invalid excessBlobGas: have %d, expected nil", header.ExcessBlobGas)
|
return fmt.Errorf("invalid excessBlobGas: have %d, expected nil", *header.ExcessBlobGas)
|
||||||
case header.BlobGasUsed != nil:
|
case header.BlobGasUsed != nil:
|
||||||
return fmt.Errorf("invalid blobGasUsed: have %d, expected nil", header.BlobGasUsed)
|
return fmt.Errorf("invalid blobGasUsed: have %d, expected nil", *header.BlobGasUsed)
|
||||||
case header.ParentBeaconRoot != nil:
|
case header.ParentBeaconRoot != nil:
|
||||||
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot)
|
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", *header.ParentBeaconRoot)
|
||||||
}
|
}
|
||||||
// Add some fake checks for tests
|
// Add some fake checks for tests
|
||||||
if ethash.fakeDelay != nil {
|
if ethash.fakeDelay != nil {
|
||||||
|
|
@ -527,7 +527,7 @@ func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
|
||||||
|
|
||||||
// SealHash returns the hash of a block prior to it being sealed.
|
// SealHash returns the hash of a block prior to it being sealed.
|
||||||
func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) {
|
func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) {
|
||||||
hasher := sha3.NewLegacyKeccak256()
|
hasher := keccak.NewLegacyKeccak256()
|
||||||
|
|
||||||
enc := []interface{}{
|
enc := []interface{}{
|
||||||
header.ParentHash,
|
header.ParentHash,
|
||||||
|
|
|
||||||
|
|
@ -53,9 +53,9 @@ func (bc *BlobConfig) blobPrice(excessBlobGas uint64) *big.Int {
|
||||||
return new(big.Int).Mul(f, big.NewInt(params.BlobTxBlobGasPerBlob))
|
return new(big.Int).Mul(f, big.NewInt(params.BlobTxBlobGasPerBlob))
|
||||||
}
|
}
|
||||||
|
|
||||||
func latestBlobConfig(cfg *params.ChainConfig, time uint64) *BlobConfig {
|
func latestBlobConfig(cfg *params.ChainConfig, time uint64) (BlobConfig, error) {
|
||||||
if cfg.BlobScheduleConfig == nil {
|
if cfg.BlobScheduleConfig == nil {
|
||||||
return nil
|
return BlobConfig{}, errors.New("no blob config")
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
london = cfg.LondonBlock
|
london = cfg.LondonBlock
|
||||||
|
|
@ -80,14 +80,14 @@ func latestBlobConfig(cfg *params.ChainConfig, time uint64) *BlobConfig {
|
||||||
case cfg.IsCancun(london, time) && s.Cancun != nil:
|
case cfg.IsCancun(london, time) && s.Cancun != nil:
|
||||||
bc = s.Cancun
|
bc = s.Cancun
|
||||||
default:
|
default:
|
||||||
return nil
|
return BlobConfig{}, errors.New("no blob config")
|
||||||
}
|
}
|
||||||
|
|
||||||
return &BlobConfig{
|
return BlobConfig{
|
||||||
Target: bc.Target,
|
Target: bc.Target,
|
||||||
Max: bc.Max,
|
Max: bc.Max,
|
||||||
UpdateFraction: bc.UpdateFraction,
|
UpdateFraction: bc.UpdateFraction,
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyEIP4844Header verifies the presence of the excessBlobGas field and that
|
// VerifyEIP4844Header verifies the presence of the excessBlobGas field and that
|
||||||
|
|
@ -98,8 +98,8 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade
|
||||||
panic("bad header pair")
|
panic("bad header pair")
|
||||||
}
|
}
|
||||||
|
|
||||||
bcfg := latestBlobConfig(config, header.Time)
|
bcfg, err := latestBlobConfig(config, header.Time)
|
||||||
if bcfg == nil {
|
if err != nil {
|
||||||
panic("called before EIP-4844 is active")
|
panic("called before EIP-4844 is active")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,7 +115,7 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade
|
||||||
return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", *header.BlobGasUsed, bcfg.maxBlobGas())
|
return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", *header.BlobGasUsed, bcfg.maxBlobGas())
|
||||||
}
|
}
|
||||||
if *header.BlobGasUsed%params.BlobTxBlobGasPerBlob != 0 {
|
if *header.BlobGasUsed%params.BlobTxBlobGasPerBlob != 0 {
|
||||||
return fmt.Errorf("blob gas used %d not a multiple of blob gas per blob %d", header.BlobGasUsed, params.BlobTxBlobGasPerBlob)
|
return fmt.Errorf("blob gas used %d not a multiple of blob gas per blob %d", *header.BlobGasUsed, params.BlobTxBlobGasPerBlob)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify the excessBlobGas is correct based on the parent header
|
// Verify the excessBlobGas is correct based on the parent header
|
||||||
|
|
@ -130,11 +130,14 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade
|
||||||
// blobs on top of the excess blob gas.
|
// blobs on top of the excess blob gas.
|
||||||
func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header, headTimestamp uint64) uint64 {
|
func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header, headTimestamp uint64) uint64 {
|
||||||
isOsaka := config.IsOsaka(config.LondonBlock, headTimestamp)
|
isOsaka := config.IsOsaka(config.LondonBlock, headTimestamp)
|
||||||
bcfg := latestBlobConfig(config, headTimestamp)
|
bcfg, err := latestBlobConfig(config, headTimestamp)
|
||||||
|
if err != nil {
|
||||||
|
panic("calculating excess blob gas on nil blob config")
|
||||||
|
}
|
||||||
return calcExcessBlobGas(isOsaka, bcfg, parent)
|
return calcExcessBlobGas(isOsaka, bcfg, parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func calcExcessBlobGas(isOsaka bool, bcfg *BlobConfig, parent *types.Header) uint64 {
|
func calcExcessBlobGas(isOsaka bool, bcfg BlobConfig, parent *types.Header) uint64 {
|
||||||
var parentExcessBlobGas, parentBlobGasUsed uint64
|
var parentExcessBlobGas, parentBlobGasUsed uint64
|
||||||
if parent.ExcessBlobGas != nil {
|
if parent.ExcessBlobGas != nil {
|
||||||
parentExcessBlobGas = *parent.ExcessBlobGas
|
parentExcessBlobGas = *parent.ExcessBlobGas
|
||||||
|
|
@ -169,8 +172,8 @@ func calcExcessBlobGas(isOsaka bool, bcfg *BlobConfig, parent *types.Header) uin
|
||||||
|
|
||||||
// CalcBlobFee calculates the blobfee from the header's excess blob gas field.
|
// CalcBlobFee calculates the blobfee from the header's excess blob gas field.
|
||||||
func CalcBlobFee(config *params.ChainConfig, header *types.Header) *big.Int {
|
func CalcBlobFee(config *params.ChainConfig, header *types.Header) *big.Int {
|
||||||
blobConfig := latestBlobConfig(config, header.Time)
|
blobConfig, err := latestBlobConfig(config, header.Time)
|
||||||
if blobConfig == nil {
|
if err != nil {
|
||||||
panic("calculating blob fee on unsupported fork")
|
panic("calculating blob fee on unsupported fork")
|
||||||
}
|
}
|
||||||
return blobConfig.blobBaseFee(*header.ExcessBlobGas)
|
return blobConfig.blobBaseFee(*header.ExcessBlobGas)
|
||||||
|
|
@ -178,8 +181,8 @@ func CalcBlobFee(config *params.ChainConfig, header *types.Header) *big.Int {
|
||||||
|
|
||||||
// MaxBlobsPerBlock returns the max blobs per block for a block at the given timestamp.
|
// MaxBlobsPerBlock returns the max blobs per block for a block at the given timestamp.
|
||||||
func MaxBlobsPerBlock(cfg *params.ChainConfig, time uint64) int {
|
func MaxBlobsPerBlock(cfg *params.ChainConfig, time uint64) int {
|
||||||
blobConfig := latestBlobConfig(cfg, time)
|
blobConfig, err := latestBlobConfig(cfg, time)
|
||||||
if blobConfig == nil {
|
if err != nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return blobConfig.Max
|
return blobConfig.Max
|
||||||
|
|
@ -193,13 +196,22 @@ func MaxBlobGasPerBlock(cfg *params.ChainConfig, time uint64) uint64 {
|
||||||
// LatestMaxBlobsPerBlock returns the latest max blobs per block defined by the
|
// LatestMaxBlobsPerBlock returns the latest max blobs per block defined by the
|
||||||
// configuration, regardless of the currently active fork.
|
// configuration, regardless of the currently active fork.
|
||||||
func LatestMaxBlobsPerBlock(cfg *params.ChainConfig) int {
|
func LatestMaxBlobsPerBlock(cfg *params.ChainConfig) int {
|
||||||
bcfg := latestBlobConfig(cfg, math.MaxUint64)
|
bcfg, err := latestBlobConfig(cfg, math.MaxUint64)
|
||||||
if bcfg == nil {
|
if err != nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return bcfg.Max
|
return bcfg.Max
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TargetBlobsPerBlock returns the target blobs per block for a block at the given timestamp.
|
||||||
|
func TargetBlobsPerBlock(cfg *params.ChainConfig, time uint64) int {
|
||||||
|
blobConfig, err := latestBlobConfig(cfg, time)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return blobConfig.Target
|
||||||
|
}
|
||||||
|
|
||||||
// fakeExponential approximates factor * e ** (numerator / denominator) using
|
// fakeExponential approximates factor * e ** (numerator / denominator) using
|
||||||
// Taylor expansion.
|
// Taylor expansion.
|
||||||
func fakeExponential(factor, numerator, denominator *big.Int) *big.Int {
|
func fakeExponential(factor, numerator, denominator *big.Int) *big.Int {
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ func (p *terminalPrompter) PromptPassword(prompt string) (passwd string, err err
|
||||||
// PromptConfirm displays the given prompt to the user and requests a boolean
|
// PromptConfirm displays the given prompt to the user and requests a boolean
|
||||||
// choice to be made, returning that choice.
|
// choice to be made, returning that choice.
|
||||||
func (p *terminalPrompter) PromptConfirm(prompt string) (bool, error) {
|
func (p *terminalPrompter) PromptConfirm(prompt string) (bool, error) {
|
||||||
input, err := p.Prompt(prompt + " [y/n] ")
|
input, err := p.PromptInput(prompt + " [y/n] ")
|
||||||
if len(input) > 0 && strings.EqualFold(input[:1], "y") {
|
if len(input) > 0 && strings.EqualFold(input[:1], "y") {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
237
core/bintrie_witness_test.go
Normal file
237
core/bintrie_witness_test.go
Normal file
|
|
@ -0,0 +1,237 @@
|
||||||
|
// Copyright 2024 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/beacon"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/triedb"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
testVerkleChainConfig = ¶ms.ChainConfig{
|
||||||
|
ChainID: big.NewInt(1),
|
||||||
|
HomesteadBlock: big.NewInt(0),
|
||||||
|
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),
|
||||||
|
Ethash: new(params.EthashConfig),
|
||||||
|
ShanghaiTime: u64(0),
|
||||||
|
VerkleTime: u64(0),
|
||||||
|
TerminalTotalDifficulty: common.Big0,
|
||||||
|
EnableVerkleAtGenesis: true,
|
||||||
|
BlobScheduleConfig: ¶ms.BlobScheduleConfig{
|
||||||
|
Verkle: params.DefaultPragueBlobConfig,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestProcessVerkle(t *testing.T) {
|
||||||
|
var (
|
||||||
|
code = common.FromHex(`6060604052600a8060106000396000f360606040526008565b00`)
|
||||||
|
intrinsicContractCreationGas, _ = IntrinsicGas(code, nil, nil, true, true, true, true)
|
||||||
|
// A contract creation that calls EXTCODECOPY in the constructor. Used to ensure that the witness
|
||||||
|
// will not contain that copied data.
|
||||||
|
// Source: https://gist.github.com/gballet/a23db1e1cb4ed105616b5920feb75985
|
||||||
|
codeWithExtCodeCopy = common.FromHex(`0x60806040526040516100109061017b565b604051809103906000f08015801561002c573d6000803e3d6000fd5b506000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555034801561007857600080fd5b5060008067ffffffffffffffff8111156100955761009461024a565b5b6040519080825280601f01601f1916602001820160405280156100c75781602001600182028036833780820191505090505b50905060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506020600083833c81610101906101e3565b60405161010d90610187565b61011791906101a3565b604051809103906000f080158015610133573d6000803e3d6000fd5b50600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505061029b565b60d58061046783390190565b6102068061053c83390190565b61019d816101d9565b82525050565b60006020820190506101b86000830184610194565b92915050565b6000819050602082019050919050565b600081519050919050565b6000819050919050565b60006101ee826101ce565b826101f8846101be565b905061020381610279565b925060208210156102435761023e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8360200360080261028e565b831692505b5050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600061028582516101d9565b80915050919050565b600082821b905092915050565b6101bd806102aa6000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f566852414610030575b600080fd5b61003861004e565b6040516100459190610146565b60405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166381ca91d36040518163ffffffff1660e01b815260040160206040518083038186803b1580156100b857600080fd5b505afa1580156100cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100f0919061010a565b905090565b60008151905061010481610170565b92915050565b6000602082840312156101205761011f61016b565b5b600061012e848285016100f5565b91505092915050565b61014081610161565b82525050565b600060208201905061015b6000830184610137565b92915050565b6000819050919050565b600080fd5b61017981610161565b811461018457600080fd5b5056fea2646970667358221220a6a0e11af79f176f9c421b7b12f441356b25f6489b83d38cc828a701720b41f164736f6c63430008070033608060405234801561001057600080fd5b5060b68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063ab5ed15014602d575b600080fd5b60336047565b604051603e9190605d565b60405180910390f35b60006001905090565b6057816076565b82525050565b6000602082019050607060008301846050565b92915050565b600081905091905056fea26469706673582212203a14eb0d5cd07c277d3e24912f110ddda3e553245a99afc4eeefb2fbae5327aa64736f6c63430008070033608060405234801561001057600080fd5b5060405161020638038061020683398181016040528101906100329190610063565b60018160001c6100429190610090565b60008190555050610145565b60008151905061005d8161012e565b92915050565b60006020828403121561007957610078610129565b5b60006100878482850161004e565b91505092915050565b600061009b826100f0565b91506100a6836100f0565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156100db576100da6100fa565b5b828201905092915050565b6000819050919050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600080fd5b610137816100e6565b811461014257600080fd5b50565b60b3806101536000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806381ca91d314602d575b600080fd5b60336047565b604051603e9190605a565b60405180910390f35b60005481565b6054816073565b82525050565b6000602082019050606d6000830184604d565b92915050565b600081905091905056fea26469706673582212209bff7098a2f526de1ad499866f27d6d0d6f17b74a413036d6063ca6a0998ca4264736f6c63430008070033`)
|
||||||
|
intrinsicCodeWithExtCodeCopyGas, _ = IntrinsicGas(codeWithExtCodeCopy, nil, nil, true, true, true, true)
|
||||||
|
signer = types.LatestSigner(testVerkleChainConfig)
|
||||||
|
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
|
bcdb = rawdb.NewMemoryDatabase() // Database for the blockchain
|
||||||
|
coinbase = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7")
|
||||||
|
gspec = &Genesis{
|
||||||
|
Config: testVerkleChainConfig,
|
||||||
|
Alloc: GenesisAlloc{
|
||||||
|
coinbase: {
|
||||||
|
Balance: big.NewInt(1000000000000000000), // 1 ether
|
||||||
|
Nonce: 0,
|
||||||
|
},
|
||||||
|
params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0},
|
||||||
|
params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode, Balance: common.Big0},
|
||||||
|
params.WithdrawalQueueAddress: {Nonce: 1, Code: params.WithdrawalQueueCode, Balance: common.Big0},
|
||||||
|
params.ConsolidationQueueAddress: {Nonce: 1, Code: params.ConsolidationQueueCode, Balance: common.Big0},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
// Verkle trees use the snapshot, which must be enabled before the
|
||||||
|
// data is saved into the tree+database.
|
||||||
|
// genesis := gspec.MustCommit(bcdb, triedb)
|
||||||
|
options := DefaultConfig().WithStateScheme(rawdb.PathScheme)
|
||||||
|
options.SnapshotLimit = 0
|
||||||
|
blockchain, _ := NewBlockChain(bcdb, gspec, beacon.New(ethash.NewFaker()), options)
|
||||||
|
defer blockchain.Stop()
|
||||||
|
|
||||||
|
txCost1 := params.TxGas
|
||||||
|
txCost2 := params.TxGas
|
||||||
|
contractCreationCost := intrinsicContractCreationGas +
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* creation with value */
|
||||||
|
739 /* execution costs */
|
||||||
|
codeWithExtCodeCopyGas := intrinsicCodeWithExtCodeCopyGas +
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation (tx) */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation (CREATE at pc=0x20) */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #0 */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #1 */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #2 */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #3 */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #4 */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #5 */
|
||||||
|
params.WitnessChunkReadCost + /* SLOAD in constructor */
|
||||||
|
params.WitnessChunkWriteCost + /* SSTORE in constructor */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation (CREATE at PC=0x121) */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #0 */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #1 */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #2 */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #3 */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #4 */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #5 */
|
||||||
|
params.WitnessChunkReadCost + /* SLOAD in constructor */
|
||||||
|
params.WitnessChunkWriteCost + /* SSTORE in constructor */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash for tx creation */
|
||||||
|
15*(params.WitnessChunkReadCost+params.WitnessChunkWriteCost) + /* code chunks #0..#14 */
|
||||||
|
uint64(4844) /* execution costs */
|
||||||
|
blockGasUsagesExpected := []uint64{
|
||||||
|
txCost1*2 + txCost2,
|
||||||
|
txCost1*2 + txCost2 + contractCreationCost + codeWithExtCodeCopyGas,
|
||||||
|
}
|
||||||
|
_, chain, _ := GenerateChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) {
|
||||||
|
gen.SetPoS()
|
||||||
|
|
||||||
|
// TODO need to check that the tx cost provided is the exact amount used (no remaining left-over)
|
||||||
|
tx, _ := types.SignTx(types.NewTransaction(uint64(i)*3, common.Address{byte(i), 2, 3}, big.NewInt(999), txCost1, big.NewInt(875000000), nil), signer, testKey)
|
||||||
|
gen.AddTx(tx)
|
||||||
|
tx, _ = types.SignTx(types.NewTransaction(uint64(i)*3+1, common.Address{}, big.NewInt(999), txCost1, big.NewInt(875000000), nil), signer, testKey)
|
||||||
|
gen.AddTx(tx)
|
||||||
|
tx, _ = types.SignTx(types.NewTransaction(uint64(i)*3+2, common.Address{}, big.NewInt(0), txCost2, big.NewInt(875000000), nil), signer, testKey)
|
||||||
|
gen.AddTx(tx)
|
||||||
|
|
||||||
|
// Add two contract creations in block #2
|
||||||
|
if i == 1 {
|
||||||
|
tx, _ = types.SignNewTx(testKey, signer, &types.LegacyTx{Nonce: 6,
|
||||||
|
Value: big.NewInt(16),
|
||||||
|
Gas: 3000000,
|
||||||
|
GasPrice: big.NewInt(875000000),
|
||||||
|
Data: code,
|
||||||
|
})
|
||||||
|
gen.AddTx(tx)
|
||||||
|
|
||||||
|
tx, _ = types.SignNewTx(testKey, signer, &types.LegacyTx{Nonce: 7,
|
||||||
|
Value: big.NewInt(0),
|
||||||
|
Gas: 3000000,
|
||||||
|
GasPrice: big.NewInt(875000000),
|
||||||
|
Data: codeWithExtCodeCopy,
|
||||||
|
})
|
||||||
|
gen.AddTx(tx)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
for i, b := range chain {
|
||||||
|
fmt.Printf("%d %x\n", i, b.Root())
|
||||||
|
}
|
||||||
|
endnum, err := blockchain.InsertChain(chain)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("block %d imported with error: %v", endnum, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range 2 {
|
||||||
|
b := blockchain.GetBlockByNumber(uint64(i) + 1)
|
||||||
|
if b == nil {
|
||||||
|
t.Fatalf("expected block %d to be present in chain", i+1)
|
||||||
|
}
|
||||||
|
if b.Hash() != chain[i].Hash() {
|
||||||
|
t.Fatalf("block #%d not found at expected height", b.NumberU64())
|
||||||
|
}
|
||||||
|
if b.GasUsed() != blockGasUsagesExpected[i] {
|
||||||
|
t.Fatalf("expected block #%d txs to use %d, got %d\n", b.NumberU64(), blockGasUsagesExpected[i], b.GasUsed())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProcessParentBlockHash(t *testing.T) {
|
||||||
|
// This test uses blocks where,
|
||||||
|
// block 1 parent hash is 0x0100....
|
||||||
|
// block 2 parent hash is 0x0200....
|
||||||
|
// etc
|
||||||
|
checkBlockHashes := func(statedb *state.StateDB, isVerkle bool) {
|
||||||
|
statedb.SetNonce(params.HistoryStorageAddress, 1, tracing.NonceChangeUnspecified)
|
||||||
|
statedb.SetCode(params.HistoryStorageAddress, params.HistoryStorageCode, tracing.CodeChangeUnspecified)
|
||||||
|
// Process n blocks, from 1 .. num
|
||||||
|
var num = 2
|
||||||
|
for i := 1; i <= num; i++ {
|
||||||
|
header := &types.Header{ParentHash: common.Hash{byte(i)}, Number: big.NewInt(int64(i)), Difficulty: new(big.Int)}
|
||||||
|
chainConfig := params.MergedTestChainConfig
|
||||||
|
if isVerkle {
|
||||||
|
chainConfig = testVerkleChainConfig
|
||||||
|
}
|
||||||
|
vmContext := NewEVMBlockContext(header, nil, new(common.Address))
|
||||||
|
evm := vm.NewEVM(vmContext, statedb, chainConfig, vm.Config{})
|
||||||
|
ProcessParentBlockHash(header.ParentHash, evm)
|
||||||
|
}
|
||||||
|
// Read block hashes for block 0 .. num-1
|
||||||
|
for i := 0; i < num; i++ {
|
||||||
|
have, want := getContractStoredBlockHash(statedb, uint64(i), isVerkle), common.Hash{byte(i + 1)}
|
||||||
|
if have != want {
|
||||||
|
t.Errorf("block %d, verkle=%v, have parent hash %v, want %v", i, isVerkle, have, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Run("MPT", func(t *testing.T) {
|
||||||
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
|
checkBlockHashes(statedb, false)
|
||||||
|
})
|
||||||
|
t.Run("Verkle", func(t *testing.T) {
|
||||||
|
db := rawdb.NewMemoryDatabase()
|
||||||
|
cacheConfig := DefaultConfig().WithStateScheme(rawdb.PathScheme)
|
||||||
|
cacheConfig.SnapshotLimit = 0
|
||||||
|
triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(true))
|
||||||
|
statedb, _ := state.New(types.EmptyVerkleHash, state.NewDatabase(triedb, nil))
|
||||||
|
checkBlockHashes(statedb, true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// getContractStoredBlockHash is a utility method which reads the stored parent blockhash for block 'number'
|
||||||
|
func getContractStoredBlockHash(statedb *state.StateDB, number uint64, isVerkle bool) common.Hash {
|
||||||
|
ringIndex := number % params.HistoryServeWindow
|
||||||
|
var key common.Hash
|
||||||
|
binary.BigEndian.PutUint64(key[24:], ringIndex)
|
||||||
|
if isVerkle {
|
||||||
|
return statedb.GetState(params.HistoryStorageAddress, key)
|
||||||
|
}
|
||||||
|
return statedb.GetState(params.HistoryStorageAddress, key)
|
||||||
|
}
|
||||||
|
|
@ -75,6 +75,8 @@ var (
|
||||||
storageReadTimer = metrics.NewRegisteredResettingTimer("chain/storage/reads", nil)
|
storageReadTimer = metrics.NewRegisteredResettingTimer("chain/storage/reads", nil)
|
||||||
storageUpdateTimer = metrics.NewRegisteredResettingTimer("chain/storage/updates", nil)
|
storageUpdateTimer = metrics.NewRegisteredResettingTimer("chain/storage/updates", nil)
|
||||||
storageCommitTimer = metrics.NewRegisteredResettingTimer("chain/storage/commits", nil)
|
storageCommitTimer = metrics.NewRegisteredResettingTimer("chain/storage/commits", nil)
|
||||||
|
codeReadTimer = metrics.NewRegisteredResettingTimer("chain/code/reads", nil)
|
||||||
|
codeReadBytesTimer = metrics.NewRegisteredResettingTimer("chain/code/readbytes", nil)
|
||||||
|
|
||||||
accountCacheHitMeter = metrics.NewRegisteredMeter("chain/account/reads/cache/process/hit", nil)
|
accountCacheHitMeter = metrics.NewRegisteredMeter("chain/account/reads/cache/process/hit", nil)
|
||||||
accountCacheMissMeter = metrics.NewRegisteredMeter("chain/account/reads/cache/process/miss", nil)
|
accountCacheMissMeter = metrics.NewRegisteredMeter("chain/account/reads/cache/process/miss", nil)
|
||||||
|
|
@ -88,6 +90,7 @@ var (
|
||||||
|
|
||||||
accountReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/account/single/reads", nil)
|
accountReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/account/single/reads", nil)
|
||||||
storageReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/storage/single/reads", nil)
|
storageReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/storage/single/reads", nil)
|
||||||
|
codeReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/code/single/reads", nil)
|
||||||
|
|
||||||
snapshotCommitTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/commits", nil)
|
snapshotCommitTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/commits", nil)
|
||||||
triedbCommitTimer = metrics.NewRegisteredResettingTimer("chain/triedb/commits", nil)
|
triedbCommitTimer = metrics.NewRegisteredResettingTimer("chain/triedb/commits", nil)
|
||||||
|
|
@ -175,6 +178,17 @@ type BlockChainConfig struct {
|
||||||
// If set to 0, all state histories across the entire chain will be retained;
|
// If set to 0, all state histories across the entire chain will be retained;
|
||||||
StateHistory uint64
|
StateHistory uint64
|
||||||
|
|
||||||
|
// Number of blocks from the chain head for which trienode histories are retained.
|
||||||
|
// If set to 0, all trienode histories across the entire chain will be retained;
|
||||||
|
// If set to -1, no trienode history will be retained;
|
||||||
|
TrienodeHistory int64
|
||||||
|
|
||||||
|
// The frequency of full-value encoding. For example, a value of 16 means
|
||||||
|
// that, on average, for a given trie node across its 16 consecutive historical
|
||||||
|
// versions, only one version is stored in full format, while the others
|
||||||
|
// are stored in diff mode for storage compression.
|
||||||
|
NodeFullValueCheckpoint uint32
|
||||||
|
|
||||||
// State snapshot related options
|
// State snapshot related options
|
||||||
SnapshotLimit int // Memory allowance (MB) to use for caching snapshot entries in memory
|
SnapshotLimit int // Memory allowance (MB) to use for caching snapshot entries in memory
|
||||||
SnapshotNoBuild bool // Whether the background generation is allowed
|
SnapshotNoBuild bool // Whether the background generation is allowed
|
||||||
|
|
@ -198,6 +212,11 @@ type BlockChainConfig struct {
|
||||||
|
|
||||||
// StateSizeTracking indicates whether the state size tracking is enabled.
|
// StateSizeTracking indicates whether the state size tracking is enabled.
|
||||||
StateSizeTracking bool
|
StateSizeTracking bool
|
||||||
|
|
||||||
|
// SlowBlockThreshold is the block execution time threshold beyond which
|
||||||
|
// detailed statistics will be logged. Negative value means disabled (default),
|
||||||
|
// zero logs all blocks, positive value filters blocks by execution time.
|
||||||
|
SlowBlockThreshold time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultConfig returns the default config.
|
// DefaultConfig returns the default config.
|
||||||
|
|
@ -248,17 +267,22 @@ func (cfg *BlockChainConfig) triedbConfig(isVerkle bool) *triedb.Config {
|
||||||
}
|
}
|
||||||
if cfg.StateScheme == rawdb.PathScheme {
|
if cfg.StateScheme == rawdb.PathScheme {
|
||||||
config.PathDB = &pathdb.Config{
|
config.PathDB = &pathdb.Config{
|
||||||
StateHistory: cfg.StateHistory,
|
TrieCleanSize: cfg.TrieCleanLimit * 1024 * 1024,
|
||||||
EnableStateIndexing: cfg.ArchiveMode,
|
StateCleanSize: cfg.SnapshotLimit * 1024 * 1024,
|
||||||
TrieCleanSize: cfg.TrieCleanLimit * 1024 * 1024,
|
|
||||||
StateCleanSize: cfg.SnapshotLimit * 1024 * 1024,
|
|
||||||
JournalDirectory: cfg.TrieJournalDirectory,
|
|
||||||
|
|
||||||
// TODO(rjl493456442): The write buffer represents the memory limit used
|
// TODO(rjl493456442): The write buffer represents the memory limit used
|
||||||
// for flushing both trie data and state data to disk. The config name
|
// for flushing both trie data and state data to disk. The config name
|
||||||
// should be updated to eliminate the confusion.
|
// should be updated to eliminate the confusion.
|
||||||
WriteBufferSize: cfg.TrieDirtyLimit * 1024 * 1024,
|
WriteBufferSize: cfg.TrieDirtyLimit * 1024 * 1024,
|
||||||
NoAsyncFlush: cfg.TrieNoAsyncFlush,
|
JournalDirectory: cfg.TrieJournalDirectory,
|
||||||
|
|
||||||
|
// Historical state configurations
|
||||||
|
StateHistory: cfg.StateHistory,
|
||||||
|
TrienodeHistory: cfg.TrienodeHistory,
|
||||||
|
EnableStateIndexing: cfg.ArchiveMode,
|
||||||
|
FullValueCheckpoint: cfg.NodeFullValueCheckpoint,
|
||||||
|
|
||||||
|
// Testing configurations
|
||||||
|
NoAsyncFlush: cfg.TrieNoAsyncFlush,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return config
|
return config
|
||||||
|
|
@ -305,6 +329,7 @@ type BlockChain struct {
|
||||||
chainHeadFeed event.Feed
|
chainHeadFeed event.Feed
|
||||||
logsFeed event.Feed
|
logsFeed event.Feed
|
||||||
blockProcFeed event.Feed
|
blockProcFeed event.Feed
|
||||||
|
newPayloadFeed event.Feed // Feed for engine API newPayload events
|
||||||
blockProcCounter int32
|
blockProcCounter int32
|
||||||
scope event.SubscriptionScope
|
scope event.SubscriptionScope
|
||||||
genesisBlock *types.Block
|
genesisBlock *types.Block
|
||||||
|
|
@ -337,7 +362,8 @@ type BlockChain struct {
|
||||||
logger *tracing.Hooks
|
logger *tracing.Hooks
|
||||||
stateSizer *state.SizeTracker // State size tracking
|
stateSizer *state.SizeTracker // State size tracking
|
||||||
|
|
||||||
lastForkReadyAlert time.Time // Last time there was a fork readiness print out
|
lastForkReadyAlert time.Time // Last time there was a fork readiness print out
|
||||||
|
slowBlockThreshold time.Duration // Block execution time threshold beyond which detailed statistics will be logged
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBlockChain returns a fully initialised block chain using information
|
// NewBlockChain returns a fully initialised block chain using information
|
||||||
|
|
@ -359,7 +385,7 @@ func NewBlockChain(db ethdb.Database, genesis *Genesis, engine consensus.Engine,
|
||||||
// yet. The corresponding chain config will be returned, either from the
|
// yet. The corresponding chain config will be returned, either from the
|
||||||
// provided genesis or from the locally stored configuration if the genesis
|
// provided genesis or from the locally stored configuration if the genesis
|
||||||
// has already been initialized.
|
// has already been initialized.
|
||||||
chainConfig, genesisHash, compatErr, err := SetupGenesisBlockWithOverride(db, triedb, genesis, cfg.Overrides)
|
chainConfig, genesisHash, compatErr, err := SetupGenesisBlockWithOverride(db, triedb, genesis, cfg.Overrides, cfg.VmConfig.Tracer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -372,19 +398,20 @@ func NewBlockChain(db ethdb.Database, genesis *Genesis, engine consensus.Engine,
|
||||||
log.Info("")
|
log.Info("")
|
||||||
|
|
||||||
bc := &BlockChain{
|
bc := &BlockChain{
|
||||||
chainConfig: chainConfig,
|
chainConfig: chainConfig,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
db: db,
|
db: db,
|
||||||
triedb: triedb,
|
triedb: triedb,
|
||||||
triegc: prque.New[int64, common.Hash](nil),
|
triegc: prque.New[int64, common.Hash](nil),
|
||||||
chainmu: syncx.NewClosableMutex(),
|
chainmu: syncx.NewClosableMutex(),
|
||||||
bodyCache: lru.NewCache[common.Hash, *types.Body](bodyCacheLimit),
|
bodyCache: lru.NewCache[common.Hash, *types.Body](bodyCacheLimit),
|
||||||
bodyRLPCache: lru.NewCache[common.Hash, rlp.RawValue](bodyCacheLimit),
|
bodyRLPCache: lru.NewCache[common.Hash, rlp.RawValue](bodyCacheLimit),
|
||||||
receiptsCache: lru.NewCache[common.Hash, []*types.Receipt](receiptsCacheLimit),
|
receiptsCache: lru.NewCache[common.Hash, []*types.Receipt](receiptsCacheLimit),
|
||||||
blockCache: lru.NewCache[common.Hash, *types.Block](blockCacheLimit),
|
blockCache: lru.NewCache[common.Hash, *types.Block](blockCacheLimit),
|
||||||
txLookupCache: lru.NewCache[common.Hash, txLookup](txLookupCacheLimit),
|
txLookupCache: lru.NewCache[common.Hash, txLookup](txLookupCacheLimit),
|
||||||
engine: engine,
|
engine: engine,
|
||||||
logger: cfg.VmConfig.Tracer,
|
logger: cfg.VmConfig.Tracer,
|
||||||
|
slowBlockThreshold: cfg.SlowBlockThreshold,
|
||||||
}
|
}
|
||||||
bc.hc, err = NewHeaderChain(db, chainConfig, engine, bc.insertStopped)
|
bc.hc, err = NewHeaderChain(db, chainConfig, engine, bc.insertStopped)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -737,21 +764,7 @@ func (bc *BlockChain) SetHead(head uint64) error {
|
||||||
if _, err := bc.setHeadBeyondRoot(head, 0, common.Hash{}, false); err != nil {
|
if _, err := bc.setHeadBeyondRoot(head, 0, common.Hash{}, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Send chain head event to update the transaction pool
|
return bc.sendChainHeadEvent()
|
||||||
header := bc.CurrentBlock()
|
|
||||||
if block := bc.GetBlock(header.Hash(), header.Number.Uint64()); block == nil {
|
|
||||||
// In a pruned node the genesis block will not exist in the freezer.
|
|
||||||
// It should not happen that we set head to any other pruned block.
|
|
||||||
if header.Number.Uint64() > 0 {
|
|
||||||
// This should never happen. In practice, previously currentBlock
|
|
||||||
// contained the entire block whereas now only a "marker", so there
|
|
||||||
// is an ever so slight chance for a race we should handle.
|
|
||||||
log.Error("Current block not found in database", "block", header.Number, "hash", header.Hash())
|
|
||||||
return fmt.Errorf("current block missing: #%d [%x..]", header.Number, header.Hash().Bytes()[:4])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bc.chainHeadFeed.Send(ChainHeadEvent{Header: header})
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetHeadWithTimestamp rewinds the local chain to a new head that has at max
|
// SetHeadWithTimestamp rewinds the local chain to a new head that has at max
|
||||||
|
|
@ -762,7 +775,12 @@ func (bc *BlockChain) SetHeadWithTimestamp(timestamp uint64) error {
|
||||||
if _, err := bc.setHeadBeyondRoot(0, timestamp, common.Hash{}, false); err != nil {
|
if _, err := bc.setHeadBeyondRoot(0, timestamp, common.Hash{}, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Send chain head event to update the transaction pool
|
return bc.sendChainHeadEvent()
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendChainHeadEvent notifies all subscribers about the new chain head,
|
||||||
|
// checking first that the current block is actually available.
|
||||||
|
func (bc *BlockChain) sendChainHeadEvent() error {
|
||||||
header := bc.CurrentBlock()
|
header := bc.CurrentBlock()
|
||||||
if block := bc.GetBlock(header.Hash(), header.Number.Uint64()); block == nil {
|
if block := bc.GetBlock(header.Hash(), header.Number.Uint64()); block == nil {
|
||||||
// In a pruned node the genesis block will not exist in the freezer.
|
// In a pruned node the genesis block will not exist in the freezer.
|
||||||
|
|
@ -945,7 +963,8 @@ func (bc *BlockChain) rewindPathHead(head *types.Header, root common.Hash) (*typ
|
||||||
// Recover if the target state if it's not available yet.
|
// Recover if the target state if it's not available yet.
|
||||||
if !bc.HasState(head.Root) {
|
if !bc.HasState(head.Root) {
|
||||||
if err := bc.triedb.Recover(head.Root); err != nil {
|
if err := bc.triedb.Recover(head.Root); err != nil {
|
||||||
log.Crit("Failed to rollback state", "err", err)
|
log.Error("Failed to rollback state, resetting to genesis", "err", err)
|
||||||
|
return bc.genesisBlock.Header(), rootNumber
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Info("Rewound to block with state", "number", head.Number, "hash", head.Hash())
|
log.Info("Rewound to block with state", "number", head.Number, "hash", head.Hash())
|
||||||
|
|
@ -1096,25 +1115,60 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
|
||||||
bc.txLookupCache.Purge()
|
bc.txLookupCache.Purge()
|
||||||
|
|
||||||
// Clear safe block, finalized block if needed
|
// Clear safe block, finalized block if needed
|
||||||
if safe := bc.CurrentSafeBlock(); safe != nil && head < safe.Number.Uint64() {
|
headBlock := bc.CurrentBlock()
|
||||||
|
if safe := bc.CurrentSafeBlock(); safe != nil && headBlock.Number.Uint64() < safe.Number.Uint64() {
|
||||||
log.Warn("SetHead invalidated safe block")
|
log.Warn("SetHead invalidated safe block")
|
||||||
bc.SetSafe(nil)
|
bc.SetSafe(nil)
|
||||||
}
|
}
|
||||||
if finalized := bc.CurrentFinalBlock(); finalized != nil && head < finalized.Number.Uint64() {
|
if finalized := bc.CurrentFinalBlock(); finalized != nil && headBlock.Number.Uint64() < finalized.Number.Uint64() {
|
||||||
log.Error("SetHead invalidated finalized block")
|
log.Error("SetHead invalidated finalized block")
|
||||||
bc.SetFinalized(nil)
|
bc.SetFinalized(nil)
|
||||||
}
|
}
|
||||||
return rootNumber, bc.loadLastState()
|
return rootNumber, bc.loadLastState()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SnapSyncCommitHead sets the current head block to the one defined by the hash
|
// SnapSyncStart disables the underlying databases (such as the trie DB and the
|
||||||
// irrelevant what the chain contents were prior.
|
// optional state snapshot) to prevent potential concurrent mutations between
|
||||||
func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error {
|
// snap sync and other chain operations.
|
||||||
|
func (bc *BlockChain) SnapSyncStart() error {
|
||||||
|
if !bc.chainmu.TryLock() {
|
||||||
|
return errChainStopped
|
||||||
|
}
|
||||||
|
defer bc.chainmu.Unlock()
|
||||||
|
|
||||||
|
// Snap sync will directly modify the persistent state, making the entire
|
||||||
|
// trie database unusable until the state is fully synced. To prevent any
|
||||||
|
// subsequent state reads, explicitly disable the trie database and state
|
||||||
|
// syncer is responsible to address and correct any state missing.
|
||||||
|
if bc.TrieDB().Scheme() == rawdb.PathScheme {
|
||||||
|
if err := bc.TrieDB().Disable(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Snap sync uses the snapshot namespace to store potentially flaky data until
|
||||||
|
// sync completely heals and finishes. Pause snapshot maintenance in the mean-
|
||||||
|
// time to prevent access.
|
||||||
|
if snapshots := bc.Snapshots(); snapshots != nil { // Only nil in tests
|
||||||
|
snapshots.Disable()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SnapSyncComplete sets the current head block to the block identified by the
|
||||||
|
// given hash, regardless of the chain contents prior to snap sync. It is
|
||||||
|
// invoked once snap sync completes and assumes that SnapSyncStart was called
|
||||||
|
// previously.
|
||||||
|
func (bc *BlockChain) SnapSyncComplete(hash common.Hash) error {
|
||||||
// Make sure that both the block as well at its state trie exists
|
// Make sure that both the block as well at its state trie exists
|
||||||
block := bc.GetBlockByHash(hash)
|
block := bc.GetBlockByHash(hash)
|
||||||
if block == nil {
|
if block == nil {
|
||||||
return fmt.Errorf("non existent block [%x..]", hash[:4])
|
return fmt.Errorf("non existent block [%x..]", hash[:4])
|
||||||
}
|
}
|
||||||
|
if !bc.chainmu.TryLock() {
|
||||||
|
return errChainStopped
|
||||||
|
}
|
||||||
|
defer bc.chainmu.Unlock()
|
||||||
|
|
||||||
// Reset the trie database with the fresh snap synced state.
|
// Reset the trie database with the fresh snap synced state.
|
||||||
root := block.Root()
|
root := block.Root()
|
||||||
if bc.triedb.Scheme() == rawdb.PathScheme {
|
if bc.triedb.Scheme() == rawdb.PathScheme {
|
||||||
|
|
@ -1125,19 +1179,16 @@ func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error {
|
||||||
if !bc.HasState(root) {
|
if !bc.HasState(root) {
|
||||||
return fmt.Errorf("non existent state [%x..]", root[:4])
|
return fmt.Errorf("non existent state [%x..]", root[:4])
|
||||||
}
|
}
|
||||||
// If all checks out, manually set the head block.
|
|
||||||
if !bc.chainmu.TryLock() {
|
|
||||||
return errChainStopped
|
|
||||||
}
|
|
||||||
bc.currentBlock.Store(block.Header())
|
|
||||||
headBlockGauge.Update(int64(block.NumberU64()))
|
|
||||||
bc.chainmu.Unlock()
|
|
||||||
|
|
||||||
// Destroy any existing state snapshot and regenerate it in the background,
|
// Destroy any existing state snapshot and regenerate it in the background,
|
||||||
// also resuming the normal maintenance of any previously paused snapshot.
|
// also resuming the normal maintenance of any previously paused snapshot.
|
||||||
if bc.snaps != nil {
|
if bc.snaps != nil {
|
||||||
bc.snaps.Rebuild(root)
|
bc.snaps.Rebuild(root)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If all checks out, manually set the head block.
|
||||||
|
bc.currentBlock.Store(block.Header())
|
||||||
|
headBlockGauge.Update(int64(block.NumberU64()))
|
||||||
|
|
||||||
log.Info("Committed new head block", "number", block.Number(), "hash", hash)
|
log.Info("Committed new head block", "number", block.Number(), "hash", hash)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -1596,21 +1647,47 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
|
||||||
//
|
//
|
||||||
// Note all the components of block(hash->number map, header, body, receipts)
|
// Note all the components of block(hash->number map, header, body, receipts)
|
||||||
// should be written atomically. BlockBatch is used for containing all components.
|
// should be written atomically. BlockBatch is used for containing all components.
|
||||||
blockBatch := bc.db.NewBatch()
|
var (
|
||||||
rawdb.WriteBlock(blockBatch, block)
|
batch = bc.db.NewBatch()
|
||||||
rawdb.WriteReceipts(blockBatch, block.Hash(), block.NumberU64(), receipts)
|
start = time.Now()
|
||||||
rawdb.WritePreimages(blockBatch, statedb.Preimages())
|
)
|
||||||
if err := blockBatch.Write(); err != nil {
|
rawdb.WriteBlock(batch, block)
|
||||||
|
rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), receipts)
|
||||||
|
rawdb.WritePreimages(batch, statedb.Preimages())
|
||||||
|
if err := batch.Write(); err != nil {
|
||||||
log.Crit("Failed to write block into disk", "err", err)
|
log.Crit("Failed to write block into disk", "err", err)
|
||||||
}
|
}
|
||||||
// Commit all cached state changes into underlying memory database.
|
log.Debug("Committed block data", "size", common.StorageSize(batch.ValueSize()), "elapsed", common.PrettyDuration(time.Since(start)))
|
||||||
root, stateUpdate, err := statedb.CommitWithUpdate(block.NumberU64(), bc.chainConfig.IsEIP158(block.Number()), bc.chainConfig.IsCancun(block.Number(), block.Time()))
|
|
||||||
if err != nil {
|
var (
|
||||||
return err
|
err error
|
||||||
}
|
root common.Hash
|
||||||
// Emit the state update to the state sizestats if it's active
|
isEIP158 = bc.chainConfig.IsEIP158(block.Number())
|
||||||
if bc.stateSizer != nil {
|
isCancun = bc.chainConfig.IsCancun(block.Number(), block.Time())
|
||||||
bc.stateSizer.Notify(stateUpdate)
|
hasStateHook = bc.logger != nil && bc.logger.OnStateUpdate != nil
|
||||||
|
hasStateSizer = bc.stateSizer != nil
|
||||||
|
)
|
||||||
|
if hasStateHook || hasStateSizer {
|
||||||
|
r, update, err := statedb.CommitWithUpdate(block.NumberU64(), isEIP158, isCancun)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if hasStateHook {
|
||||||
|
trUpdate, err := update.ToTracingUpdate()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
bc.logger.OnStateUpdate(trUpdate)
|
||||||
|
}
|
||||||
|
if hasStateSizer {
|
||||||
|
bc.stateSizer.Notify(update)
|
||||||
|
}
|
||||||
|
root = r
|
||||||
|
} else {
|
||||||
|
root, err = statedb.Commit(block.NumberU64(), isEIP158, isCancun)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// If node is running in path mode, skip explicit gc operation
|
// If node is running in path mode, skip explicit gc operation
|
||||||
// which is unnecessary in this mode.
|
// which is unnecessary in this mode.
|
||||||
|
|
@ -1847,7 +1924,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
|
||||||
// still need re-execution to generate snapshots that are missing
|
// still need re-execution to generate snapshots that are missing
|
||||||
case err != nil && !errors.Is(err, ErrKnownBlock):
|
case err != nil && !errors.Is(err, ErrKnownBlock):
|
||||||
stats.ignored += len(it.chain)
|
stats.ignored += len(it.chain)
|
||||||
bc.reportBlock(block, nil, err)
|
bc.reportBadBlock(block, nil, err)
|
||||||
return nil, it.index, err
|
return nil, it.index, err
|
||||||
}
|
}
|
||||||
// Track the singleton witness from this chain insertion (if any)
|
// Track the singleton witness from this chain insertion (if any)
|
||||||
|
|
@ -1915,6 +1992,14 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, it.index, err
|
return nil, it.index, err
|
||||||
}
|
}
|
||||||
|
res.stats.reportMetrics()
|
||||||
|
|
||||||
|
// Log slow block only if a single block is inserted (usually after the
|
||||||
|
// initial sync) to not overwhelm the users.
|
||||||
|
if len(chain) == 1 {
|
||||||
|
res.stats.logSlow(block, bc.slowBlockThreshold)
|
||||||
|
}
|
||||||
|
|
||||||
// Report the import stats before returning the various results
|
// Report the import stats before returning the various results
|
||||||
stats.processed++
|
stats.processed++
|
||||||
stats.usedGas += res.usedGas
|
stats.usedGas += res.usedGas
|
||||||
|
|
@ -1975,15 +2060,20 @@ type blockProcessingResult struct {
|
||||||
procTime time.Duration
|
procTime time.Duration
|
||||||
status WriteStatus
|
status WriteStatus
|
||||||
witness *stateless.Witness
|
witness *stateless.Witness
|
||||||
|
stats *ExecuteStats
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bpr *blockProcessingResult) Witness() *stateless.Witness {
|
func (bpr *blockProcessingResult) Witness() *stateless.Witness {
|
||||||
return bpr.witness
|
return bpr.witness
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (bpr *blockProcessingResult) Stats() *ExecuteStats {
|
||||||
|
return bpr.stats
|
||||||
|
}
|
||||||
|
|
||||||
// ProcessBlock executes and validates the given block. If there was no error
|
// ProcessBlock executes and validates the given block. If there was no error
|
||||||
// it writes the block and associated state to database.
|
// it writes the block and associated state to database.
|
||||||
func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, setHead bool, makeWitness bool) (_ *blockProcessingResult, blockEndErr error) {
|
func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, setHead bool, makeWitness bool) (result *blockProcessingResult, blockEndErr error) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
startTime = time.Now()
|
startTime = time.Now()
|
||||||
|
|
@ -2017,18 +2107,11 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s
|
||||||
}
|
}
|
||||||
// Upload the statistics of reader at the end
|
// Upload the statistics of reader at the end
|
||||||
defer func() {
|
defer func() {
|
||||||
stats := prefetch.GetStats()
|
if result != nil {
|
||||||
accountCacheHitPrefetchMeter.Mark(stats.AccountHit)
|
result.stats.StatePrefetchCacheStats = prefetch.GetStats()
|
||||||
accountCacheMissPrefetchMeter.Mark(stats.AccountMiss)
|
result.stats.StateReadCacheStats = process.GetStats()
|
||||||
storageCacheHitPrefetchMeter.Mark(stats.StorageHit)
|
}
|
||||||
storageCacheMissPrefetchMeter.Mark(stats.StorageMiss)
|
|
||||||
stats = process.GetStats()
|
|
||||||
accountCacheHitMeter.Mark(stats.AccountHit)
|
|
||||||
accountCacheMissMeter.Mark(stats.AccountMiss)
|
|
||||||
storageCacheHitMeter.Mark(stats.StorageHit)
|
|
||||||
storageCacheMissMeter.Mark(stats.StorageMiss)
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func(start time.Time, throwaway *state.StateDB, block *types.Block) {
|
go func(start time.Time, throwaway *state.StateDB, block *types.Block) {
|
||||||
// Disable tracing for prefetcher executions.
|
// Disable tracing for prefetcher executions.
|
||||||
vmCfg := bc.cfg.VmConfig
|
vmCfg := bc.cfg.VmConfig
|
||||||
|
|
@ -2083,14 +2166,14 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s
|
||||||
pstart := time.Now()
|
pstart := time.Now()
|
||||||
res, err := bc.processor.Process(block, statedb, bc.cfg.VmConfig)
|
res, err := bc.processor.Process(block, statedb, bc.cfg.VmConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bc.reportBlock(block, res, err)
|
bc.reportBadBlock(block, res, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ptime := time.Since(pstart)
|
ptime := time.Since(pstart)
|
||||||
|
|
||||||
vstart := time.Now()
|
vstart := time.Now()
|
||||||
if err := bc.validator.ValidateState(block, statedb, res, false); err != nil {
|
if err := bc.validator.ValidateState(block, statedb, res, false); err != nil {
|
||||||
bc.reportBlock(block, res, err)
|
bc.reportBadBlock(block, res, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
vtime := time.Since(vstart)
|
vtime := time.Since(vstart)
|
||||||
|
|
@ -2124,26 +2207,34 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xvtime := time.Since(xvstart)
|
var (
|
||||||
proctime := time.Since(startTime) // processing + validation + cross validation
|
xvtime = time.Since(xvstart)
|
||||||
|
proctime = time.Since(startTime) // processing + validation + cross validation
|
||||||
|
stats = &ExecuteStats{}
|
||||||
|
)
|
||||||
// Update the metrics touched during block processing and validation
|
// Update the metrics touched during block processing and validation
|
||||||
accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing)
|
stats.AccountReads = statedb.AccountReads // Account reads are complete(in processing)
|
||||||
storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing)
|
stats.StorageReads = statedb.StorageReads // Storage reads are complete(in processing)
|
||||||
if statedb.AccountLoaded != 0 {
|
stats.AccountUpdates = statedb.AccountUpdates // Account updates are complete(in validation)
|
||||||
accountReadSingleTimer.Update(statedb.AccountReads / time.Duration(statedb.AccountLoaded))
|
stats.StorageUpdates = statedb.StorageUpdates // Storage updates are complete(in validation)
|
||||||
}
|
stats.AccountHashes = statedb.AccountHashes // Account hashes are complete(in validation)
|
||||||
if statedb.StorageLoaded != 0 {
|
stats.CodeReads = statedb.CodeReads
|
||||||
storageReadSingleTimer.Update(statedb.StorageReads / time.Duration(statedb.StorageLoaded))
|
|
||||||
}
|
stats.AccountLoaded = statedb.AccountLoaded
|
||||||
accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation)
|
stats.AccountUpdated = statedb.AccountUpdated
|
||||||
storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation)
|
stats.AccountDeleted = statedb.AccountDeleted
|
||||||
accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation)
|
stats.StorageLoaded = statedb.StorageLoaded
|
||||||
triehash := statedb.AccountHashes // The time spent on tries hashing
|
stats.StorageUpdated = int(statedb.StorageUpdated.Load())
|
||||||
trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update
|
stats.StorageDeleted = int(statedb.StorageDeleted.Load())
|
||||||
blockExecutionTimer.Update(ptime - (statedb.AccountReads + statedb.StorageReads)) // The time spent on EVM processing
|
|
||||||
blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation
|
stats.CodeLoaded = statedb.CodeLoaded
|
||||||
blockCrossValidationTimer.Update(xvtime) // The time spent on stateless cross validation
|
stats.CodeLoadBytes = statedb.CodeLoadBytes
|
||||||
|
stats.CodeUpdated = statedb.CodeUpdated
|
||||||
|
stats.CodeUpdateBytes = statedb.CodeUpdateBytes
|
||||||
|
|
||||||
|
stats.Execution = ptime - (statedb.AccountReads + statedb.StorageReads + statedb.CodeReads) // The time spent on EVM processing
|
||||||
|
stats.Validation = vtime - (statedb.AccountHashes + statedb.AccountUpdates + statedb.StorageUpdates) // The time spent on block validation
|
||||||
|
stats.CrossValidation = xvtime // The time spent on stateless cross validation
|
||||||
|
|
||||||
// Write the block to the chain and get the status.
|
// Write the block to the chain and get the status.
|
||||||
var (
|
var (
|
||||||
|
|
@ -2165,24 +2256,22 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the metrics touched during block commit
|
// Update the metrics touched during block commit
|
||||||
accountCommitTimer.Update(statedb.AccountCommits) // Account commits are complete, we can mark them
|
stats.AccountCommits = statedb.AccountCommits // Account commits are complete, we can mark them
|
||||||
storageCommitTimer.Update(statedb.StorageCommits) // Storage commits are complete, we can mark them
|
stats.StorageCommits = statedb.StorageCommits // Storage commits are complete, we can mark them
|
||||||
snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them
|
stats.SnapshotCommit = statedb.SnapshotCommits // Snapshot commits are complete, we can mark them
|
||||||
triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them
|
stats.TrieDBCommit = statedb.TrieDBCommits // Trie database commits are complete, we can mark them
|
||||||
|
stats.BlockWrite = time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits
|
||||||
|
|
||||||
blockWriteTimer.Update(time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits)
|
|
||||||
elapsed := time.Since(startTime) + 1 // prevent zero division
|
elapsed := time.Since(startTime) + 1 // prevent zero division
|
||||||
blockInsertTimer.Update(elapsed)
|
stats.TotalTime = elapsed
|
||||||
|
stats.MgasPerSecond = float64(res.GasUsed) * 1000 / float64(elapsed)
|
||||||
// TODO(rjl493456442) generalize the ResettingTimer
|
|
||||||
mgasps := float64(res.GasUsed) * 1000 / float64(elapsed)
|
|
||||||
chainMgaspsMeter.Update(time.Duration(mgasps))
|
|
||||||
|
|
||||||
return &blockProcessingResult{
|
return &blockProcessingResult{
|
||||||
usedGas: res.GasUsed,
|
usedGas: res.GasUsed,
|
||||||
procTime: proctime,
|
procTime: proctime,
|
||||||
status: status,
|
status: status,
|
||||||
witness: witness,
|
witness: witness,
|
||||||
|
stats: stats,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2667,8 +2756,8 @@ func (bc *BlockChain) skipBlock(err error, it *insertIterator) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// reportBlock logs a bad block error.
|
// reportBadBlock logs a bad block error.
|
||||||
func (bc *BlockChain) reportBlock(block *types.Block, res *ProcessResult, err error) {
|
func (bc *BlockChain) reportBadBlock(block *types.Block, res *ProcessResult, err error) {
|
||||||
var receipts types.Receipts
|
var receipts types.Receipts
|
||||||
if res != nil {
|
if res != nil {
|
||||||
receipts = res.Receipts
|
receipts = res.Receipts
|
||||||
|
|
|
||||||
|
|
@ -131,28 +131,6 @@ func (it *insertIterator) next() (*types.Block, error) {
|
||||||
return it.chain[it.index], it.validator.ValidateBody(it.chain[it.index])
|
return it.chain[it.index], it.validator.ValidateBody(it.chain[it.index])
|
||||||
}
|
}
|
||||||
|
|
||||||
// peek returns the next block in the iterator, along with any potential validation
|
|
||||||
// error for that block, but does **not** advance the iterator.
|
|
||||||
//
|
|
||||||
// Both header and body validation errors (nil too) is cached into the iterator
|
|
||||||
// to avoid duplicating work on the following next() call.
|
|
||||||
// nolint:unused
|
|
||||||
func (it *insertIterator) peek() (*types.Block, error) {
|
|
||||||
// If we reached the end of the chain, abort
|
|
||||||
if it.index+1 >= len(it.chain) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
// Wait for verification result if not yet done
|
|
||||||
if len(it.errors) <= it.index+1 {
|
|
||||||
it.errors = append(it.errors, <-it.results)
|
|
||||||
}
|
|
||||||
if it.errors[it.index+1] != nil {
|
|
||||||
return it.chain[it.index+1], it.errors[it.index+1]
|
|
||||||
}
|
|
||||||
// Block header valid, ignore body validation since we don't have a parent anyway
|
|
||||||
return it.chain[it.index+1], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// previous returns the previous header that was being processed, or nil.
|
// previous returns the previous header that was being processed, or nil.
|
||||||
func (it *insertIterator) previous() *types.Header {
|
func (it *insertIterator) previous() *types.Header {
|
||||||
if it.index < 1 {
|
if it.index < 1 {
|
||||||
|
|
|
||||||
|
|
@ -522,3 +522,13 @@ func (bc *BlockChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscript
|
||||||
func (bc *BlockChain) SubscribeBlockProcessingEvent(ch chan<- bool) event.Subscription {
|
func (bc *BlockChain) SubscribeBlockProcessingEvent(ch chan<- bool) event.Subscription {
|
||||||
return bc.scope.Track(bc.blockProcFeed.Subscribe(ch))
|
return bc.scope.Track(bc.blockProcFeed.Subscribe(ch))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SubscribeNewPayloadEvent registers a subscription for NewPayloadEvent.
|
||||||
|
func (bc *BlockChain) SubscribeNewPayloadEvent(ch chan<- NewPayloadEvent) event.Subscription {
|
||||||
|
return bc.scope.Track(bc.newPayloadFeed.Subscribe(ch))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendNewPayloadEvent sends a NewPayloadEvent to subscribers.
|
||||||
|
func (bc *BlockChain) SendNewPayloadEvent(ev NewPayloadEvent) {
|
||||||
|
bc.newPayloadFeed.Send(ev)
|
||||||
|
}
|
||||||
|
|
|
||||||
265
core/blockchain_stats.go
Normal file
265
core/blockchain_stats.go
Normal file
|
|
@ -0,0 +1,265 @@
|
||||||
|
// Copyright 2025 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExecuteStats includes all the statistics of a block execution in details.
|
||||||
|
type ExecuteStats struct {
|
||||||
|
// State read times
|
||||||
|
AccountReads time.Duration // Time spent on the account reads
|
||||||
|
StorageReads time.Duration // Time spent on the storage reads
|
||||||
|
AccountHashes time.Duration // Time spent on the account trie hash
|
||||||
|
AccountUpdates time.Duration // Time spent on the account trie update
|
||||||
|
AccountCommits time.Duration // Time spent on the account trie commit
|
||||||
|
StorageUpdates time.Duration // Time spent on the storage trie update
|
||||||
|
StorageCommits time.Duration // Time spent on the storage trie commit
|
||||||
|
CodeReads time.Duration // Time spent on the contract code read
|
||||||
|
|
||||||
|
AccountLoaded int // Number of accounts loaded
|
||||||
|
AccountUpdated int // Number of accounts updated
|
||||||
|
AccountDeleted int // Number of accounts deleted
|
||||||
|
StorageLoaded int // Number of storage slots loaded
|
||||||
|
StorageUpdated int // Number of storage slots updated
|
||||||
|
StorageDeleted int // Number of storage slots deleted
|
||||||
|
CodeLoaded int // Number of contract code loaded
|
||||||
|
CodeLoadBytes int // Number of bytes read from contract code
|
||||||
|
CodeUpdated int // Number of contract code written (CREATE/CREATE2 + EIP-7702)
|
||||||
|
CodeUpdateBytes int // Total bytes of code written
|
||||||
|
|
||||||
|
Execution time.Duration // Time spent on the EVM execution
|
||||||
|
Validation time.Duration // Time spent on the block validation
|
||||||
|
CrossValidation time.Duration // Optional, time spent on the block cross validation
|
||||||
|
SnapshotCommit time.Duration // Time spent on snapshot commit
|
||||||
|
TrieDBCommit time.Duration // Time spent on database commit
|
||||||
|
BlockWrite time.Duration // Time spent on block write
|
||||||
|
TotalTime time.Duration // The total time spent on block execution
|
||||||
|
MgasPerSecond float64 // The million gas processed per second
|
||||||
|
|
||||||
|
// Cache hit rates
|
||||||
|
StateReadCacheStats state.ReaderStats
|
||||||
|
StatePrefetchCacheStats state.ReaderStats
|
||||||
|
}
|
||||||
|
|
||||||
|
// reportMetrics uploads execution statistics to the metrics system.
|
||||||
|
func (s *ExecuteStats) reportMetrics() {
|
||||||
|
if s.AccountLoaded != 0 {
|
||||||
|
accountReadTimer.Update(s.AccountReads)
|
||||||
|
accountReadSingleTimer.Update(s.AccountReads / time.Duration(s.AccountLoaded))
|
||||||
|
}
|
||||||
|
if s.StorageLoaded != 0 {
|
||||||
|
storageReadTimer.Update(s.StorageReads)
|
||||||
|
storageReadSingleTimer.Update(s.StorageReads / time.Duration(s.StorageLoaded))
|
||||||
|
}
|
||||||
|
if s.CodeLoaded != 0 {
|
||||||
|
codeReadTimer.Update(s.CodeReads)
|
||||||
|
codeReadSingleTimer.Update(s.CodeReads / time.Duration(s.CodeLoaded))
|
||||||
|
codeReadBytesTimer.Update(time.Duration(s.CodeLoadBytes))
|
||||||
|
}
|
||||||
|
accountUpdateTimer.Update(s.AccountUpdates) // Account updates are complete(in validation)
|
||||||
|
storageUpdateTimer.Update(s.StorageUpdates) // Storage updates are complete(in validation)
|
||||||
|
accountHashTimer.Update(s.AccountHashes) // Account hashes are complete(in validation)
|
||||||
|
accountCommitTimer.Update(s.AccountCommits) // Account commits are complete, we can mark them
|
||||||
|
storageCommitTimer.Update(s.StorageCommits) // Storage commits are complete, we can mark them
|
||||||
|
|
||||||
|
blockExecutionTimer.Update(s.Execution) // The time spent on EVM processing
|
||||||
|
blockValidationTimer.Update(s.Validation) // The time spent on block validation
|
||||||
|
blockCrossValidationTimer.Update(s.CrossValidation) // The time spent on stateless cross validation
|
||||||
|
snapshotCommitTimer.Update(s.SnapshotCommit) // Snapshot commits are complete, we can mark them
|
||||||
|
triedbCommitTimer.Update(s.TrieDBCommit) // Trie database commits are complete, we can mark them
|
||||||
|
blockWriteTimer.Update(s.BlockWrite) // The time spent on block write
|
||||||
|
blockInsertTimer.Update(s.TotalTime) // The total time spent on block execution
|
||||||
|
chainMgaspsMeter.Update(time.Duration(s.MgasPerSecond)) // TODO(rjl493456442) generalize the ResettingTimer
|
||||||
|
|
||||||
|
// Cache hit rates
|
||||||
|
accountCacheHitPrefetchMeter.Mark(s.StatePrefetchCacheStats.AccountCacheHit)
|
||||||
|
accountCacheMissPrefetchMeter.Mark(s.StatePrefetchCacheStats.AccountCacheMiss)
|
||||||
|
storageCacheHitPrefetchMeter.Mark(s.StatePrefetchCacheStats.StorageCacheHit)
|
||||||
|
storageCacheMissPrefetchMeter.Mark(s.StatePrefetchCacheStats.StorageCacheMiss)
|
||||||
|
|
||||||
|
accountCacheHitMeter.Mark(s.StateReadCacheStats.AccountCacheHit)
|
||||||
|
accountCacheMissMeter.Mark(s.StateReadCacheStats.AccountCacheMiss)
|
||||||
|
storageCacheHitMeter.Mark(s.StateReadCacheStats.StorageCacheHit)
|
||||||
|
storageCacheMissMeter.Mark(s.StateReadCacheStats.StorageCacheMiss)
|
||||||
|
}
|
||||||
|
|
||||||
|
// slowBlockLog represents the JSON structure for slow block logging.
|
||||||
|
// This format is designed for cross-client compatibility with other
|
||||||
|
// Ethereum execution clients (reth, Besu, Nethermind).
|
||||||
|
type slowBlockLog struct {
|
||||||
|
Level string `json:"level"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
Block slowBlockInfo `json:"block"`
|
||||||
|
Timing slowBlockTime `json:"timing"`
|
||||||
|
Throughput slowBlockThru `json:"throughput"`
|
||||||
|
StateReads slowBlockReads `json:"state_reads"`
|
||||||
|
StateWrites slowBlockWrites `json:"state_writes"`
|
||||||
|
Cache slowBlockCache `json:"cache"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type slowBlockInfo struct {
|
||||||
|
Number uint64 `json:"number"`
|
||||||
|
Hash common.Hash `json:"hash"`
|
||||||
|
GasUsed uint64 `json:"gas_used"`
|
||||||
|
TxCount int `json:"tx_count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type slowBlockTime struct {
|
||||||
|
ExecutionMs float64 `json:"execution_ms"`
|
||||||
|
StateReadMs float64 `json:"state_read_ms"`
|
||||||
|
StateHashMs float64 `json:"state_hash_ms"`
|
||||||
|
CommitMs float64 `json:"commit_ms"`
|
||||||
|
TotalMs float64 `json:"total_ms"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type slowBlockThru struct {
|
||||||
|
MgasPerSec float64 `json:"mgas_per_sec"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type slowBlockReads struct {
|
||||||
|
Accounts int `json:"accounts"`
|
||||||
|
StorageSlots int `json:"storage_slots"`
|
||||||
|
Code int `json:"code"`
|
||||||
|
CodeBytes int `json:"code_bytes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type slowBlockWrites struct {
|
||||||
|
Accounts int `json:"accounts"`
|
||||||
|
AccountsDeleted int `json:"accounts_deleted"`
|
||||||
|
StorageSlots int `json:"storage_slots"`
|
||||||
|
StorageSlotsDeleted int `json:"storage_slots_deleted"`
|
||||||
|
Code int `json:"code"`
|
||||||
|
CodeBytes int `json:"code_bytes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// slowBlockCache represents cache hit/miss statistics for cross-client analysis.
|
||||||
|
type slowBlockCache struct {
|
||||||
|
Account slowBlockCacheEntry `json:"account"`
|
||||||
|
Storage slowBlockCacheEntry `json:"storage"`
|
||||||
|
Code slowBlockCodeCacheEntry `json:"code"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// slowBlockCacheEntry represents cache statistics for account/storage caches.
|
||||||
|
type slowBlockCacheEntry struct {
|
||||||
|
Hits int64 `json:"hits"`
|
||||||
|
Misses int64 `json:"misses"`
|
||||||
|
HitRate float64 `json:"hit_rate"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// slowBlockCodeCacheEntry represents cache statistics for code cache with byte-level granularity.
|
||||||
|
type slowBlockCodeCacheEntry struct {
|
||||||
|
Hits int64 `json:"hits"`
|
||||||
|
Misses int64 `json:"misses"`
|
||||||
|
HitRate float64 `json:"hit_rate"`
|
||||||
|
HitBytes int64 `json:"hit_bytes"`
|
||||||
|
MissBytes int64 `json:"miss_bytes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculateHitRate computes the cache hit rate as a percentage (0-100).
|
||||||
|
func calculateHitRate(hits, misses int64) float64 {
|
||||||
|
if total := hits + misses; total > 0 {
|
||||||
|
return float64(hits) / float64(total) * 100.0
|
||||||
|
}
|
||||||
|
return 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
// durationToMs converts a time.Duration to milliseconds as a float64
|
||||||
|
// with sub-millisecond precision for accurate cross-client metrics.
|
||||||
|
func durationToMs(d time.Duration) float64 {
|
||||||
|
return float64(d.Nanoseconds()) / 1e6
|
||||||
|
}
|
||||||
|
|
||||||
|
// logSlow prints the detailed execution statistics in JSON format if the block
|
||||||
|
// is regarded as slow. The JSON format is designed for cross-client compatibility
|
||||||
|
// with other Ethereum execution clients.
|
||||||
|
func (s *ExecuteStats) logSlow(block *types.Block, slowBlockThreshold time.Duration) {
|
||||||
|
// Negative threshold means disabled (default when flag not set)
|
||||||
|
if slowBlockThreshold < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Threshold of 0 logs all blocks; positive threshold filters
|
||||||
|
if slowBlockThreshold > 0 && s.TotalTime < slowBlockThreshold {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logEntry := slowBlockLog{
|
||||||
|
Level: "warn",
|
||||||
|
Msg: "Slow block",
|
||||||
|
Block: slowBlockInfo{
|
||||||
|
Number: block.NumberU64(),
|
||||||
|
Hash: block.Hash(),
|
||||||
|
GasUsed: block.GasUsed(),
|
||||||
|
TxCount: len(block.Transactions()),
|
||||||
|
},
|
||||||
|
Timing: slowBlockTime{
|
||||||
|
ExecutionMs: durationToMs(s.Execution),
|
||||||
|
StateReadMs: durationToMs(s.AccountReads + s.StorageReads + s.CodeReads),
|
||||||
|
StateHashMs: durationToMs(s.AccountHashes + s.AccountUpdates + s.StorageUpdates),
|
||||||
|
CommitMs: durationToMs(max(s.AccountCommits, s.StorageCommits) + s.TrieDBCommit + s.SnapshotCommit + s.BlockWrite),
|
||||||
|
TotalMs: durationToMs(s.TotalTime),
|
||||||
|
},
|
||||||
|
Throughput: slowBlockThru{
|
||||||
|
MgasPerSec: s.MgasPerSecond,
|
||||||
|
},
|
||||||
|
StateReads: slowBlockReads{
|
||||||
|
Accounts: s.AccountLoaded,
|
||||||
|
StorageSlots: s.StorageLoaded,
|
||||||
|
Code: s.CodeLoaded,
|
||||||
|
CodeBytes: s.CodeLoadBytes,
|
||||||
|
},
|
||||||
|
StateWrites: slowBlockWrites{
|
||||||
|
Accounts: s.AccountUpdated,
|
||||||
|
AccountsDeleted: s.AccountDeleted,
|
||||||
|
StorageSlots: s.StorageUpdated,
|
||||||
|
StorageSlotsDeleted: s.StorageDeleted,
|
||||||
|
Code: s.CodeUpdated,
|
||||||
|
CodeBytes: s.CodeUpdateBytes,
|
||||||
|
},
|
||||||
|
Cache: slowBlockCache{
|
||||||
|
Account: slowBlockCacheEntry{
|
||||||
|
Hits: s.StateReadCacheStats.AccountCacheHit,
|
||||||
|
Misses: s.StateReadCacheStats.AccountCacheMiss,
|
||||||
|
HitRate: calculateHitRate(s.StateReadCacheStats.AccountCacheHit, s.StateReadCacheStats.AccountCacheMiss),
|
||||||
|
},
|
||||||
|
Storage: slowBlockCacheEntry{
|
||||||
|
Hits: s.StateReadCacheStats.StorageCacheHit,
|
||||||
|
Misses: s.StateReadCacheStats.StorageCacheMiss,
|
||||||
|
HitRate: calculateHitRate(s.StateReadCacheStats.StorageCacheHit, s.StateReadCacheStats.StorageCacheMiss),
|
||||||
|
},
|
||||||
|
Code: slowBlockCodeCacheEntry{
|
||||||
|
Hits: s.StateReadCacheStats.CodeStats.CacheHit,
|
||||||
|
Misses: s.StateReadCacheStats.CodeStats.CacheMiss,
|
||||||
|
HitRate: calculateHitRate(s.StateReadCacheStats.CodeStats.CacheHit, s.StateReadCacheStats.CodeStats.CacheMiss),
|
||||||
|
HitBytes: s.StateReadCacheStats.CodeStats.CacheHitBytes,
|
||||||
|
MissBytes: s.StateReadCacheStats.CodeStats.CacheMissBytes,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
jsonBytes, err := json.Marshal(logEntry)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to marshal slow block log", "error", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Warn(string(jsonBytes))
|
||||||
|
}
|
||||||
|
|
@ -162,12 +162,12 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
|
||||||
}
|
}
|
||||||
res, err := blockchain.processor.Process(block, statedb, vm.Config{})
|
res, err := blockchain.processor.Process(block, statedb, vm.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
blockchain.reportBlock(block, res, err)
|
blockchain.reportBadBlock(block, res, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = blockchain.validator.ValidateState(block, statedb, res, false)
|
err = blockchain.validator.ValidateState(block, statedb, res, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
blockchain.reportBlock(block, res, err)
|
blockchain.reportBadBlock(block, res, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4515,3 +4515,45 @@ func TestGetCanonicalReceipt(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestSetHeadBeyondRootFinalizedBug tests the issue where the finalized block
|
||||||
|
// is not cleared when rewinding past it using setHeadBeyondRoot.
|
||||||
|
func TestSetHeadBeyondRootFinalizedBug(t *testing.T) {
|
||||||
|
// Create a clean blockchain with 100 blocks using PathScheme (PBSS)
|
||||||
|
_, _, blockchain, err := newCanonical(ethash.NewFaker(), 100, true, rawdb.PathScheme)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create pristine chain: %v", err)
|
||||||
|
}
|
||||||
|
defer blockchain.Stop()
|
||||||
|
|
||||||
|
// Set the "Finalized" marker to the current Head (Block 100)
|
||||||
|
headBlock := blockchain.CurrentBlock()
|
||||||
|
if headBlock.Number.Uint64() != 100 {
|
||||||
|
t.Fatalf("Setup failed: expected head 100, got %d", headBlock.Number.Uint64())
|
||||||
|
}
|
||||||
|
blockchain.SetFinalized(headBlock)
|
||||||
|
|
||||||
|
// Verify setup
|
||||||
|
if blockchain.CurrentFinalBlock().Number.Uint64() != 100 {
|
||||||
|
t.Fatalf("Setup failed: Finalized block should be 100")
|
||||||
|
}
|
||||||
|
targetBlock := blockchain.GetBlockByNumber(50)
|
||||||
|
|
||||||
|
// Call setHeadBeyondRoot with:
|
||||||
|
// head = 100
|
||||||
|
// repair = true
|
||||||
|
if _, err := blockchain.setHeadBeyondRoot(100, 0, targetBlock.Root(), true); err != nil {
|
||||||
|
t.Fatalf("Failed to rewind: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
currentFinal := blockchain.CurrentFinalBlock()
|
||||||
|
currentHead := blockchain.CurrentBlock().Number.Uint64()
|
||||||
|
|
||||||
|
// The previous finalized block (100) is now invalid because we rewound to 50.
|
||||||
|
// The function should have cleared the finalized marker (set to nil).
|
||||||
|
if currentFinal != nil && currentFinal.Number.Uint64() > currentHead {
|
||||||
|
t.Errorf("Chain Head: %d , Finalized Block: %d , Finalized block was >= head block.",
|
||||||
|
currentHead,
|
||||||
|
currentFinal.Number.Uint64())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/triedb"
|
"github.com/ethereum/go-ethereum/triedb"
|
||||||
"github.com/ethereum/go-verkle"
|
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -427,7 +426,11 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forcibly use hash-based state scheme for retaining all nodes in disk.
|
// Forcibly use hash-based state scheme for retaining all nodes in disk.
|
||||||
triedb := triedb.NewDatabase(db, triedb.HashDefaults)
|
var triedbConfig *triedb.Config = triedb.HashDefaults
|
||||||
|
if config.IsVerkle(config.ChainID, 0) {
|
||||||
|
triedbConfig = triedb.VerkleDefaults
|
||||||
|
}
|
||||||
|
triedb := triedb.NewDatabase(db, triedbConfig)
|
||||||
defer triedb.Close()
|
defer triedb.Close()
|
||||||
|
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
|
|
@ -472,9 +475,13 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||||
// then generate chain on top.
|
// then generate chain on top.
|
||||||
func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, gen func(int, *BlockGen)) (ethdb.Database, []*types.Block, []types.Receipts) {
|
func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, gen func(int, *BlockGen)) (ethdb.Database, []*types.Block, []types.Receipts) {
|
||||||
db := rawdb.NewMemoryDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
triedb := triedb.NewDatabase(db, triedb.HashDefaults)
|
var triedbConfig *triedb.Config = triedb.HashDefaults
|
||||||
|
if genesis.Config != nil && genesis.Config.IsVerkle(genesis.Config.ChainID, 0) {
|
||||||
|
triedbConfig = triedb.VerkleDefaults
|
||||||
|
}
|
||||||
|
triedb := triedb.NewDatabase(db, triedbConfig)
|
||||||
defer triedb.Close()
|
defer triedb.Close()
|
||||||
_, err := genesis.Commit(db, triedb)
|
_, err := genesis.Commit(db, triedb, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -482,117 +489,6 @@ func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int,
|
||||||
return db, blocks, receipts
|
return db, blocks, receipts
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine consensus.Engine, db ethdb.Database, trdb *triedb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts, []*verkle.VerkleProof, []verkle.StateDiff) {
|
|
||||||
if config == nil {
|
|
||||||
config = params.TestChainConfig
|
|
||||||
}
|
|
||||||
proofs := make([]*verkle.VerkleProof, 0, n)
|
|
||||||
keyvals := make([]verkle.StateDiff, 0, n)
|
|
||||||
cm := newChainMaker(parent, config, engine)
|
|
||||||
|
|
||||||
genblock := func(i int, parent *types.Block, triedb *triedb.Database, statedb *state.StateDB) (*types.Block, types.Receipts) {
|
|
||||||
b := &BlockGen{i: i, cm: cm, parent: parent, statedb: statedb, engine: engine}
|
|
||||||
b.header = cm.makeHeader(parent, statedb, b.engine)
|
|
||||||
|
|
||||||
// TODO uncomment when proof generation is merged
|
|
||||||
// Save pre state for proof generation
|
|
||||||
// preState := statedb.Copy()
|
|
||||||
|
|
||||||
// EIP-2935 / 7709
|
|
||||||
blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase)
|
|
||||||
blockContext.Random = &common.Hash{} // enable post-merge instruction set
|
|
||||||
evm := vm.NewEVM(blockContext, statedb, cm.config, vm.Config{})
|
|
||||||
ProcessParentBlockHash(b.header.ParentHash, evm)
|
|
||||||
|
|
||||||
// Execute any user modifications to the block.
|
|
||||||
if gen != nil {
|
|
||||||
gen(i, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
requests := b.collectRequests(false)
|
|
||||||
if requests != nil {
|
|
||||||
reqHash := types.CalcRequestsHash(requests)
|
|
||||||
b.header.RequestsHash = &reqHash
|
|
||||||
}
|
|
||||||
|
|
||||||
body := &types.Body{
|
|
||||||
Transactions: b.txs,
|
|
||||||
Uncles: b.uncles,
|
|
||||||
Withdrawals: b.withdrawals,
|
|
||||||
}
|
|
||||||
block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, body, b.receipts)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write state changes to DB.
|
|
||||||
root, err := statedb.Commit(b.header.Number.Uint64(), config.IsEIP158(b.header.Number), config.IsCancun(b.header.Number, b.header.Time))
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("state write error: %v", err))
|
|
||||||
}
|
|
||||||
if err = triedb.Commit(root, false); err != nil {
|
|
||||||
panic(fmt.Sprintf("trie write error: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
proofs = append(proofs, block.ExecutionWitness().VerkleProof)
|
|
||||||
keyvals = append(keyvals, block.ExecutionWitness().StateDiff)
|
|
||||||
|
|
||||||
return block, b.receipts
|
|
||||||
}
|
|
||||||
|
|
||||||
sdb := state.NewDatabase(trdb, nil)
|
|
||||||
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
statedb, err := state.New(parent.Root(), sdb)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
block, receipts := genblock(i, parent, trdb, statedb)
|
|
||||||
|
|
||||||
// Post-process the receipts.
|
|
||||||
// Here we assign the final block hash and other info into the receipt.
|
|
||||||
// In order for DeriveFields to work, the transaction and receipt lists need to be
|
|
||||||
// of equal length. If AddUncheckedTx or AddUncheckedReceipt are used, there will be
|
|
||||||
// extra ones, so we just trim the lists here.
|
|
||||||
receiptsCount := len(receipts)
|
|
||||||
txs := block.Transactions()
|
|
||||||
if len(receipts) > len(txs) {
|
|
||||||
receipts = receipts[:len(txs)]
|
|
||||||
} else if len(receipts) < len(txs) {
|
|
||||||
txs = txs[:len(receipts)]
|
|
||||||
}
|
|
||||||
var blobGasPrice *big.Int
|
|
||||||
if block.ExcessBlobGas() != nil {
|
|
||||||
blobGasPrice = eip4844.CalcBlobFee(cm.config, block.Header())
|
|
||||||
}
|
|
||||||
if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Time(), block.BaseFee(), blobGasPrice, txs); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Re-expand to ensure all receipts are returned.
|
|
||||||
receipts = receipts[:receiptsCount]
|
|
||||||
|
|
||||||
// Advance the chain.
|
|
||||||
cm.add(block, receipts)
|
|
||||||
parent = block
|
|
||||||
}
|
|
||||||
return cm.chain, cm.receipts, proofs, keyvals
|
|
||||||
}
|
|
||||||
|
|
||||||
func GenerateVerkleChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, gen func(int, *BlockGen)) (common.Hash, ethdb.Database, []*types.Block, []types.Receipts, []*verkle.VerkleProof, []verkle.StateDiff) {
|
|
||||||
db := rawdb.NewMemoryDatabase()
|
|
||||||
cacheConfig := DefaultConfig().WithStateScheme(rawdb.PathScheme)
|
|
||||||
cacheConfig.SnapshotLimit = 0
|
|
||||||
triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(true))
|
|
||||||
defer triedb.Close()
|
|
||||||
genesisBlock, err := genesis.Commit(db, triedb)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
blocks, receipts, proofs, keyvals := GenerateVerkleChain(genesis.Config, genesisBlock, engine, db, triedb, n, gen)
|
|
||||||
return genesisBlock.Hash(), db, blocks, receipts, proofs, keyvals
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cm *chainMaker) makeHeader(parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header {
|
func (cm *chainMaker) makeHeader(parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header {
|
||||||
time := parent.Time() + 10 // block time is fixed at 10 seconds
|
time := parent.Time() + 10 // block time is fixed at 10 seconds
|
||||||
parentHeader := parent.Header()
|
parentHeader := parent.Header()
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,9 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -35,3 +38,10 @@ type ChainEvent struct {
|
||||||
type ChainHeadEvent struct {
|
type ChainHeadEvent struct {
|
||||||
Header *types.Header
|
Header *types.Header
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewPayloadEvent is posted when engine_newPayloadVX processes a block.
|
||||||
|
type NewPayloadEvent struct {
|
||||||
|
Hash common.Hash
|
||||||
|
Number uint64
|
||||||
|
ProcessingTime time.Duration
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,12 +80,9 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
|
||||||
func NewEVMTxContext(msg *Message) vm.TxContext {
|
func NewEVMTxContext(msg *Message) vm.TxContext {
|
||||||
ctx := vm.TxContext{
|
ctx := vm.TxContext{
|
||||||
Origin: msg.From,
|
Origin: msg.From,
|
||||||
GasPrice: new(big.Int).Set(msg.GasPrice),
|
GasPrice: uint256.MustFromBig(msg.GasPrice),
|
||||||
BlobHashes: msg.BlobHashes,
|
BlobHashes: msg.BlobHashes,
|
||||||
}
|
}
|
||||||
if msg.BlobGasFeeCap != nil {
|
|
||||||
ctx.BlobFeeCap = new(big.Int).Set(msg.BlobGasFeeCap)
|
|
||||||
}
|
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -288,5 +288,32 @@
|
||||||
{"blockNumber": 22958100, "blockId": "0xe38e0ff7b0c4065ca42ea577bc32f2566ca46f2ddeedcc4bc1f8fb00e7f26329", "firstIndex": 19260242424},
|
{"blockNumber": 22958100, "blockId": "0xe38e0ff7b0c4065ca42ea577bc32f2566ca46f2ddeedcc4bc1f8fb00e7f26329", "firstIndex": 19260242424},
|
||||||
{"blockNumber": 22988600, "blockId": "0x04ca74758b22e0ea54b8c992022ff21c16a2af9c45144c3b0f80de921a7eee82", "firstIndex": 19327351273},
|
{"blockNumber": 22988600, "blockId": "0x04ca74758b22e0ea54b8c992022ff21c16a2af9c45144c3b0f80de921a7eee82", "firstIndex": 19327351273},
|
||||||
{"blockNumber": 23018392, "blockId": "0x61cc979b00bc97b48356f986a5b9ec997d674bc904c2a2e4b0f17de08e50b3bb", "firstIndex": 19394459627},
|
{"blockNumber": 23018392, "blockId": "0x61cc979b00bc97b48356f986a5b9ec997d674bc904c2a2e4b0f17de08e50b3bb", "firstIndex": 19394459627},
|
||||||
{"blockNumber": 23048524, "blockId": "0x489de15d95739ede4ab15e8b5151d80d4dc85ae10e7be800b1a4723094a678df", "firstIndex": 19461570073}
|
{"blockNumber": 23048524, "blockId": "0x489de15d95739ede4ab15e8b5151d80d4dc85ae10e7be800b1a4723094a678df", "firstIndex": 19461570073},
|
||||||
|
{"blockNumber": 23078983, "blockId": "0xd64da4fe45a0a349101b8ce1a6336fb099d8b00cc274d0eb59356e134190b8f2", "firstIndex": 19528679292},
|
||||||
|
{"blockNumber": 23109224, "blockId": "0xbb6c29f91820fcf6caef881bdfe61eb690f9796f8f139c56eaf27aa601fe5ed2", "firstIndex": 19595787850},
|
||||||
|
{"blockNumber": 23136690, "blockId": "0xc1915739edff731d469ec1500ad05102c0d68cc1ef062411d2e9741b8ebdc571", "firstIndex": 19662896969},
|
||||||
|
{"blockNumber": 23164324, "blockId": "0x97d0078f2a22a8fbde4660d5f11846d00a669c606e42291df55e863190914a9f", "firstIndex": 19730004997},
|
||||||
|
{"blockNumber": 23192975, "blockId": "0x8463749ec09f55fccdd962498f93d6468d744faedc35da8097642cd4609e08f2", "firstIndex": 19797111604},
|
||||||
|
{"blockNumber": 23219805, "blockId": "0x76ca51d01b5724f1b0f6c3acb50dfcdb00e1648a475dd7599174b301c25e5517", "firstIndex": 19864222312},
|
||||||
|
{"blockNumber": 23236331, "blockId": "0x388f9e36b3ec2120d2b4adfdcdb0c0b8de139eef107e327670dd77fc581c2c5f", "firstIndex": 19931331831},
|
||||||
|
{"blockNumber": 23260849, "blockId": "0xe4a467164dbc8f9beebf0c8478a9e7ee16dfce65e2da423b1048601831222ba7", "firstIndex": 19998441286},
|
||||||
|
{"blockNumber": 23282795, "blockId": "0x74ad210aa1bfdd4bcf61298ebff622da758c36c38d62d001f2440d09e73ef6c7", "firstIndex": 20065548083},
|
||||||
|
{"blockNumber": 23300759, "blockId": "0xa405f5ea21a5207d3cde718a1e3fb7f0ce3dd87ac6040a0db52da0e9488e63f6", "firstIndex": 20132623334},
|
||||||
|
{"blockNumber": 23319772, "blockId": "0xafae645dd057af450eddf69c7604bde0136524abc5b7d6697426427ef2d30724", "firstIndex": 20199767615},
|
||||||
|
{"blockNumber": 23342113, "blockId": "0x8482c4be13294cfd862d500051c8b4efb95b50f4a79717da6aeabb2a6ff3e199", "firstIndex": 20266874986},
|
||||||
|
{"blockNumber": 23366974, "blockId": "0xf6047cafea5da7aaf20691df700d759fe84f5aa2176d9dd42c6ae138899a29ea", "firstIndex": 20333983351},
|
||||||
|
{"blockNumber": 23397579, "blockId": "0xe94815fe0278659a26e15b023c0c3877abf6f1265710c5dfddf161ee8af01b40", "firstIndex": 20401094335},
|
||||||
|
{"blockNumber": 23425940, "blockId": "0xa98d6d48b93d9ef848c340b47cf9d191f36e76375dd747d8adcb39d72251822d", "firstIndex": 20468200506},
|
||||||
|
{"blockNumber": 23452402, "blockId": "0x5f26ff308c0883a04f4a92411bcd05e50538d95a96532452f43b71fde4af908d", "firstIndex": 20535311178},
|
||||||
|
{"blockNumber": 23478884, "blockId": "0x23a81186c21218f7034ee81dcd72db71edcbc0e97da26703b8026b6d4a81f693", "firstIndex": 20602384106},
|
||||||
|
{"blockNumber": 23507136, "blockId": "0xb1d4a2bd836c5d78b678f0bfffd651bdfeae8b7965639b640f8745193b142323", "firstIndex": 20669529935},
|
||||||
|
{"blockNumber": 23535463, "blockId": "0x1886a719a6376352753242ec5093c434938b9a90356facdbdaafd2670da97d82", "firstIndex": 20736637374},
|
||||||
|
{"blockNumber": 23564278, "blockId": "0xcdc5a1349f45430771fa2080555f20b80b2d84f575728dbb8bd3b633fbb0a00b", "firstIndex": 20803747399},
|
||||||
|
{"blockNumber": 23594711, "blockId": "0xbbf41e407367feeb865b305e38aee8bef84ba62b66efbd6fcd3b16a5d50cc055", "firstIndex": 20870854523},
|
||||||
|
{"blockNumber": 23627417, "blockId": "0x1b3c6bd39c5aa7c73101e7e946964b3d7afecf3f253efda8de5610dd99cbee82", "firstIndex": 20937963176},
|
||||||
|
{"blockNumber": 23660347, "blockId": "0xadc8ac88c281f50c3aaf1d08149100e8f91a16bbe09b28ac86665bcea681d41b", "firstIndex": 21005072865},
|
||||||
|
{"blockNumber": 23692228, "blockId": "0xeb4040468161d9d5b6863eb62e4f21f72a1944f910ecfa95ee6a9dbc39e92ef0", "firstIndex": 21072181753},
|
||||||
|
{"blockNumber": 23722331, "blockId": "0xdfc9be1b43488148868da0c8ac56e99e0ffde18bcc418755c4765e745fe74024", "firstIndex": 21139291342},
|
||||||
|
{"blockNumber": 23752866, "blockId": "0xb9cf0dfee429a1450f5fb7a237729cf7d0c49e7e35c00dc3709f197c091f8b39", "firstIndex": 21206399901},
|
||||||
|
{"blockNumber": 23784485, "blockId": "0x92f5f119078b4ef7ad99273e2ae6f874cfb663e80d741a821e0bb7c25c0369c7", "firstIndex": 21273505141}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -434,7 +434,7 @@ func (f *FilterMaps) safeDeleteWithLogs(deleteFn func(db ethdb.KeyValueStore, ha
|
||||||
lastLogPrinted = start
|
lastLogPrinted = start
|
||||||
)
|
)
|
||||||
switch err := deleteFn(f.db, f.hashScheme, func(deleted bool) bool {
|
switch err := deleteFn(f.db, f.hashScheme, func(deleted bool) bool {
|
||||||
if deleted && !logPrinted || time.Since(lastLogPrinted) > time.Second*10 {
|
if deleted && (!logPrinted || time.Since(lastLogPrinted) > time.Second*10) {
|
||||||
log.Info(action+" in progress...", "elapsed", common.PrettyDuration(time.Since(start)))
|
log.Info(action+" in progress...", "elapsed", common.PrettyDuration(time.Since(start)))
|
||||||
logPrinted, lastLogPrinted = true, time.Now()
|
logPrinted, lastLogPrinted = true, time.Now()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,10 +76,16 @@ func TestCreation(t *testing.T) {
|
||||||
{20000000, 1681338454, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1681338455}}, // Last Gray Glacier block
|
{20000000, 1681338454, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1681338455}}, // Last Gray Glacier block
|
||||||
{20000000, 1681338455, ID{Hash: checksumToBytes(0xdce96c2d), Next: 1710338135}}, // First Shanghai block
|
{20000000, 1681338455, ID{Hash: checksumToBytes(0xdce96c2d), Next: 1710338135}}, // First Shanghai block
|
||||||
{30000000, 1710338134, ID{Hash: checksumToBytes(0xdce96c2d), Next: 1710338135}}, // Last Shanghai block
|
{30000000, 1710338134, ID{Hash: checksumToBytes(0xdce96c2d), Next: 1710338135}}, // Last Shanghai block
|
||||||
{40000000, 1710338135, ID{Hash: checksumToBytes(0x9f3d2254), Next: 1746612311}}, // First Cancun block
|
{30000000, 1710338135, ID{Hash: checksumToBytes(0x9f3d2254), Next: 1746612311}}, // First Cancun block
|
||||||
{30000000, 1746022486, ID{Hash: checksumToBytes(0x9f3d2254), Next: 1746612311}}, // Last Cancun block
|
{30000000, 1746022486, ID{Hash: checksumToBytes(0x9f3d2254), Next: 1746612311}}, // Last Cancun block
|
||||||
{30000000, 1746612311, ID{Hash: checksumToBytes(0xc376cf8b), Next: 0}}, // First Prague block
|
{30000000, 1746612311, ID{Hash: checksumToBytes(0xc376cf8b), Next: 1764798551}}, // First Prague block
|
||||||
{50000000, 2000000000, ID{Hash: checksumToBytes(0xc376cf8b), Next: 0}}, // Future Prague block
|
{30000000, 1764798550, ID{Hash: checksumToBytes(0xc376cf8b), Next: 1764798551}}, // Last Prague block
|
||||||
|
{30000000, 1764798551, ID{Hash: checksumToBytes(0x5167e2a6), Next: 1765290071}}, // First Osaka block
|
||||||
|
{30000000, 1765290070, ID{Hash: checksumToBytes(0x5167e2a6), Next: 1765290071}}, // Last Osaka block
|
||||||
|
{30000000, 1765290071, ID{Hash: checksumToBytes(0xcba2a1c0), Next: 1767747671}}, // First BPO1 block
|
||||||
|
{30000000, 1767747670, ID{Hash: checksumToBytes(0xcba2a1c0), Next: 1767747671}}, // Last BPO1 block
|
||||||
|
{30000000, 1767747671, ID{Hash: checksumToBytes(0x07c9462e), Next: 0}}, // First BPO2 block
|
||||||
|
{50000000, 2000000000, ID{Hash: checksumToBytes(0x07c9462e), Next: 0}}, // Future BPO2 block
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Sepolia test cases
|
// Sepolia test cases
|
||||||
|
|
@ -162,6 +168,9 @@ func TestValidation(t *testing.T) {
|
||||||
legacyConfig.ShanghaiTime = nil
|
legacyConfig.ShanghaiTime = nil
|
||||||
legacyConfig.CancunTime = nil
|
legacyConfig.CancunTime = nil
|
||||||
legacyConfig.PragueTime = nil
|
legacyConfig.PragueTime = nil
|
||||||
|
legacyConfig.OsakaTime = nil
|
||||||
|
legacyConfig.BPO1Time = nil
|
||||||
|
legacyConfig.BPO2Time = nil
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
config *params.ChainConfig
|
config *params.ChainConfig
|
||||||
|
|
@ -361,11 +370,11 @@ func TestValidation(t *testing.T) {
|
||||||
// Local is mainnet Shanghai, remote is random Shanghai.
|
// Local is mainnet Shanghai, remote is random Shanghai.
|
||||||
{params.MainnetChainConfig, 20000000, 1681338455, ID{Hash: checksumToBytes(0x12345678), Next: 0}, ErrLocalIncompatibleOrStale},
|
{params.MainnetChainConfig, 20000000, 1681338455, ID{Hash: checksumToBytes(0x12345678), Next: 0}, ErrLocalIncompatibleOrStale},
|
||||||
|
|
||||||
// Local is mainnet Prague, far in the future. Remote announces Gopherium (non existing fork)
|
// Local is mainnet BPO2, far in the future. Remote announces Gopherium (non existing fork)
|
||||||
// at some future timestamp 8888888888, for itself, but past block for local. Local is incompatible.
|
// at some future timestamp 8888888888, for itself, but past block for local. Local is incompatible.
|
||||||
//
|
//
|
||||||
// This case detects non-upgraded nodes with majority hash power (typical Ropsten mess).
|
// This case detects non-upgraded nodes with majority hash power (typical Ropsten mess).
|
||||||
{params.MainnetChainConfig, 88888888, 8888888888, ID{Hash: checksumToBytes(0xc376cf8b), Next: 8888888888}, ErrLocalIncompatibleOrStale},
|
{params.MainnetChainConfig, 88888888, 8888888888, ID{Hash: checksumToBytes(0x07c9462e), Next: 8888888888}, ErrLocalIncompatibleOrStale},
|
||||||
|
|
||||||
// Local is mainnet Shanghai. Remote is also in Shanghai, but announces Gopherium (non existing
|
// Local is mainnet Shanghai. Remote is also in Shanghai, but announces Gopherium (non existing
|
||||||
// fork) at timestamp 1668000000, before Cancun. Local is incompatible.
|
// fork) at timestamp 1668000000, before Cancun. Local is incompatible.
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) {
|
||||||
|
|
||||||
// flushAlloc is very similar with hash, but the main difference is all the
|
// flushAlloc is very similar with hash, but the main difference is all the
|
||||||
// generated states will be persisted into the given database.
|
// generated states will be persisted into the given database.
|
||||||
func flushAlloc(ga *types.GenesisAlloc, triedb *triedb.Database) (common.Hash, error) {
|
func flushAlloc(ga *types.GenesisAlloc, triedb *triedb.Database, tracer *tracing.Hooks) (common.Hash, error) {
|
||||||
emptyRoot := types.EmptyRootHash
|
emptyRoot := types.EmptyRootHash
|
||||||
if triedb.IsVerkle() {
|
if triedb.IsVerkle() {
|
||||||
emptyRoot = types.EmptyVerkleHash
|
emptyRoot = types.EmptyVerkleHash
|
||||||
|
|
@ -185,12 +185,28 @@ func flushAlloc(ga *types.GenesisAlloc, triedb *triedb.Database) (common.Hash, e
|
||||||
statedb.SetState(addr, key, value)
|
statedb.SetState(addr, key, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
root, err := statedb.Commit(0, false, false)
|
|
||||||
if err != nil {
|
var root common.Hash
|
||||||
return common.Hash{}, err
|
if tracer != nil && tracer.OnStateUpdate != nil {
|
||||||
|
r, update, err := statedb.CommitWithUpdate(0, false, false)
|
||||||
|
if err != nil {
|
||||||
|
return common.Hash{}, err
|
||||||
|
}
|
||||||
|
trUpdate, err := update.ToTracingUpdate()
|
||||||
|
if err != nil {
|
||||||
|
return common.Hash{}, err
|
||||||
|
}
|
||||||
|
tracer.OnStateUpdate(trUpdate)
|
||||||
|
root = r
|
||||||
|
} else {
|
||||||
|
root, err = statedb.Commit(0, false, false)
|
||||||
|
if err != nil {
|
||||||
|
return common.Hash{}, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commit newly generated states into disk if it's not empty.
|
// Commit newly generated states into disk if it's not empty.
|
||||||
if root != types.EmptyRootHash {
|
if root != emptyRoot {
|
||||||
if err := triedb.Commit(root, true); err != nil {
|
if err := triedb.Commit(root, true); err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -296,10 +312,10 @@ func (o *ChainOverrides) apply(cfg *params.ChainConfig) error {
|
||||||
// specify a fork block below the local head block). In case of a conflict, the
|
// specify a fork block below the local head block). In case of a conflict, the
|
||||||
// error is a *params.ConfigCompatError and the new, unwritten config is returned.
|
// error is a *params.ConfigCompatError and the new, unwritten config is returned.
|
||||||
func SetupGenesisBlock(db ethdb.Database, triedb *triedb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
|
func SetupGenesisBlock(db ethdb.Database, triedb *triedb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
|
||||||
return SetupGenesisBlockWithOverride(db, triedb, genesis, nil)
|
return SetupGenesisBlockWithOverride(db, triedb, genesis, nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, genesis *Genesis, overrides *ChainOverrides) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
|
func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, genesis *Genesis, overrides *ChainOverrides, tracer *tracing.Hooks) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
|
||||||
// Copy the genesis, so we can operate on a copy.
|
// Copy the genesis, so we can operate on a copy.
|
||||||
genesis = genesis.copy()
|
genesis = genesis.copy()
|
||||||
// Sanitize the supplied genesis, ensuring it has the associated chain
|
// Sanitize the supplied genesis, ensuring it has the associated chain
|
||||||
|
|
@ -320,7 +336,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
|
||||||
return nil, common.Hash{}, nil, err
|
return nil, common.Hash{}, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
block, err := genesis.Commit(db, triedb)
|
block, err := genesis.Commit(db, triedb, tracer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, common.Hash{}, nil, err
|
return nil, common.Hash{}, nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -348,7 +364,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
|
||||||
if hash := genesis.ToBlock().Hash(); hash != ghash {
|
if hash := genesis.ToBlock().Hash(); hash != ghash {
|
||||||
return nil, common.Hash{}, nil, &GenesisMismatchError{ghash, hash}
|
return nil, common.Hash{}, nil, &GenesisMismatchError{ghash, hash}
|
||||||
}
|
}
|
||||||
block, err := genesis.Commit(db, triedb)
|
block, err := genesis.Commit(db, triedb, tracer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, common.Hash{}, nil, err
|
return nil, common.Hash{}, nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -537,7 +553,7 @@ func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block {
|
||||||
|
|
||||||
// Commit writes the block and state of a genesis specification to the database.
|
// Commit writes the block and state of a genesis specification to the database.
|
||||||
// The block is committed as the canonical head block.
|
// The block is committed as the canonical head block.
|
||||||
func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Block, error) {
|
func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database, tracer *tracing.Hooks) (*types.Block, error) {
|
||||||
if g.Number != 0 {
|
if g.Number != 0 {
|
||||||
return nil, errors.New("can't commit genesis block with number > 0")
|
return nil, errors.New("can't commit genesis block with number > 0")
|
||||||
}
|
}
|
||||||
|
|
@ -552,7 +568,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo
|
||||||
return nil, errors.New("can't start clique chain without signers")
|
return nil, errors.New("can't start clique chain without signers")
|
||||||
}
|
}
|
||||||
// flush the data to disk and compute the state root
|
// flush the data to disk and compute the state root
|
||||||
root, err := flushAlloc(&g.Alloc, triedb)
|
root, err := flushAlloc(&g.Alloc, triedb, tracer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -578,7 +594,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo
|
||||||
// MustCommit writes the genesis block and state to db, panicking on error.
|
// MustCommit writes the genesis block and state to db, panicking on error.
|
||||||
// The block is committed as the canonical head block.
|
// The block is committed as the canonical head block.
|
||||||
func (g *Genesis) MustCommit(db ethdb.Database, triedb *triedb.Database) *types.Block {
|
func (g *Genesis) MustCommit(db ethdb.Database, triedb *triedb.Database) *types.Block {
|
||||||
block, err := g.Commit(db, triedb)
|
block, err := g.Commit(db, triedb, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -669,23 +685,24 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis {
|
||||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||||
Difficulty: big.NewInt(0),
|
Difficulty: big.NewInt(0),
|
||||||
Alloc: map[common.Address]types.Account{
|
Alloc: map[common.Address]types.Account{
|
||||||
common.BytesToAddress([]byte{0x01}): {Balance: big.NewInt(1)}, // ECRecover
|
common.BytesToAddress([]byte{0x01}): {Balance: big.NewInt(1)}, // ECRecover
|
||||||
common.BytesToAddress([]byte{0x02}): {Balance: big.NewInt(1)}, // SHA256
|
common.BytesToAddress([]byte{0x02}): {Balance: big.NewInt(1)}, // SHA256
|
||||||
common.BytesToAddress([]byte{0x03}): {Balance: big.NewInt(1)}, // RIPEMD
|
common.BytesToAddress([]byte{0x03}): {Balance: big.NewInt(1)}, // RIPEMD
|
||||||
common.BytesToAddress([]byte{0x04}): {Balance: big.NewInt(1)}, // Identity
|
common.BytesToAddress([]byte{0x04}): {Balance: big.NewInt(1)}, // Identity
|
||||||
common.BytesToAddress([]byte{0x05}): {Balance: big.NewInt(1)}, // ModExp
|
common.BytesToAddress([]byte{0x05}): {Balance: big.NewInt(1)}, // ModExp
|
||||||
common.BytesToAddress([]byte{0x06}): {Balance: big.NewInt(1)}, // ECAdd
|
common.BytesToAddress([]byte{0x06}): {Balance: big.NewInt(1)}, // ECAdd
|
||||||
common.BytesToAddress([]byte{0x07}): {Balance: big.NewInt(1)}, // ECScalarMul
|
common.BytesToAddress([]byte{0x07}): {Balance: big.NewInt(1)}, // ECScalarMul
|
||||||
common.BytesToAddress([]byte{0x08}): {Balance: big.NewInt(1)}, // ECPairing
|
common.BytesToAddress([]byte{0x08}): {Balance: big.NewInt(1)}, // ECPairing
|
||||||
common.BytesToAddress([]byte{0x09}): {Balance: big.NewInt(1)}, // BLAKE2b
|
common.BytesToAddress([]byte{0x09}): {Balance: big.NewInt(1)}, // BLAKE2b
|
||||||
common.BytesToAddress([]byte{0x0a}): {Balance: big.NewInt(1)}, // KZGPointEval
|
common.BytesToAddress([]byte{0x0a}): {Balance: big.NewInt(1)}, // KZGPointEval
|
||||||
common.BytesToAddress([]byte{0x0b}): {Balance: big.NewInt(1)}, // BLSG1Add
|
common.BytesToAddress([]byte{0x0b}): {Balance: big.NewInt(1)}, // BLSG1Add
|
||||||
common.BytesToAddress([]byte{0x0c}): {Balance: big.NewInt(1)}, // BLSG1MultiExp
|
common.BytesToAddress([]byte{0x0c}): {Balance: big.NewInt(1)}, // BLSG1MultiExp
|
||||||
common.BytesToAddress([]byte{0x0d}): {Balance: big.NewInt(1)}, // BLSG2Add
|
common.BytesToAddress([]byte{0x0d}): {Balance: big.NewInt(1)}, // BLSG2Add
|
||||||
common.BytesToAddress([]byte{0x0e}): {Balance: big.NewInt(1)}, // BLSG2MultiExp
|
common.BytesToAddress([]byte{0x0e}): {Balance: big.NewInt(1)}, // BLSG2MultiExp
|
||||||
common.BytesToAddress([]byte{0x0f}): {Balance: big.NewInt(1)}, // BLSG1Pairing
|
common.BytesToAddress([]byte{0x0f}): {Balance: big.NewInt(1)}, // BLSG1Pairing
|
||||||
common.BytesToAddress([]byte{0x10}): {Balance: big.NewInt(1)}, // BLSG1MapG1
|
common.BytesToAddress([]byte{0x10}): {Balance: big.NewInt(1)}, // BLSG1MapG1
|
||||||
common.BytesToAddress([]byte{0x11}): {Balance: big.NewInt(1)}, // BLSG2MapG2
|
common.BytesToAddress([]byte{0x11}): {Balance: big.NewInt(1)}, // BLSG2MapG2
|
||||||
|
common.BytesToAddress([]byte{0x1, 00}): {Balance: big.NewInt(1)}, // P256Verify
|
||||||
// Pre-deploy system contracts
|
// Pre-deploy system contracts
|
||||||
params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0},
|
params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0},
|
||||||
params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode, Balance: common.Big0},
|
params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode, Balance: common.Big0},
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
|
||||||
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) {
|
||||||
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
||||||
customg.Commit(db, tdb)
|
customg.Commit(db, tdb, nil)
|
||||||
return SetupGenesisBlock(db, tdb, nil)
|
return SetupGenesisBlock(db, tdb, nil)
|
||||||
},
|
},
|
||||||
wantHash: customghash,
|
wantHash: customghash,
|
||||||
|
|
@ -98,7 +98,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
|
||||||
name: "custom block in DB, genesis == sepolia",
|
name: "custom block in DB, genesis == sepolia",
|
||||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
|
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
|
||||||
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
||||||
customg.Commit(db, tdb)
|
customg.Commit(db, tdb, nil)
|
||||||
return SetupGenesisBlock(db, tdb, DefaultSepoliaGenesisBlock())
|
return SetupGenesisBlock(db, tdb, DefaultSepoliaGenesisBlock())
|
||||||
},
|
},
|
||||||
wantErr: &GenesisMismatchError{Stored: customghash, New: params.SepoliaGenesisHash},
|
wantErr: &GenesisMismatchError{Stored: customghash, New: params.SepoliaGenesisHash},
|
||||||
|
|
@ -107,7 +107,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
|
||||||
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) {
|
||||||
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
||||||
customg.Commit(db, tdb)
|
customg.Commit(db, tdb, nil)
|
||||||
return SetupGenesisBlock(db, tdb, DefaultHoodiGenesisBlock())
|
return SetupGenesisBlock(db, tdb, DefaultHoodiGenesisBlock())
|
||||||
},
|
},
|
||||||
wantErr: &GenesisMismatchError{Stored: customghash, New: params.HoodiGenesisHash},
|
wantErr: &GenesisMismatchError{Stored: customghash, New: params.HoodiGenesisHash},
|
||||||
|
|
@ -116,7 +116,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
|
||||||
name: "compatible config in DB",
|
name: "compatible config in DB",
|
||||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
|
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
|
||||||
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
||||||
oldcustomg.Commit(db, tdb)
|
oldcustomg.Commit(db, tdb, nil)
|
||||||
return SetupGenesisBlock(db, tdb, &customg)
|
return SetupGenesisBlock(db, tdb, &customg)
|
||||||
},
|
},
|
||||||
wantHash: customghash,
|
wantHash: customghash,
|
||||||
|
|
@ -128,7 +128,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
|
||||||
// Commit the 'old' genesis block with Homestead transition at #2.
|
// Commit the 'old' genesis block with Homestead transition at #2.
|
||||||
// Advance to block #4, past the homestead transition block of customg.
|
// Advance to block #4, past the homestead transition block of customg.
|
||||||
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
||||||
oldcustomg.Commit(db, tdb)
|
oldcustomg.Commit(db, tdb, nil)
|
||||||
|
|
||||||
bc, _ := NewBlockChain(db, &oldcustomg, ethash.NewFullFaker(), DefaultConfig().WithStateScheme(scheme))
|
bc, _ := NewBlockChain(db, &oldcustomg, ethash.NewFullFaker(), DefaultConfig().WithStateScheme(scheme))
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
@ -308,7 +308,7 @@ func TestVerkleGenesisCommit(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := common.FromHex("018d20eebb130b5e2b796465fe36aafab650650729a92435aec071bf2386f080")
|
expected := common.FromHex("b94812c1674dcf4f2bc98f4503d15f4cc674265135bcf3be6e4417b60881042a")
|
||||||
got := genesis.ToBlock().Root().Bytes()
|
got := genesis.ToBlock().Root().Bytes()
|
||||||
if !bytes.Equal(got, expected) {
|
if !bytes.Equal(got, expected) {
|
||||||
t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got)
|
t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got)
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ func TestHeaderInsertion(t *testing.T) {
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
gspec = &Genesis{BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges}
|
gspec = &Genesis{BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges}
|
||||||
)
|
)
|
||||||
gspec.Commit(db, triedb.NewDatabase(db, nil))
|
gspec.Commit(db, triedb.NewDatabase(db, nil), nil)
|
||||||
hc, err := NewHeaderChain(db, gspec.Config, ethash.NewFaker(), func() bool { return false })
|
hc, err := NewHeaderChain(db, gspec.Config, ethash.NewFaker(), func() bool { return false })
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ func LoadTransitionState(db ethdb.KeyValueReader, root common.Hash, isVerkle boo
|
||||||
// Initialize the first transition state, with the "ended"
|
// Initialize the first transition state, with the "ended"
|
||||||
// field set to true if the database was created
|
// field set to true if the database was created
|
||||||
// as a verkle database.
|
// as a verkle database.
|
||||||
log.Debug("no transition state found, starting fresh", "is verkle", db)
|
log.Debug("no transition state found, starting fresh", "verkle", isVerkle)
|
||||||
|
|
||||||
// Start with a fresh state
|
// Start with a fresh state
|
||||||
ts = &TransitionState{Ended: isVerkle}
|
ts = &TransitionState{Ended: isVerkle}
|
||||||
|
|
|
||||||
|
|
@ -83,65 +83,6 @@ type NumberHash struct {
|
||||||
Hash common.Hash
|
Hash common.Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadAllHashesInRange retrieves all the hashes assigned to blocks at certain
|
|
||||||
// heights, both canonical and reorged forks included.
|
|
||||||
// This method considers both limits to be _inclusive_.
|
|
||||||
func ReadAllHashesInRange(db ethdb.Iteratee, first, last uint64) []*NumberHash {
|
|
||||||
var (
|
|
||||||
start = encodeBlockNumber(first)
|
|
||||||
keyLength = len(headerPrefix) + 8 + 32
|
|
||||||
hashes = make([]*NumberHash, 0, 1+last-first)
|
|
||||||
it = db.NewIterator(headerPrefix, start)
|
|
||||||
)
|
|
||||||
defer it.Release()
|
|
||||||
for it.Next() {
|
|
||||||
key := it.Key()
|
|
||||||
if len(key) != keyLength {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
num := binary.BigEndian.Uint64(key[len(headerPrefix) : len(headerPrefix)+8])
|
|
||||||
if num > last {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
hash := common.BytesToHash(key[len(key)-32:])
|
|
||||||
hashes = append(hashes, &NumberHash{num, hash})
|
|
||||||
}
|
|
||||||
return hashes
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadAllCanonicalHashes retrieves all canonical number and hash mappings at the
|
|
||||||
// certain chain range. If the accumulated entries reaches the given threshold,
|
|
||||||
// abort the iteration and return the semi-finish result.
|
|
||||||
func ReadAllCanonicalHashes(db ethdb.Iteratee, from uint64, to uint64, limit int) ([]uint64, []common.Hash) {
|
|
||||||
// Short circuit if the limit is 0.
|
|
||||||
if limit == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
numbers []uint64
|
|
||||||
hashes []common.Hash
|
|
||||||
)
|
|
||||||
// Construct the key prefix of start point.
|
|
||||||
start, end := headerHashKey(from), headerHashKey(to)
|
|
||||||
it := db.NewIterator(nil, start)
|
|
||||||
defer it.Release()
|
|
||||||
|
|
||||||
for it.Next() {
|
|
||||||
if bytes.Compare(it.Key(), end) >= 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if key := it.Key(); len(key) == len(headerPrefix)+8+1 && bytes.Equal(key[len(key)-1:], headerHashSuffix) {
|
|
||||||
numbers = append(numbers, binary.BigEndian.Uint64(key[len(headerPrefix):len(headerPrefix)+8]))
|
|
||||||
hashes = append(hashes, common.BytesToHash(it.Value()))
|
|
||||||
// If the accumulated entries reaches the limit threshold, return.
|
|
||||||
if len(numbers) >= limit {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return numbers, hashes
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadHeaderNumber returns the header number assigned to a hash.
|
// ReadHeaderNumber returns the header number assigned to a hash.
|
||||||
func ReadHeaderNumber(db ethdb.KeyValueReader, hash common.Hash) (uint64, bool) {
|
func ReadHeaderNumber(db ethdb.KeyValueReader, hash common.Hash) (uint64, bool) {
|
||||||
data, _ := db.Get(headerNumberKey(hash))
|
data, _ := db.Get(headerNumberKey(hash))
|
||||||
|
|
@ -886,40 +827,6 @@ func WriteBadBlock(db ethdb.KeyValueStore, block *types.Block) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteBadBlocks deletes all the bad blocks from the database
|
|
||||||
func DeleteBadBlocks(db ethdb.KeyValueWriter) {
|
|
||||||
if err := db.Delete(badBlockKey); err != nil {
|
|
||||||
log.Crit("Failed to delete bad blocks", "err", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FindCommonAncestor returns the last common ancestor of two block headers
|
|
||||||
func FindCommonAncestor(db ethdb.Reader, a, b *types.Header) *types.Header {
|
|
||||||
for bn := b.Number.Uint64(); a.Number.Uint64() > bn; {
|
|
||||||
a = ReadHeader(db, a.ParentHash, a.Number.Uint64()-1)
|
|
||||||
if a == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for an := a.Number.Uint64(); an < b.Number.Uint64(); {
|
|
||||||
b = ReadHeader(db, b.ParentHash, b.Number.Uint64()-1)
|
|
||||||
if b == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for a.Hash() != b.Hash() {
|
|
||||||
a = ReadHeader(db, a.ParentHash, a.Number.Uint64()-1)
|
|
||||||
if a == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
b = ReadHeader(db, b.ParentHash, b.Number.Uint64()-1)
|
|
||||||
if b == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadHeadHeader returns the current canonical head header.
|
// ReadHeadHeader returns the current canonical head header.
|
||||||
func ReadHeadHeader(db ethdb.Reader) *types.Header {
|
func ReadHeadHeader(db ethdb.Reader) *types.Header {
|
||||||
headHeaderHash := ReadHeadHeaderHash(db)
|
headHeaderHash := ReadHeadHeaderHash(db)
|
||||||
|
|
|
||||||
|
|
@ -23,15 +23,14 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"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/crypto/keccak"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"golang.org/x/crypto/sha3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Tests block header storage and retrieval operations.
|
// Tests block header storage and retrieval operations.
|
||||||
|
|
@ -53,10 +52,7 @@ func TestHeaderStorage(t *testing.T) {
|
||||||
if entry := ReadHeaderRLP(db, header.Hash(), header.Number.Uint64()); entry == nil {
|
if entry := ReadHeaderRLP(db, header.Hash(), header.Number.Uint64()); entry == nil {
|
||||||
t.Fatalf("Stored header RLP not found")
|
t.Fatalf("Stored header RLP not found")
|
||||||
} else {
|
} else {
|
||||||
hasher := sha3.NewLegacyKeccak256()
|
if hash := crypto.Keccak256Hash(entry); hash != header.Hash() {
|
||||||
hasher.Write(entry)
|
|
||||||
|
|
||||||
if hash := common.BytesToHash(hasher.Sum(nil)); hash != header.Hash() {
|
|
||||||
t.Fatalf("Retrieved RLP header mismatch: have %v, want %v", entry, header)
|
t.Fatalf("Retrieved RLP header mismatch: have %v, want %v", entry, header)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -73,8 +69,7 @@ func TestBodyStorage(t *testing.T) {
|
||||||
|
|
||||||
// Create a test body to move around the database and make sure it's really new
|
// Create a test body to move around the database and make sure it's really new
|
||||||
body := &types.Body{Uncles: []*types.Header{{Extra: []byte("test header")}}}
|
body := &types.Body{Uncles: []*types.Header{{Extra: []byte("test header")}}}
|
||||||
|
hasher := keccak.NewLegacyKeccak256()
|
||||||
hasher := sha3.NewLegacyKeccak256()
|
|
||||||
rlp.Encode(hasher, body)
|
rlp.Encode(hasher, body)
|
||||||
hash := common.BytesToHash(hasher.Sum(nil))
|
hash := common.BytesToHash(hasher.Sum(nil))
|
||||||
|
|
||||||
|
|
@ -91,10 +86,7 @@ func TestBodyStorage(t *testing.T) {
|
||||||
if entry := ReadBodyRLP(db, hash, 0); entry == nil {
|
if entry := ReadBodyRLP(db, hash, 0); entry == nil {
|
||||||
t.Fatalf("Stored body RLP not found")
|
t.Fatalf("Stored body RLP not found")
|
||||||
} else {
|
} else {
|
||||||
hasher := sha3.NewLegacyKeccak256()
|
if calc := crypto.Keccak256Hash(entry); calc != hash {
|
||||||
hasher.Write(entry)
|
|
||||||
|
|
||||||
if calc := common.BytesToHash(hasher.Sum(nil)); calc != hash {
|
|
||||||
t.Fatalf("Retrieved RLP body mismatch: have %v, want %v", entry, body)
|
t.Fatalf("Retrieved RLP body mismatch: have %v, want %v", entry, body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -249,13 +241,6 @@ func TestBadBlockStorage(t *testing.T) {
|
||||||
t.Fatalf("The bad blocks are not sorted #[%d](%d) < #[%d](%d)", i, badBlocks[i].NumberU64(), i+1, badBlocks[i+1].NumberU64())
|
t.Fatalf("The bad blocks are not sorted #[%d](%d) < #[%d](%d)", i, badBlocks[i].NumberU64(), i+1, badBlocks[i+1].NumberU64())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete all bad blocks
|
|
||||||
DeleteBadBlocks(db)
|
|
||||||
badBlocks = ReadAllBadBlocks(db)
|
|
||||||
if len(badBlocks) != 0 {
|
|
||||||
t.Fatalf("Failed to delete bad blocks")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that canonical numbers can be mapped to hashes and retrieved.
|
// Tests that canonical numbers can be mapped to hashes and retrieved.
|
||||||
|
|
@ -516,37 +501,6 @@ func TestWriteAncientHeaderChain(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCanonicalHashIteration(t *testing.T) {
|
|
||||||
var cases = []struct {
|
|
||||||
from, to uint64
|
|
||||||
limit int
|
|
||||||
expect []uint64
|
|
||||||
}{
|
|
||||||
{1, 8, 0, nil},
|
|
||||||
{1, 8, 1, []uint64{1}},
|
|
||||||
{1, 8, 10, []uint64{1, 2, 3, 4, 5, 6, 7}},
|
|
||||||
{1, 9, 10, []uint64{1, 2, 3, 4, 5, 6, 7, 8}},
|
|
||||||
{2, 9, 10, []uint64{2, 3, 4, 5, 6, 7, 8}},
|
|
||||||
{9, 10, 10, nil},
|
|
||||||
}
|
|
||||||
// Test empty db iteration
|
|
||||||
db := NewMemoryDatabase()
|
|
||||||
numbers, _ := ReadAllCanonicalHashes(db, 0, 10, 10)
|
|
||||||
if len(numbers) != 0 {
|
|
||||||
t.Fatalf("No entry should be returned to iterate an empty db")
|
|
||||||
}
|
|
||||||
// Fill database with testing data.
|
|
||||||
for i := uint64(1); i <= 8; i++ {
|
|
||||||
WriteCanonicalHash(db, common.Hash{}, i)
|
|
||||||
}
|
|
||||||
for i, c := range cases {
|
|
||||||
numbers, _ := ReadAllCanonicalHashes(db, c.from, c.to, c.limit)
|
|
||||||
if !reflect.DeepEqual(numbers, c.expect) {
|
|
||||||
t.Fatalf("Case %d failed, want %v, got %v", i, c.expect, numbers)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHashesInRange(t *testing.T) {
|
func TestHashesInRange(t *testing.T) {
|
||||||
mkHeader := func(number, seq int) *types.Header {
|
mkHeader := func(number, seq int) *types.Header {
|
||||||
h := types.Header{
|
h := types.Header{
|
||||||
|
|
@ -565,18 +519,6 @@ func TestHashesInRange(t *testing.T) {
|
||||||
total++
|
total++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if have, want := len(ReadAllHashesInRange(db, 10, 10)), 10; have != want {
|
|
||||||
t.Fatalf("Wrong number of hashes read, want %d, got %d", want, have)
|
|
||||||
}
|
|
||||||
if have, want := len(ReadAllHashesInRange(db, 10, 9)), 0; have != want {
|
|
||||||
t.Fatalf("Wrong number of hashes read, want %d, got %d", want, have)
|
|
||||||
}
|
|
||||||
if have, want := len(ReadAllHashesInRange(db, 0, 100)), total; have != want {
|
|
||||||
t.Fatalf("Wrong number of hashes read, want %d, got %d", want, have)
|
|
||||||
}
|
|
||||||
if have, want := len(ReadAllHashesInRange(db, 9, 10)), 9+10; have != want {
|
|
||||||
t.Fatalf("Wrong number of hashes read, want %d, got %d", want, have)
|
|
||||||
}
|
|
||||||
if have, want := len(ReadAllHashes(db, 10)), 10; have != want {
|
if have, want := len(ReadAllHashes(db, 10)), 10; have != want {
|
||||||
t.Fatalf("Wrong number of hashes read, want %d, got %d", want, have)
|
t.Fatalf("Wrong number of hashes read, want %d, got %d", want, have)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue