mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-02-26 15:47:21 +00:00
Compare commits
253 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be92f5487e | ||
|
|
8a4345611d | ||
|
|
f811bfe4fd | ||
|
|
406a852ec8 | ||
|
|
2a45272408 | ||
|
|
8450e40798 | ||
|
|
9ecb6c4ae6 | ||
|
|
e636e4e3c1 | ||
|
|
cbf3d8fed2 | ||
|
|
199ac16e07 | ||
|
|
01083736c8 | ||
|
|
59ad40e562 | ||
|
|
c2e1785a48 | ||
|
|
82fad31540 | ||
|
|
1625064c68 | ||
|
|
1d1a094d51 | ||
|
|
e40aa46e88 | ||
|
|
d3dd48e59d | ||
|
|
00cbd2e6f4 | ||
|
|
453d0f9299 | ||
|
|
6d865ccd30 | ||
|
|
54f72c796f | ||
|
|
2a62df3815 | ||
|
|
01fe1d716c | ||
|
|
3eed0580d4 | ||
|
|
1054276906 | ||
|
|
0cf3d3ba4f | ||
|
|
9b78f45e33 | ||
|
|
c709c19b40 | ||
|
|
550ca91b17 | ||
|
|
a4b3898f90 | ||
|
|
0cba803fba | ||
|
|
ad88b68a46 | ||
|
|
c50e5edfaf | ||
|
|
d8b92cb9e6 | ||
|
|
ac85a6f254 | ||
|
|
4f38a76438 | ||
|
|
ece2b19ac0 | ||
|
|
f2869793df | ||
|
|
9426444825 | ||
|
|
995fa79bf5 | ||
|
|
919b238c82 | ||
|
|
3011d83e6f | ||
|
|
341907cdb8 | ||
|
|
30656d714e | ||
|
|
15a9e92bbd | ||
|
|
4d4883731e | ||
|
|
e2d21d0e9c | ||
|
|
986d115da7 | ||
|
|
bbb1ab8d16 | ||
|
|
7faa676b03 | ||
|
|
32a35bfcd3 | ||
|
|
c9b7ae422c | ||
|
|
c12959dc8c | ||
|
|
bc0db302ed | ||
|
|
777265620d | ||
|
|
ad459f4fac | ||
|
|
e64c8d8e26 | ||
|
|
9967fb7c5c | ||
|
|
aa457eda4b | ||
|
|
14c2408957 | ||
|
|
7b7be249cb | ||
|
|
6b82cef68f | ||
|
|
bba41f8072 | ||
|
|
8e1de223ad | ||
|
|
54a91b3ad8 | ||
|
|
b9288765a3 | ||
|
|
19f37003fb | ||
|
|
16a6531ac2 | ||
|
|
6530945dcd | ||
|
|
a951aacb70 | ||
|
|
a5e6a157e5 | ||
|
|
cb97c48cb6 | ||
|
|
845009f684 | ||
|
|
a179ccf6f0 | ||
|
|
c974722dc0 | ||
|
|
9a6905318a | ||
|
|
628ff79be3 | ||
|
|
7046e63244 | ||
|
|
2513feddf8 | ||
|
|
424bc22ab8 | ||
|
|
1e9dfd5bb0 | ||
|
|
0a8fd6841c | ||
|
|
3d05284928 | ||
|
|
344d01e2be | ||
|
|
56be36f672 | ||
|
|
181a3ae9e0 | ||
|
|
e250836973 | ||
|
|
c2595381bf | ||
|
|
9a8e14e77e | ||
|
|
251b863107 | ||
|
|
1022c7637d | ||
|
|
35922bcd33 | ||
|
|
8fad02ac63 | ||
|
|
54ab4e3c7d | ||
|
|
2eb1ccc6c4 | ||
|
|
46d804776b | ||
|
|
d58f6291a2 | ||
|
|
d0af257aa2 | ||
|
|
500931bc82 | ||
|
|
ef815c59a2 | ||
|
|
e78be59dc9 | ||
|
|
0495350388 | ||
|
|
3d78da9171 | ||
|
|
add1890a57 | ||
|
|
588dd94aad | ||
|
|
715bf8e81e | ||
|
|
b6fb79cdf9 | ||
|
|
23c3498836 | ||
|
|
9ba13b6097 | ||
|
|
494908a852 | ||
|
|
e3e556b266 | ||
|
|
a9acb3ff93 | ||
|
|
94710f79a2 | ||
|
|
3b17e78274 | ||
|
|
5b99d2bba4 | ||
|
|
ea4935430b | ||
|
|
5a1990d1d8 | ||
|
|
1278b4891d | ||
|
|
31d5d82ce5 | ||
|
|
c890637af9 | ||
|
|
127d1f42bb | ||
|
|
7cd400612f | ||
|
|
4eb5b66d9e | ||
|
|
b993cb6f38 | ||
|
|
f51870e40e | ||
|
|
52f998d5ec | ||
|
|
d5efd34010 | ||
|
|
a32851fac9 | ||
|
|
64d22fd7f7 | ||
|
|
9623dcbca2 | ||
|
|
01b39c96bf | ||
|
|
957a3602d9 | ||
|
|
710008450f | ||
|
|
eaaa5b716d | ||
|
|
a8a4804895 | ||
|
|
de5ea2ffd8 | ||
|
|
b635e0632c | ||
|
|
32fea008d8 | ||
|
|
b2843a11d6 | ||
|
|
25439aac04 | ||
|
|
52ae75afcd | ||
|
|
d9aaab13d3 | ||
|
|
b3e7d9ee44 | ||
|
|
b84097d22e | ||
|
|
3f641dba87 | ||
|
|
57f84866bc | ||
|
|
b9702ed27b | ||
|
|
4531bfebec | ||
|
|
27b3a6087e | ||
|
|
2e5cd21edf | ||
|
|
bf141fbfb1 | ||
|
|
dd7daace9d | ||
|
|
5dfcffcf3c | ||
|
|
bd77b77ede | ||
|
|
ffe9dc97e5 | ||
|
|
7aae33eacf | ||
|
|
6978ab48aa | ||
|
|
15f52a2937 | ||
|
|
e20b05ec7f | ||
|
|
a9eaf2ffd8 | ||
|
|
3a5560fa98 | ||
|
|
16f50285b7 | ||
|
|
472e3a24ac | ||
|
|
56d201b0fe | ||
|
|
1b702f71d9 | ||
|
|
b98b255449 | ||
|
|
13a8798fa3 | ||
|
|
1ce71a1895 | ||
|
|
215ee6ac18 | ||
|
|
c21fe5475f | ||
|
|
9a346873b8 | ||
|
|
e58c785424 | ||
|
|
228933a660 | ||
|
|
66134b35df | ||
|
|
31f9c9ff75 | ||
|
|
af47d9b472 | ||
|
|
dbca85869f | ||
|
|
e63e37be5e | ||
|
|
73a2df2b0a | ||
|
|
657c99f116 | ||
|
|
129c562900 | ||
|
|
d3679c2f2e | ||
|
|
212967d0e1 | ||
|
|
be94ea1c40 | ||
|
|
042c47ce1a | ||
|
|
da3822dcec | ||
|
|
6f2cbb7a27 | ||
|
|
cd3f9b24e9 | ||
|
|
5d51208334 | ||
|
|
f12f0ec0cd | ||
|
|
fbbaa3c849 | ||
|
|
28376aea78 | ||
|
|
a122dbe459 | ||
|
|
fed8e09ab0 | ||
|
|
f691d661c4 | ||
|
|
f43228152b | ||
|
|
446fdebdc3 | ||
|
|
b3b46ce435 | ||
|
|
795a7ab58a | ||
|
|
aa1a8dacae | ||
|
|
8d1b1c20d0 | ||
|
|
6426257c0f | ||
|
|
9bab01bee4 | ||
|
|
6452b7ad05 | ||
|
|
7805e203f0 | ||
|
|
3bbf5f5b6a | ||
|
|
c55a12197e | ||
|
|
3e48e0779c | ||
|
|
689ea10f35 | ||
|
|
ed4d00fd83 | ||
|
|
1468331f9d | ||
|
|
3f7cd905b0 | ||
|
|
cf93077fab | ||
|
|
62334a9d46 | ||
|
|
960c87a944 | ||
|
|
ebf93555b1 | ||
|
|
b04df226fa | ||
|
|
2a4847a7d1 | ||
|
|
a6191d8272 | ||
|
|
5748dd18e7 | ||
|
|
b5c3b32eeb | ||
|
|
495a1d2b1a | ||
|
|
f8e5b53f88 | ||
|
|
f4817b7a53 | ||
|
|
e0d81d1e99 | ||
|
|
5e6f7374de | ||
|
|
2a2f106a01 | ||
|
|
81c5b43029 | ||
|
|
95273afec4 | ||
|
|
aa36bcd0aa | ||
|
|
488d987fc4 | ||
|
|
fa16c89bfd | ||
|
|
f23d506b7d | ||
|
|
eb8f32588b | ||
|
|
48d708a194 | ||
|
|
12a389f065 | ||
|
|
3d2a4cb053 | ||
|
|
d8f9801305 | ||
|
|
7368b34a4b | ||
|
|
5f4cc3f57d | ||
|
|
ca91254259 | ||
|
|
fbd89be047 | ||
|
|
7755ee3e4f | ||
|
|
ebc7dc9e37 | ||
|
|
d2a5dba48f | ||
|
|
982235f5e0 | ||
|
|
7f9b06e7aa | ||
|
|
6420ee3592 | ||
|
|
15ff378a89 | ||
|
|
395425902d | ||
|
|
19aa8020a9 | ||
|
|
d39af344dc |
454 changed files with 27323 additions and 9050 deletions
4
.github/workflows/go.yml
vendored
4
.github/workflows/go.yml
vendored
|
|
@ -69,8 +69,8 @@ jobs:
|
||||||
|
|
||||||
- name: Install cross toolchain
|
- name: Install cross toolchain
|
||||||
run: |
|
run: |
|
||||||
apt-get update
|
sudo apt-get update
|
||||||
apt-get -yq --no-install-suggests --no-install-recommends install gcc-multilib
|
sudo apt-get -yq --no-install-suggests --no-install-recommends install gcc-multilib
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: go run build/ci.go test -arch 386 -short -p 8
|
run: go run build/ci.go test -arch 386 -short -p 8
|
||||||
|
|
|
||||||
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');
|
||||||
|
|
|
||||||
98
AGENTS.md
Normal file
98
AGENTS.md
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
# AGENTS
|
||||||
|
|
||||||
|
## Guidelines
|
||||||
|
|
||||||
|
- **Keep changes minimal and focused.** Only modify code directly related to the task at hand. Do not refactor unrelated code, rename existing variables or functions for style, or bundle unrelated fixes into the same commit or PR.
|
||||||
|
- **Do not add, remove, or update dependencies** unless the task explicitly requires it.
|
||||||
|
|
||||||
|
## Pre-Commit Checklist
|
||||||
|
|
||||||
|
Before every commit, run **all** of the following checks and ensure they pass:
|
||||||
|
|
||||||
|
### 1. Formatting
|
||||||
|
|
||||||
|
Before committing, always run `gofmt` and `goimports` on all modified files:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
gofmt -w <modified files>
|
||||||
|
goimports -w <modified files>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Build All Commands
|
||||||
|
|
||||||
|
Verify that all tools compile successfully:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make all
|
||||||
|
```
|
||||||
|
|
||||||
|
This builds all executables under `cmd/`, including `keeper` which has special build requirements.
|
||||||
|
|
||||||
|
### 3. Tests
|
||||||
|
|
||||||
|
While iterating during development, use `-short` for faster feedback:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go run ./build/ci.go test -short
|
||||||
|
```
|
||||||
|
|
||||||
|
Before committing, run the full test suite **without** `-short` to ensure all tests pass, including the Ethereum execution-spec tests and all state/block test permutations:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go run ./build/ci.go test
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Linting
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go run ./build/ci.go lint
|
||||||
|
```
|
||||||
|
|
||||||
|
This runs additional style checks. Fix any issues before committing.
|
||||||
|
|
||||||
|
### 5. Generated Code
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go run ./build/ci.go check_generate
|
||||||
|
```
|
||||||
|
|
||||||
|
Ensures that all generated files (e.g., `gen_*.go`) are up to date. If this fails, first install the required code generators by running `make devtools`, then run the appropriate `go generate` commands and include the updated files in your commit.
|
||||||
|
|
||||||
|
### 6. Dependency Hygiene
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go run ./build/ci.go check_baddeps
|
||||||
|
```
|
||||||
|
|
||||||
|
Verifies that no forbidden dependencies have been introduced.
|
||||||
|
|
||||||
|
## Commit Message Format
|
||||||
|
|
||||||
|
Commit messages must be prefixed with the package(s) they modify, followed by a short lowercase description:
|
||||||
|
|
||||||
|
```
|
||||||
|
<package(s)>: description
|
||||||
|
```
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- `core/vm: fix stack overflow in PUSH instruction`
|
||||||
|
- `eth, rpc: make trace configs optional`
|
||||||
|
- `cmd/geth: add new flag for sync mode`
|
||||||
|
|
||||||
|
Use comma-separated package names when multiple areas are affected. Keep the description concise.
|
||||||
|
|
||||||
|
## Pull Request Title Format
|
||||||
|
|
||||||
|
PR titles follow the same convention as commit messages:
|
||||||
|
|
||||||
|
```
|
||||||
|
<list of modified paths>: description
|
||||||
|
```
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- `core/vm: fix stack overflow in PUSH instruction`
|
||||||
|
- `core, eth: add arena allocator support`
|
||||||
|
- `cmd/geth, internal/ethapi: refactor transaction args`
|
||||||
|
- `trie/archiver: streaming subtree archival to fix OOM`
|
||||||
|
|
||||||
|
Use the top-level package paths, comma-separated if multiple areas are affected. Only mention the directories with functional changes, interface changes that trickle all over the codebase should not generate an exhaustive list. The description should be a short, lowercase summary of the change.
|
||||||
|
|
@ -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{}{}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,10 @@ func (ec *engineClient) updateLoop(headCh <-chan types.ChainHeadEvent) {
|
||||||
if status, err := ec.callForkchoiceUpdated(forkName, event); err == nil {
|
if status, err := ec.callForkchoiceUpdated(forkName, event); err == nil {
|
||||||
log.Info("Successful ForkchoiceUpdated", "head", event.Block.Hash(), "status", status)
|
log.Info("Successful ForkchoiceUpdated", "head", event.Block.Hash(), "status", status)
|
||||||
} else {
|
} else {
|
||||||
|
if err.Error() == "beacon syncer reorging" {
|
||||||
|
log.Debug("Failed ForkchoiceUpdated", "head", event.Block.Hash(), "error", err)
|
||||||
|
continue // ignore beacon syncer reorging errors, this error can occur if the blsync is skipping a block
|
||||||
|
}
|
||||||
log.Error("Failed ForkchoiceUpdated", "head", event.Block.Hash(), "error", err)
|
log.Error("Failed ForkchoiceUpdated", "head", event.Block.Hash(), "error", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -101,7 +105,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 +123,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 +149,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)
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ func (p PayloadAttributes) MarshalJSON() ([]byte, error) {
|
||||||
SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
|
SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||||
|
SlotNumber *hexutil.Uint64 `json:"slotNumber"`
|
||||||
}
|
}
|
||||||
var enc PayloadAttributes
|
var enc PayloadAttributes
|
||||||
enc.Timestamp = hexutil.Uint64(p.Timestamp)
|
enc.Timestamp = hexutil.Uint64(p.Timestamp)
|
||||||
|
|
@ -28,6 +29,7 @@ func (p PayloadAttributes) MarshalJSON() ([]byte, error) {
|
||||||
enc.SuggestedFeeRecipient = p.SuggestedFeeRecipient
|
enc.SuggestedFeeRecipient = p.SuggestedFeeRecipient
|
||||||
enc.Withdrawals = p.Withdrawals
|
enc.Withdrawals = p.Withdrawals
|
||||||
enc.BeaconRoot = p.BeaconRoot
|
enc.BeaconRoot = p.BeaconRoot
|
||||||
|
enc.SlotNumber = (*hexutil.Uint64)(p.SlotNumber)
|
||||||
return json.Marshal(&enc)
|
return json.Marshal(&enc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -39,6 +41,7 @@ func (p *PayloadAttributes) UnmarshalJSON(input []byte) error {
|
||||||
SuggestedFeeRecipient *common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
|
SuggestedFeeRecipient *common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||||
|
SlotNumber *hexutil.Uint64 `json:"slotNumber"`
|
||||||
}
|
}
|
||||||
var dec PayloadAttributes
|
var dec PayloadAttributes
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
|
@ -62,5 +65,8 @@ func (p *PayloadAttributes) UnmarshalJSON(input []byte) error {
|
||||||
if dec.BeaconRoot != nil {
|
if dec.BeaconRoot != nil {
|
||||||
p.BeaconRoot = dec.BeaconRoot
|
p.BeaconRoot = dec.BeaconRoot
|
||||||
}
|
}
|
||||||
|
if dec.SlotNumber != nil {
|
||||||
|
p.SlotNumber = (*uint64)(dec.SlotNumber)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,24 +17,24 @@ 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"`
|
SlotNumber *hexutil.Uint64 `json:"slotNumber"`
|
||||||
}
|
}
|
||||||
var enc ExecutableData
|
var enc ExecutableData
|
||||||
enc.ParentHash = e.ParentHash
|
enc.ParentHash = e.ParentHash
|
||||||
|
|
@ -59,31 +59,31 @@ 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
|
enc.SlotNumber = (*hexutil.Uint64)(e.SlotNumber)
|
||||||
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"`
|
SlotNumber *hexutil.Uint64 `json:"slotNumber"`
|
||||||
}
|
}
|
||||||
var dec ExecutableData
|
var dec ExecutableData
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
|
@ -157,8 +157,8 @@ 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 {
|
if dec.SlotNumber != nil {
|
||||||
e.ExecutionWitness = dec.ExecutionWitness
|
e.SlotNumber = (*uint64)(dec.SlotNumber)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,13 @@ var (
|
||||||
// ExecutionPayloadV3 has the syntax of ExecutionPayloadV2 and appends the new
|
// ExecutionPayloadV3 has the syntax of ExecutionPayloadV2 and appends the new
|
||||||
// fields: blobGasUsed and excessBlobGas.
|
// fields: blobGasUsed and excessBlobGas.
|
||||||
PayloadV3 PayloadVersion = 0x3
|
PayloadV3 PayloadVersion = 0x3
|
||||||
|
|
||||||
|
// PayloadV4 is the identifier of ExecutionPayloadV4 introduced in amsterdam fork.
|
||||||
|
//
|
||||||
|
// https://github.com/ethereum/execution-apis/blob/main/src/engine/amsterdam.md#executionpayloadv4
|
||||||
|
// ExecutionPayloadV4 has the syntax of ExecutionPayloadV3 and appends the new
|
||||||
|
// field slotNumber.
|
||||||
|
PayloadV4 PayloadVersion = 0x4
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate go run github.com/fjl/gencodec -type PayloadAttributes -field-override payloadAttributesMarshaling -out gen_blockparams.go
|
//go:generate go run github.com/fjl/gencodec -type PayloadAttributes -field-override payloadAttributesMarshaling -out gen_blockparams.go
|
||||||
|
|
@ -62,35 +69,37 @@ type PayloadAttributes struct {
|
||||||
SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
|
SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||||
|
SlotNumber *uint64 `json:"slotNumber"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSON type overrides for PayloadAttributes.
|
// JSON type overrides for PayloadAttributes.
|
||||||
type payloadAttributesMarshaling struct {
|
type payloadAttributesMarshaling struct {
|
||||||
Timestamp hexutil.Uint64
|
Timestamp hexutil.Uint64
|
||||||
|
SlotNumber *hexutil.Uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:generate go run github.com/fjl/gencodec -type ExecutableData -field-override executableDataMarshaling -out gen_ed.go
|
//go:generate go run github.com/fjl/gencodec -type ExecutableData -field-override executableDataMarshaling -out gen_ed.go
|
||||||
|
|
||||||
// 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"`
|
SlotNumber *uint64 `json:"slotNumber"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSON type overrides for executableData.
|
// JSON type overrides for executableData.
|
||||||
|
|
@ -105,6 +114,7 @@ type executableDataMarshaling struct {
|
||||||
Transactions []hexutil.Bytes
|
Transactions []hexutil.Bytes
|
||||||
BlobGasUsed *hexutil.Uint64
|
BlobGasUsed *hexutil.Uint64
|
||||||
ExcessBlobGas *hexutil.Uint64
|
ExcessBlobGas *hexutil.Uint64
|
||||||
|
SlotNumber *hexutil.Uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// StatelessPayloadStatusV1 is the result of a stateless payload execution.
|
// StatelessPayloadStatusV1 is the result of a stateless payload execution.
|
||||||
|
|
@ -214,7 +224,7 @@ func encodeTransactions(txs []*types.Transaction) [][]byte {
|
||||||
return enc
|
return enc
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
|
func DecodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
|
||||||
var txs = make([]*types.Transaction, len(enc))
|
var txs = make([]*types.Transaction, len(enc))
|
||||||
for i, encTx := range enc {
|
for i, encTx := range enc {
|
||||||
var tx types.Transaction
|
var tx types.Transaction
|
||||||
|
|
@ -252,7 +262,7 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b
|
||||||
// for stateless execution, so it skips checking if the executable data hashes to
|
// for stateless execution, so it skips checking if the executable data hashes to
|
||||||
// the requested hash (stateless has to *compute* the root hash, it's not given).
|
// the requested hash (stateless has to *compute* the root hash, it's not given).
|
||||||
func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte) (*types.Block, error) {
|
func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte) (*types.Block, error) {
|
||||||
txs, err := decodeTransactions(data.Transactions)
|
txs, err := DecodeTransactions(data.Transactions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -314,10 +324,10 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H
|
||||||
BlobGasUsed: data.BlobGasUsed,
|
BlobGasUsed: data.BlobGasUsed,
|
||||||
ParentBeaconRoot: beaconRoot,
|
ParentBeaconRoot: beaconRoot,
|
||||||
RequestsHash: requestsHash,
|
RequestsHash: requestsHash,
|
||||||
|
SlotNumber: data.SlotNumber,
|
||||||
}
|
}
|
||||||
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 +335,24 @@ 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(),
|
SlotNumber: block.SlotNumber(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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,6 +103,9 @@ 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) {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -5,81 +5,102 @@
|
||||||
# https://github.com/ethereum/execution-spec-tests/releases/download/v5.1.0
|
# https://github.com/ethereum/execution-spec-tests/releases/download/v5.1.0
|
||||||
a3192784375acec7eaec492799d5c5d0c47a2909a3cc40178898e4ecd20cc416 fixtures_develop.tar.gz
|
a3192784375acec7eaec492799d5c5d0c47a2909a3cc40178898e4ecd20cc416 fixtures_develop.tar.gz
|
||||||
|
|
||||||
# version:golang 1.25.1
|
# version:golang 1.25.7
|
||||||
# https://go.dev/dl/
|
# https://go.dev/dl/
|
||||||
d010c109cee94d80efe681eab46bdea491ac906bf46583c32e9f0dbb0bd1a594 go1.25.1.src.tar.gz
|
178f2832820274b43e177d32f06a3ebb0129e427dd20a5e4c88df2c1763cf10a go1.25.7.src.tar.gz
|
||||||
1d622468f767a1b9fe1e1e67bd6ce6744d04e0c68712adc689748bbeccb126bb go1.25.1.darwin-amd64.tar.gz
|
81bf2a1f20633f62d55d826d82dde3b0570cf1408a91e15781b266037299285b go1.25.7.aix-ppc64.tar.gz
|
||||||
68deebb214f39d542e518ebb0598a406ab1b5a22bba8ec9ade9f55fb4dd94a6c go1.25.1.darwin-arm64.tar.gz
|
bf5050a2152f4053837b886e8d9640c829dbacbc3370f913351eb0904cb706f5 go1.25.7.darwin-amd64.tar.gz
|
||||||
d03cdcbc9bd8baf5cf028de390478e9e2b3e4d0afe5a6582dedc19bfe6a263b2 go1.25.1.linux-386.tar.gz
|
ff18369ffad05c57d5bed888b660b31385f3c913670a83ef557cdfd98ea9ae1b go1.25.7.darwin-arm64.tar.gz
|
||||||
7716a0d940a0f6ae8e1f3b3f4f36299dc53e31b16840dbd171254312c41ca12e go1.25.1.linux-amd64.tar.gz
|
c5dccd7f192dd7b305dc209fb316ac1917776d74bd8e4d532ef2772f305bf42a go1.25.7.dragonfly-amd64.tar.gz
|
||||||
65a3e34fb2126f55b34e1edfc709121660e1be2dee6bdf405fc399a63a95a87d go1.25.1.linux-arm64.tar.gz
|
a2de97c8ac74bf64b0ae73fe9d379e61af530e061bc7f8f825044172ffe61a8b go1.25.7.freebsd-386.tar.gz
|
||||||
eb949be683e82a99e9861dafd7057e31ea40b161eae6c4cd18fdc0e8c4ae6225 go1.25.1.linux-armv6l.tar.gz
|
055f9e138787dcafa81eb0314c8ff70c6dd0f6dba1e8a6957fef5d5efd1ab8fd go1.25.7.freebsd-amd64.tar.gz
|
||||||
be13d5479b8c75438f2efcaa8c191fba3af684b3228abc9c99c7aa8502f34424 go1.25.1.windows-386.zip
|
60e7f7a7c990f0b9539ac8ed668155746997d404643a4eecd47b3dee1b7e710b go1.25.7.freebsd-arm.tar.gz
|
||||||
4a974de310e7ee1d523d2fcedb114ba5fa75408c98eb3652023e55ccf3fa7cab go1.25.1.windows-amd64.zip
|
631e03d5fd4c526e2f499154d8c6bf4cb081afb2fff171c428722afc9539d53a go1.25.7.freebsd-arm64.tar.gz
|
||||||
45ab4290adbd6ee9e7f18f0d57eaa9008fdbef590882778ed93eac3c8cca06c5 go1.25.1.aix-ppc64.tar.gz
|
8a264fd685823808140672812e3ad9c43f6ad59444c0dc14cdd3a1351839ddd5 go1.25.7.freebsd-riscv64.tar.gz
|
||||||
2e3c1549bed3124763774d648f291ac42611232f48320ebbd23517c909c09b81 go1.25.1.dragonfly-amd64.tar.gz
|
57c672447d906a1bcab98f2b11492d54521a791aacbb4994a25169e59cbe289a go1.25.7.illumos-amd64.tar.gz
|
||||||
dc0198dd4ec520e13f26798def8750544edf6448d8e9c43fd2a814e4885932af go1.25.1.freebsd-386.tar.gz
|
2866517e9ca81e6a2e85a930e9b11bc8a05cfeb2fc6dc6cb2765e7fb3c14b715 go1.25.7.linux-386.tar.gz
|
||||||
c4f1a7e7b258406e6f3b677ecdbd97bbb23ff9c0d44be4eb238a07d360f69ac8 go1.25.1.freebsd-amd64.tar.gz
|
12e6d6a191091ae27dc31f6efc630e3a3b8ba409baf3573d955b196fdf086005 go1.25.7.linux-amd64.tar.gz
|
||||||
7772fc5ff71ed39297ec0c1599fc54e399642c9b848eac989601040923b0de9c go1.25.1.freebsd-arm.tar.gz
|
ba611a53534135a81067240eff9508cd7e256c560edd5d8c2fef54f083c07129 go1.25.7.linux-arm64.tar.gz
|
||||||
5bb011d5d5b6218b12189f07aa0be618ab2002662fff1ca40afba7389735c207 go1.25.1.freebsd-arm64.tar.gz
|
1ba07e0eb86b839e72467f4b5c7a5597d07f30bcf5563c951410454f7cda5266 go1.25.7.linux-armv6l.tar.gz
|
||||||
ccac716240cb049bebfafcb7eebc3758512178a4c51fc26da9cc032035d850c8 go1.25.1.freebsd-riscv64.tar.gz
|
775753fc5952a334c415f08768df2f0b73a3228a16e8f5f63d545daacb4e3357 go1.25.7.linux-loong64.tar.gz
|
||||||
cc53910ffb9fcfdd988a9fa25b5423bae1cfa01b19616be646700e1f5453b466 go1.25.1.illumos-amd64.tar.gz
|
1a023bb367c5fbb4c637a2f6dc23ff17c6591ad929ce16ea88c74d857153b307 go1.25.7.linux-mips.tar.gz
|
||||||
efe809f923bcedab44bf7be2b3af8d182b512b1bf9c07d302e0c45d26c8f56f3 go1.25.1.linux-loong64.tar.gz
|
a8e97223d8aa6fdfd45f132a4784d2f536bbac5f3d63a24b63d33b6bfe1549af go1.25.7.linux-mips64.tar.gz
|
||||||
c0de33679f6ed68991dc42dc4a602e74a666e3e166c1748ee1b5d1a7ea2ffbb2 go1.25.1.linux-mips.tar.gz
|
eb9edb6223330d5e20275667c65dea076b064c08e595fe4eba5d7d6055cfaccf go1.25.7.linux-mips64le.tar.gz
|
||||||
c270f7b0c0bdfbcd54fef4481227c40d41bb518f9ae38ee930870f04a0a6a589 go1.25.1.linux-mips64.tar.gz
|
9c1e693552a5f9bb9e0012d1c5e01456ecefbc59bef53a77305222ce10aba368 go1.25.7.linux-mipsle.tar.gz
|
||||||
80be871ba9c944f34d1868cdf5047e1cf2e1289fe08cdb90e2453d2f0d6965ae go1.25.1.linux-mips64le.tar.gz
|
28a788798e7329acbbc0ac2caa5e4368b1e5ede646cc24429c991214cfb45c63 go1.25.7.linux-ppc64.tar.gz
|
||||||
9f09defa9bb22ebf2cde76162f40958564e57ce5c2b3649bc063bebcbc9294c1 go1.25.1.linux-mipsle.tar.gz
|
42124c0edc92464e2b37b2d7fcd3658f0c47ebd6a098732415a522be8cb88e3f go1.25.7.linux-ppc64le.tar.gz
|
||||||
2c76b7d278c1d43ad19d478ad3f0f05e7b782b64b90870701b314fa48b5f43c6 go1.25.1.linux-ppc64.tar.gz
|
88d59c6893c8425875d6eef8e3434bc2fa2552e5ad4c058c6cd8cd710a0301c8 go1.25.7.linux-riscv64.tar.gz
|
||||||
8b0c8d3ee5b1b5c28b6bd63dc4438792012e01d03b4bf7a61d985c87edab7d1f go1.25.1.linux-ppc64le.tar.gz
|
c6b77facf666dc68195ecab05dbf0ebb4e755b2a8b7734c759880557f1c29b0c go1.25.7.linux-s390x.tar.gz
|
||||||
22fe934a9d0c9c57275716c55b92d46ebd887cec3177c9140705efa9f84ba1e2 go1.25.1.linux-riscv64.tar.gz
|
f14c184d9ade0ee04c7735d4071257b90896ecbde1b32adae84135f055e6399b go1.25.7.netbsd-386.tar.gz
|
||||||
9cfe517ba423f59f3738ca5c3d907c103253cffbbcc2987142f79c5de8c1bf93 go1.25.1.linux-s390x.tar.gz
|
7e7389e404dca1088c31f0fc07f1dd60891d7182bcd621469c14f7e79eceb3ff go1.25.7.netbsd-amd64.tar.gz
|
||||||
6af8a08353e76205d5b743dd7a3f0126684f96f62be0a31b75daf9837e512c46 go1.25.1.netbsd-386.tar.gz
|
70388bb3ef2f03dbf1357e9056bd09034a67e018262557354f8cf549766b3f9d go1.25.7.netbsd-arm.tar.gz
|
||||||
e5d534ff362edb1bd8c8e10892b6a027c4c1482454245d1529167676498684c7 go1.25.1.netbsd-amd64.tar.gz
|
8c1cda9d25bfc9b18d24d5f95fc23949dd3ff99fa408a6cfa40e2cf12b07e362 go1.25.7.netbsd-arm64.tar.gz
|
||||||
88bcf39254fdcea6a199c1c27d787831b652427ce60851ae9e41a3d7eb477f45 go1.25.1.netbsd-arm.tar.gz
|
42f0d1bfbe39b8401cccb84dd66b30795b97bfc9620dfdc17c5cd4fcf6495cb0 go1.25.7.openbsd-386.tar.gz
|
||||||
d7c2eabe1d04ee47bcaea2816fdd90dbd25d90d4dfa756faa9786c788e4f3a4e go1.25.1.netbsd-arm64.tar.gz
|
e514879c0a28bc32123cd52c4c093de912477fe83f36a6d07517d066ef55391a go1.25.7.openbsd-amd64.tar.gz
|
||||||
14a2845977eb4dde11d929858c437a043467c427db87899935e90cee04a38d72 go1.25.1.openbsd-386.tar.gz
|
8cd22530695a0218232bf7efea8f162df1697a3106942ac4129b8c3de39ce4ef go1.25.7.openbsd-arm.tar.gz
|
||||||
d27ac54b38a13a09c81e67c82ac70d387037341c85c3399291c73e13e83fdd8c go1.25.1.openbsd-amd64.tar.gz
|
938720f6ebc0d1c53d7840321d3a31f29fd02496e84a6538f442a9311dc1cc9a go1.25.7.openbsd-arm64.tar.gz
|
||||||
0f4ab5f02500afa4befd51fed1e8b45e4d07ca050f641cc3acc76eaa4027b2c3 go1.25.1.openbsd-arm.tar.gz
|
a4c378b73b98f89a3596c2ef51aabbb28783d9ca29f7e317d8ca07939660ce6f go1.25.7.openbsd-ppc64.tar.gz
|
||||||
d46c3bd156843656f7f3cb0dec27ea51cd926ec3f7b80744bf8156e67c1c812f go1.25.1.openbsd-arm64.tar.gz
|
937b58734fbeaa8c7941a0e4285e7e84b7885396e8d11c23f9ab1a8ff10ff20e go1.25.7.openbsd-riscv64.tar.gz
|
||||||
c550514c67f22e409be10e40eace761e2e43069f4ef086ae6e60aac736c2b679 go1.25.1.openbsd-ppc64.tar.gz
|
61a093c8c5244916f25740316386bb9f141545dcf01b06a79d1c78ece488403e go1.25.7.plan9-386.tar.gz
|
||||||
8a09a8714a2556eb13fc1f10b7ce2553fcea4971e3330fc3be0efd24aab45734 go1.25.1.openbsd-riscv64.tar.gz
|
7fc8f6689c9de8ccb7689d2278035fa83c2d601409101840df6ddfe09ba58699 go1.25.7.plan9-amd64.tar.gz
|
||||||
b0e1fefaf0c7abd71f139a54eee9767944aff5f0bc9d69c968234804884e552f go1.25.1.plan9-386.tar.gz
|
9661dff8eaeeb62f1c3aadbc5ff189a2e6744e1ec885e32dbcb438f58a34def5 go1.25.7.plan9-arm.tar.gz
|
||||||
e94732c94f149690aa0ab11c26090577211b4a988137cb2c03ec0b54e750402e go1.25.1.plan9-amd64.tar.gz
|
28ecba0e1d7950c8b29a4a04962dd49c3bf5221f55a44f17d98f369f82859cf4 go1.25.7.solaris-amd64.tar.gz
|
||||||
7eb80e9de1e817d9089a54e8c7c5c8d8ed9e5fb4d4a012fc0f18fc422a484f0c go1.25.1.plan9-arm.tar.gz
|
baa6b488291801642fa620026169e38bec2da2ac187cd3ae2145721cf826bbc3 go1.25.7.windows-386.zip
|
||||||
1261dfad7c4953c0ab90381bc1242dc54e394db7485c59349428d532b2273343 go1.25.1.solaris-amd64.tar.gz
|
c75e5f4ff62d085cc0017be3ad19d5536f46825fa05db06ec468941f847e3228 go1.25.7.windows-amd64.zip
|
||||||
04bc3c078e9e904c4d58d6ac2532a5bdd402bd36a9ff0b5949b3c5e6006a05ee go1.25.1.windows-arm64.zip
|
807033f85931bc4a589ca8497535dcbeb1f30d506e47fa200f5f04c4a71c3d9f go1.25.7.windows-arm64.zip
|
||||||
|
|
||||||
# version:golangci 2.4.0
|
# version:golangci 2.10.1
|
||||||
# https://github.com/golangci/golangci-lint/releases/
|
# https://github.com/golangci/golangci-lint/releases/
|
||||||
# https://github.com/golangci/golangci-lint/releases/download/v2.4.0/
|
# https://github.com/golangci/golangci-lint/releases/download/v2.10.1
|
||||||
7904ce63f79db44934939cf7a063086ea0ea98e9b19eba0a9d52ccdd0d21951c golangci-lint-2.4.0-darwin-amd64.tar.gz
|
66fb0da81b8033b477f97eea420d4b46b230ca172b8bb87c6610109f3772b6b6 golangci-lint-2.10.1-darwin-amd64.tar.gz
|
||||||
cd4dd53fa09b6646baff5fd22b8c64d91db02c21c7496df27992d75d34feec59 golangci-lint-2.4.0-darwin-arm64.tar.gz
|
03bfadf67e52b441b7ec21305e501c717df93c959836d66c7f97312654acb297 golangci-lint-2.10.1-darwin-arm64.tar.gz
|
||||||
d58f426ebe14cc257e81562b4bf37a488ffb4ffbbb3ec73041eb3b38bb25c0e1 golangci-lint-2.4.0-freebsd-386.tar.gz
|
c9a44658ccc8f7b8dbbd4ae6020ba91c1a5d3987f4d91ced0f7d2bea013e57ca golangci-lint-2.10.1-freebsd-386.tar.gz
|
||||||
6ec4a6177fc6c0dd541fbcb3a7612845266d020d35cc6fa92959220cdf64ca39 golangci-lint-2.4.0-freebsd-amd64.tar.gz
|
a513c5cb4e0f5bd5767001af9d5e97e7868cfc2d9c46739a4df93e713cfb24af golangci-lint-2.10.1-freebsd-amd64.tar.gz
|
||||||
4d473e3e71c01feaa915a0604fb35758b41284fb976cdeac3f842118d9ee7e17 golangci-lint-2.4.0-freebsd-armv6.tar.gz
|
2ef38eefc4b5cee2febacb75a30579526e5656c16338a921d80e59a8e87d4425 golangci-lint-2.10.1-freebsd-arm64.tar.gz
|
||||||
58727746c6530801a3f9a702a5945556a5eb7e88809222536dd9f9d54cafaeff golangci-lint-2.4.0-freebsd-armv7.tar.gz
|
8fea6766318b4829e766bbe325f10191d75297dcc44ae35bf374816037878e38 golangci-lint-2.10.1-freebsd-armv6.tar.gz
|
||||||
fbf28c662760e24c32f82f8d16dffdb4a82de7726a52ba1fad94f890c22997ea golangci-lint-2.4.0-illumos-amd64.tar.gz
|
30b629870574d6254f3e8804e5a74b34f98e1263c9d55465830d739c88b862ed golangci-lint-2.10.1-freebsd-armv7.tar.gz
|
||||||
a15a000a8981ef665e971e0f67e2acda9066a9e37a59344393b7351d8fb49c81 golangci-lint-2.4.0-linux-386.tar.gz
|
c0db839f866ce80b1b6c96167aa101cfe50d9c936f42d942a3c1cbdc1801af68 golangci-lint-2.10.1-illumos-amd64.tar.gz
|
||||||
fae792524c04424c0ac369f5b8076f04b45cf29fc945a370e55d369a8dc11840 golangci-lint-2.4.0-linux-amd64.tar.gz
|
280eb56636e9175f671cd7b755d7d67f628ae2ed00a164d1e443c43c112034e5 golangci-lint-2.10.1-linux-386.deb
|
||||||
70ac11f55b80ec78fd3a879249cc9255121b8dfd7f7ed4fc46ed137f4abf17e7 golangci-lint-2.4.0-linux-arm64.tar.gz
|
065a7d99da61dc7dfbfef2e2d7053dd3fa6672598f2747117aa4bb5f45e7df7f golangci-lint-2.10.1-linux-386.rpm
|
||||||
4acdc40e5cebe99e4e7ced358a05b2e71789f409b41cb4f39bbb86ccfa14b1dc golangci-lint-2.4.0-linux-armv6.tar.gz
|
a55918c03bb413b2662287653ab2ae2fef4e37428b247dad6348724adde9d770 golangci-lint-2.10.1-linux-386.tar.gz
|
||||||
2a68749568fa22b4a97cb88dbea655595563c795076536aa6c087f7968784bf3 golangci-lint-2.4.0-linux-armv7.tar.gz
|
8aa9b3aa14f39745eeb7fc7ff50bcac683e785397d1e4bc9afd2184b12c4ce86 golangci-lint-2.10.1-linux-amd64.deb
|
||||||
9e3369afb023711036dcb0b4f45c9fe2792af962fa1df050c9f6ac101a6c5d73 golangci-lint-2.4.0-linux-loong64.tar.gz
|
62a111688e9e305032334a2cbc84f4d971b64bb3bffc99d3f80081d57fb25e32 golangci-lint-2.10.1-linux-amd64.rpm
|
||||||
bb9143d6329be2c4dbfffef9564078e7da7d88e7dde6c829b6263d98e072229e golangci-lint-2.4.0-linux-mips64.tar.gz
|
dfa775874cf0561b404a02a8f4481fc69b28091da95aa697259820d429b09c99 golangci-lint-2.10.1-linux-amd64.tar.gz
|
||||||
5ad1765b40d56cd04d4afd805b3ba6f4bfd9b36181da93c31e9b17e483d8608d golangci-lint-2.4.0-linux-mips64le.tar.gz
|
b3f36937e8ea1660739dc0f5c892ea59c9c21ed4e75a91a25957c561f7f79a55 golangci-lint-2.10.1-linux-arm64.deb
|
||||||
918936fb9c0d5ba96bef03cf4348b03938634cfcced49be1e9bb29cb5094fa73 golangci-lint-2.4.0-linux-ppc64le.tar.gz
|
36d50314d53683b1f1a2a6cedfb5a9468451b481c64ab9e97a8e843ea088074d golangci-lint-2.10.1-linux-arm64.rpm
|
||||||
f7474c638e1fb67ebbdc654b55ca0125377ea0bc88e8fee8d964a4f24eacf828 golangci-lint-2.4.0-linux-riscv64.tar.gz
|
6652b42ae02915eb2f9cb2a2e0cac99514c8eded8388d88ae3e06e1a52c00de8 golangci-lint-2.10.1-linux-arm64.tar.gz
|
||||||
b617a9543997c8bfceaffa88a75d4e595030c6add69fba800c1e4d8f5fe253dd golangci-lint-2.4.0-linux-s390x.tar.gz
|
a32d8d318e803496812dd3461f250e52ccc7f53c47b95ce404a9cf55778ceb6a golangci-lint-2.10.1-linux-armv6.deb
|
||||||
7db027b03a9ba328f795215b04f594036837bc7dd0dd7cd16776b02a6167981c golangci-lint-2.4.0-netbsd-386.tar.gz
|
41d065f4c8ea165a1531abea644988ee2e973e4f0b49f9725ed3b979dac45112 golangci-lint-2.10.1-linux-armv6.rpm
|
||||||
52d8f9393f4313df0a62b752c37775e3af0b818e43e8dd28954351542d7c60bc golangci-lint-2.4.0-netbsd-amd64.tar.gz
|
59159a4df03aabbde69d15c7b7b3df143363cbb41f4bd4b200caffb8e34fb734 golangci-lint-2.10.1-linux-armv6.tar.gz
|
||||||
5c0086027fb5a4af3829e530c8115db4b35d11afe1914322eef528eb8cd38c69 golangci-lint-2.4.0-netbsd-arm64.tar.gz
|
b2e8ec0e050a1e2251dfe1561434999d202f5a3f9fa47ce94378b0fd1662ea5a golangci-lint-2.10.1-linux-armv7.deb
|
||||||
6b779d6ed1aed87cefe195cc11759902b97a76551b593312c6833f2635a3488f golangci-lint-2.4.0-netbsd-armv6.tar.gz
|
28c9331429a497da27e9c77846063bd0e8275e878ffedb4eb9e9f21d24771cc0 golangci-lint-2.10.1-linux-armv7.rpm
|
||||||
f00d1f4b7ec3468a0f9fffd0d9ea036248b029b7621cbc9a59c449ef94356d09 golangci-lint-2.4.0-netbsd-armv7.tar.gz
|
818f33e95b273e3769284b25563b51ef6a294e9e25acf140fda5830c075a1a59 golangci-lint-2.10.1-linux-armv7.tar.gz
|
||||||
3ce671b0b42b58e35066493aab75a7e2826c9e079988f1ba5d814a4029faaf87 golangci-lint-2.4.0-windows-386.zip
|
6b6b85ed4b7c27f51097dd681523000409dde835e86e6e314e87be4bb013e2ab golangci-lint-2.10.1-linux-loong64.deb
|
||||||
003112f7a56746feaabf20b744054bf9acdf900c9e77176383623c4b1d76aaa9 golangci-lint-2.4.0-windows-amd64.zip
|
94050a0cf06169e2ae44afb307dcaafa7d7c3b38c0c23b5652cf9cb60f0c337f golangci-lint-2.10.1-linux-loong64.rpm
|
||||||
dc0c2092af5d47fc2cd31a1dfe7b4c7e765fab22de98bd21ef2ffcc53ad9f54f golangci-lint-2.4.0-windows-arm64.zip
|
25820300fccb8c961c1cdcb1f77928040c079e04c43a3a5ceb34b1cb4a1c5c8d golangci-lint-2.10.1-linux-loong64.tar.gz
|
||||||
0263d23e20a260cb1592d35e12a388f99efe2c51b3611fdc66fbd9db1fce664d golangci-lint-2.4.0-windows-armv6.zip
|
98bf39d10139fdcaa37f94950e9bbb8888660ae468847ae0bf1cb5bf67c1f68b golangci-lint-2.10.1-linux-mips64.deb
|
||||||
9403c03bf648e6313036e0273149d44bad1b9ad53889b6d00e4ccb842ba3c058 golangci-lint-2.4.0-windows-armv7.zip
|
df3ce5f03808dcceaa8b683d1d06e95c885f09b59dc8e15deb840fbe2b3e3299 golangci-lint-2.10.1-linux-mips64.rpm
|
||||||
|
972508dda523067e6e6a1c8e6609d63bc7c4153819c11b947d439235cf17bac2 golangci-lint-2.10.1-linux-mips64.tar.gz
|
||||||
|
1d37f2919e183b5bf8b1777ed8c4b163d3b491d0158355a7999d647655cbbeb6 golangci-lint-2.10.1-linux-mips64le.deb
|
||||||
|
e341d031002cd09a416329ed40f674231051a38544b8f94deb2d1708ce1f4a6f golangci-lint-2.10.1-linux-mips64le.rpm
|
||||||
|
393560122b9cb5538df0c357d30eb27b6ee563533fbb9b138c8db4fd264002af golangci-lint-2.10.1-linux-mips64le.tar.gz
|
||||||
|
21ca46b6a96442e8957677a3ca059c6b93674a68a01b1c71f4e5df0ea2e96d19 golangci-lint-2.10.1-linux-ppc64le.deb
|
||||||
|
57fe0cbca0a9bbdf1547c5e8aa7d278e6896b438d72a541bae6bc62c38b43d1e golangci-lint-2.10.1-linux-ppc64le.rpm
|
||||||
|
e2883db9fa51584e5e203c64456f29993550a7faadc84e3faccdb48f0669992e golangci-lint-2.10.1-linux-ppc64le.tar.gz
|
||||||
|
aa6da0e98ab0ba3bb7582e112174c349907d5edfeff90a551dca3c6eecf92fc0 golangci-lint-2.10.1-linux-riscv64.deb
|
||||||
|
3c68d76cd884a7aad206223a980b9c20bb9ea74b560fa27ed02baf2389189234 golangci-lint-2.10.1-linux-riscv64.rpm
|
||||||
|
3bca11bfac4197205639cbd4676a5415054e629ac6c12ea10fcbe33ef852d9c3 golangci-lint-2.10.1-linux-riscv64.tar.gz
|
||||||
|
0c6aed2ce49db2586adbac72c80d871f06feb1caf4c0763a5ca98fec809a8f0b golangci-lint-2.10.1-linux-s390x.deb
|
||||||
|
16c285adfe1061d69dd8e503be69f87c7202857c6f4add74ac02e3571158fbec golangci-lint-2.10.1-linux-s390x.rpm
|
||||||
|
21011ad368eb04f024201b832095c6b5f96d0888de194cca5bfe4d9307d6364b golangci-lint-2.10.1-linux-s390x.tar.gz
|
||||||
|
7b5191e77a70485918712e31ed55159956323e4911bab1b67569c9d86e1b75eb golangci-lint-2.10.1-netbsd-386.tar.gz
|
||||||
|
07801fd38d293ebad10826f8285525a39ea91ce5ddad77d05bfa90bda9c884a9 golangci-lint-2.10.1-netbsd-amd64.tar.gz
|
||||||
|
7e7219d71c1bf33b98c328c93dc0560706dd896a1c43c44696e5222fc9d7446e golangci-lint-2.10.1-netbsd-arm64.tar.gz
|
||||||
|
92fbc90b9eec0e572269b0f5492a2895c426b086a68372fde49b7e4d4020863e golangci-lint-2.10.1-netbsd-armv6.tar.gz
|
||||||
|
f67b3ae1f47caeefa507a4ebb0c8336958a19011fe48766443212030f75d004b golangci-lint-2.10.1-netbsd-armv7.tar.gz
|
||||||
|
a40bc091c10cea84eaee1a90b84b65f5e8652113b0a600bb099e4e4d9d7caddb golangci-lint-2.10.1-windows-386.zip
|
||||||
|
c60c87695e79db8e320f0e5be885059859de52bb5ee5f11be5577828570bc2a3 golangci-lint-2.10.1-windows-amd64.zip
|
||||||
|
636ab790c8dcea8034aa34aba6031ca3893d68f7eda000460ab534341fadbab1 golangci-lint-2.10.1-windows-arm64.zip
|
||||||
|
|
||||||
# This is the builder on PPA that will build Go itself (inception-y), don't modify!
|
# This is the builder on PPA that will build Go itself (inception-y), don't modify!
|
||||||
#
|
#
|
||||||
|
|
|
||||||
27
build/ci.go
27
build/ci.go
|
|
@ -107,6 +107,18 @@ var (
|
||||||
Tags: "ziren",
|
Tags: "ziren",
|
||||||
Env: map[string]string{"GOMIPS": "softfloat", "CGO_ENABLED": "0"},
|
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",
|
Name: "example",
|
||||||
Tags: "example",
|
Tags: "example",
|
||||||
|
|
@ -156,8 +168,6 @@ var (
|
||||||
"focal", // 20.04, EOL: 04/2030
|
"focal", // 20.04, EOL: 04/2030
|
||||||
"jammy", // 22.04, EOL: 04/2032
|
"jammy", // 22.04, EOL: 04/2032
|
||||||
"noble", // 24.04, EOL: 04/2034
|
"noble", // 24.04, EOL: 04/2034
|
||||||
"oracular", // 24.10, EOL: 07/2025
|
|
||||||
"plucky", // 25.04, EOL: 01/2026
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is where the tests should be unpacked.
|
// This is where the tests should be unpacked.
|
||||||
|
|
@ -331,6 +341,10 @@ 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, " "))
|
||||||
}
|
}
|
||||||
|
|
@ -446,9 +460,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)
|
||||||
}
|
}
|
||||||
|
|
@ -458,7 +477,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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
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
|
|
||||||
|
|
@ -86,9 +86,3 @@ func protoOffset(proto Proto) uint64 {
|
||||||
panic("unhandled protocol")
|
panic("unhandled protocol")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// msgTypePtr is the constraint for protocol message types.
|
|
||||||
type msgTypePtr[U any] interface {
|
|
||||||
*U
|
|
||||||
Kind() byte
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth/protocols/snap"
|
"github.com/ethereum/go-ethereum/eth/protocols/snap"
|
||||||
"github.com/ethereum/go-ethereum/internal/utesting"
|
"github.com/ethereum/go-ethereum/internal/utesting"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||||
)
|
)
|
||||||
|
|
@ -937,10 +938,14 @@ func (s *Suite) snapGetTrieNodes(t *utesting.T, tc *trieNodesTest) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// write0 request
|
// write0 request
|
||||||
|
paths, err := rlp.EncodeToRawList(tc.paths)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
req := &snap.GetTrieNodesPacket{
|
req := &snap.GetTrieNodesPacket{
|
||||||
ID: uint64(rand.Int63()),
|
ID: uint64(rand.Int63()),
|
||||||
Root: tc.root,
|
Root: tc.root,
|
||||||
Paths: tc.paths,
|
Paths: paths,
|
||||||
Bytes: tc.nBytes,
|
Bytes: tc.nBytes,
|
||||||
}
|
}
|
||||||
msg, err := conn.snapRequest(snap.GetTrieNodesMsg, req)
|
msg, err := conn.snapRequest(snap.GetTrieNodesMsg, req)
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/internal/utesting"
|
"github.com/ethereum/go-ethereum/internal/utesting"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -151,7 +152,11 @@ func (s *Suite) TestGetBlockHeaders(t *utesting.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to get headers for given request: %v", err)
|
t.Fatalf("failed to get headers for given request: %v", err)
|
||||||
}
|
}
|
||||||
if !headersMatch(expected, headers.BlockHeadersRequest) {
|
received, err := headers.List.Items()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("invalid headers received: %v", err)
|
||||||
|
}
|
||||||
|
if !headersMatch(expected, received) {
|
||||||
t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected, headers)
|
t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected, headers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -237,7 +242,7 @@ concurrently, with different request IDs.`)
|
||||||
|
|
||||||
// Wait for responses.
|
// Wait for responses.
|
||||||
// Note they can arrive in either order.
|
// Note they can arrive in either order.
|
||||||
resp, err := collectResponses(conn, 2, func(msg *eth.BlockHeadersPacket) uint64 {
|
resp, err := collectHeaderResponses(conn, 2, func(msg *eth.BlockHeadersPacket) uint64 {
|
||||||
if msg.RequestId != 111 && msg.RequestId != 222 {
|
if msg.RequestId != 111 && msg.RequestId != 222 {
|
||||||
t.Fatalf("response with unknown request ID: %v", msg.RequestId)
|
t.Fatalf("response with unknown request ID: %v", msg.RequestId)
|
||||||
}
|
}
|
||||||
|
|
@ -248,17 +253,11 @@ concurrently, with different request IDs.`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if headers match.
|
// Check if headers match.
|
||||||
resp1 := resp[111]
|
if err := s.checkHeadersAgainstChain(req1, resp[111]); err != nil {
|
||||||
if expected, err := s.chain.GetHeaders(req1); err != nil {
|
t.Fatal(err)
|
||||||
t.Fatalf("failed to get expected headers for request 1: %v", err)
|
|
||||||
} else if !headersMatch(expected, resp1.BlockHeadersRequest) {
|
|
||||||
t.Fatalf("header mismatch for request ID %v: \nexpected %v \ngot %v", 111, expected, resp1)
|
|
||||||
}
|
}
|
||||||
resp2 := resp[222]
|
if err := s.checkHeadersAgainstChain(req2, resp[222]); err != nil {
|
||||||
if expected, err := s.chain.GetHeaders(req2); err != nil {
|
t.Fatal(err)
|
||||||
t.Fatalf("failed to get expected headers for request 2: %v", err)
|
|
||||||
} else if !headersMatch(expected, resp2.BlockHeadersRequest) {
|
|
||||||
t.Fatalf("header mismatch for request ID %v: \nexpected %v \ngot %v", 222, expected, resp2)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -303,8 +302,8 @@ same request ID. The node should handle the request by responding to both reques
|
||||||
|
|
||||||
// Wait for the responses. They can arrive in either order, and we can't tell them
|
// Wait for the responses. They can arrive in either order, and we can't tell them
|
||||||
// apart by their request ID, so use the number of headers instead.
|
// apart by their request ID, so use the number of headers instead.
|
||||||
resp, err := collectResponses(conn, 2, func(msg *eth.BlockHeadersPacket) uint64 {
|
resp, err := collectHeaderResponses(conn, 2, func(msg *eth.BlockHeadersPacket) uint64 {
|
||||||
id := uint64(len(msg.BlockHeadersRequest))
|
id := uint64(msg.List.Len())
|
||||||
if id != 2 && id != 3 {
|
if id != 2 && id != 3 {
|
||||||
t.Fatalf("invalid number of headers in response: %d", id)
|
t.Fatalf("invalid number of headers in response: %d", id)
|
||||||
}
|
}
|
||||||
|
|
@ -315,26 +314,35 @@ same request ID. The node should handle the request by responding to both reques
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if headers match.
|
// Check if headers match.
|
||||||
resp1 := resp[2]
|
if err := s.checkHeadersAgainstChain(request1, resp[2]); err != nil {
|
||||||
if expected, err := s.chain.GetHeaders(request1); err != nil {
|
t.Fatal(err)
|
||||||
t.Fatalf("failed to get expected headers for request 1: %v", err)
|
|
||||||
} else if !headersMatch(expected, resp1.BlockHeadersRequest) {
|
|
||||||
t.Fatalf("headers mismatch: \nexpected %v \ngot %v", expected, resp1)
|
|
||||||
}
|
}
|
||||||
resp2 := resp[3]
|
if err := s.checkHeadersAgainstChain(request2, resp[3]); err != nil {
|
||||||
if expected, err := s.chain.GetHeaders(request2); err != nil {
|
t.Fatal(err)
|
||||||
t.Fatalf("failed to get expected headers for request 2: %v", err)
|
|
||||||
} else if !headersMatch(expected, resp2.BlockHeadersRequest) {
|
|
||||||
t.Fatalf("headers mismatch: \nexpected %v \ngot %v", expected, resp2)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Suite) checkHeadersAgainstChain(req *eth.GetBlockHeadersPacket, resp *eth.BlockHeadersPacket) error {
|
||||||
|
received2, err := resp.List.Items()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid headers in response with request ID %v (%d items): %v", resp.RequestId, resp.List.Len(), err)
|
||||||
|
}
|
||||||
|
if expected, err := s.chain.GetHeaders(req); err != nil {
|
||||||
|
return fmt.Errorf("test chain failed to get expected headers for request: %v", err)
|
||||||
|
} else if !headersMatch(expected, received2) {
|
||||||
|
return fmt.Errorf("header mismatch for request ID %v (%d items): \nexpected %v \ngot %v", resp.RequestId, resp.List.Len(), expected, resp)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// collectResponses waits for n messages of type T on the given connection.
|
// collectResponses waits for n messages of type T on the given connection.
|
||||||
// The messsages are collected according to the 'identity' function.
|
// The messsages are collected according to the 'identity' function.
|
||||||
func collectResponses[T any, P msgTypePtr[T]](conn *Conn, n int, identity func(P) uint64) (map[uint64]P, error) {
|
//
|
||||||
resp := make(map[uint64]P, n)
|
// This function is written in a generic way to handle
|
||||||
|
func collectHeaderResponses(conn *Conn, n int, identity func(*eth.BlockHeadersPacket) uint64) (map[uint64]*eth.BlockHeadersPacket, error) {
|
||||||
|
resp := make(map[uint64]*eth.BlockHeadersPacket, n)
|
||||||
for range n {
|
for range n {
|
||||||
r := new(T)
|
r := new(eth.BlockHeadersPacket)
|
||||||
if err := conn.ReadMsg(ethProto, eth.BlockHeadersMsg, r); err != nil {
|
if err := conn.ReadMsg(ethProto, eth.BlockHeadersMsg, r); err != nil {
|
||||||
return resp, fmt.Errorf("read error: %v", err)
|
return resp, fmt.Errorf("read error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -373,10 +381,8 @@ and expects a response.`)
|
||||||
if got, want := headers.RequestId, req.RequestId; got != want {
|
if got, want := headers.RequestId, req.RequestId; got != want {
|
||||||
t.Fatalf("unexpected request id")
|
t.Fatalf("unexpected request id")
|
||||||
}
|
}
|
||||||
if expected, err := s.chain.GetHeaders(req); err != nil {
|
if err := s.checkHeadersAgainstChain(req, headers); err != nil {
|
||||||
t.Fatalf("failed to get expected block headers: %v", err)
|
t.Fatal(err)
|
||||||
} else if !headersMatch(expected, headers.BlockHeadersRequest) {
|
|
||||||
t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected, headers)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -407,9 +413,8 @@ func (s *Suite) TestGetBlockBodies(t *utesting.T) {
|
||||||
if got, want := resp.RequestId, req.RequestId; got != want {
|
if got, want := resp.RequestId, req.RequestId; got != want {
|
||||||
t.Fatalf("unexpected request id in respond", got, want)
|
t.Fatalf("unexpected request id in respond", got, want)
|
||||||
}
|
}
|
||||||
bodies := resp.BlockBodiesResponse
|
if resp.List.Len() != len(req.GetBlockBodiesRequest) {
|
||||||
if len(bodies) != len(req.GetBlockBodiesRequest) {
|
t.Fatalf("wrong bodies in response: expected %d bodies, got %d", len(req.GetBlockBodiesRequest), resp.List.Len())
|
||||||
t.Fatalf("wrong bodies in response: expected %d bodies, got %d", len(req.GetBlockBodiesRequest), len(bodies))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -433,7 +438,7 @@ func (s *Suite) TestGetReceipts(t *utesting.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create block bodies request.
|
// Create receipts request.
|
||||||
req := ð.GetReceiptsPacket{
|
req := ð.GetReceiptsPacket{
|
||||||
RequestId: 66,
|
RequestId: 66,
|
||||||
GetReceiptsRequest: (eth.GetReceiptsRequest)(hashes),
|
GetReceiptsRequest: (eth.GetReceiptsRequest)(hashes),
|
||||||
|
|
@ -449,8 +454,8 @@ func (s *Suite) TestGetReceipts(t *utesting.T) {
|
||||||
if got, want := resp.RequestId, req.RequestId; got != want {
|
if got, want := resp.RequestId, req.RequestId; got != want {
|
||||||
t.Fatalf("unexpected request id in respond", got, want)
|
t.Fatalf("unexpected request id in respond", got, want)
|
||||||
}
|
}
|
||||||
if len(resp.List) != len(req.GetReceiptsRequest) {
|
if resp.List.Len() != len(req.GetReceiptsRequest) {
|
||||||
t.Fatalf("wrong bodies in response: expected %d bodies, got %d", len(req.GetReceiptsRequest), len(resp.List))
|
t.Fatalf("wrong receipts in response: expected %d receipts, got %d", len(req.GetReceiptsRequest), resp.List.Len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -804,7 +809,11 @@ on another peer connection using GetPooledTransactions.`)
|
||||||
if got, want := msg.RequestId, req.RequestId; got != want {
|
if got, want := msg.RequestId, req.RequestId; got != want {
|
||||||
t.Fatalf("unexpected request id in response: got %d, want %d", got, want)
|
t.Fatalf("unexpected request id in response: got %d, want %d", got, want)
|
||||||
}
|
}
|
||||||
for _, got := range msg.PooledTransactionsResponse {
|
responseTxs, err := msg.List.Items()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("invalid transactions in response: %v", err)
|
||||||
|
}
|
||||||
|
for _, got := range responseTxs {
|
||||||
if _, exists := set[got.Hash()]; !exists {
|
if _, exists := set[got.Hash()]; !exists {
|
||||||
t.Fatalf("unexpected tx received: %v", got.Hash())
|
t.Fatalf("unexpected tx received: %v", got.Hash())
|
||||||
}
|
}
|
||||||
|
|
@ -976,7 +985,9 @@ func (s *Suite) TestBlobViolations(t *utesting.T) {
|
||||||
if err := conn.ReadMsg(ethProto, eth.GetPooledTransactionsMsg, req); err != nil {
|
if err := conn.ReadMsg(ethProto, eth.GetPooledTransactionsMsg, req); err != nil {
|
||||||
t.Fatalf("reading pooled tx request failed: %v", err)
|
t.Fatalf("reading pooled tx request failed: %v", err)
|
||||||
}
|
}
|
||||||
resp := eth.PooledTransactionsPacket{RequestId: req.RequestId, PooledTransactionsResponse: test.resp}
|
|
||||||
|
encTxs, _ := rlp.EncodeToRawList(test.resp)
|
||||||
|
resp := eth.PooledTransactionsPacket{RequestId: req.RequestId, List: encTxs}
|
||||||
if err := conn.Write(ethProto, eth.PooledTransactionsMsg, resp); err != nil {
|
if err := conn.Write(ethProto, eth.PooledTransactionsMsg, resp); err != nil {
|
||||||
t.Fatalf("writing pooled tx response failed: %v", err)
|
t.Fatalf("writing pooled tx response failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1104,7 +1115,8 @@ func (s *Suite) testBadBlobTx(t *utesting.T, tx *types.Transaction, badTx *types
|
||||||
// the good peer is connected, and has announced the tx.
|
// the good peer is connected, and has announced the tx.
|
||||||
// proceed to send the incorrect one from the bad peer.
|
// proceed to send the incorrect one from the bad peer.
|
||||||
|
|
||||||
resp := eth.PooledTransactionsPacket{RequestId: req.RequestId, PooledTransactionsResponse: eth.PooledTransactionsResponse(types.Transactions{badTx})}
|
encTxs, _ := rlp.EncodeToRawList([]*types.Transaction{badTx})
|
||||||
|
resp := eth.PooledTransactionsPacket{RequestId: req.RequestId, List: encTxs}
|
||||||
if err := conn.Write(ethProto, eth.PooledTransactionsMsg, resp); err != nil {
|
if err := conn.Write(ethProto, eth.PooledTransactionsMsg, resp); err != nil {
|
||||||
errc <- fmt.Errorf("writing pooled tx response failed: %v", err)
|
errc <- fmt.Errorf("writing pooled tx response failed: %v", err)
|
||||||
return
|
return
|
||||||
|
|
@ -1164,7 +1176,8 @@ func (s *Suite) testBadBlobTx(t *utesting.T, tx *types.Transaction, badTx *types
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp := eth.PooledTransactionsPacket{RequestId: req.RequestId, PooledTransactionsResponse: eth.PooledTransactionsResponse(types.Transactions{tx})}
|
encTxs, _ := rlp.EncodeToRawList([]*types.Transaction{tx})
|
||||||
|
resp := eth.PooledTransactionsPacket{RequestId: req.RequestId, List: encTxs}
|
||||||
if err := conn.Write(ethProto, eth.PooledTransactionsMsg, resp); err != nil {
|
if err := conn.Write(ethProto, eth.PooledTransactionsMsg, resp); err != nil {
|
||||||
errc <- fmt.Errorf("writing pooled tx response failed: %v", err)
|
errc <- fmt.Errorf("writing pooled tx response failed: %v", err)
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/eth/protocols/eth"
|
"github.com/ethereum/go-ethereum/eth/protocols/eth"
|
||||||
"github.com/ethereum/go-ethereum/internal/utesting"
|
"github.com/ethereum/go-ethereum/internal/utesting"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// sendTxs sends the given transactions to the node and
|
// sendTxs sends the given transactions to the node and
|
||||||
|
|
@ -51,7 +52,8 @@ func (s *Suite) sendTxs(t *utesting.T, txs []*types.Transaction) error {
|
||||||
return fmt.Errorf("peering failed: %v", err)
|
return fmt.Errorf("peering failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = sendConn.Write(ethProto, eth.TransactionsMsg, eth.TransactionsPacket(txs)); err != nil {
|
encTxs, _ := rlp.EncodeToRawList(txs)
|
||||||
|
if err = sendConn.Write(ethProto, eth.TransactionsMsg, eth.TransactionsPacket{RawList: encTxs}); err != nil {
|
||||||
return fmt.Errorf("failed to write message to connection: %v", err)
|
return fmt.Errorf("failed to write message to connection: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,7 +70,8 @@ func (s *Suite) sendTxs(t *utesting.T, txs []*types.Transaction) error {
|
||||||
}
|
}
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case *eth.TransactionsPacket:
|
case *eth.TransactionsPacket:
|
||||||
for _, tx := range *msg {
|
txs, _ := msg.Items()
|
||||||
|
for _, tx := range txs {
|
||||||
got[tx.Hash()] = true
|
got[tx.Hash()] = true
|
||||||
}
|
}
|
||||||
case *eth.NewPooledTransactionHashesPacket:
|
case *eth.NewPooledTransactionHashesPacket:
|
||||||
|
|
@ -80,9 +83,10 @@ func (s *Suite) sendTxs(t *utesting.T, txs []*types.Transaction) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Logf("invalid GetBlockHeaders request: %v", err)
|
t.Logf("invalid GetBlockHeaders request: %v", err)
|
||||||
}
|
}
|
||||||
|
encHeaders, _ := rlp.EncodeToRawList(headers)
|
||||||
recvConn.Write(ethProto, eth.BlockHeadersMsg, ð.BlockHeadersPacket{
|
recvConn.Write(ethProto, eth.BlockHeadersMsg, ð.BlockHeadersPacket{
|
||||||
RequestId: msg.RequestId,
|
RequestId: msg.RequestId,
|
||||||
BlockHeadersRequest: headers,
|
List: encHeaders,
|
||||||
})
|
})
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unexpected eth wire msg: %s", pretty.Sdump(msg))
|
return fmt.Errorf("unexpected eth wire msg: %s", pretty.Sdump(msg))
|
||||||
|
|
@ -167,9 +171,10 @@ func (s *Suite) sendInvalidTxs(t *utesting.T, txs []*types.Transaction) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Logf("invalid GetBlockHeaders request: %v", err)
|
t.Logf("invalid GetBlockHeaders request: %v", err)
|
||||||
}
|
}
|
||||||
|
encHeaders, _ := rlp.EncodeToRawList(headers)
|
||||||
recvConn.Write(ethProto, eth.BlockHeadersMsg, ð.BlockHeadersPacket{
|
recvConn.Write(ethProto, eth.BlockHeadersMsg, ð.BlockHeadersPacket{
|
||||||
RequestId: msg.RequestId,
|
RequestId: msg.RequestId,
|
||||||
BlockHeadersRequest: headers,
|
List: encHeaders,
|
||||||
})
|
})
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unexpected eth message: %v", pretty.Sdump(msg))
|
return fmt.Errorf("unexpected eth message: %v", pretty.Sdump(msg))
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ func (s *Suite) AllTests() []utesting.Test {
|
||||||
{Name: "Ping", Fn: s.TestPing},
|
{Name: "Ping", Fn: s.TestPing},
|
||||||
{Name: "PingLargeRequestID", Fn: s.TestPingLargeRequestID},
|
{Name: "PingLargeRequestID", Fn: s.TestPingLargeRequestID},
|
||||||
{Name: "PingMultiIP", Fn: s.TestPingMultiIP},
|
{Name: "PingMultiIP", Fn: s.TestPingMultiIP},
|
||||||
{Name: "PingHandshakeInterrupted", Fn: s.TestPingHandshakeInterrupted},
|
{Name: "HandshakeResend", Fn: s.TestHandshakeResend},
|
||||||
{Name: "TalkRequest", Fn: s.TestTalkRequest},
|
{Name: "TalkRequest", Fn: s.TestTalkRequest},
|
||||||
{Name: "FindnodeZeroDistance", Fn: s.TestFindnodeZeroDistance},
|
{Name: "FindnodeZeroDistance", Fn: s.TestFindnodeZeroDistance},
|
||||||
{Name: "FindnodeResults", Fn: s.TestFindnodeResults},
|
{Name: "FindnodeResults", Fn: s.TestFindnodeResults},
|
||||||
|
|
@ -158,22 +158,20 @@ the attempt from a different IP.`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestPingHandshakeInterrupted starts a handshake, but doesn't finish it and sends a second ordinary message
|
// TestHandshakeResend starts a handshake, but doesn't finish it and sends a second ordinary message
|
||||||
// packet instead of a handshake message packet. The remote node should respond with
|
// packet instead of a handshake message packet. The remote node should repeat the previous WHOAREYOU
|
||||||
// another WHOAREYOU challenge for the second packet.
|
// challenge for the first PING.
|
||||||
func (s *Suite) TestPingHandshakeInterrupted(t *utesting.T) {
|
func (s *Suite) TestHandshakeResend(t *utesting.T) {
|
||||||
t.Log(`TestPingHandshakeInterrupted starts a handshake, but doesn't finish it and sends a second ordinary message
|
|
||||||
packet instead of a handshake message packet. The remote node should respond with
|
|
||||||
another WHOAREYOU challenge for the second packet.`)
|
|
||||||
|
|
||||||
conn, l1 := s.listen1(t)
|
conn, l1 := s.listen1(t)
|
||||||
defer conn.close()
|
defer conn.close()
|
||||||
|
|
||||||
// First PING triggers challenge.
|
// First PING triggers challenge.
|
||||||
ping := &v5wire.Ping{ReqID: conn.nextReqID()}
|
ping := &v5wire.Ping{ReqID: conn.nextReqID()}
|
||||||
conn.write(l1, ping, nil)
|
conn.write(l1, ping, nil)
|
||||||
|
var challenge1 *v5wire.Whoareyou
|
||||||
switch resp := conn.read(l1).(type) {
|
switch resp := conn.read(l1).(type) {
|
||||||
case *v5wire.Whoareyou:
|
case *v5wire.Whoareyou:
|
||||||
|
challenge1 = resp
|
||||||
t.Logf("got WHOAREYOU for PING")
|
t.Logf("got WHOAREYOU for PING")
|
||||||
default:
|
default:
|
||||||
t.Fatal("expected WHOAREYOU, got", resp)
|
t.Fatal("expected WHOAREYOU, got", resp)
|
||||||
|
|
@ -181,9 +179,16 @@ another WHOAREYOU challenge for the second packet.`)
|
||||||
|
|
||||||
// Send second PING.
|
// Send second PING.
|
||||||
ping2 := &v5wire.Ping{ReqID: conn.nextReqID()}
|
ping2 := &v5wire.Ping{ReqID: conn.nextReqID()}
|
||||||
switch resp := conn.reqresp(l1, ping2).(type) {
|
conn.write(l1, ping2, nil)
|
||||||
case *v5wire.Pong:
|
switch resp := conn.read(l1).(type) {
|
||||||
checkPong(t, resp, ping2, l1)
|
case *v5wire.Whoareyou:
|
||||||
|
if resp.Nonce != challenge1.Nonce {
|
||||||
|
t.Fatalf("wrong nonce %x in WHOAREYOU (want %x)", resp.Nonce[:], challenge1.Nonce[:])
|
||||||
|
}
|
||||||
|
if !bytes.Equal(resp.ChallengeData, challenge1.ChallengeData) {
|
||||||
|
t.Fatalf("wrong ChallengeData in resent WHOAREYOU (want %x)", resp.ChallengeData, challenge1.ChallengeData)
|
||||||
|
}
|
||||||
|
resp.Node = conn.remote
|
||||||
default:
|
default:
|
||||||
t.Fatal("expected WHOAREYOU, got", resp)
|
t.Fatal("expected WHOAREYOU, got", resp)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
128
cmd/era/main.go
128
cmd/era/main.go
|
|
@ -30,6 +30,8 @@ import (
|
||||||
"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/internal/era"
|
"github.com/ethereum/go-ethereum/internal/era"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/era/execdb"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/era/onedb"
|
||||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/internal/flags"
|
"github.com/ethereum/go-ethereum/internal/flags"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
@ -53,7 +55,7 @@ var (
|
||||||
eraSizeFlag = &cli.IntFlag{
|
eraSizeFlag = &cli.IntFlag{
|
||||||
Name: "size",
|
Name: "size",
|
||||||
Usage: "number of blocks per era",
|
Usage: "number of blocks per era",
|
||||||
Value: era.MaxEra1Size,
|
Value: era.MaxSize,
|
||||||
}
|
}
|
||||||
txsFlag = &cli.BoolFlag{
|
txsFlag = &cli.BoolFlag{
|
||||||
Name: "txs",
|
Name: "txs",
|
||||||
|
|
@ -131,7 +133,7 @@ func block(ctx *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// info prints some high-level information about the era1 file.
|
// info prints some high-level information about the era file.
|
||||||
func info(ctx *cli.Context) error {
|
func info(ctx *cli.Context) error {
|
||||||
epoch, err := strconv.ParseUint(ctx.Args().First(), 10, 64)
|
epoch, err := strconv.ParseUint(ctx.Args().First(), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -142,33 +144,34 @@ func info(ctx *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer e.Close()
|
defer e.Close()
|
||||||
acc, err := e.Accumulator()
|
var (
|
||||||
if err != nil {
|
accHex string
|
||||||
return fmt.Errorf("error reading accumulator: %w", err)
|
tdStr string
|
||||||
|
)
|
||||||
|
if acc, err := e.Accumulator(); err == nil {
|
||||||
|
accHex = acc.Hex()
|
||||||
}
|
}
|
||||||
td, err := e.InitialTD()
|
if td, err := e.InitialTD(); err == nil {
|
||||||
if err != nil {
|
tdStr = td.String()
|
||||||
return fmt.Errorf("error reading total difficulty: %w", err)
|
|
||||||
}
|
}
|
||||||
info := struct {
|
info := struct {
|
||||||
Accumulator common.Hash `json:"accumulator"`
|
Accumulator string `json:"accumulator,omitempty"`
|
||||||
TotalDifficulty *big.Int `json:"totalDifficulty"`
|
TotalDifficulty string `json:"totalDifficulty,omitempty"`
|
||||||
StartBlock uint64 `json:"startBlock"`
|
StartBlock uint64 `json:"startBlock"`
|
||||||
Count uint64 `json:"count"`
|
Count uint64 `json:"count"`
|
||||||
}{
|
}{
|
||||||
acc, td, e.Start(), e.Count(),
|
accHex, tdStr, e.Start(), e.Count(),
|
||||||
}
|
}
|
||||||
b, _ := json.MarshalIndent(info, "", " ")
|
b, _ := json.MarshalIndent(info, "", " ")
|
||||||
fmt.Println(string(b))
|
fmt.Println(string(b))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// open opens an era1 file at a certain epoch.
|
// open opens an era file at a certain epoch.
|
||||||
func open(ctx *cli.Context, epoch uint64) (*era.Era, error) {
|
func open(ctx *cli.Context, epoch uint64) (era.Era, error) {
|
||||||
var (
|
dir := ctx.String(dirFlag.Name)
|
||||||
dir = ctx.String(dirFlag.Name)
|
network := ctx.String(networkFlag.Name)
|
||||||
network = ctx.String(networkFlag.Name)
|
|
||||||
)
|
|
||||||
entries, err := era.ReadDir(dir, network)
|
entries, err := era.ReadDir(dir, network)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error reading era dir: %w", err)
|
return nil, fmt.Errorf("error reading era dir: %w", err)
|
||||||
|
|
@ -176,7 +179,28 @@ func open(ctx *cli.Context, epoch uint64) (*era.Era, error) {
|
||||||
if epoch >= uint64(len(entries)) {
|
if epoch >= uint64(len(entries)) {
|
||||||
return nil, fmt.Errorf("epoch out-of-bounds: last %d, want %d", len(entries)-1, epoch)
|
return nil, fmt.Errorf("epoch out-of-bounds: last %d, want %d", len(entries)-1, epoch)
|
||||||
}
|
}
|
||||||
return era.Open(filepath.Join(dir, entries[epoch]))
|
path := filepath.Join(dir, entries[epoch])
|
||||||
|
return openByPath(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// openByPath tries to open a single file as either eraE or era1 based on extension,
|
||||||
|
// falling back to the other reader if needed.
|
||||||
|
func openByPath(path string) (era.Era, error) {
|
||||||
|
switch strings.ToLower(filepath.Ext(path)) {
|
||||||
|
case ".erae":
|
||||||
|
if e, err := execdb.Open(path); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return e, nil
|
||||||
|
}
|
||||||
|
case ".era1":
|
||||||
|
if e, err := onedb.Open(path); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return e, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("unsupported or unreadable era file: %s", path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify checks each era1 file in a directory to ensure it is well-formed and
|
// verify checks each era1 file in a directory to ensure it is well-formed and
|
||||||
|
|
@ -203,18 +227,58 @@ func verify(ctx *cli.Context) error {
|
||||||
return fmt.Errorf("error reading %s: %w", dir, err)
|
return fmt.Errorf("error reading %s: %w", dir, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(entries) != len(roots) {
|
// Build the verification list respecting the rule:
|
||||||
return errors.New("number of era1 files should match the number of accumulator hashes")
|
// era1: must have accumulator, always verify
|
||||||
|
// erae: verify only if accumulator exists (pre-merge)
|
||||||
|
|
||||||
|
// Build list of files to verify.
|
||||||
|
verify := make([]string, 0, len(entries))
|
||||||
|
|
||||||
|
for _, name := range entries {
|
||||||
|
path := filepath.Join(dir, name)
|
||||||
|
ext := strings.ToLower(filepath.Ext(name))
|
||||||
|
|
||||||
|
switch ext {
|
||||||
|
case ".era1":
|
||||||
|
e, err := onedb.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error opening era1 file %s: %w", name, err)
|
||||||
|
}
|
||||||
|
_, accErr := e.Accumulator()
|
||||||
|
e.Close()
|
||||||
|
if accErr != nil {
|
||||||
|
return fmt.Errorf("era1 file %s missing accumulator: %w", name, accErr)
|
||||||
|
}
|
||||||
|
verify = append(verify, path)
|
||||||
|
|
||||||
|
case ".erae":
|
||||||
|
e, err := execdb.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error opening erae file %s: %w", name, err)
|
||||||
|
}
|
||||||
|
_, accErr := e.Accumulator()
|
||||||
|
e.Close()
|
||||||
|
if accErr == nil {
|
||||||
|
verify = append(verify, path) // pre-merge only
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported era file: %s", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(verify) != len(roots) {
|
||||||
|
return fmt.Errorf("mismatch between eras to verify (%d) and provided roots (%d)", len(verify), len(roots))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify each epoch matches the expected root.
|
// Verify each epoch matches the expected root.
|
||||||
for i, want := range roots {
|
for i, want := range roots {
|
||||||
// Wrap in function so defers don't stack.
|
// Wrap in function so defers don't stack.
|
||||||
err := func() error {
|
err := func() error {
|
||||||
name := entries[i]
|
path := verify[i]
|
||||||
e, err := era.Open(filepath.Join(dir, name))
|
name := filepath.Base(path)
|
||||||
|
e, err := openByPath(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error opening era1 file %s: %w", name, err)
|
return fmt.Errorf("error opening era file %s: %w", name, err)
|
||||||
}
|
}
|
||||||
defer e.Close()
|
defer e.Close()
|
||||||
// Read accumulator and check against expected.
|
// Read accumulator and check against expected.
|
||||||
|
|
@ -243,7 +307,7 @@ func verify(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkAccumulator verifies the accumulator matches the data in the Era.
|
// checkAccumulator verifies the accumulator matches the data in the Era.
|
||||||
func checkAccumulator(e *era.Era) error {
|
func checkAccumulator(e era.Era) error {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
want common.Hash
|
want common.Hash
|
||||||
|
|
@ -257,7 +321,7 @@ func checkAccumulator(e *era.Era) error {
|
||||||
if td, err = e.InitialTD(); err != nil {
|
if td, err = e.InitialTD(); err != nil {
|
||||||
return fmt.Errorf("error reading total difficulty: %w", err)
|
return fmt.Errorf("error reading total difficulty: %w", err)
|
||||||
}
|
}
|
||||||
it, err := era.NewIterator(e)
|
it, err := e.Iterator()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error making era iterator: %w", err)
|
return fmt.Errorf("error making era iterator: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -290,9 +354,13 @@ func checkAccumulator(e *era.Era) error {
|
||||||
if rr != block.ReceiptHash() {
|
if rr != block.ReceiptHash() {
|
||||||
return fmt.Errorf("receipt root in block %d mismatch: want %s, got %s", block.NumberU64(), block.ReceiptHash(), rr)
|
return fmt.Errorf("receipt root in block %d mismatch: want %s, got %s", block.NumberU64(), block.ReceiptHash(), rr)
|
||||||
}
|
}
|
||||||
hashes = append(hashes, block.Hash())
|
// Only include pre-merge blocks in accumulator calculation.
|
||||||
td.Add(td, block.Difficulty())
|
// Post-merge blocks have difficulty == 0.
|
||||||
tds = append(tds, new(big.Int).Set(td))
|
if block.Difficulty().Sign() > 0 {
|
||||||
|
hashes = append(hashes, block.Hash())
|
||||||
|
td.Add(td, block.Difficulty())
|
||||||
|
tds = append(tds, new(big.Int).Set(td))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if it.Error() != nil {
|
if it.Error() != nil {
|
||||||
return fmt.Errorf("error reading block %d: %w", it.Number(), it.Error())
|
return fmt.Errorf("error reading block %d: %w", it.Number(), it.Error())
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ type header struct {
|
||||||
BlobGasUsed *uint64 `json:"blobGasUsed" rlp:"optional"`
|
BlobGasUsed *uint64 `json:"blobGasUsed" rlp:"optional"`
|
||||||
ExcessBlobGas *uint64 `json:"excessBlobGas" rlp:"optional"`
|
ExcessBlobGas *uint64 `json:"excessBlobGas" rlp:"optional"`
|
||||||
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
||||||
|
SlotNumber *uint64 `json:"slotNumber" rlp:"optional"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type headerMarshaling struct {
|
type headerMarshaling struct {
|
||||||
|
|
@ -68,6 +69,7 @@ type headerMarshaling struct {
|
||||||
BaseFee *math.HexOrDecimal256
|
BaseFee *math.HexOrDecimal256
|
||||||
BlobGasUsed *math.HexOrDecimal64
|
BlobGasUsed *math.HexOrDecimal64
|
||||||
ExcessBlobGas *math.HexOrDecimal64
|
ExcessBlobGas *math.HexOrDecimal64
|
||||||
|
SlotNumber *math.HexOrDecimal64
|
||||||
}
|
}
|
||||||
|
|
||||||
type bbInput struct {
|
type bbInput struct {
|
||||||
|
|
@ -136,6 +138,7 @@ func (i *bbInput) ToBlock() *types.Block {
|
||||||
BlobGasUsed: i.Header.BlobGasUsed,
|
BlobGasUsed: i.Header.BlobGasUsed,
|
||||||
ExcessBlobGas: i.Header.ExcessBlobGas,
|
ExcessBlobGas: i.Header.ExcessBlobGas,
|
||||||
ParentBeaconRoot: i.Header.ParentBeaconBlockRoot,
|
ParentBeaconRoot: i.Header.ParentBeaconBlockRoot,
|
||||||
|
SlotNumber: i.Header.SlotNumber,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill optional values.
|
// Fill optional values.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -100,6 +102,7 @@ type stEnv struct {
|
||||||
ParentExcessBlobGas *uint64 `json:"parentExcessBlobGas,omitempty"`
|
ParentExcessBlobGas *uint64 `json:"parentExcessBlobGas,omitempty"`
|
||||||
ParentBlobGasUsed *uint64 `json:"parentBlobGasUsed,omitempty"`
|
ParentBlobGasUsed *uint64 `json:"parentBlobGasUsed,omitempty"`
|
||||||
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||||
|
SlotNumber *uint64 `json:"slotNumber"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type stEnvMarshaling struct {
|
type stEnvMarshaling struct {
|
||||||
|
|
@ -118,6 +121,7 @@ type stEnvMarshaling struct {
|
||||||
ExcessBlobGas *math.HexOrDecimal64
|
ExcessBlobGas *math.HexOrDecimal64
|
||||||
ParentExcessBlobGas *math.HexOrDecimal64
|
ParentExcessBlobGas *math.HexOrDecimal64
|
||||||
ParentBlobGasUsed *math.HexOrDecimal64
|
ParentBlobGasUsed *math.HexOrDecimal64
|
||||||
|
SlotNumber *math.HexOrDecimal64
|
||||||
}
|
}
|
||||||
|
|
||||||
type rejectedTx struct {
|
type rejectedTx struct {
|
||||||
|
|
@ -142,7 +146,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}
|
||||||
|
|
@ -192,6 +197,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
ExcessBlobGas: pre.Env.ParentExcessBlobGas,
|
ExcessBlobGas: pre.Env.ParentExcessBlobGas,
|
||||||
BlobGasUsed: pre.Env.ParentBlobGasUsed,
|
BlobGasUsed: pre.Env.ParentBlobGasUsed,
|
||||||
BaseFee: pre.Env.ParentBaseFee,
|
BaseFee: pre.Env.ParentBaseFee,
|
||||||
|
SlotNumber: pre.Env.SlotNumber,
|
||||||
}
|
}
|
||||||
header := &types.Header{
|
header := &types.Header{
|
||||||
Time: pre.Env.Timestamp,
|
Time: pre.Env.Timestamp,
|
||||||
|
|
@ -262,6 +268,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
gaspool.SetGas(prevGas)
|
gaspool.SetGas(prevGas)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if receipt.Logs == nil {
|
||||||
|
receipt.Logs = []*types.Log{}
|
||||||
|
}
|
||||||
includedTxs = append(includedTxs, tx)
|
includedTxs = append(includedTxs, tx)
|
||||||
if hashError != nil {
|
if hashError != nil {
|
||||||
return nil, nil, nil, NewError(ErrorMissingBlockhash, hashError)
|
return nil, nil, nil, NewError(ErrorMissingBlockhash, hashError)
|
||||||
|
|
@ -301,6 +310,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 +374,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 +383,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 +404,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 +420,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
|
||||||
|
|
|
||||||
|
|
@ -56,27 +56,35 @@ func (l *fileWritingTracer) Write(p []byte) (n int, err error) {
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// newFileWriter creates a set of hooks which wraps inner hooks (typically a logger),
|
// newFileWriter creates a tracer which wraps inner hooks (typically a logger),
|
||||||
// and writes the output to a file, one file per transaction.
|
// and writes the output to a file, one file per transaction.
|
||||||
func newFileWriter(baseDir string, innerFn func(out io.Writer) *tracing.Hooks) *tracing.Hooks {
|
func newFileWriter(baseDir string, innerFn func(out io.Writer) *tracing.Hooks) *tracers.Tracer {
|
||||||
t := &fileWritingTracer{
|
t := &fileWritingTracer{
|
||||||
baseDir: baseDir,
|
baseDir: baseDir,
|
||||||
suffix: "jsonl",
|
suffix: "jsonl",
|
||||||
}
|
}
|
||||||
t.inner = innerFn(t) // instantiate the inner tracer
|
t.inner = innerFn(t) // instantiate the inner tracer
|
||||||
return t.hooks()
|
return &tracers.Tracer{
|
||||||
|
Hooks: t.hooks(),
|
||||||
|
GetResult: func() (json.RawMessage, error) { return json.RawMessage("{}"), nil },
|
||||||
|
Stop: func(err error) {},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// newResultWriter creates a set of hooks wraps and invokes an underlying tracer,
|
// newResultWriter creates a tracer that wraps and invokes an underlying tracer,
|
||||||
// and writes the result (getResult-output) to file, one per transaction.
|
// and writes the result (getResult-output) to file, one per transaction.
|
||||||
func newResultWriter(baseDir string, tracer *tracers.Tracer) *tracing.Hooks {
|
func newResultWriter(baseDir string, tracer *tracers.Tracer) *tracers.Tracer {
|
||||||
t := &fileWritingTracer{
|
t := &fileWritingTracer{
|
||||||
baseDir: baseDir,
|
baseDir: baseDir,
|
||||||
getResult: tracer.GetResult,
|
getResult: tracer.GetResult,
|
||||||
inner: tracer.Hooks,
|
inner: tracer.Hooks,
|
||||||
suffix: "json",
|
suffix: "json",
|
||||||
}
|
}
|
||||||
return t.hooks()
|
return &tracers.Tracer{
|
||||||
|
Hooks: t.hooks(),
|
||||||
|
GetResult: func() (json.RawMessage, error) { return json.RawMessage("{}"), nil },
|
||||||
|
Stop: func(err error) {},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnTxStart creates a new output-file specific for this transaction, and invokes
|
// OnTxStart creates a new output-file specific for this transaction, and invokes
|
||||||
|
|
|
||||||
|
|
@ -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.",
|
||||||
|
|
@ -149,6 +162,11 @@ var (
|
||||||
strings.Join(vm.ActivateableEips(), ", ")),
|
strings.Join(vm.ActivateableEips(), ", ")),
|
||||||
Value: "GrayGlacier",
|
Value: "GrayGlacier",
|
||||||
}
|
}
|
||||||
|
OpcodeCountFlag = &cli.StringFlag{
|
||||||
|
Name: "opcode.count",
|
||||||
|
Usage: "If set, opcode execution counts will be written to this file (relative to output.basedir).",
|
||||||
|
Value: "",
|
||||||
|
}
|
||||||
VerbosityFlag = &cli.IntFlag{
|
VerbosityFlag = &cli.IntFlag{
|
||||||
Name: "verbosity",
|
Name: "verbosity",
|
||||||
Usage: "sets the verbosity level",
|
Usage: "sets the verbosity level",
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ func (h header) MarshalJSON() ([]byte, error) {
|
||||||
BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed" rlp:"optional"`
|
BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed" rlp:"optional"`
|
||||||
ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas" rlp:"optional"`
|
ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas" rlp:"optional"`
|
||||||
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
||||||
|
SlotNumber *math.HexOrDecimal64 `json:"slotNumber" rlp:"optional"`
|
||||||
}
|
}
|
||||||
var enc header
|
var enc header
|
||||||
enc.ParentHash = h.ParentHash
|
enc.ParentHash = h.ParentHash
|
||||||
|
|
@ -60,6 +61,7 @@ func (h header) MarshalJSON() ([]byte, error) {
|
||||||
enc.BlobGasUsed = (*math.HexOrDecimal64)(h.BlobGasUsed)
|
enc.BlobGasUsed = (*math.HexOrDecimal64)(h.BlobGasUsed)
|
||||||
enc.ExcessBlobGas = (*math.HexOrDecimal64)(h.ExcessBlobGas)
|
enc.ExcessBlobGas = (*math.HexOrDecimal64)(h.ExcessBlobGas)
|
||||||
enc.ParentBeaconBlockRoot = h.ParentBeaconBlockRoot
|
enc.ParentBeaconBlockRoot = h.ParentBeaconBlockRoot
|
||||||
|
enc.SlotNumber = (*math.HexOrDecimal64)(h.SlotNumber)
|
||||||
return json.Marshal(&enc)
|
return json.Marshal(&enc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,6 +88,7 @@ func (h *header) UnmarshalJSON(input []byte) error {
|
||||||
BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed" rlp:"optional"`
|
BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed" rlp:"optional"`
|
||||||
ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas" rlp:"optional"`
|
ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas" rlp:"optional"`
|
||||||
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
||||||
|
SlotNumber *math.HexOrDecimal64 `json:"slotNumber" rlp:"optional"`
|
||||||
}
|
}
|
||||||
var dec header
|
var dec header
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
|
@ -155,5 +158,8 @@ func (h *header) UnmarshalJSON(input []byte) error {
|
||||||
if dec.ParentBeaconBlockRoot != nil {
|
if dec.ParentBeaconBlockRoot != nil {
|
||||||
h.ParentBeaconBlockRoot = dec.ParentBeaconBlockRoot
|
h.ParentBeaconBlockRoot = dec.ParentBeaconBlockRoot
|
||||||
}
|
}
|
||||||
|
if dec.SlotNumber != nil {
|
||||||
|
h.SlotNumber = (*uint64)(dec.SlotNumber)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ func (s stEnv) MarshalJSON() ([]byte, error) {
|
||||||
ParentExcessBlobGas *math.HexOrDecimal64 `json:"parentExcessBlobGas,omitempty"`
|
ParentExcessBlobGas *math.HexOrDecimal64 `json:"parentExcessBlobGas,omitempty"`
|
||||||
ParentBlobGasUsed *math.HexOrDecimal64 `json:"parentBlobGasUsed,omitempty"`
|
ParentBlobGasUsed *math.HexOrDecimal64 `json:"parentBlobGasUsed,omitempty"`
|
||||||
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||||
|
SlotNumber *math.HexOrDecimal64 `json:"slotNumber"`
|
||||||
}
|
}
|
||||||
var enc stEnv
|
var enc stEnv
|
||||||
enc.Coinbase = common.UnprefixedAddress(s.Coinbase)
|
enc.Coinbase = common.UnprefixedAddress(s.Coinbase)
|
||||||
|
|
@ -59,6 +60,7 @@ func (s stEnv) MarshalJSON() ([]byte, error) {
|
||||||
enc.ParentExcessBlobGas = (*math.HexOrDecimal64)(s.ParentExcessBlobGas)
|
enc.ParentExcessBlobGas = (*math.HexOrDecimal64)(s.ParentExcessBlobGas)
|
||||||
enc.ParentBlobGasUsed = (*math.HexOrDecimal64)(s.ParentBlobGasUsed)
|
enc.ParentBlobGasUsed = (*math.HexOrDecimal64)(s.ParentBlobGasUsed)
|
||||||
enc.ParentBeaconBlockRoot = s.ParentBeaconBlockRoot
|
enc.ParentBeaconBlockRoot = s.ParentBeaconBlockRoot
|
||||||
|
enc.SlotNumber = (*math.HexOrDecimal64)(s.SlotNumber)
|
||||||
return json.Marshal(&enc)
|
return json.Marshal(&enc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,6 +87,7 @@ func (s *stEnv) UnmarshalJSON(input []byte) error {
|
||||||
ParentExcessBlobGas *math.HexOrDecimal64 `json:"parentExcessBlobGas,omitempty"`
|
ParentExcessBlobGas *math.HexOrDecimal64 `json:"parentExcessBlobGas,omitempty"`
|
||||||
ParentBlobGasUsed *math.HexOrDecimal64 `json:"parentBlobGasUsed,omitempty"`
|
ParentBlobGasUsed *math.HexOrDecimal64 `json:"parentBlobGasUsed,omitempty"`
|
||||||
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||||
|
SlotNumber *math.HexOrDecimal64 `json:"slotNumber"`
|
||||||
}
|
}
|
||||||
var dec stEnv
|
var dec stEnv
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
|
@ -154,5 +157,8 @@ func (s *stEnv) UnmarshalJSON(input []byte) error {
|
||||||
if dec.ParentBeaconBlockRoot != nil {
|
if dec.ParentBeaconBlockRoot != nil {
|
||||||
s.ParentBeaconBlockRoot = dec.ParentBeaconBlockRoot
|
s.ParentBeaconBlockRoot = dec.ParentBeaconBlockRoot
|
||||||
}
|
}
|
||||||
|
if dec.SlotNumber != nil {
|
||||||
|
s.SlotNumber = (*uint64)(dec.SlotNumber)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,9 +115,6 @@ func Transaction(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
var results []result
|
var results []result
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
if err := it.Err(); err != nil {
|
|
||||||
return NewError(ErrorIO, err)
|
|
||||||
}
|
|
||||||
var tx types.Transaction
|
var tx types.Transaction
|
||||||
err := rlp.DecodeBytes(it.Value(), &tx)
|
err := rlp.DecodeBytes(it.Value(), &tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -188,6 +185,10 @@ func Transaction(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
results = append(results, r)
|
results = append(results, r)
|
||||||
}
|
}
|
||||||
|
if err := it.Err(); err != nil {
|
||||||
|
return NewError(ErrorIO, err)
|
||||||
|
}
|
||||||
|
|
||||||
out, err := json.MarshalIndent(results, "", " ")
|
out, err := json.MarshalIndent(results, "", " ")
|
||||||
fmt.Println(string(out))
|
fmt.Println(string(out))
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -28,15 +28,23 @@ 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/eth/tracers/native"
|
||||||
"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 +83,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 +99,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 +121,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
|
||||||
|
|
@ -152,14 +168,15 @@ func Transition(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure tracer
|
// Configure tracer
|
||||||
|
var tracer *tracers.Tracer
|
||||||
if ctx.IsSet(TraceTracerFlag.Name) { // Custom tracing
|
if ctx.IsSet(TraceTracerFlag.Name) { // Custom tracing
|
||||||
config := json.RawMessage(ctx.String(TraceTracerConfigFlag.Name))
|
config := json.RawMessage(ctx.String(TraceTracerConfigFlag.Name))
|
||||||
tracer, err := tracers.DefaultDirectory.New(ctx.String(TraceTracerFlag.Name),
|
innerTracer, err := tracers.DefaultDirectory.New(ctx.String(TraceTracerFlag.Name),
|
||||||
nil, config, chainConfig)
|
nil, config, chainConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return NewError(ErrorConfig, fmt.Errorf("failed instantiating tracer: %v", err))
|
return NewError(ErrorConfig, fmt.Errorf("failed instantiating tracer: %v", err))
|
||||||
}
|
}
|
||||||
vmConfig.Tracer = newResultWriter(baseDir, tracer)
|
tracer = newResultWriter(baseDir, innerTracer)
|
||||||
} else if ctx.Bool(TraceFlag.Name) { // JSON opcode tracing
|
} else if ctx.Bool(TraceFlag.Name) { // JSON opcode tracing
|
||||||
logConfig := &logger.Config{
|
logConfig := &logger.Config{
|
||||||
DisableStack: ctx.Bool(TraceDisableStackFlag.Name),
|
DisableStack: ctx.Bool(TraceDisableStackFlag.Name),
|
||||||
|
|
@ -167,24 +184,61 @@ func Transition(ctx *cli.Context) error {
|
||||||
EnableReturnData: ctx.Bool(TraceEnableReturnDataFlag.Name),
|
EnableReturnData: ctx.Bool(TraceEnableReturnDataFlag.Name),
|
||||||
}
|
}
|
||||||
if ctx.Bool(TraceEnableCallFramesFlag.Name) {
|
if ctx.Bool(TraceEnableCallFramesFlag.Name) {
|
||||||
vmConfig.Tracer = newFileWriter(baseDir, func(out io.Writer) *tracing.Hooks {
|
tracer = newFileWriter(baseDir, func(out io.Writer) *tracing.Hooks {
|
||||||
return logger.NewJSONLoggerWithCallFrames(logConfig, out)
|
return logger.NewJSONLoggerWithCallFrames(logConfig, out)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
vmConfig.Tracer = newFileWriter(baseDir, func(out io.Writer) *tracing.Hooks {
|
tracer = newFileWriter(baseDir, func(out io.Writer) *tracing.Hooks {
|
||||||
return logger.NewJSONLogger(logConfig, out)
|
return logger.NewJSONLogger(logConfig, out)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Configure opcode counter
|
||||||
|
var opcodeTracer *tracers.Tracer
|
||||||
|
if ctx.IsSet(OpcodeCountFlag.Name) && ctx.String(OpcodeCountFlag.Name) != "" {
|
||||||
|
opcodeTracer = native.NewOpcodeCounter()
|
||||||
|
if tracer != nil {
|
||||||
|
// If we have an existing tracer, multiplex with the opcode tracer
|
||||||
|
mux, _ := native.NewMuxTracer([]string{"trace", "opcode"}, []*tracers.Tracer{tracer, opcodeTracer})
|
||||||
|
vmConfig.Tracer = mux.Hooks
|
||||||
|
} else {
|
||||||
|
vmConfig.Tracer = opcodeTracer.Hooks
|
||||||
|
}
|
||||||
|
} else if tracer != nil {
|
||||||
|
vmConfig.Tracer = tracer.Hooks
|
||||||
|
}
|
||||||
// Run the test and aggregate the result
|
// Run the test and aggregate the result
|
||||||
s, result, body, err := prestate.Apply(vmConfig, chainConfig, txIt, ctx.Int64(RewardFlag.Name))
|
s, result, body, err := prestate.Apply(vmConfig, chainConfig, txIt, ctx.Int64(RewardFlag.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// Write opcode counts if enabled
|
||||||
|
if opcodeTracer != nil {
|
||||||
|
fname := ctx.String(OpcodeCountFlag.Name)
|
||||||
|
result, err := opcodeTracer.GetResult()
|
||||||
|
if err != nil {
|
||||||
|
return NewError(ErrorJson, fmt.Errorf("failed getting opcode counts: %v", err))
|
||||||
|
}
|
||||||
|
if err := saveFile(baseDir, fname, result); err != nil {
|
||||||
|
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 +360,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 +387,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 +412,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,64 @@ 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,
|
||||||
|
t8ntool.OpcodeCountFlag,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 +263,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)
|
||||||
|
|
|
||||||
2
cmd/evm/testdata/1/exp.json
vendored
2
cmd/evm/testdata/1/exp.json
vendored
|
|
@ -24,7 +24,7 @@
|
||||||
"status": "0x1",
|
"status": "0x1",
|
||||||
"cumulativeGasUsed": "0x5208",
|
"cumulativeGasUsed": "0x5208",
|
||||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"logs": null,
|
"logs": [],
|
||||||
"transactionHash": "0x0557bacce3375c98d806609b8d5043072f0b6a8bae45ae5a67a00d3a1a18d673",
|
"transactionHash": "0x0557bacce3375c98d806609b8d5043072f0b6a8bae45ae5a67a00d3a1a18d673",
|
||||||
"contractAddress": "0x0000000000000000000000000000000000000000",
|
"contractAddress": "0x0000000000000000000000000000000000000000",
|
||||||
"gasUsed": "0x5208",
|
"gasUsed": "0x5208",
|
||||||
|
|
|
||||||
4
cmd/evm/testdata/13/exp2.json
vendored
4
cmd/evm/testdata/13/exp2.json
vendored
|
|
@ -12,7 +12,7 @@
|
||||||
"status": "0x0",
|
"status": "0x0",
|
||||||
"cumulativeGasUsed": "0x84d0",
|
"cumulativeGasUsed": "0x84d0",
|
||||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"logs": null,
|
"logs": [],
|
||||||
"transactionHash": "0xa98a24882ea90916c6a86da650fbc6b14238e46f0af04a131ce92be897507476",
|
"transactionHash": "0xa98a24882ea90916c6a86da650fbc6b14238e46f0af04a131ce92be897507476",
|
||||||
"contractAddress": "0x0000000000000000000000000000000000000000",
|
"contractAddress": "0x0000000000000000000000000000000000000000",
|
||||||
"gasUsed": "0x84d0",
|
"gasUsed": "0x84d0",
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
"status": "0x0",
|
"status": "0x0",
|
||||||
"cumulativeGasUsed": "0x109a0",
|
"cumulativeGasUsed": "0x109a0",
|
||||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"logs": null,
|
"logs": [],
|
||||||
"transactionHash": "0x36bad80acce7040c45fd32764b5c2b2d2e6f778669fb41791f73f546d56e739a",
|
"transactionHash": "0x36bad80acce7040c45fd32764b5c2b2d2e6f778669fb41791f73f546d56e739a",
|
||||||
"contractAddress": "0x0000000000000000000000000000000000000000",
|
"contractAddress": "0x0000000000000000000000000000000000000000",
|
||||||
"gasUsed": "0x84d0",
|
"gasUsed": "0x84d0",
|
||||||
|
|
|
||||||
2
cmd/evm/testdata/23/exp.json
vendored
2
cmd/evm/testdata/23/exp.json
vendored
|
|
@ -11,7 +11,7 @@
|
||||||
"status": "0x1",
|
"status": "0x1",
|
||||||
"cumulativeGasUsed": "0x520b",
|
"cumulativeGasUsed": "0x520b",
|
||||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"logs": null,
|
"logs": [],
|
||||||
"transactionHash": "0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81",
|
"transactionHash": "0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81",
|
||||||
"contractAddress": "0x0000000000000000000000000000000000000000",
|
"contractAddress": "0x0000000000000000000000000000000000000000",
|
||||||
"gasUsed": "0x520b",
|
"gasUsed": "0x520b",
|
||||||
|
|
|
||||||
4
cmd/evm/testdata/24/exp.json
vendored
4
cmd/evm/testdata/24/exp.json
vendored
|
|
@ -27,7 +27,7 @@
|
||||||
"status": "0x1",
|
"status": "0x1",
|
||||||
"cumulativeGasUsed": "0xa861",
|
"cumulativeGasUsed": "0xa861",
|
||||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"logs": null,
|
"logs": [],
|
||||||
"transactionHash": "0x92ea4a28224d033afb20e0cc2b290d4c7c2d61f6a4800a680e4e19ac962ee941",
|
"transactionHash": "0x92ea4a28224d033afb20e0cc2b290d4c7c2d61f6a4800a680e4e19ac962ee941",
|
||||||
"contractAddress": "0x0000000000000000000000000000000000000000",
|
"contractAddress": "0x0000000000000000000000000000000000000000",
|
||||||
"gasUsed": "0xa861",
|
"gasUsed": "0xa861",
|
||||||
|
|
@ -41,7 +41,7 @@
|
||||||
"status": "0x1",
|
"status": "0x1",
|
||||||
"cumulativeGasUsed": "0x10306",
|
"cumulativeGasUsed": "0x10306",
|
||||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"logs": null,
|
"logs": [],
|
||||||
"transactionHash": "0x16b1d912f1d664f3f60f4e1b5f296f3c82a64a1a253117b4851d18bc03c4f1da",
|
"transactionHash": "0x16b1d912f1d664f3f60f4e1b5f296f3c82a64a1a253117b4851d18bc03c4f1da",
|
||||||
"contractAddress": "0x0000000000000000000000000000000000000000",
|
"contractAddress": "0x0000000000000000000000000000000000000000",
|
||||||
"gasUsed": "0x5aa5",
|
"gasUsed": "0x5aa5",
|
||||||
|
|
|
||||||
2
cmd/evm/testdata/25/exp.json
vendored
2
cmd/evm/testdata/25/exp.json
vendored
|
|
@ -23,7 +23,7 @@
|
||||||
"status": "0x1",
|
"status": "0x1",
|
||||||
"cumulativeGasUsed": "0x5208",
|
"cumulativeGasUsed": "0x5208",
|
||||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"logs": null,
|
"logs": [],
|
||||||
"transactionHash": "0x92ea4a28224d033afb20e0cc2b290d4c7c2d61f6a4800a680e4e19ac962ee941",
|
"transactionHash": "0x92ea4a28224d033afb20e0cc2b290d4c7c2d61f6a4800a680e4e19ac962ee941",
|
||||||
"contractAddress": "0x0000000000000000000000000000000000000000",
|
"contractAddress": "0x0000000000000000000000000000000000000000",
|
||||||
"gasUsed": "0x5208",
|
"gasUsed": "0x5208",
|
||||||
|
|
|
||||||
2
cmd/evm/testdata/28/exp.json
vendored
2
cmd/evm/testdata/28/exp.json
vendored
|
|
@ -28,7 +28,7 @@
|
||||||
"status": "0x1",
|
"status": "0x1",
|
||||||
"cumulativeGasUsed": "0xa865",
|
"cumulativeGasUsed": "0xa865",
|
||||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"logs": null,
|
"logs": [],
|
||||||
"transactionHash": "0x7508d7139d002a4b3a26a4f12dec0d87cb46075c78bf77a38b569a133b509262",
|
"transactionHash": "0x7508d7139d002a4b3a26a4f12dec0d87cb46075c78bf77a38b569a133b509262",
|
||||||
"contractAddress": "0x0000000000000000000000000000000000000000",
|
"contractAddress": "0x0000000000000000000000000000000000000000",
|
||||||
"gasUsed": "0xa865",
|
"gasUsed": "0xa865",
|
||||||
|
|
|
||||||
2
cmd/evm/testdata/29/exp.json
vendored
2
cmd/evm/testdata/29/exp.json
vendored
|
|
@ -26,7 +26,7 @@
|
||||||
"status": "0x1",
|
"status": "0x1",
|
||||||
"cumulativeGasUsed": "0x5208",
|
"cumulativeGasUsed": "0x5208",
|
||||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"logs": null,
|
"logs": [],
|
||||||
"transactionHash": "0x84f70aba406a55628a0620f26d260f90aeb6ccc55fed6ec2ac13dd4f727032ed",
|
"transactionHash": "0x84f70aba406a55628a0620f26d260f90aeb6ccc55fed6ec2ac13dd4f727032ed",
|
||||||
"contractAddress": "0x0000000000000000000000000000000000000000",
|
"contractAddress": "0x0000000000000000000000000000000000000000",
|
||||||
"gasUsed": "0x5208",
|
"gasUsed": "0x5208",
|
||||||
|
|
|
||||||
2
cmd/evm/testdata/3/exp.json
vendored
2
cmd/evm/testdata/3/exp.json
vendored
|
|
@ -24,7 +24,7 @@
|
||||||
"status": "0x1",
|
"status": "0x1",
|
||||||
"cumulativeGasUsed": "0x521f",
|
"cumulativeGasUsed": "0x521f",
|
||||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"logs": null,
|
"logs": [],
|
||||||
"transactionHash": "0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81",
|
"transactionHash": "0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81",
|
||||||
"contractAddress": "0x0000000000000000000000000000000000000000",
|
"contractAddress": "0x0000000000000000000000000000000000000000",
|
||||||
"gasUsed": "0x521f",
|
"gasUsed": "0x521f",
|
||||||
|
|
|
||||||
4
cmd/evm/testdata/30/exp.json
vendored
4
cmd/evm/testdata/30/exp.json
vendored
|
|
@ -25,7 +25,7 @@
|
||||||
"status": "0x1",
|
"status": "0x1",
|
||||||
"cumulativeGasUsed": "0x5208",
|
"cumulativeGasUsed": "0x5208",
|
||||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"logs": null,
|
"logs": [],
|
||||||
"transactionHash": "0xa98a24882ea90916c6a86da650fbc6b14238e46f0af04a131ce92be897507476",
|
"transactionHash": "0xa98a24882ea90916c6a86da650fbc6b14238e46f0af04a131ce92be897507476",
|
||||||
"contractAddress": "0x0000000000000000000000000000000000000000",
|
"contractAddress": "0x0000000000000000000000000000000000000000",
|
||||||
"gasUsed": "0x5208",
|
"gasUsed": "0x5208",
|
||||||
|
|
@ -40,7 +40,7 @@
|
||||||
"status": "0x1",
|
"status": "0x1",
|
||||||
"cumulativeGasUsed": "0xa410",
|
"cumulativeGasUsed": "0xa410",
|
||||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"logs": null,
|
"logs": [],
|
||||||
"transactionHash": "0x36bad80acce7040c45fd32764b5c2b2d2e6f778669fb41791f73f546d56e739a",
|
"transactionHash": "0x36bad80acce7040c45fd32764b5c2b2d2e6f778669fb41791f73f546d56e739a",
|
||||||
"contractAddress": "0x0000000000000000000000000000000000000000",
|
"contractAddress": "0x0000000000000000000000000000000000000000",
|
||||||
"gasUsed": "0x5208",
|
"gasUsed": "0x5208",
|
||||||
|
|
|
||||||
2
cmd/evm/testdata/33/exp.json
vendored
2
cmd/evm/testdata/33/exp.json
vendored
|
|
@ -44,7 +44,7 @@
|
||||||
"root": "0x",
|
"root": "0x",
|
||||||
"status": "0x1",
|
"status": "0x1",
|
||||||
"cumulativeGasUsed": "0x15fa9",
|
"cumulativeGasUsed": "0x15fa9",
|
||||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","logs": null,"transactionHash": "0x0417aab7c1d8a3989190c3167c132876ce9b8afd99262c5a0f9d06802de3d7ef",
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","logs": [],"transactionHash": "0x0417aab7c1d8a3989190c3167c132876ce9b8afd99262c5a0f9d06802de3d7ef",
|
||||||
"contractAddress": "0x0000000000000000000000000000000000000000",
|
"contractAddress": "0x0000000000000000000000000000000000000000",
|
||||||
"gasUsed": "0x15fa9",
|
"gasUsed": "0x15fa9",
|
||||||
"effectiveGasPrice": null,
|
"effectiveGasPrice": null,
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
@ -43,6 +44,8 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/internal/debug"
|
"github.com/ethereum/go-ethereum/internal/debug"
|
||||||
"github.com/ethereum/go-ethereum/internal/era"
|
"github.com/ethereum/go-ethereum/internal/era"
|
||||||
"github.com/ethereum/go-ethereum/internal/era/eradl"
|
"github.com/ethereum/go-ethereum/internal/era/eradl"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/era/execdb"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/era/onedb"
|
||||||
"github.com/ethereum/go-ethereum/internal/flags"
|
"github.com/ethereum/go-ethereum/internal/flags"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
|
|
@ -96,6 +99,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,
|
||||||
|
|
@ -107,6 +111,7 @@ if one is set. Otherwise it prints the genesis from the datadir.`,
|
||||||
utils.MetricsInfluxDBUsernameFlag,
|
utils.MetricsInfluxDBUsernameFlag,
|
||||||
utils.MetricsInfluxDBPasswordFlag,
|
utils.MetricsInfluxDBPasswordFlag,
|
||||||
utils.MetricsInfluxDBTagsFlag,
|
utils.MetricsInfluxDBTagsFlag,
|
||||||
|
utils.MetricsInfluxDBIntervalFlag,
|
||||||
utils.MetricsInfluxDBTokenFlag,
|
utils.MetricsInfluxDBTokenFlag,
|
||||||
utils.MetricsInfluxDBBucketFlag,
|
utils.MetricsInfluxDBBucketFlag,
|
||||||
utils.MetricsInfluxDBOrganizationFlag,
|
utils.MetricsInfluxDBOrganizationFlag,
|
||||||
|
|
@ -119,6 +124,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)
|
||||||
|
|
@ -150,7 +157,7 @@ be gzipped.`,
|
||||||
Name: "import-history",
|
Name: "import-history",
|
||||||
Usage: "Import an Era archive",
|
Usage: "Import an Era archive",
|
||||||
ArgsUsage: "<dir>",
|
ArgsUsage: "<dir>",
|
||||||
Flags: slices.Concat([]cli.Flag{utils.TxLookupLimitFlag, utils.TransactionHistoryFlag}, utils.DatabaseFlags, utils.NetworkFlags),
|
Flags: slices.Concat([]cli.Flag{utils.TxLookupLimitFlag, utils.TransactionHistoryFlag, utils.EraFormatFlag}, utils.DatabaseFlags, utils.NetworkFlags),
|
||||||
Description: `
|
Description: `
|
||||||
The import-history command will import blocks and their corresponding receipts
|
The import-history command will import blocks and their corresponding receipts
|
||||||
from Era archives.
|
from Era archives.
|
||||||
|
|
@ -161,7 +168,7 @@ from Era archives.
|
||||||
Name: "export-history",
|
Name: "export-history",
|
||||||
Usage: "Export blockchain history to Era archives",
|
Usage: "Export blockchain history to Era archives",
|
||||||
ArgsUsage: "<dir> <first> <last>",
|
ArgsUsage: "<dir> <first> <last>",
|
||||||
Flags: utils.DatabaseFlags,
|
Flags: slices.Concat([]cli.Flag{utils.EraFormatFlag}, utils.DatabaseFlags),
|
||||||
Description: `
|
Description: `
|
||||||
The export-history command will export blocks and their corresponding receipts
|
The export-history command will export blocks and their corresponding receipts
|
||||||
into Era archives. Eras are typically packaged in steps of 8192 blocks.
|
into Era archives. Eras are typically packaged in steps of 8192 blocks.
|
||||||
|
|
@ -295,7 +302,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)
|
||||||
}
|
}
|
||||||
|
|
@ -513,15 +520,27 @@ func importHistory(ctx *cli.Context) error {
|
||||||
network = networks[0]
|
network = networks[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := utils.ImportHistory(chain, dir, network); err != nil {
|
var (
|
||||||
|
format = ctx.String(utils.EraFormatFlag.Name)
|
||||||
|
from func(era.ReadAtSeekCloser) (era.Era, error)
|
||||||
|
)
|
||||||
|
switch format {
|
||||||
|
case "era1", "era":
|
||||||
|
from = onedb.From
|
||||||
|
case "erae":
|
||||||
|
from = execdb.From
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown --era.format %q (expected 'era1' or 'erae')", format)
|
||||||
|
}
|
||||||
|
if err := utils.ImportHistory(chain, dir, network, from); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Import done in %v\n", time.Since(start))
|
fmt.Printf("Import done in %v\n", time.Since(start))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// exportHistory exports chain history in Era archives at a specified
|
// exportHistory exports chain history in Era archives at a specified directory.
|
||||||
// directory.
|
|
||||||
func exportHistory(ctx *cli.Context) error {
|
func exportHistory(ctx *cli.Context) error {
|
||||||
if ctx.Args().Len() != 3 {
|
if ctx.Args().Len() != 3 {
|
||||||
utils.Fatalf("usage: %s", ctx.Command.ArgsUsage)
|
utils.Fatalf("usage: %s", ctx.Command.ArgsUsage)
|
||||||
|
|
@ -547,10 +566,26 @@ func exportHistory(ctx *cli.Context) error {
|
||||||
if head := chain.CurrentSnapBlock(); uint64(last) > head.Number.Uint64() {
|
if head := chain.CurrentSnapBlock(); uint64(last) > head.Number.Uint64() {
|
||||||
utils.Fatalf("Export error: block number %d larger than head block %d\n", uint64(last), head.Number.Uint64())
|
utils.Fatalf("Export error: block number %d larger than head block %d\n", uint64(last), head.Number.Uint64())
|
||||||
}
|
}
|
||||||
err := utils.ExportHistory(chain, dir, uint64(first), uint64(last), uint64(era.MaxEra1Size))
|
|
||||||
if err != nil {
|
var (
|
||||||
|
format = ctx.String(utils.EraFormatFlag.Name)
|
||||||
|
filename func(network string, epoch int, root common.Hash) string
|
||||||
|
newBuilder func(w io.Writer) era.Builder
|
||||||
|
)
|
||||||
|
switch format {
|
||||||
|
case "era1", "era":
|
||||||
|
newBuilder = func(w io.Writer) era.Builder { return onedb.NewBuilder(w) }
|
||||||
|
filename = func(network string, epoch int, root common.Hash) string { return onedb.Filename(network, epoch, root) }
|
||||||
|
case "erae":
|
||||||
|
newBuilder = func(w io.Writer) era.Builder { return execdb.NewBuilder(w) }
|
||||||
|
filename = func(network string, epoch int, root common.Hash) string { return execdb.Filename(network, epoch, root) }
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown archive format %q (use 'era1' or 'erae')", format)
|
||||||
|
}
|
||||||
|
if err := utils.ExportHistory(chain, dir, uint64(first), uint64(last), newBuilder, filename); err != nil {
|
||||||
utils.Fatalf("Export error: %v\n", err)
|
utils.Fatalf("Export error: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Export done in %v\n", time.Since(start))
|
fmt.Printf("Export done in %v\n", time.Since(start))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,11 +35,11 @@ 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"
|
||||||
"github.com/ethereum/go-ethereum/internal/flags"
|
"github.com/ethereum/go-ethereum/internal/flags"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/telemetry/tracesetup"
|
||||||
"github.com/ethereum/go-ethereum/internal/version"
|
"github.com/ethereum/go-ethereum/internal/version"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
|
|
@ -240,9 +240,15 @@ func makeFullNode(ctx *cli.Context) *node.Node {
|
||||||
cfg.Eth.OverrideVerkle = &v
|
cfg.Eth.OverrideVerkle = &v
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start metrics export if enabled
|
// Start metrics export if enabled.
|
||||||
utils.SetupMetrics(&cfg.Metrics)
|
utils.SetupMetrics(&cfg.Metrics)
|
||||||
|
|
||||||
|
// Setup OpenTelemetry reporting if enabled.
|
||||||
|
if err := tracesetup.SetupTelemetry(cfg.Node.OpenTelemetry, stack); err != nil {
|
||||||
|
utils.Fatalf("failed to setup OpenTelemetry: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Ethereum service.
|
||||||
backend, eth := utils.RegisterEthService(stack, &cfg.Eth)
|
backend, eth := utils.RegisterEthService(stack, &cfg.Eth)
|
||||||
|
|
||||||
// Create gauge with geth system and build information
|
// Create gauge with geth system and build information
|
||||||
|
|
@ -273,11 +279,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))
|
||||||
|
|
||||||
|
|
@ -371,6 +377,9 @@ func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) {
|
||||||
if ctx.IsSet(utils.MetricsInfluxDBTagsFlag.Name) {
|
if ctx.IsSet(utils.MetricsInfluxDBTagsFlag.Name) {
|
||||||
cfg.Metrics.InfluxDBTags = ctx.String(utils.MetricsInfluxDBTagsFlag.Name)
|
cfg.Metrics.InfluxDBTags = ctx.String(utils.MetricsInfluxDBTagsFlag.Name)
|
||||||
}
|
}
|
||||||
|
if ctx.IsSet(utils.MetricsInfluxDBIntervalFlag.Name) {
|
||||||
|
cfg.Metrics.InfluxDBInterval = ctx.Duration(utils.MetricsInfluxDBIntervalFlag.Name)
|
||||||
|
}
|
||||||
if ctx.IsSet(utils.MetricsEnableInfluxDBV2Flag.Name) {
|
if ctx.IsSet(utils.MetricsEnableInfluxDBV2Flag.Name) {
|
||||||
cfg.Metrics.EnableInfluxDBV2 = ctx.Bool(utils.MetricsEnableInfluxDBV2Flag.Name)
|
cfg.Metrics.EnableInfluxDBV2 = ctx.Bool(utils.MetricsEnableInfluxDBV2Flag.Name)
|
||||||
}
|
}
|
||||||
|
|
@ -399,9 +408,9 @@ func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) {
|
||||||
ctx.IsSet(utils.MetricsInfluxDBBucketFlag.Name)
|
ctx.IsSet(utils.MetricsInfluxDBBucketFlag.Name)
|
||||||
|
|
||||||
if enableExport && v2FlagIsSet {
|
if enableExport && v2FlagIsSet {
|
||||||
utils.Fatalf("Flags --influxdb.metrics.organization, --influxdb.metrics.token, --influxdb.metrics.bucket are only available for influxdb-v2")
|
utils.Fatalf("Flags --%s, --%s, --%s are only available for influxdb-v2", utils.MetricsInfluxDBOrganizationFlag.Name, utils.MetricsInfluxDBTokenFlag.Name, utils.MetricsInfluxDBBucketFlag.Name)
|
||||||
} else if enableExportV2 && v1FlagIsSet {
|
} else if enableExportV2 && v1FlagIsSet {
|
||||||
utils.Fatalf("Flags --influxdb.metrics.username, --influxdb.metrics.password are only available for influxdb-v1")
|
utils.Fatalf("Flags --%s, --%s are only available for influxdb-v1", utils.MetricsInfluxDBUsernameFlag.Name, utils.MetricsInfluxDBPasswordFlag.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ipcAPIs = "admin:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0"
|
ipcAPIs = "admin:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 testing:1.0 txpool:1.0 web3:1.0"
|
||||||
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
|
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -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...)...)
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
@ -37,11 +38,11 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/tablewriter"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -54,6 +55,23 @@ var (
|
||||||
Name: "remove.chain",
|
Name: "remove.chain",
|
||||||
Usage: "If set, selects the state data for removal",
|
Usage: "If set, selects the state data for removal",
|
||||||
}
|
}
|
||||||
|
inspectTrieTopFlag = &cli.IntFlag{
|
||||||
|
Name: "top",
|
||||||
|
Usage: "Print the top N results per ranking category",
|
||||||
|
Value: 10,
|
||||||
|
}
|
||||||
|
inspectTrieDumpPathFlag = &cli.StringFlag{
|
||||||
|
Name: "dump-path",
|
||||||
|
Usage: "Path for the trie statistics dump file",
|
||||||
|
}
|
||||||
|
inspectTrieSummarizeFlag = &cli.StringFlag{
|
||||||
|
Name: "summarize",
|
||||||
|
Usage: "Summarize an existing trie dump file (skip trie traversal)",
|
||||||
|
}
|
||||||
|
inspectTrieContractFlag = &cli.StringFlag{
|
||||||
|
Name: "contract",
|
||||||
|
Usage: "Inspect only the storage of the given contract address (skips full account trie walk)",
|
||||||
|
}
|
||||||
|
|
||||||
removedbCommand = &cli.Command{
|
removedbCommand = &cli.Command{
|
||||||
Action: removeDB,
|
Action: removeDB,
|
||||||
|
|
@ -75,6 +93,7 @@ Remove blockchain and state databases`,
|
||||||
dbCompactCmd,
|
dbCompactCmd,
|
||||||
dbGetCmd,
|
dbGetCmd,
|
||||||
dbDeleteCmd,
|
dbDeleteCmd,
|
||||||
|
dbInspectTrieCmd,
|
||||||
dbPutCmd,
|
dbPutCmd,
|
||||||
dbGetSlotsCmd,
|
dbGetSlotsCmd,
|
||||||
dbDumpFreezerIndex,
|
dbDumpFreezerIndex,
|
||||||
|
|
@ -93,6 +112,22 @@ Remove blockchain and state databases`,
|
||||||
Usage: "Inspect the storage size for each type of data in the database",
|
Usage: "Inspect the storage size for each type of data in the database",
|
||||||
Description: `This commands iterates the entire database. If the optional 'prefix' and 'start' arguments are provided, then the iteration is limited to the given subset of data.`,
|
Description: `This commands iterates the entire database. If the optional 'prefix' and 'start' arguments are provided, then the iteration is limited to the given subset of data.`,
|
||||||
}
|
}
|
||||||
|
dbInspectTrieCmd = &cli.Command{
|
||||||
|
Action: inspectTrie,
|
||||||
|
Name: "inspect-trie",
|
||||||
|
ArgsUsage: "<blocknum>",
|
||||||
|
Flags: slices.Concat([]cli.Flag{
|
||||||
|
utils.ExcludeStorageFlag,
|
||||||
|
inspectTrieTopFlag,
|
||||||
|
utils.OutputFileFlag,
|
||||||
|
inspectTrieDumpPathFlag,
|
||||||
|
inspectTrieSummarizeFlag,
|
||||||
|
inspectTrieContractFlag,
|
||||||
|
}, utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
|
Usage: "Print detailed trie information about the structure of account trie and storage tries.",
|
||||||
|
Description: `This commands iterates the entrie trie-backed state. If the 'blocknum' is not specified,
|
||||||
|
the latest block number will be used by default.`,
|
||||||
|
}
|
||||||
dbCheckStateContentCmd = &cli.Command{
|
dbCheckStateContentCmd = &cli.Command{
|
||||||
Action: checkStateContent,
|
Action: checkStateContent,
|
||||||
Name: "check-state-content",
|
Name: "check-state-content",
|
||||||
|
|
@ -386,6 +421,88 @@ func checkStateContent(ctx *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func inspectTrie(ctx *cli.Context) error {
|
||||||
|
topN := ctx.Int(inspectTrieTopFlag.Name)
|
||||||
|
if topN <= 0 {
|
||||||
|
return fmt.Errorf("invalid --%s value %d (must be > 0)", inspectTrieTopFlag.Name, topN)
|
||||||
|
}
|
||||||
|
config := &trie.InspectConfig{
|
||||||
|
NoStorage: ctx.Bool(utils.ExcludeStorageFlag.Name),
|
||||||
|
TopN: topN,
|
||||||
|
Path: ctx.String(utils.OutputFileFlag.Name),
|
||||||
|
}
|
||||||
|
|
||||||
|
if summarizePath := ctx.String(inspectTrieSummarizeFlag.Name); summarizePath != "" {
|
||||||
|
if ctx.NArg() > 0 {
|
||||||
|
return fmt.Errorf("block number argument is not supported with --%s", inspectTrieSummarizeFlag.Name)
|
||||||
|
}
|
||||||
|
config.DumpPath = summarizePath
|
||||||
|
log.Info("Summarizing trie dump", "path", summarizePath, "top", topN)
|
||||||
|
return trie.Summarize(summarizePath, config)
|
||||||
|
}
|
||||||
|
if ctx.NArg() > 1 {
|
||||||
|
return fmt.Errorf("excessive number of arguments: %v", ctx.Command.ArgsUsage)
|
||||||
|
}
|
||||||
|
|
||||||
|
stack, _ := makeConfigNode(ctx)
|
||||||
|
db := utils.MakeChainDatabase(ctx, stack, false)
|
||||||
|
defer stack.Close()
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
var (
|
||||||
|
trieRoot common.Hash
|
||||||
|
hash common.Hash
|
||||||
|
number uint64
|
||||||
|
)
|
||||||
|
switch {
|
||||||
|
case ctx.NArg() == 0 || ctx.Args().Get(0) == "latest":
|
||||||
|
head := rawdb.ReadHeadHeaderHash(db)
|
||||||
|
n, ok := rawdb.ReadHeaderNumber(db, head)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("could not load head block hash")
|
||||||
|
}
|
||||||
|
number = n
|
||||||
|
case ctx.Args().Get(0) == "snapshot":
|
||||||
|
trieRoot = rawdb.ReadSnapshotRoot(db)
|
||||||
|
number = math.MaxUint64
|
||||||
|
default:
|
||||||
|
var err error
|
||||||
|
number, err = strconv.ParseUint(ctx.Args().Get(0), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to parse blocknum, Args[0]: %v, err: %v", ctx.Args().Get(0), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if number != math.MaxUint64 {
|
||||||
|
hash = rawdb.ReadCanonicalHash(db, number)
|
||||||
|
if hash == (common.Hash{}) {
|
||||||
|
return fmt.Errorf("canonical hash for block %d not found", number)
|
||||||
|
}
|
||||||
|
blockHeader := rawdb.ReadHeader(db, hash, number)
|
||||||
|
trieRoot = blockHeader.Root
|
||||||
|
}
|
||||||
|
if trieRoot == (common.Hash{}) {
|
||||||
|
log.Error("Empty root hash")
|
||||||
|
}
|
||||||
|
|
||||||
|
config.DumpPath = ctx.String(inspectTrieDumpPathFlag.Name)
|
||||||
|
if config.DumpPath == "" {
|
||||||
|
config.DumpPath = stack.ResolvePath("trie-dump.bin")
|
||||||
|
}
|
||||||
|
|
||||||
|
triedb := utils.MakeTrieDatabase(ctx, stack, db, false, true, false)
|
||||||
|
defer triedb.Close()
|
||||||
|
|
||||||
|
if contractAddr := ctx.String(inspectTrieContractFlag.Name); contractAddr != "" {
|
||||||
|
address := common.HexToAddress(contractAddr)
|
||||||
|
log.Info("Inspecting contract", "address", address, "root", trieRoot, "block", number)
|
||||||
|
return trie.InspectContract(triedb, db, trieRoot, address)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Inspecting trie", "root", trieRoot, "block", number, "dump", config.DumpPath, "top", topN)
|
||||||
|
return trie.Inspect(triedb, trieRoot, config)
|
||||||
|
}
|
||||||
|
|
||||||
func showDBStats(db ethdb.KeyValueStater) {
|
func showDBStats(db ethdb.KeyValueStater) {
|
||||||
stats, err := db.Stat()
|
stats, err := db.Stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -94,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
|
||||||
|
|
@ -118,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
|
||||||
|
|
@ -156,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{
|
||||||
|
|
@ -191,6 +195,14 @@ var (
|
||||||
utils.BatchResponseMaxSize,
|
utils.BatchResponseMaxSize,
|
||||||
utils.RPCTxSyncDefaultTimeoutFlag,
|
utils.RPCTxSyncDefaultTimeoutFlag,
|
||||||
utils.RPCTxSyncMaxTimeoutFlag,
|
utils.RPCTxSyncMaxTimeoutFlag,
|
||||||
|
utils.RPCGlobalRangeLimitFlag,
|
||||||
|
utils.RPCTelemetryFlag,
|
||||||
|
utils.RPCTelemetryEndpointFlag,
|
||||||
|
utils.RPCTelemetryUserFlag,
|
||||||
|
utils.RPCTelemetryPasswordFlag,
|
||||||
|
utils.RPCTelemetryInstanceIDFlag,
|
||||||
|
utils.RPCTelemetryTagsFlag,
|
||||||
|
utils.RPCTelemetrySampleRatioFlag,
|
||||||
}
|
}
|
||||||
|
|
||||||
metricsFlags = []cli.Flag{
|
metricsFlags = []cli.Flag{
|
||||||
|
|
@ -204,6 +216,7 @@ var (
|
||||||
utils.MetricsInfluxDBUsernameFlag,
|
utils.MetricsInfluxDBUsernameFlag,
|
||||||
utils.MetricsInfluxDBPasswordFlag,
|
utils.MetricsInfluxDBPasswordFlag,
|
||||||
utils.MetricsInfluxDBTagsFlag,
|
utils.MetricsInfluxDBTagsFlag,
|
||||||
|
utils.MetricsInfluxDBIntervalFlag,
|
||||||
utils.MetricsEnableInfluxDBV2Flag,
|
utils.MetricsEnableInfluxDBV2Flag,
|
||||||
utils.MetricsInfluxDBTokenFlag,
|
utils.MetricsInfluxDBTokenFlag,
|
||||||
utils.MetricsInfluxDBBucketFlag,
|
utils.MetricsInfluxDBBucketFlag,
|
||||||
|
|
@ -239,7 +252,6 @@ func init() {
|
||||||
javascriptCommand,
|
javascriptCommand,
|
||||||
// See misccmd.go:
|
// See misccmd.go:
|
||||||
versionCommand,
|
versionCommand,
|
||||||
versionCheckCommand,
|
|
||||||
licenseCommand,
|
licenseCommand,
|
||||||
// See config.go
|
// See config.go
|
||||||
dumpConfigCommand,
|
dumpConfigCommand,
|
||||||
|
|
@ -249,8 +261,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
|
||||||
}
|
}
|
||||||
|
|
@ -12,34 +12,35 @@ 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.5 // 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-logr/logr v1.4.3 // indirect
|
||||||
|
github.com/go-logr/stdr v1.2.2 // 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
|
||||||
github.com/golang/snappy v1.0.0 // indirect
|
github.com/golang/snappy v1.0.0 // indirect
|
||||||
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
|
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||||
golang.org/x/sync v0.12.0 // indirect
|
go.opentelemetry.io/otel v1.39.0 // indirect
|
||||||
golang.org/x/sys v0.36.0 // indirect
|
go.opentelemetry.io/otel/metric v1.39.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/trace v1.39.0 // indirect
|
||||||
|
golang.org/x/crypto v0.44.0 // indirect
|
||||||
|
golang.org/x/sync v0.18.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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,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=
|
||||||
|
|
@ -46,12 +44,15 @@ github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3
|
||||||
github.com/ethereum/c-kzg-4844/v2 v2.1.5/go.mod h1:u59hRTTah4Co6i9fDWtiCjTrblJv0UwsqZKCc0GfgUs=
|
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=
|
||||||
github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
|
github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
|
||||||
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||||
|
|
@ -63,12 +64,16 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
|
||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
|
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
|
||||||
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
|
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
|
||||||
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=
|
||||||
|
|
@ -80,17 +85,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=
|
||||||
|
|
@ -105,36 +105,44 @@ 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=
|
||||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
|
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||||
|
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||||
|
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||||
|
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||||
|
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||||
|
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||||
|
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
|
||||||
|
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
|
||||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME=
|
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME=
|
||||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
||||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
|
@ -52,7 +53,7 @@ func main() {
|
||||||
}
|
}
|
||||||
vmConfig := vm.Config{}
|
vmConfig := vm.Config{}
|
||||||
|
|
||||||
crossStateRoot, crossReceiptRoot, err := core.ExecuteStateless(chainConfig, vmConfig, payload.Block, payload.Witness)
|
crossStateRoot, crossReceiptRoot, err := core.ExecuteStateless(context.Background(), chainConfig, vmConfig, payload.Block, payload.Witness)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "stateless self-validation failed: %v\n", err)
|
fmt.Fprintf(os.Stderr, "stateless self-validation failed: %v\n", err)
|
||||||
os.Exit(10)
|
os.Exit(10)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
158
cmd/utils/cmd.go
158
cmd/utils/cmd.go
|
|
@ -57,6 +57,8 @@ const (
|
||||||
importBatchSize = 2500
|
importBatchSize = 2500
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type EraFileFormat int
|
||||||
|
|
||||||
// ErrImportInterrupted is returned when the user interrupts the import process.
|
// ErrImportInterrupted is returned when the user interrupts the import process.
|
||||||
var ErrImportInterrupted = errors.New("interrupted")
|
var ErrImportInterrupted = errors.New("interrupted")
|
||||||
|
|
||||||
|
|
@ -250,7 +252,7 @@ func readList(filename string) ([]string, error) {
|
||||||
// ImportHistory imports Era1 files containing historical block information,
|
// ImportHistory imports Era1 files containing historical block information,
|
||||||
// starting from genesis. The assumption is held that the provided chain
|
// starting from genesis. The assumption is held that the provided chain
|
||||||
// segment in Era1 file should all be canonical and verified.
|
// segment in Era1 file should all be canonical and verified.
|
||||||
func ImportHistory(chain *core.BlockChain, dir string, network string) error {
|
func ImportHistory(chain *core.BlockChain, dir string, network string, from func(f era.ReadAtSeekCloser) (era.Era, error)) error {
|
||||||
if chain.CurrentSnapBlock().Number.BitLen() != 0 {
|
if chain.CurrentSnapBlock().Number.BitLen() != 0 {
|
||||||
return errors.New("history import only supported when starting from genesis")
|
return errors.New("history import only supported when starting from genesis")
|
||||||
}
|
}
|
||||||
|
|
@ -263,42 +265,49 @@ func ImportHistory(chain *core.BlockChain, dir string, network string) error {
|
||||||
return fmt.Errorf("unable to read checksums.txt: %w", err)
|
return fmt.Errorf("unable to read checksums.txt: %w", err)
|
||||||
}
|
}
|
||||||
if len(checksums) != len(entries) {
|
if len(checksums) != len(entries) {
|
||||||
return fmt.Errorf("expected equal number of checksums and entries, have: %d checksums, %d entries", len(checksums), len(entries))
|
return fmt.Errorf("expected equal number of checksums and entries, have: %d checksums, %d entries",
|
||||||
|
len(checksums), len(entries))
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
start = time.Now()
|
start = time.Now()
|
||||||
reported = time.Now()
|
reported = time.Now()
|
||||||
imported = 0
|
imported = 0
|
||||||
h = sha256.New()
|
h = sha256.New()
|
||||||
buf = bytes.NewBuffer(nil)
|
scratch = bytes.NewBuffer(nil)
|
||||||
)
|
)
|
||||||
for i, filename := range entries {
|
|
||||||
|
for i, file := range entries {
|
||||||
err := func() error {
|
err := func() error {
|
||||||
f, err := os.Open(filepath.Join(dir, filename))
|
path := filepath.Join(dir, file)
|
||||||
|
|
||||||
|
// validate against checksum file in directory
|
||||||
|
f, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to open era: %w", err)
|
return fmt.Errorf("open %s: %w", path, err)
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
// Validate checksum.
|
|
||||||
if _, err := io.Copy(h, f); err != nil {
|
if _, err := io.Copy(h, f); err != nil {
|
||||||
return fmt.Errorf("unable to recalculate checksum: %w", err)
|
return fmt.Errorf("checksum %s: %w", path, err)
|
||||||
}
|
|
||||||
if have, want := common.BytesToHash(h.Sum(buf.Bytes()[:])).Hex(), checksums[i]; have != want {
|
|
||||||
return fmt.Errorf("checksum mismatch: have %s, want %s", have, want)
|
|
||||||
}
|
}
|
||||||
|
got := common.BytesToHash(h.Sum(scratch.Bytes()[:])).Hex()
|
||||||
|
want := checksums[i]
|
||||||
h.Reset()
|
h.Reset()
|
||||||
buf.Reset()
|
scratch.Reset()
|
||||||
|
|
||||||
|
if got != want {
|
||||||
|
return fmt.Errorf("%s checksum mismatch: have %s want %s", file, got, want)
|
||||||
|
}
|
||||||
// Import all block data from Era1.
|
// Import all block data from Era1.
|
||||||
e, err := era.From(f)
|
e, err := from(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error opening era: %w", err)
|
return fmt.Errorf("error opening era: %w", err)
|
||||||
}
|
}
|
||||||
it, err := era.NewIterator(e)
|
it, err := e.Iterator()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error making era reader: %w", err)
|
return fmt.Errorf("error creating iterator: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
block, err := it.Block()
|
block, err := it.Block()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -311,26 +320,28 @@ func ImportHistory(chain *core.BlockChain, dir string, network string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
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})
|
enc := types.EncodeBlockReceiptLists([]types.Receipts{receipts})
|
||||||
if _, err := chain.InsertReceiptChain([]*types.Block{block}, encReceipts, math.MaxUint64); err != nil {
|
if _, err := chain.InsertReceiptChain([]*types.Block{block}, enc, 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++
|
||||||
|
|
||||||
// Give the user some feedback that something is happening.
|
|
||||||
if time.Since(reported) >= 8*time.Second {
|
if time.Since(reported) >= 8*time.Second {
|
||||||
log.Info("Importing Era files", "head", it.Number(), "imported", imported, "elapsed", common.PrettyDuration(time.Since(start)))
|
log.Info("Importing Era files", "head", it.Number(), "imported", imported,
|
||||||
|
"elapsed", common.PrettyDuration(time.Since(start)))
|
||||||
imported = 0
|
imported = 0
|
||||||
reported = time.Now()
|
reported = time.Now()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err := it.Error(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}()
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -389,7 +400,6 @@ func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, las
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer fh.Close()
|
defer fh.Close()
|
||||||
|
|
||||||
var writer io.Writer = fh
|
var writer io.Writer = fh
|
||||||
if strings.HasSuffix(fn, ".gz") {
|
if strings.HasSuffix(fn, ".gz") {
|
||||||
writer = gzip.NewWriter(writer)
|
writer = gzip.NewWriter(writer)
|
||||||
|
|
@ -405,7 +415,7 @@ func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, las
|
||||||
|
|
||||||
// ExportHistory exports blockchain history into the specified directory,
|
// ExportHistory exports blockchain history into the specified directory,
|
||||||
// following the Era format.
|
// following the Era format.
|
||||||
func ExportHistory(bc *core.BlockChain, dir string, first, last, step uint64) error {
|
func ExportHistory(bc *core.BlockChain, dir string, first, last uint64, newBuilder func(io.Writer) era.Builder, filename func(network string, epoch int, lastBlockHash common.Hash) string) error {
|
||||||
log.Info("Exporting blockchain history", "dir", dir)
|
log.Info("Exporting blockchain history", "dir", dir)
|
||||||
if head := bc.CurrentBlock().Number.Uint64(); head < last {
|
if head := bc.CurrentBlock().Number.Uint64(); head < last {
|
||||||
log.Warn("Last block beyond head, setting last = head", "head", head, "last", last)
|
log.Warn("Last block beyond head, setting last = head", "head", head, "last", last)
|
||||||
|
|
@ -418,76 +428,100 @@ func ExportHistory(bc *core.BlockChain, dir string, first, last, step uint64) er
|
||||||
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
|
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
|
||||||
return fmt.Errorf("error creating output directory: %w", err)
|
return fmt.Errorf("error creating output directory: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
start = time.Now()
|
start = time.Now()
|
||||||
reported = time.Now()
|
reported = time.Now()
|
||||||
h = sha256.New()
|
h = sha256.New()
|
||||||
buf = bytes.NewBuffer(nil)
|
buf = bytes.NewBuffer(nil)
|
||||||
|
td = new(big.Int)
|
||||||
checksums []string
|
checksums []string
|
||||||
)
|
)
|
||||||
td := new(big.Int)
|
|
||||||
for i := uint64(0); i < first; i++ {
|
// Compute initial TD by accumulating difficulty from genesis to first-1.
|
||||||
td.Add(td, bc.GetHeaderByNumber(i).Difficulty)
|
// This is necessary because TD is no longer stored in the database. Only
|
||||||
|
// compute if a segment of the export is pre-merge.
|
||||||
|
b := bc.GetBlockByNumber(first)
|
||||||
|
if b == nil {
|
||||||
|
return fmt.Errorf("block #%d not found", first)
|
||||||
}
|
}
|
||||||
for i := first; i <= last; i += step {
|
if first > 0 && b.Difficulty().Sign() != 0 {
|
||||||
err := func() error {
|
log.Info("Computing initial total difficulty", "from", 0, "to", first-1)
|
||||||
filename := filepath.Join(dir, era.Filename(network, int(i/step), common.Hash{}))
|
for i := uint64(0); i < first; i++ {
|
||||||
f, err := os.Create(filename)
|
b := bc.GetBlockByNumber(i)
|
||||||
|
if b == nil {
|
||||||
|
return fmt.Errorf("block #%d not found while computing initial TD", i)
|
||||||
|
}
|
||||||
|
td.Add(td, b.Difficulty())
|
||||||
|
}
|
||||||
|
log.Info("Initial total difficulty computed", "td", td)
|
||||||
|
}
|
||||||
|
|
||||||
|
for batch := first; batch <= last; batch += uint64(era.MaxSize) {
|
||||||
|
idx := int(batch / uint64(era.MaxSize))
|
||||||
|
tmpPath := filepath.Join(dir, filename(network, idx, common.Hash{}))
|
||||||
|
|
||||||
|
if err := func() error {
|
||||||
|
f, err := os.Create(tmpPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not create era file: %w", err)
|
return err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
w := era.NewBuilder(f)
|
builder := newBuilder(f)
|
||||||
for j := uint64(0); j < step && j <= last-i; j++ {
|
|
||||||
var (
|
for j := uint64(0); j < uint64(era.MaxSize) && batch+j <= last; j++ {
|
||||||
n = i + j
|
n := batch + j
|
||||||
block = bc.GetBlockByNumber(n)
|
block := bc.GetBlockByNumber(n)
|
||||||
)
|
|
||||||
if block == nil {
|
if block == nil {
|
||||||
return fmt.Errorf("export failed on #%d: not found", n)
|
return fmt.Errorf("block #%d not found", n)
|
||||||
}
|
}
|
||||||
receipts := bc.GetReceiptsByHash(block.Hash())
|
receipt := bc.GetReceiptsByHash(block.Hash())
|
||||||
if receipts == nil {
|
if receipt == nil {
|
||||||
return fmt.Errorf("export failed on #%d: receipts not found", n)
|
return fmt.Errorf("receipts for #%d missing", n)
|
||||||
}
|
}
|
||||||
td.Add(td, block.Difficulty())
|
|
||||||
if err := w.Add(block, receipts, new(big.Int).Set(td)); err != nil {
|
// For pre-merge blocks, pass accumulated TD.
|
||||||
|
// For post-merge blocks (difficulty == 0), pass nil TD.
|
||||||
|
var blockTD *big.Int
|
||||||
|
if block.Difficulty().Sign() != 0 {
|
||||||
|
td.Add(td, block.Difficulty())
|
||||||
|
blockTD = new(big.Int).Set(td)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := builder.Add(block, receipt, blockTD); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
root, err := w.Finalize()
|
id, err := builder.Finalize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("export failed to finalize %d: %w", step/i, err)
|
return err
|
||||||
}
|
}
|
||||||
// Set correct filename with root.
|
|
||||||
os.Rename(filename, filepath.Join(dir, era.Filename(network, int(i/step), root)))
|
|
||||||
|
|
||||||
// Compute checksum of entire Era1.
|
|
||||||
if _, err := f.Seek(0, io.SeekStart); err != nil {
|
if _, err := f.Seek(0, io.SeekStart); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := io.Copy(h, f); err != nil {
|
|
||||||
return fmt.Errorf("unable to calculate checksum: %w", err)
|
|
||||||
}
|
|
||||||
checksums = append(checksums, common.BytesToHash(h.Sum(buf.Bytes()[:])).Hex())
|
|
||||||
h.Reset()
|
h.Reset()
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
return nil
|
if _, err := io.Copy(h, f); err != nil {
|
||||||
}()
|
return err
|
||||||
if err != nil {
|
}
|
||||||
|
checksums = append(checksums, common.BytesToHash(h.Sum(buf.Bytes()[:])).Hex())
|
||||||
|
|
||||||
|
// Close before rename. It's required on Windows.
|
||||||
|
f.Close()
|
||||||
|
final := filepath.Join(dir, filename(network, idx, id))
|
||||||
|
return os.Rename(tmpPath, final)
|
||||||
|
}(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if time.Since(reported) >= 8*time.Second {
|
if time.Since(reported) >= 8*time.Second {
|
||||||
log.Info("Exporting blocks", "exported", i, "elapsed", common.PrettyDuration(time.Since(start)))
|
log.Info("export progress", "exported", batch, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||||
reported = time.Now()
|
reported = time.Now()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
os.WriteFile(filepath.Join(dir, "checksums.txt"), []byte(strings.Join(checksums, "\n")), os.ModePerm)
|
_ = os.WriteFile(filepath.Join(dir, "checksums.txt"), []byte(strings.Join(checksums, "\n")), os.ModePerm)
|
||||||
|
|
||||||
log.Info("Exported blockchain to", "dir", dir)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -114,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,
|
||||||
|
|
@ -137,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,
|
||||||
}
|
}
|
||||||
|
|
@ -218,6 +218,16 @@ var (
|
||||||
Usage: "Max number of elements (0 = no limit)",
|
Usage: "Max number of elements (0 = no limit)",
|
||||||
Value: 0,
|
Value: 0,
|
||||||
}
|
}
|
||||||
|
TopFlag = &cli.IntFlag{
|
||||||
|
Name: "top",
|
||||||
|
Usage: "Print the top N results",
|
||||||
|
Value: 5,
|
||||||
|
}
|
||||||
|
OutputFileFlag = &cli.StringFlag{
|
||||||
|
Name: "output",
|
||||||
|
Usage: "Writes the result in json to the output",
|
||||||
|
Value: "",
|
||||||
|
}
|
||||||
|
|
||||||
SnapshotFlag = &cli.BoolFlag{
|
SnapshotFlag = &cli.BoolFlag{
|
||||||
Name: "snapshot",
|
Name: "snapshot",
|
||||||
|
|
@ -295,6 +305,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)",
|
||||||
|
|
@ -553,6 +575,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{
|
||||||
|
|
@ -631,6 +658,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",
|
||||||
|
|
@ -667,6 +700,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{
|
||||||
|
|
@ -859,14 +898,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",
|
||||||
|
|
@ -987,6 +1026,13 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
|
||||||
Category: flags.MetricsCategory,
|
Category: flags.MetricsCategory,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetricsInfluxDBIntervalFlag = &cli.DurationFlag{
|
||||||
|
Name: "metrics.influxdb.interval",
|
||||||
|
Usage: "Interval between metrics reports to InfluxDB (with time unit, e.g. 10s)",
|
||||||
|
Value: metrics.DefaultConfig.InfluxDBInterval,
|
||||||
|
Category: flags.MetricsCategory,
|
||||||
|
}
|
||||||
|
|
||||||
MetricsEnableInfluxDBV2Flag = &cli.BoolFlag{
|
MetricsEnableInfluxDBV2Flag = &cli.BoolFlag{
|
||||||
Name: "metrics.influxdbv2",
|
Name: "metrics.influxdbv2",
|
||||||
Usage: "Enable metrics export/push to an external InfluxDB v2 database",
|
Usage: "Enable metrics export/push to an external InfluxDB v2 database",
|
||||||
|
|
@ -1013,6 +1059,55 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
|
||||||
Value: metrics.DefaultConfig.InfluxDBOrganization,
|
Value: metrics.DefaultConfig.InfluxDBOrganization,
|
||||||
Category: flags.MetricsCategory,
|
Category: flags.MetricsCategory,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RPC Telemetry
|
||||||
|
RPCTelemetryFlag = &cli.BoolFlag{
|
||||||
|
Name: "rpc.telemetry",
|
||||||
|
Usage: "Enable RPC telemetry",
|
||||||
|
Category: flags.APICategory,
|
||||||
|
}
|
||||||
|
|
||||||
|
RPCTelemetryEndpointFlag = &cli.StringFlag{
|
||||||
|
Name: "rpc.telemetry.endpoint",
|
||||||
|
Usage: "Defines where RPC telemetry is sent (e.g., http://localhost:4318)",
|
||||||
|
Category: flags.APICategory,
|
||||||
|
}
|
||||||
|
|
||||||
|
RPCTelemetryUserFlag = &cli.StringFlag{
|
||||||
|
Name: "rpc.telemetry.username",
|
||||||
|
Usage: "HTTP Basic Auth username for OpenTelemetry",
|
||||||
|
Category: flags.APICategory,
|
||||||
|
}
|
||||||
|
|
||||||
|
RPCTelemetryPasswordFlag = &cli.StringFlag{
|
||||||
|
Name: "rpc.telemetry.password",
|
||||||
|
Usage: "HTTP Basic Auth password for OpenTelemetry",
|
||||||
|
Category: flags.APICategory,
|
||||||
|
}
|
||||||
|
|
||||||
|
RPCTelemetryInstanceIDFlag = &cli.StringFlag{
|
||||||
|
Name: "rpc.telemetry.instance-id",
|
||||||
|
Usage: "OpenTelemetry instance ID",
|
||||||
|
Category: flags.APICategory,
|
||||||
|
}
|
||||||
|
|
||||||
|
RPCTelemetryTagsFlag = &cli.StringFlag{
|
||||||
|
Name: "rpc.telemetry.tags",
|
||||||
|
Usage: "Comma-separated tags (key/values) added as attributes to the OpenTelemetry resource struct",
|
||||||
|
Category: flags.APICategory,
|
||||||
|
}
|
||||||
|
|
||||||
|
RPCTelemetrySampleRatioFlag = &cli.Float64Flag{
|
||||||
|
Name: "rpc.telemetry.sample-ratio",
|
||||||
|
Usage: "Defines the sampling ratio for RPC telemetry (0.0 to 1.0)",
|
||||||
|
Value: 1.0,
|
||||||
|
Category: flags.APICategory,
|
||||||
|
}
|
||||||
|
// Era flags are a group of flags related to the era archive format.
|
||||||
|
EraFormatFlag = &cli.StringFlag{
|
||||||
|
Name: "era.format",
|
||||||
|
Usage: "Archive format: 'era1' or 'erae'",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -1363,13 +1458,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)
|
||||||
|
|
@ -1399,6 +1498,7 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) {
|
||||||
setNodeUserIdent(ctx, cfg)
|
setNodeUserIdent(ctx, cfg)
|
||||||
SetDataDir(ctx, cfg)
|
SetDataDir(ctx, cfg)
|
||||||
setSmartCard(ctx, cfg)
|
setSmartCard(ctx, cfg)
|
||||||
|
setOpenTelemetry(ctx, cfg)
|
||||||
|
|
||||||
if ctx.IsSet(JWTSecretFlag.Name) {
|
if ctx.IsSet(JWTSecretFlag.Name) {
|
||||||
cfg.JWTSecret = ctx.String(JWTSecretFlag.Name)
|
cfg.JWTSecret = ctx.String(JWTSecretFlag.Name)
|
||||||
|
|
@ -1415,7 +1515,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)
|
||||||
|
|
@ -1466,6 +1566,33 @@ func setSmartCard(ctx *cli.Context, cfg *node.Config) {
|
||||||
cfg.SmartCardDaemonPath = path
|
cfg.SmartCardDaemonPath = path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setOpenTelemetry(ctx *cli.Context, cfg *node.Config) {
|
||||||
|
tcfg := &cfg.OpenTelemetry
|
||||||
|
if ctx.IsSet(RPCTelemetryFlag.Name) {
|
||||||
|
tcfg.Enabled = ctx.Bool(RPCTelemetryFlag.Name)
|
||||||
|
}
|
||||||
|
if ctx.IsSet(RPCTelemetryEndpointFlag.Name) {
|
||||||
|
tcfg.Endpoint = ctx.String(RPCTelemetryEndpointFlag.Name)
|
||||||
|
}
|
||||||
|
if ctx.IsSet(RPCTelemetryUserFlag.Name) {
|
||||||
|
tcfg.AuthUser = ctx.String(RPCTelemetryUserFlag.Name)
|
||||||
|
}
|
||||||
|
if ctx.IsSet(RPCTelemetryPasswordFlag.Name) {
|
||||||
|
tcfg.AuthPassword = ctx.String(RPCTelemetryPasswordFlag.Name)
|
||||||
|
}
|
||||||
|
if ctx.IsSet(RPCTelemetryInstanceIDFlag.Name) {
|
||||||
|
tcfg.InstanceID = ctx.String(RPCTelemetryInstanceIDFlag.Name)
|
||||||
|
}
|
||||||
|
if ctx.IsSet(RPCTelemetryTagsFlag.Name) {
|
||||||
|
tcfg.Tags = ctx.String(RPCTelemetryTagsFlag.Name)
|
||||||
|
}
|
||||||
|
tcfg.SampleRatio = ctx.Float64(RPCTelemetrySampleRatioFlag.Name)
|
||||||
|
|
||||||
|
if tcfg.Endpoint != "" && !tcfg.Enabled {
|
||||||
|
log.Warn(fmt.Sprintf("OpenTelemetry endpoint configured but telemetry is not enabled, use --%s to enable.", RPCTelemetryFlag.Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func SetDataDir(ctx *cli.Context, cfg *node.Config) {
|
func SetDataDir(ctx *cli.Context, cfg *node.Config) {
|
||||||
switch {
|
switch {
|
||||||
case ctx.IsSet(DataDirFlag.Name):
|
case ctx.IsSet(DataDirFlag.Name):
|
||||||
|
|
@ -1571,6 +1698,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) {
|
||||||
|
|
@ -1603,8 +1733,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, OverrideGenesisFlag)
|
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
|
||||||
|
|
@ -1651,9 +1781,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
|
||||||
}
|
}
|
||||||
|
|
@ -1674,8 +1801,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")
|
||||||
|
|
@ -1683,6 +1811,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)
|
||||||
}
|
}
|
||||||
|
|
@ -1708,7 +1842,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)
|
||||||
|
|
@ -1734,6 +1871,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 {
|
||||||
|
|
@ -1903,10 +2043,18 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
}
|
}
|
||||||
cfg.Genesis = genesis
|
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)
|
||||||
|
|
@ -2070,6 +2218,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",
|
||||||
|
|
@ -2114,13 +2263,14 @@ func SetupMetrics(cfg *metrics.Config) {
|
||||||
bucket = cfg.InfluxDBBucket
|
bucket = cfg.InfluxDBBucket
|
||||||
organization = cfg.InfluxDBOrganization
|
organization = cfg.InfluxDBOrganization
|
||||||
tagsMap = SplitTagsFlag(cfg.InfluxDBTags)
|
tagsMap = SplitTagsFlag(cfg.InfluxDBTags)
|
||||||
|
interval = cfg.InfluxDBInterval
|
||||||
)
|
)
|
||||||
if enableExport {
|
if enableExport {
|
||||||
log.Info("Enabling metrics export to InfluxDB")
|
log.Info("Enabling metrics export to InfluxDB", "interval", interval)
|
||||||
go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", tagsMap)
|
go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, interval, endpoint, database, username, password, "geth.", tagsMap)
|
||||||
} else if enableExportV2 {
|
} else if enableExportV2 {
|
||||||
log.Info("Enabling metrics export to InfluxDB (v2)")
|
log.Info("Enabling metrics export to InfluxDB (v2)", "interval", interval)
|
||||||
go influxdb.InfluxDBV2WithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, token, bucket, organization, "geth.", tagsMap)
|
go influxdb.InfluxDBV2WithTags(metrics.DefaultRegistry, interval, endpoint, token, bucket, organization, "geth.", tagsMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expvar exporter.
|
// Expvar exporter.
|
||||||
|
|
@ -2272,15 +2422,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,
|
||||||
|
|
||||||
|
|
@ -2292,6 +2445,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
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/internal/era"
|
"github.com/ethereum/go-ethereum/internal/era"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/era/execdb"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/era/onedb"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/ethereum/go-ethereum/triedb"
|
"github.com/ethereum/go-ethereum/triedb"
|
||||||
|
|
@ -44,136 +46,148 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHistoryImportAndExport(t *testing.T) {
|
func TestHistoryImportAndExport(t *testing.T) {
|
||||||
var (
|
for _, tt := range []struct {
|
||||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
name string
|
||||||
address = crypto.PubkeyToAddress(key.PublicKey)
|
builder func(io.Writer) era.Builder
|
||||||
genesis = &core.Genesis{
|
filename func(network string, epoch int, root common.Hash) string
|
||||||
Config: params.TestChainConfig,
|
from func(f era.ReadAtSeekCloser) (era.Era, error)
|
||||||
Alloc: types.GenesisAlloc{address: {Balance: big.NewInt(1000000000000000000)}},
|
}{
|
||||||
}
|
{"era1", onedb.NewBuilder, onedb.Filename, onedb.From},
|
||||||
signer = types.LatestSigner(genesis.Config)
|
{"erae", execdb.NewBuilder, execdb.Filename, execdb.From},
|
||||||
)
|
} {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
// Generate chain.
|
|
||||||
db, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), int(count), func(i int, g *core.BlockGen) {
|
|
||||||
if i == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
tx, err := types.SignNewTx(key, signer, &types.DynamicFeeTx{
|
|
||||||
ChainID: genesis.Config.ChainID,
|
|
||||||
Nonce: uint64(i - 1),
|
|
||||||
GasTipCap: common.Big0,
|
|
||||||
GasFeeCap: g.PrevBlock(0).BaseFee(),
|
|
||||||
Gas: 50000,
|
|
||||||
To: &common.Address{0xaa},
|
|
||||||
Value: big.NewInt(int64(i)),
|
|
||||||
Data: nil,
|
|
||||||
AccessList: nil,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error creating tx: %v", err)
|
|
||||||
}
|
|
||||||
g.AddTx(tx)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Initialize BlockChain.
|
|
||||||
chain, err := core.NewBlockChain(db, genesis, ethash.NewFaker(), nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to initialize chain: %v", err)
|
|
||||||
}
|
|
||||||
if _, err := chain.InsertChain(blocks); err != nil {
|
|
||||||
t.Fatalf("error inserting chain: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make temp directory for era files.
|
|
||||||
dir := t.TempDir()
|
|
||||||
|
|
||||||
// Export history to temp directory.
|
|
||||||
if err := ExportHistory(chain, dir, 0, count, step); err != nil {
|
|
||||||
t.Fatalf("error exporting history: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read checksums.
|
|
||||||
b, err := os.ReadFile(filepath.Join(dir, "checksums.txt"))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to read checksums: %v", err)
|
|
||||||
}
|
|
||||||
checksums := strings.Split(string(b), "\n")
|
|
||||||
|
|
||||||
// Verify each Era.
|
|
||||||
entries, _ := era.ReadDir(dir, "mainnet")
|
|
||||||
for i, filename := range entries {
|
|
||||||
func() {
|
|
||||||
f, err := os.Open(filepath.Join(dir, filename))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error opening era file: %v", err)
|
|
||||||
}
|
|
||||||
var (
|
var (
|
||||||
h = sha256.New()
|
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
buf = bytes.NewBuffer(nil)
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
genesis = &core.Genesis{
|
||||||
|
Config: params.TestChainConfig,
|
||||||
|
Alloc: types.GenesisAlloc{address: {Balance: big.NewInt(1000000000000000000)}},
|
||||||
|
}
|
||||||
|
signer = types.LatestSigner(genesis.Config)
|
||||||
)
|
)
|
||||||
if _, err := io.Copy(h, f); err != nil {
|
|
||||||
t.Fatalf("unable to recalculate checksum: %v", err)
|
// Generate chain.
|
||||||
}
|
db, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), int(count), func(i int, g *core.BlockGen) {
|
||||||
if got, want := common.BytesToHash(h.Sum(buf.Bytes()[:])).Hex(), checksums[i]; got != want {
|
if i == 0 {
|
||||||
t.Fatalf("checksum %d does not match: got %s, want %s", i, got, want)
|
return
|
||||||
}
|
|
||||||
e, err := era.From(f)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error opening era: %v", err)
|
|
||||||
}
|
|
||||||
defer e.Close()
|
|
||||||
it, err := era.NewIterator(e)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error making era reader: %v", err)
|
|
||||||
}
|
|
||||||
for j := 0; it.Next(); j++ {
|
|
||||||
n := i*int(step) + j
|
|
||||||
if it.Error() != nil {
|
|
||||||
t.Fatalf("error reading block entry %d: %v", n, it.Error())
|
|
||||||
}
|
}
|
||||||
block, receipts, err := it.BlockAndReceipts()
|
tx, err := types.SignNewTx(key, signer, &types.DynamicFeeTx{
|
||||||
|
ChainID: genesis.Config.ChainID,
|
||||||
|
Nonce: uint64(i - 1),
|
||||||
|
GasTipCap: common.Big0,
|
||||||
|
GasFeeCap: g.PrevBlock(0).BaseFee(),
|
||||||
|
Gas: 50000,
|
||||||
|
To: &common.Address{0xaa},
|
||||||
|
Value: big.NewInt(int64(i)),
|
||||||
|
Data: nil,
|
||||||
|
AccessList: nil,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error reading block entry %d: %v", n, err)
|
t.Fatalf("error creating tx: %v", err)
|
||||||
}
|
|
||||||
want := chain.GetBlockByNumber(uint64(n))
|
|
||||||
if want, got := uint64(n), block.NumberU64(); want != got {
|
|
||||||
t.Fatalf("blocks out of order: want %d, got %d", want, got)
|
|
||||||
}
|
|
||||||
if want.Hash() != block.Hash() {
|
|
||||||
t.Fatalf("block hash mismatch %d: want %s, got %s", n, want.Hash().Hex(), block.Hash().Hex())
|
|
||||||
}
|
|
||||||
if got := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); got != want.TxHash() {
|
|
||||||
t.Fatalf("tx hash %d mismatch: want %s, got %s", n, want.TxHash(), got)
|
|
||||||
}
|
|
||||||
if got := types.CalcUncleHash(block.Uncles()); got != want.UncleHash() {
|
|
||||||
t.Fatalf("uncle hash %d mismatch: want %s, got %s", n, want.UncleHash(), got)
|
|
||||||
}
|
|
||||||
if got := types.DeriveSha(receipts, trie.NewStackTrie(nil)); got != want.ReceiptHash() {
|
|
||||||
t.Fatalf("receipt root %d mismatch: want %s, got %s", n, want.ReceiptHash(), got)
|
|
||||||
}
|
}
|
||||||
|
g.AddTx(tx)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Initialize BlockChain.
|
||||||
|
chain, err := core.NewBlockChain(db, genesis, ethash.NewFaker(), nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to initialize chain: %v", err)
|
||||||
|
}
|
||||||
|
if _, err := chain.InsertChain(blocks); err != nil {
|
||||||
|
t.Fatalf("error inserting chain: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now import Era.
|
// Make temp directory for era files.
|
||||||
db2, err := rawdb.Open(rawdb.NewMemoryDatabase(), rawdb.OpenOptions{})
|
dir := t.TempDir()
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
t.Cleanup(func() {
|
|
||||||
db2.Close()
|
|
||||||
})
|
|
||||||
|
|
||||||
genesis.MustCommit(db2, triedb.NewDatabase(db2, triedb.HashDefaults))
|
// Export history to temp directory.
|
||||||
imported, err := core.NewBlockChain(db2, genesis, ethash.NewFaker(), nil)
|
if err := ExportHistory(chain, dir, 0, count, tt.builder, tt.filename); err != nil {
|
||||||
if err != nil {
|
t.Fatalf("error exporting history: %v", err)
|
||||||
t.Fatalf("unable to initialize chain: %v", err)
|
}
|
||||||
}
|
|
||||||
if err := ImportHistory(imported, dir, "mainnet"); err != nil {
|
// Read checksums.
|
||||||
t.Fatalf("failed to import chain: %v", err)
|
b, err := os.ReadFile(filepath.Join(dir, "checksums.txt"))
|
||||||
}
|
if err != nil {
|
||||||
if have, want := imported.CurrentHeader(), chain.CurrentHeader(); have.Hash() != want.Hash() {
|
t.Fatalf("failed to read checksums: %v", err)
|
||||||
t.Fatalf("imported chain does not match expected, have (%d, %s) want (%d, %s)", have.Number, have.Hash(), want.Number, want.Hash())
|
}
|
||||||
|
checksums := strings.Split(string(b), "\n")
|
||||||
|
|
||||||
|
// Verify each Era.
|
||||||
|
entries, _ := era.ReadDir(dir, "mainnet")
|
||||||
|
for i, filename := range entries {
|
||||||
|
func() {
|
||||||
|
f, err := os.Open(filepath.Join(dir, filename))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error opening era file: %v", err)
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
h = sha256.New()
|
||||||
|
buf = bytes.NewBuffer(nil)
|
||||||
|
)
|
||||||
|
if _, err := io.Copy(h, f); err != nil {
|
||||||
|
t.Fatalf("unable to recalculate checksum: %v", err)
|
||||||
|
}
|
||||||
|
if got, want := common.BytesToHash(h.Sum(buf.Bytes()[:])).Hex(), checksums[i]; got != want {
|
||||||
|
t.Fatalf("checksum %d does not match: got %s, want %s", i, got, want)
|
||||||
|
}
|
||||||
|
e, err := tt.from(f)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error opening era: %v", err)
|
||||||
|
}
|
||||||
|
defer e.Close()
|
||||||
|
it, err := e.Iterator()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error making era reader: %v", err)
|
||||||
|
}
|
||||||
|
for j := 0; it.Next(); j++ {
|
||||||
|
n := i*int(step) + j
|
||||||
|
if it.Error() != nil {
|
||||||
|
t.Fatalf("error reading block entry %d: %v", n, it.Error())
|
||||||
|
}
|
||||||
|
block, receipts, err := it.BlockAndReceipts()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error reading block entry %d: %v", n, err)
|
||||||
|
}
|
||||||
|
want := chain.GetBlockByNumber(uint64(n))
|
||||||
|
if want, got := uint64(n), block.NumberU64(); want != got {
|
||||||
|
t.Fatalf("blocks out of order: want %d, got %d", want, got)
|
||||||
|
}
|
||||||
|
if want.Hash() != block.Hash() {
|
||||||
|
t.Fatalf("block hash mismatch %d: want %s, got %s", n, want.Hash().Hex(), block.Hash().Hex())
|
||||||
|
}
|
||||||
|
if got := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); got != want.TxHash() {
|
||||||
|
t.Fatalf("tx hash %d mismatch: want %s, got %s", n, want.TxHash(), got)
|
||||||
|
}
|
||||||
|
if got := types.CalcUncleHash(block.Uncles()); got != want.UncleHash() {
|
||||||
|
t.Fatalf("uncle hash %d mismatch: want %s, got %s", n, want.UncleHash(), got)
|
||||||
|
}
|
||||||
|
if got := types.DeriveSha(receipts, trie.NewStackTrie(nil)); got != want.ReceiptHash() {
|
||||||
|
t.Fatalf("receipt root %d mismatch: want %s, got %s", n, want.ReceiptHash(), got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now import Era.
|
||||||
|
db2, err := rawdb.Open(rawdb.NewMemoryDatabase(), rawdb.OpenOptions{})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
t.Cleanup(func() {
|
||||||
|
db2.Close()
|
||||||
|
})
|
||||||
|
|
||||||
|
genesis.MustCommit(db2, triedb.NewDatabase(db2, triedb.HashDefaults))
|
||||||
|
imported, err := core.NewBlockChain(db2, genesis, ethash.NewFaker(), nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to initialize chain: %v", err)
|
||||||
|
}
|
||||||
|
if err := ImportHistory(imported, dir, "mainnet", tt.from); err != nil {
|
||||||
|
t.Fatalf("failed to import chain: %v", err)
|
||||||
|
}
|
||||||
|
if have, want := imported.CurrentHeader(), chain.CurrentHeader(); have.Hash() != want.Hash() {
|
||||||
|
t.Fatalf("imported chain does not match expected, have (%d, %s) want (%d, %s)", have.Number, have.Hash(), want.Number, want.Hash())
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
@ -272,6 +272,14 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
amsterdam := chain.Config().IsAmsterdam(header.Number, header.Time)
|
||||||
|
if amsterdam && header.SlotNumber == nil {
|
||||||
|
return errors.New("header is missing slotNumber")
|
||||||
|
}
|
||||||
|
if !amsterdam && header.SlotNumber != nil {
|
||||||
|
return fmt.Errorf("invalid slotNumber: have %d, expected nil", *header.SlotNumber)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -365,46 +373,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,13 @@ 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)
|
||||||
|
case header.SlotNumber != nil:
|
||||||
|
return fmt.Errorf("invalid slotNumber, have %#x, expected nil", *header.SlotNumber)
|
||||||
}
|
}
|
||||||
// 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 +644,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
|
||||||
|
|
@ -694,6 +696,9 @@ func encodeSigHeader(w io.Writer, header *types.Header) {
|
||||||
if header.ParentBeaconRoot != nil {
|
if header.ParentBeaconRoot != nil {
|
||||||
panic("unexpected parent beacon root value in clique")
|
panic("unexpected parent beacon root value in clique")
|
||||||
}
|
}
|
||||||
|
if header.SlotNumber != nil {
|
||||||
|
panic("unexpected slot number value in clique")
|
||||||
|
}
|
||||||
if err := rlp.Encode(w, enc); err != nil {
|
if err := rlp.Encode(w, enc); err != nil {
|
||||||
panic("can't encode: " + err.Error())
|
panic("can't encode: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,13 @@ 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)
|
||||||
|
case header.SlotNumber != nil:
|
||||||
|
return fmt.Errorf("invalid slotNumber, have %#x, expected nil", *header.SlotNumber)
|
||||||
}
|
}
|
||||||
// Add some fake checks for tests
|
// Add some fake checks for tests
|
||||||
if ethash.fakeDelay != nil {
|
if ethash.fakeDelay != nil {
|
||||||
|
|
@ -527,7 +529,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,
|
||||||
|
|
@ -559,6 +561,9 @@ func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) {
|
||||||
if header.ParentBeaconRoot != nil {
|
if header.ParentBeaconRoot != nil {
|
||||||
panic("parent beacon root set on ethash")
|
panic("parent beacon root set on ethash")
|
||||||
}
|
}
|
||||||
|
if header.SlotNumber != nil {
|
||||||
|
panic("slot number set on ethash")
|
||||||
|
}
|
||||||
rlp.Encode(hasher, enc)
|
rlp.Encode(hasher, enc)
|
||||||
hasher.Sum(hash[:0])
|
hasher.Sum(hash[:0])
|
||||||
return hash
|
return hash
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,10 @@ func VerifyEIP1559Header(config *params.ChainConfig, parent, header *types.Heade
|
||||||
if header.BaseFee == nil {
|
if header.BaseFee == nil {
|
||||||
return errors.New("header is missing baseFee")
|
return errors.New("header is missing baseFee")
|
||||||
}
|
}
|
||||||
|
// Verify the parent header is not malformed
|
||||||
|
if config.IsLondon(parent.Number) && parent.BaseFee == nil {
|
||||||
|
return errors.New("parent header is missing baseFee")
|
||||||
|
}
|
||||||
// Verify the baseFee is correct based on the parent header.
|
// Verify the baseFee is correct based on the parent header.
|
||||||
expectedBaseFee := CalcBaseFee(config, parent)
|
expectedBaseFee := CalcBaseFee(config, parent)
|
||||||
if header.BaseFee.Cmp(expectedBaseFee) != 0 {
|
if header.BaseFee.Cmp(expectedBaseFee) != 0 {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue