Compare commits
195 Commits
big_merge_
...
fix-v1.3.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05c1f1438c | ||
|
|
4b5eebead1 | ||
|
|
b5603d2e98 | ||
|
|
c8cc91963f | ||
|
|
bd13416162 | ||
|
|
b7b64da564 | ||
|
|
73f27a590f | ||
|
|
5e74ea650d | ||
|
|
5378df3702 | ||
|
|
40cae45436 | ||
|
|
361e8413e6 | ||
|
|
36a283ef98 | ||
|
|
78d1cade19 | ||
|
|
82beb2c5f3 | ||
|
|
3761bf0426 | ||
|
|
29427c51fd | ||
|
|
220be95117 | ||
|
|
f0d9f61bf6 | ||
|
|
d49da4348c | ||
|
|
fecd2bfafe | ||
|
|
ef13f3194d | ||
|
|
c6aeee2001 | ||
|
|
58602e6b53 | ||
|
|
d10200175e | ||
|
|
a6a956263e | ||
|
|
ef462c2b47 | ||
|
|
4829027a54 | ||
|
|
bea8f8ecfc | ||
|
|
04d62b53da | ||
|
|
d8b85839ee | ||
|
|
e606461454 | ||
|
|
1c3d31c19f | ||
|
|
0d5ecb5b90 | ||
|
|
1469bce18a | ||
|
|
a17fef4f15 | ||
|
|
fee8a25957 | ||
|
|
ccb4d55a7c | ||
|
|
8ed5d24e1d | ||
|
|
5853329c63 | ||
|
|
69531d67a8 | ||
|
|
7b22894146 | ||
|
|
b2de32fb16 | ||
|
|
73d19c00cd | ||
|
|
5fa1755329 | ||
|
|
23a8d00334 | ||
|
|
3349a24333 | ||
|
|
7f2ef5987f | ||
|
|
8d51cec12e | ||
|
|
de1a126ec5 | ||
|
|
124939aaa4 | ||
|
|
a25a2143ce | ||
|
|
7c8fa2b880 | ||
|
|
a6befb5078 | ||
|
|
8e56d6b875 | ||
|
|
0bdd0d20e5 | ||
|
|
267c5c028c | ||
|
|
c25594257d | ||
|
|
ad09930bdf | ||
|
|
eb4ea42196 | ||
|
|
0ba5816cc7 | ||
|
|
354c0d7180 | ||
|
|
9badb15e80 | ||
|
|
f28b98a994 | ||
|
|
01a4b00a2b | ||
|
|
474860ef77 | ||
|
|
4d2bd1253d | ||
|
|
ca058b7a69 | ||
|
|
f4b7cdfe38 | ||
|
|
f6fb2e9116 | ||
|
|
e44de3ab27 | ||
|
|
07c46abcbe | ||
|
|
8a440e753f | ||
|
|
5ee77bbe8b | ||
|
|
8205fdc525 | ||
|
|
0b632d97f3 | ||
|
|
84b268f6fb | ||
|
|
f628e32ba5 | ||
|
|
e4910b9540 | ||
|
|
2e69dcb342 | ||
|
|
64be7df9e2 | ||
|
|
1ebf2a4376 | ||
|
|
8ce9cdaae3 | ||
|
|
b3df096358 | ||
|
|
4b107c5303 | ||
|
|
fe928d4778 | ||
|
|
a140a5a324 | ||
|
|
e3ef62f3bd | ||
|
|
fa5d0cf287 | ||
|
|
6c788d7675 | ||
|
|
a30beeba59 | ||
|
|
aa15df2814 | ||
|
|
195ae35130 | ||
|
|
5db73c9837 | ||
|
|
3a5ec36c54 | ||
|
|
7891b210e0 | ||
|
|
3076ad2ab9 | ||
|
|
d9873bbf38 | ||
|
|
3e6c16afd3 | ||
|
|
1ddd337d1c | ||
|
|
a182557ac3 | ||
|
|
4b32d400ee | ||
|
|
7e6b43a5c7 | ||
|
|
5b78f5761a | ||
|
|
885de2c1ca | ||
|
|
afc3b42241 | ||
|
|
a2f9ac0c8b | ||
|
|
761563155c | ||
|
|
8b00720640 | ||
|
|
a8409158a5 | ||
|
|
a3507cc2c1 | ||
|
|
b494339e10 | ||
|
|
f7e9adc2c8 | ||
|
|
70ccc3d1fe | ||
|
|
20dcaabfdc | ||
|
|
c409eb6ac6 | ||
|
|
cf80501de5 | ||
|
|
3ce568ff44 | ||
|
|
8e19728ea7 | ||
|
|
1edb34fd67 | ||
|
|
789442372d | ||
|
|
c92b6ce2ad | ||
|
|
cd0356b106 | ||
|
|
0224d48df4 | ||
|
|
497fdf8358 | ||
|
|
8b94dd6b59 | ||
|
|
4be9481558 | ||
|
|
3fc9f750d1 | ||
|
|
72ffb0cbed | ||
|
|
1dca486622 | ||
|
|
a4eee3bdaa | ||
|
|
53559fc4d7 | ||
|
|
62862471f8 | ||
|
|
ea9c962d1f | ||
|
|
f5a854c9c4 | ||
|
|
604f1608b3 | ||
|
|
56424d390f | ||
|
|
0d9151eb8f | ||
|
|
3e298c1586 | ||
|
|
3bf998f55c | ||
|
|
fd6e7bb3b2 | ||
|
|
01d75a9d21 | ||
|
|
4493ab8a07 | ||
|
|
a6cfcfe2b3 | ||
|
|
9f5842e0ec | ||
|
|
fdfc6371f6 | ||
|
|
5a3109b1bf | ||
|
|
c3199ab5fc | ||
|
|
9baffb33b6 | ||
|
|
d3a6f9a19e | ||
|
|
713d8d66a9 | ||
|
|
4be2e1bb70 | ||
|
|
959b7332bf | ||
|
|
dda8c00eec | ||
|
|
423d4137e5 | ||
|
|
181218128b | ||
|
|
b86459a722 | ||
|
|
73cfed0ea1 | ||
|
|
35d85e250b | ||
|
|
43e2c779b4 | ||
|
|
17ffdf1a9d | ||
|
|
f8439514e3 | ||
|
|
5cd647bb7d | ||
|
|
44b2f4a787 | ||
|
|
0d47213199 | ||
|
|
4259f4c1f8 | ||
|
|
c26a30392a | ||
|
|
6932673003 | ||
|
|
4b45c5993c | ||
|
|
35b21cac14 | ||
|
|
f8bc2b76ac | ||
|
|
c955dd2189 | ||
|
|
b8bad314ed | ||
|
|
528d97b541 | ||
|
|
720ff1fe57 | ||
|
|
d179056512 | ||
|
|
2f7d305013 | ||
|
|
b3ef585957 | ||
|
|
c5647b128c | ||
|
|
52e2cb86a5 | ||
|
|
41f0667ce1 | ||
|
|
2c7a07bc57 | ||
|
|
1bc27f6d98 | ||
|
|
9edad94115 | ||
|
|
e379117b79 | ||
|
|
782aea5841 | ||
|
|
fe5df933b6 | ||
|
|
bb6bdc055d | ||
|
|
1c17c47df7 | ||
|
|
7a19cd27b6 | ||
|
|
c431373bd5 | ||
|
|
2b836937a2 | ||
|
|
34b065aecb | ||
|
|
5f87ddf9f6 | ||
|
|
fd58e6f0ac | ||
|
|
9ed95d826e |
2
.github/commitlint.config.js
vendored
2
.github/commitlint.config.js
vendored
@@ -36,7 +36,7 @@ module.exports = {
|
||||
'header-max-length': [
|
||||
2,
|
||||
'always',
|
||||
72,
|
||||
80,
|
||||
],
|
||||
},
|
||||
helpUrl:
|
||||
|
||||
6
.github/workflows/build-test.yml
vendored
6
.github/workflows/build-test.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
- develop
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
unit-test:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.19.x]
|
||||
go-version: [1.21.x]
|
||||
os: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
@@ -47,5 +47,3 @@ jobs:
|
||||
run: |
|
||||
go mod download
|
||||
make geth
|
||||
|
||||
|
||||
|
||||
2
.github/workflows/commit-lint.yml
vendored
2
.github/workflows/commit-lint.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
- develop
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
|
||||
|
||||
56
.github/workflows/evm-tests.yml
vendored
Normal file
56
.github/workflows/evm-tests.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
name: EVM Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
evm-test:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.21.x]
|
||||
os: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
# In order:
|
||||
# * Module download cache
|
||||
# * Build cache (Linux)
|
||||
# * Build cache (Mac)
|
||||
# * Build cache (Windows)
|
||||
path: |
|
||||
~/go/pkg/mod
|
||||
~/.cache/go-build
|
||||
~/Library/Caches/go-build
|
||||
~\AppData\Local\go-build
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- name: EVM Test
|
||||
env:
|
||||
CGO_CFLAGS: "-O -D__BLST_PORTABLE__"
|
||||
CGO_CFLAGS_ALLOW: "-O -D__BLST_PORTABLE__"
|
||||
ANDROID_HOME: "" # Skip android test
|
||||
run: |
|
||||
git submodule update --init --depth 1 --recursive
|
||||
go mod download
|
||||
cd tests
|
||||
sed -i -e 's/\/\/ bt.skipLoad/bt.skipLoad/g' block_test.go
|
||||
bash -x run-evm-tests.sh
|
||||
2
.github/workflows/integration-test.yml
vendored
2
.github/workflows/integration-test.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
- develop
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
|
||||
|
||||
8
.github/workflows/lint.yml
vendored
8
.github/workflows/lint.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
- develop
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
golang-lint:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.19.x]
|
||||
go-version: [1.21.x]
|
||||
os: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
@@ -44,13 +44,13 @@ jobs:
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- run: |
|
||||
go mod download
|
||||
go mod tidy
|
||||
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
with:
|
||||
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
|
||||
version: v1.52.2
|
||||
version: v1.55.2
|
||||
working-directory: ./
|
||||
skip-pkg-cache: true
|
||||
skip-cache: true
|
||||
|
||||
37
.github/workflows/nancy.yml
vendored
Normal file
37
.github/workflows/nancy.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
name: Go Nancy
|
||||
|
||||
on:
|
||||
# Scan changed files in PRs (diff-aware scanning):
|
||||
pull_request: {}
|
||||
# Scan on-demand through GitHub Actions interface:
|
||||
workflow_dispatch: {}
|
||||
# Scan mainline branches and report all findings:
|
||||
push:
|
||||
branches: ["master", "develop"]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.21.x]
|
||||
os: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Go 1.x in order to write go.list file
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
- name: Go mod tidy
|
||||
run: go mod tidy
|
||||
|
||||
- name: WriteGoList
|
||||
run: go list -json -deps ./... > go.list
|
||||
|
||||
- name: Nancy
|
||||
uses: sonatype-nexus-community/nancy-github-action@main
|
||||
with:
|
||||
nancyCommand: sleuth --loud
|
||||
2
.github/workflows/pre-release.yml
vendored
2
.github/workflows/pre-release.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
name: Build Release
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.19.x]
|
||||
go-version: [1.21.x]
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
name: Build Release
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.19.x]
|
||||
go-version: [1.21.x]
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
|
||||
5
.github/workflows/unit-test.yml
vendored
5
.github/workflows/unit-test.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
- develop
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
unit-test:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.19.x]
|
||||
go-version: [1.21.x]
|
||||
os: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
@@ -51,4 +51,3 @@ jobs:
|
||||
run: |
|
||||
go mod download
|
||||
make test
|
||||
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -14,7 +14,6 @@
|
||||
*/**/*tx_database*
|
||||
*/**/*dapps*
|
||||
build/_vendor/pkg
|
||||
/tests/truffle/storage
|
||||
|
||||
#*
|
||||
.#*
|
||||
|
||||
@@ -15,7 +15,6 @@ output:
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- goconst
|
||||
- goimports
|
||||
- gosimple
|
||||
- govet
|
||||
@@ -42,9 +41,6 @@ linters:
|
||||
linters-settings:
|
||||
gofmt:
|
||||
simplify: true
|
||||
goconst:
|
||||
min-len: 3 # minimum length of string constant
|
||||
min-occurrences: 6 # minimum number of occurrences
|
||||
|
||||
issues:
|
||||
exclude-rules:
|
||||
|
||||
22
.travis.yml
22
.travis.yml
@@ -13,7 +13,7 @@ jobs:
|
||||
- stage: lint
|
||||
os: linux
|
||||
dist: bionic
|
||||
go: 1.20.x
|
||||
go: 1.21.x
|
||||
env:
|
||||
- lint
|
||||
git:
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
os: linux
|
||||
arch: amd64
|
||||
dist: bionic
|
||||
go: 1.20.x
|
||||
go: 1.21.x
|
||||
env:
|
||||
- docker
|
||||
services:
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
os: linux
|
||||
arch: arm64
|
||||
dist: bionic
|
||||
go: 1.20.x
|
||||
go: 1.21.x
|
||||
env:
|
||||
- docker
|
||||
services:
|
||||
@@ -63,7 +63,7 @@ jobs:
|
||||
os: linux
|
||||
dist: bionic
|
||||
sudo: required
|
||||
go: 1.20.x
|
||||
go: 1.21.x
|
||||
env:
|
||||
- azure-linux
|
||||
- GO111MODULE=on
|
||||
@@ -97,7 +97,7 @@ jobs:
|
||||
- stage: build
|
||||
if: type = push
|
||||
os: osx
|
||||
go: 1.20.x
|
||||
go: 1.21.x
|
||||
env:
|
||||
- azure-osx
|
||||
- GO111MODULE=on
|
||||
@@ -112,7 +112,7 @@ jobs:
|
||||
os: linux
|
||||
arch: amd64
|
||||
dist: bionic
|
||||
go: 1.20.x
|
||||
go: 1.21.x
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
script:
|
||||
@@ -123,7 +123,7 @@ jobs:
|
||||
os: linux
|
||||
arch: arm64
|
||||
dist: bionic
|
||||
go: 1.19.x
|
||||
go: 1.20.x
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
script:
|
||||
@@ -132,7 +132,7 @@ jobs:
|
||||
- stage: build
|
||||
os: linux
|
||||
dist: bionic
|
||||
go: 1.19.x
|
||||
go: 1.20.x
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
script:
|
||||
@@ -143,7 +143,7 @@ jobs:
|
||||
if: type = cron || (type = push && tag ~= /^v[0-9]/)
|
||||
os: linux
|
||||
dist: bionic
|
||||
go: 1.20.x
|
||||
go: 1.21.x
|
||||
env:
|
||||
- ubuntu-ppa
|
||||
- GO111MODULE=on
|
||||
@@ -167,7 +167,7 @@ jobs:
|
||||
if: type = cron
|
||||
os: linux
|
||||
dist: bionic
|
||||
go: 1.20.x
|
||||
go: 1.21.x
|
||||
env:
|
||||
- azure-purge
|
||||
- GO111MODULE=on
|
||||
@@ -181,7 +181,7 @@ jobs:
|
||||
if: type = cron
|
||||
os: linux
|
||||
dist: bionic
|
||||
go: 1.20.x
|
||||
go: 1.21.x
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
script:
|
||||
|
||||
279
CHANGELOG.md
279
CHANGELOG.md
@@ -1,4 +1,283 @@
|
||||
# Changelog
|
||||
## v1.3.11
|
||||
BUGFIX
|
||||
* [\#2288](https://github.com/bnb-chain/bsc/pull/2288) fix: add FeynmanFix upgrade for a testnet issue
|
||||
|
||||
## v1.3.10
|
||||
FEATURE
|
||||
* [\#2047](https://github.com/bnb-chain/bsc/pull/2047) feat: add new fork block and precompile contract for BEP294 and BEP299
|
||||
|
||||
## v1.3.9
|
||||
FEATURE
|
||||
* [\#2186](https://github.com/bnb-chain/bsc/pull/2186) log: support maxBackups in config.toml
|
||||
|
||||
BUGFIX
|
||||
* [\#2160](https://github.com/bnb-chain/bsc/pull/2160) cmd: fix dump cli cannot work in path mode
|
||||
* [\#2183](https://github.com/bnb-chain/bsc/pull/2183) p2p: resolved deadlock on p2p server shutdown
|
||||
|
||||
IMPROVEMENT
|
||||
* [\#2177](https://github.com/bnb-chain/bsc/pull/0000) build(deps): bump github.com/quic-go/quic-go from 0.39.3 to 0.39.4
|
||||
* [\#2185](https://github.com/bnb-chain/bsc/pull/2185) consensus/parlia: set nonce before evm run
|
||||
* [\#2190](https://github.com/bnb-chain/bsc/pull/2190) fix(legacypool): deprecate already known error
|
||||
* [\#2195](https://github.com/bnb-chain/bsc/pull/2195) eth/fetcher: downgrade state tx log
|
||||
|
||||
## v1.3.8
|
||||
FEATURE
|
||||
* [\#2074](https://github.com/bnb-chain/bsc/pull/2074) faucet: new faucet client
|
||||
* [\#2082](https://github.com/bnb-chain/bsc/pull/2082) cmd/dbcmd: add inspect trie tool
|
||||
* [\#2140](https://github.com/bnb-chain/bsc/pull/2140) eth/fetcher: allow underpriced transactions in after timeout
|
||||
* [\#2115](https://github.com/bnb-chain/bsc/pull/2115) p2p: no peer reconnect if explicitly disconnected
|
||||
* [\#2128](https://github.com/bnb-chain/bsc/pull/2128) go.mod: upgrade prysm to support built with go@v1.21
|
||||
* [\#2151](https://github.com/bnb-chain/bsc/pull/2151) feat: enable NoDial should still dial static nodes
|
||||
* [\#2144](https://github.com/bnb-chain/bsc/pull/2144) p2p: reset disconnect set with magic enode ID
|
||||
|
||||
BUGFIX
|
||||
* [\#2095](https://github.com/bnb-chain/bsc/pull/2095) rpc: fix ns/µs mismatch in metrics
|
||||
* [\#2083](https://github.com/bnb-chain/bsc/pull/2083) triedb/pathdb: fix async node buffer diskroot mismatches when journaling
|
||||
* [\#2120](https://github.com/bnb-chain/bsc/pull/2120) ethdb/pebble: cap memory table size as maxMemTableSize-1
|
||||
* [\#2107](https://github.com/bnb-chain/bsc/pull/2107) cmd/geth: fix parse state scheme
|
||||
* [\#2121](https://github.com/bnb-chain/bsc/pull/2121) parlia: fix verifyVoteAttestation when verify a batch of headers
|
||||
* [\#2132](https://github.com/bnb-chain/bsc/pull/2132) core: fix systemcontracts.GenesisHash when run bsc firstly without init
|
||||
* [\#2155](https://github.com/bnb-chain/bsc/pull/2155) cmd, core: resolve scheme from a read-write database and refactor resolveChainFreezerDir func
|
||||
|
||||
IMPROVEMENT
|
||||
* [\#2099](https://github.com/bnb-chain/bsc/pull/2099) params/config: remove useless toml tag for hardforks
|
||||
* [\#2100](https://github.com/bnb-chain/bsc/pull/2100) core/genesis: support chapel to run without geth init
|
||||
* [\#2101](https://github.com/bnb-chain/bsc/pull/2101) core: add metrics for bad block
|
||||
* [\#2109](https://github.com/bnb-chain/bsc/pull/2109) cmd/geth: tidy flags for geth command
|
||||
* [\#1953](https://github.com/bnb-chain/bsc/pull/1953) build(deps): bump github.com/docker/docker
|
||||
* [\#2086](https://github.com/bnb-chain/bsc/pull/2086) build(deps): bump golang.org/x/crypto from 0.12.0 to 0.17.0
|
||||
* [\#2106](https://github.com/bnb-chain/bsc/pull/2106) params: use rialto to test builtin network logic
|
||||
* [\#2098](https://github.com/bnb-chain/bsc/pull/2098) cmd, les, tests: remove light client code
|
||||
* [\#2114](https://github.com/bnb-chain/bsc/pull/2114) p2p: add serve metrics
|
||||
* [\#2123](https://github.com/bnb-chain/bsc/pull/2123) p2p, eth: improve logs
|
||||
* [\#2116](https://github.com/bnb-chain/bsc/pull/2116) tests: revive evm test cases
|
||||
* [\#2161](https://github.com/bnb-chain/bsc/pull/2161) code: remove IsEuler check from worker.go
|
||||
* [\#2167](https://github.com/bnb-chain/bsc/pull/2167) improve: increase SystemTxsGas from 1,500,000 to 5,000,000
|
||||
* [\#2172](https://github.com/bnb-chain/bsc/pull/2172) improve: remove sharedpool from miner
|
||||
* [\#1332](https://github.com/bnb-chain/bsc/pull/1332) core/state: no need to prune block if the same
|
||||
|
||||
## v1.3.7
|
||||
FEATURE
|
||||
* [\#2067](https://github.com/bnb-chain/bsc/pull/2067) cmd/geth: add check func to validate state scheme
|
||||
* [\#2068](https://github.com/bnb-chain/bsc/pull/2068) internal/ethapi: implement eth_getBlockReceipts
|
||||
|
||||
BUGFIX
|
||||
* [\#2035](https://github.com/bnb-chain/bsc/pull/2035) all: pull snap sync PRs from upstream v1.13.5
|
||||
* [\#2072](https://github.com/bnb-chain/bsc/pull/2072) fix: fix the pebble config of level option
|
||||
* [\#2078](https://github.com/bnb-chain/bsc/pull/2078) core: LoadChainConfig return the predefined config for built-in networks firstly
|
||||
|
||||
## v1.3.6
|
||||
FEATURE
|
||||
* [\#2012](https://github.com/bnb-chain/bsc/pull/2012) cmd, core, ethdb: enable Pebble on 32 bits and OpenBSD
|
||||
* [\#2063](https://github.com/bnb-chain/bsc/pull/2063) log: support to disable log rotate by hours
|
||||
* [\#2064](https://github.com/bnb-chain/bsc/pull/2064) log: limit rotateHours in range [0,23]
|
||||
|
||||
BUGFIX
|
||||
* [\#2058](https://github.com/bnb-chain/bsc/pull/2058) params: set default hardfork times
|
||||
|
||||
IMPROVEMENT
|
||||
* [\#2015](https://github.com/bnb-chain/bsc/pull/2015) cmd, core, eth: change default network from ETH to BSC
|
||||
* [\#2036](https://github.com/bnb-chain/bsc/pull/2036) cmd/jsutils: add 2 tools get validator version and block txs number
|
||||
* [\#2037](https://github.com/bnb-chain/bsc/pull/2037) core/txpool/legacypool: respect nolocals-setting
|
||||
* [\#2042](https://github.com/bnb-chain/bsc/pull/2042) core/systemcontracts: update CommitUrl for keplerUpgrade
|
||||
* [\#2043](https://github.com/bnb-chain/bsc/pull/2043) tests/truffle: adapt changes in bsc-genesis-contracts
|
||||
* [\#2051](https://github.com/bnb-chain/bsc/pull/2051) core/vote: wait some blocks before voting since mining begin
|
||||
* [\#2060](https://github.com/bnb-chain/bsc/pull/2060) cmd/utils: allow HTTPHost and WSHost flags precede
|
||||
|
||||
## v1.3.5
|
||||
FEATURE
|
||||
* [\#1970](https://github.com/bnb-chain/bsc/pull/1970) core: enable Shanghai EIPs
|
||||
* [\#1973](https://github.com/bnb-chain/bsc/pull/1973) core/systemcontracts: include BEP-319 on kepler hardfork
|
||||
|
||||
BUGFIX
|
||||
* [\#1964](https://github.com/bnb-chain/bsc/pull/1964) consensus/parlia: hardfork block can be epoch block
|
||||
* [\#1979](https://github.com/bnb-chain/bsc/pull/1979) fix: upgrade pebble and improve config
|
||||
* [\#1980](https://github.com/bnb-chain/bsc/pull/1980) internal/ethapi: fix null effectiveGasPrice in GetTransactionReceipt
|
||||
|
||||
IMPROVEMENT
|
||||
* [\#1977](https://github.com/bnb-chain/bsc/pull/1977) doc: add instructions for starting fullnode with pbss
|
||||
|
||||
## v1.3.4
|
||||
BUGFIX
|
||||
* fix: remove pipecommit in miner
|
||||
* add a hard fork: Hertzfix
|
||||
|
||||
## v1.3.3
|
||||
BUGFIX
|
||||
* [\#1986](https://github.com/bnb-chain/bsc/pull/1986) fix(cmd): check pruneancient when creating db
|
||||
|
||||
IMPROVEMENT
|
||||
* [\#2000](https://github.com/bnb-chain/bsc/pull/2000) cmd/utils: exit process if txlookuplimit flag is set
|
||||
|
||||
## v1.3.2
|
||||
BUGFIX
|
||||
* fix: remove sharedPool
|
||||
|
||||
IMPROVEMENT
|
||||
* [\#2007](https://github.com/bnb-chain/bsc/pull/2007) consensus/parlia: increase size of snapshot cache in parlia
|
||||
* [\#2008](https://github.com/bnb-chain/bsc/pull/2008) consensus/parlia: recover faster when snapshot of parlia is gone in disk
|
||||
|
||||
## v1.3.1
|
||||
FEATURE
|
||||
* [\#1881](https://github.com/bnb-chain/bsc/pull/1881) feat: active pbss
|
||||
* [\#1882](https://github.com/bnb-chain/bsc/pull/1882) cmd/geth: add hbss to pbss convert tool
|
||||
* [\#1916](https://github.com/bnb-chain/bsc/pull/1916) feat: cherry-pick pbss patch commits from eth repo in v1.13.2
|
||||
* [\#1939](https://github.com/bnb-chain/bsc/pull/1939) dependency: go version to 1.20 and some dependencies in go.mod
|
||||
* [\#1955](https://github.com/bnb-chain/bsc/pull/1955) eth, trie/triedb/pathdb: pbss patches
|
||||
* [\#1962](https://github.com/bnb-chain/bsc/pull/1962) cherry pick pbss patches from go-ethereum
|
||||
|
||||
BUGFIX
|
||||
* [\#1923](https://github.com/bnb-chain/bsc/pull/1923) consensus/parlia: fix nextForkHash in Extra filed of block header
|
||||
* [\#1950](https://github.com/bnb-chain/bsc/pull/1950) fix: 2 APIs of get receipt related
|
||||
* [\#1951](https://github.com/bnb-chain/bsc/pull/1951) txpool: fix a potential crash issue in shutdown;
|
||||
* [\#1963](https://github.com/bnb-chain/bsc/pull/1963) fix: revert trie commited flag after delete statedb mpt cache
|
||||
|
||||
IMPROVEMENT
|
||||
* [\#1948](https://github.com/bnb-chain/bsc/pull/1948) performance: commitTire concurrently
|
||||
* [\#1949](https://github.com/bnb-chain/bsc/pull/1949) code: remove accountTrieCache and storageTrieCache
|
||||
* [\#1954](https://github.com/bnb-chain/bsc/pull/1954) trie: keep trie prefetch during validation phase
|
||||
|
||||
## v1.3.0
|
||||
#### RPC
|
||||
* [internal/ethapi: add debug_getRawReceipts RPC method (#24773)](https://github.com/bnb-chain/bsc/pull/1840/commits/ae7d834bc752a2d94fef9d354ee78fcb9425f3d1)
|
||||
* [node, rpc: add ReadHeaderTimeout config option (#25338)](https://github.com/bnb-chain/bsc/pull/1840/commits/9244f87dc1c8869a2632176f719e515217720a43)
|
||||
* [rpc: check that "version" is "2.0" in request objects (#25570)](https://github.com/bnb-chain/bsc/pull/1840/commits/38e002f4641c2779c897ccaca575ec5ddeee9254)
|
||||
* [rpc: support injecting HTTP headers through context (#26023)](https://github.com/bnb-chain/bsc/pull/1840/commits/add337e0f7bad02f3cf535c66cd31f252b0b5c99)
|
||||
* [rpc: websocket should respect the "HTTP_PROXY" by default (#27264)](https://github.com/bnb-chain/bsc/pull/1840/commits/73697529994e14996b7740730481e926d5ec3e40)
|
||||
* [rpc: change BlockNumber constant values to match ethclient (#27219)](https://github.com/bnb-chain/bsc/pull/1840/commits/9231770811cda0473a7fa4e2bccc95bf62aae634)
|
||||
* [eth: make debug_StorageRangeAt take a block hash or number (#27328)](https://github.com/bnb-chain/bsc/pull/1840/commits/d789c68b667e13eb5cefd19d09ae84f7d016df6a)
|
||||
* [eth,core: add api debug_getTrieFlushInterval (#27303)](https://github.com/bnb-chain/bsc/pull/1840/commits/0783cb7d91ad7b3cdf72ac6c6edaec8318673eb6)
|
||||
* [rpc: add limit for batch request items and response size (#26681)](https://github.com/bnb-chain/bsc/pull/1840/commits/f3314bb6df4c86e650f0e47cbb5a21ca0616ac11)
|
||||
* [core/types: support yParity field in JSON transactions (#27744)](https://github.com/bnb-chain/bsc/pull/1840/commits/bb148dd342ba03ce40cf04295e193c94b9dda322)
|
||||
* [eth/filters: send rpctransactions in pending-subscription (#26126)](https://github.com/bnb-chain/bsc/pull/1840/commits/8c5ce1107b3110c7cb735d8dfa91c9c701393c85)
|
||||
#### Flag
|
||||
* [cmd/geth: rename --whitelist to --eth.requiredblocks (#24505)](https://github.com/bnb-chain/bsc/pull/1840/commits/dbfd3972624c1d82db21f5dfceab8fde7a1eee0a)
|
||||
* [cmd: migrate to urfave/cli/v2 (#24751)](https://github.com/bnb-chain/bsc/pull/1840/commits/52ed3570c483693fdd6667add7e3050520ad3ba2)
|
||||
* [cmd/utils: print warning when --metrics.port set without --metrics.ad…](https://github.com/bnb-chain/bsc/pull/1840/commits/8846c07d044f30dca8cd0db91c6245f71f4b24fa)
|
||||
* [cmd/devp2p: add --extaddr flag (#26312)](https://github.com/bnb-chain/bsc/pull/1840/commits/b44abf56a966016cbb651648ac2d7b6705e80b11)
|
||||
* [core,eth: adddebug_setTrieFlushInterval to change trie flush frequ](https://github.com/bnb-chain/bsc/pull/1840/commits/711afbc7fd76f1f206429e26f9aa5bf98bc7b43d)
|
||||
* [miner, cmd, eth: require explicit etherbase address (#26413)](https://github.com/bnb-chain/bsc/pull/1840/commits/2b44ef5f93cc7479a77890917a29684b56e9167a)
|
||||
* [cmd/geth: Add[--log.format] cli param (#27001)](https://github.com/bnb-chain/bsc/pull/1840/commits/2d1492821d058a3488b4da2c1f62906eaf6d7c95)
|
||||
* [cmd/geth: rename --vmodule to --log.vmodule (#27071)](https://github.com/bnb-chain/bsc/pull/1840/commits/f2df2b1981fa1e014e4cb34cf9a8dd7b8519e0ac)
|
||||
* [params, trie: add verkle fork management + upgrade go-verkle (#27464)](https://github.com/bnb-chain/bsc/pull/1840/commits/85b8d1c06c49342966cad2bbdc17d0dc28b66ffd)
|
||||
#### GraphQL
|
||||
* [graphql: fee history fields (#24452)](https://github.com/bnb-chain/bsc/pull/1840/commits/57cec892536270fc6dafae01ded2c528ffa370e9)
|
||||
* [graphql: add rawReceipt field to transaction type (#24738)](https://github.com/bnb-chain/bsc/pull/1840/commits/d73df893a6fc528e69506397322205bd9258b6fa)
|
||||
* [graphql: add raw fields to block and tx (#24816)](https://github.com/bnb-chain/bsc/pull/1840/commits/29a6b6bcac170ca7f8fceb242eba45ff15df17a1)
|
||||
* [graphql: return correct logs for tx (#25612)](https://github.com/bnb-chain/bsc/pull/1840/commits/d0dc349fd36bd79f94516c866251783641ed12f1)
|
||||
* [graphql: add query timeout (#26116)](https://github.com/bnb-chain/bsc/pull/1840/commits/ee9ff064694c445a3a6972001ccbce2cc5b9c3f2)
|
||||
* [graphql, node, rpc: improve HTTP write timeout handling (#25457)](https://github.com/bnb-chain/bsc/pull/1840/commits/f20eba426a1a871f98d0d988bfd51767364650b7)
|
||||
* [graphql: implement withdrawals (EIP-4895) (#27072)](https://github.com/bnb-chain/bsc/pull/1840/commits/fbe432fa1584bc976fe0242d999a7dd8903378b2)
|
||||
#### Client
|
||||
* [ethclient: add CallContractAtHash (#24355)](https://github.com/bnb-chain/bsc/pull/1700/commits/e98114da4feedf6dfb17b9839fc2c314cf1e5768)
|
||||
* [ethclient: add PeerCount method (#24849)](https://github.com/bnb-chain/bsc/pull/1840/commits/f5ff022dbca2b14af59974154874537b5ed4cc5e)
|
||||
* [ethereum, ethclient: add FeeHistory support (#25403)](https://github.com/bnb-chain/bsc/pull/1840/commits/9ad508018e4790da0c1c00ac355f206fca12ab7c)
|
||||
* [eth/filters, ethclient/gethclient: add fullTx option to pending tx fi…](https://github.com/bnb-chain/bsc/pull/1840/commits/5b1a04b9c749d804b51159fe12246c56de8515c1)
|
||||
* [ethclient: include withdrawals in ethclient block responses (#26778)](https://github.com/bnb-chain/bsc/pull/1840/commits/e1b98f49a5075694c5022f5ec74425e40da415dd)
|
||||
#### Tracer
|
||||
* [eth/tracers/js: drop duktape engine (#24934)](https://github.com/bnb-chain/bsc/pull/1840/commits/ba47d800b13058885288c38bd174babb38560c89)
|
||||
* [eth/tracers: add support for block overrides in debug_traceCall (#24871)](https://github.com/bnb-chain/bsc/pull/1840/commits/d8a2305565b1f97c451f8595e0f65358d6842714)
|
||||
* [eth/tracers: add onlyTopCall option to callTracer (#25430)](https://github.com/bnb-chain/bsc/pull/1840/commits/86de2e516e5a4a2bbe1d29b46a0f460fbdde8303)
|
||||
* [eth/tracers: remove revertReasonTracer, add revert reason to callTracer](https://github.com/bnb-chain/bsc/pull/1840/commits/ff1f49245d641a7268ade38cf512bdc7b26f9b7c)
|
||||
* [eth/tracers: add diffMode to prestateTracer (#25422)](https://github.com/bnb-chain/bsc/pull/1840/commits/5d52a35931bba10f438ce4f41410442dd9cd396c)
|
||||
* [eth/tracers: add multiplexing tracer (#26086)](https://github.com/bnb-chain/bsc/pull/1840/commits/53b624b56d4f36c90ebf8046bd1ca78c87a3b6df)
|
||||
* [core/vm: set tracer-observable value of a delegatecall to match parent `value`](https://github.com/bnb-chain/bsc/pull/1840/commits/b0cd8c4a5c4f0f25011ed64235a3ea1280f03c51)
|
||||
* [eth/tracers: add native flatCallTracer (aka parity style tracer) (#26…](https://github.com/bnb-chain/bsc/pull/1840/commits/2ad150d986dab085965be047c94af6b2952a9e24)
|
||||
* [eth/tracers/native: set created address to nil in case of failure (#2…](https://github.com/bnb-chain/bsc/pull/1840/commits/41af42e97c9d62d303a883cc3c143f560867fa34)
|
||||
* [eth/tracers: report correct gasLimit in call tracers (#27029)](https://github.com/bnb-chain/bsc/pull/1840/commits/0b76eb3708626fbd2eb9c1b58d7b4eac6a5eec15)
|
||||
* [eth/tracers: addtxHashfield on txTraceResult (#27183)](https://github.com/bnb-chain/bsc/pull/1840/commits/604e215d1bb070dff98fb76aa965064c74e3633f)
|
||||
* [eth/tracers: add ReturnData in the tracer's response (#27704)](https://github.com/bnb-chain/bsc/pull/1840/commits/1e069cf8026a9f71b5f7e80959465e4b273d5806)
|
||||
#### Command
|
||||
* [cmd/geth: inspect snapshot dangling storage (#24643)](https://github.com/bnb-chain/bsc/pull/1840/commits/92e3c56e7be26aac4a25859f55f234aadeec7dbf)
|
||||
* [core/state/snapshot: detect and clean up dangling storage snapshot in generation](https://github.com/bnb-chain/bsc/pull/1840/commits/59ac229f87831bd74b4dc07d34f54137cca78095)
|
||||
* [internal/ethapi: add db operations to api (#24739)](https://github.com/bnb-chain/bsc/pull/1840/commits/16701c51697e28986feebd122c6a491e4d9ac0e7)
|
||||
* [cmd/geth: adddb check-state-contentto verify integrity of trie nodes (#24840)](https://github.com/bnb-chain/bsc/pull/1840/commits/e0a9752b965f243313f2c32a91d306600dc3863c)
|
||||
* [ethdb/remotedb, cmd: add support for remote (readonly) databases](https://github.com/bnb-chain/bsc/pull/1840/commits/57192bd0dc545d921306f6a4d7566c0c70c764c5)
|
||||
* [cmd/abigen: accept combined-json via stdin (#24960)](https://github.com/bnb-chain/bsc/pull/1840/commits/0287e1a7c00c1eaad1a99b4ea05d70f1ed685140)
|
||||
* [cmd/geth: extend traverseRawState command (#24954)](https://github.com/bnb-chain/bsc/pull/1840/commits/a10660b7f8f4fa218ee62a7664b47eb6028fee84)
|
||||
* [cmd/geth, core/state/snapshot: rework journal loading, implement account-check (#24765)](https://github.com/bnb-chain/bsc/pull/1840/commits/c375ee91e99cd9c072f2fe9b535c5cb780b5f8a0)
|
||||
* [cmd/geth: add a verkle subcommand (#25718)](https://github.com/bnb-chain/bsc/pull/1840/commits/9d717167aaf27a48d56ad9d1a2c36f90eba1cc13)
|
||||
* [cmd/geth, cmd/utils: geth attach with custom headers (#25829)](https://github.com/bnb-chain/bsc/pull/1840/commits/ea26fc8a6c44ebb48223f991048f41b2ec0a6414)
|
||||
* [core/rawdb: refactor db inspector for extending multiple ancient storage](https://github.com/bnb-chain/bsc/pull/1840/commits/60e30a940bbba2c0d26de040195a5ccdb14d8c10)
|
||||
* [cmd/clef: addlist-accountsandlist-walletsto CLI (#26080)](https://github.com/bnb-chain/bsc/pull/1840/commits/f3a005f176372ff291dfa7c02ee1c87d18e9c788)
|
||||
* [cmd/clef: add importraw feature to clef (#26058)](https://github.com/bnb-chain/bsc/pull/1840/commits/17744639dafc5a54f21e220660bd39d765a09051)
|
||||
* [cmd/devp2p: add more nodekey commands (#26129)](https://github.com/bnb-chain/bsc/pull/1840/commits/913973436bb88b652faffc10d8f97e4c19722883)
|
||||
* [internal/web3ext: fix eth_call stateOverrides in console (#26265)](https://github.com/bnb-chain/bsc/pull/1840/commits/1325fef1025b9feb3342308265b6d1399614be30)
|
||||
* [cmd/evm: add blocktest subcommand to evm (#26526)](https://github.com/bnb-chain/bsc/pull/1840/commits/90f15a0230be34a292c5d0574ee7910ee44267de)
|
||||
#### HardFork
|
||||
* [params: define cancun and prague as timestamp based forks (#26481)](https://github.com/bnb-chain/bsc/pull/1840/commits/f3a005f176372ff291dfa7c02ee1c87d18e9c788)
|
||||
* [all: tie timestamp based forks to the passage of London (#27279)](https://github.com/bnb-chain/bsc/pull/1840/commits/85a4b82b3373fc5f3fa8b7c68061c55b0db0e9b7)
|
||||
##### Shanghai
|
||||
* [core/vm: implement EIP-3855: PUSH0 instruction (#24039)](https://github.com/bnb-chain/bsc/pull/1840/commits/3b967d16caf306ccf8eb78b3a68bec36fa2a52ee)
|
||||
* [core: implement EIP-3651, warm coinbase (#25819)](https://github.com/bnb-chain/bsc/pull/1840/commits/ec2ec2d08e28571dc189903f743cc3931da254a9)
|
||||
* [core/vm: implement EIP-3860: Limit and meter initcode (#23847)](https://github.com/bnb-chain/bsc/pull/1840/commits/793f0f9ec860f6f51e0cec943a268c10863097c7)
|
||||
* [all: implement withdrawals (EIP-4895) (#26484)](https://github.com/bnb-chain/bsc/pull/1840/commits/2a2b0419fb966c54fb86b17bbccea743a45b4d2a)
|
||||
##### CanCun (almost ready)
|
||||
* [all: implement EIP-1153 transient storage (#26003)](https://github.com/bnb-chain/bsc/pull/1840/commits/b4ea2bf7dda9def5374ed3ab16a3dfd872eaa40a)
|
||||
* [core: 4844 opcode and precompile (#27356)](https://github.com/bnb-chain/bsc/pull/1840/commits/c537ace249805903f068c4c66b90558848b49a2f)
|
||||
* [core/vm: implement EIP-5656, mcopy instruction (#26181)](https://github.com/bnb-chain/bsc/pull/1840/commits/5c9cbc218a67ea6d71652f0d93f4c354a687a965)
|
||||
* [core/state, core/vm: implement EIP 6780 (#27189)](https://github.com/bnb-chain/bsc/pull/1840/commits/988d84aa7caf8e71ce441fa65f80d44216d9e00e)
|
||||
#### New Feature
|
||||
* [eth: introduce eth67 protocol (#24093)](https://github.com/bnb-chain/bsc/pull/1840/commits/30602163d5d8321fbc68afdcbbaf2362b2641bde)
|
||||
* [eth: implement eth/68 (#25980)](https://github.com/bnb-chain/bsc/pull/1840/commits/b0d44338bbcefee044f1f635a84487cbbd8f0538)
|
||||
* [PBBS(ready to activate)](https://github.com/ethereum/go-ethereum/commits?author=rjl493456442)
|
||||
#### P2P
|
||||
* [eth/fetcher: throttle peers which deliver many invalid transactions (…](https://github.com/bnb-chain/bsc/pull/1840/commits/7f2890a9be1f91368582479f171248b972b45ae3)
|
||||
#### Build
|
||||
* [build/bot: add ppa-build.sh (#24919)](https://github.com/bnb-chain/bsc/pull/1840/commits/adcad1cd39ad2bc9ddab67b4bee3023b3e6c9873)
|
||||
* [more checs in ci](https://github.com/bnb-chain/bsc/pull/1840/files#diff-6179837f7df53a6f05c522b6b7bb566d484d5465d9894fb04910dd08bb40dcc9)
|
||||
#### Improvement
|
||||
* [all: use 'embed' instead of go-bindata (#24744)](https://github.com/bnb-chain/bsc/pull/1840/commits/7ab15490e93e6384cfaa233238777ea88a88b8b6)
|
||||
* [all: move genesis initialization to blockchain (#25523)](https://github.com/bnb-chain/bsc/pull/1840/commits/d10c28030944d1c32febba3f45ae8c175ab34063)
|
||||
#### Clear Up
|
||||
* [common/compiler, cmd/abigen: remove solc/vyper compiler integration](https://github.com/bnb-chain/bsc/pull/1840/commits/8541ddbd951370b2a42df8d82b0633ff0efeba12)
|
||||
* [all: remove concept of public/private API definitions (#25053)](https://github.com/bnb-chain/bsc/pull/1840/commits/10dc5dce0871bf8c24bac41b04e47c3b9ad2b93e)
|
||||
* [cmd/geth: drop geth js command (#25000)](https://github.com/bnb-chain/bsc/pull/1840/commits/f20a56926551ae91a349498f9ce97c8ee373d6bb)
|
||||
* [core/genesis: remove calaverasAllocData (#25516)](https://github.com/bnb-chain/bsc/pull/1840/commits/141cd425310b503c5678e674a8c3872cf46b7086)
|
||||
* [node: drop support for static & trusted node list files (#25610)](https://github.com/bnb-chain/bsc/pull/1840/commits/3630cafb34f7c48b9cc78cf736309275cbd70f74)
|
||||
* [core: drop legacy receipt types (#26225)](https://github.com/bnb-chain/bsc/pull/1840/commits/10347c6b54d5b28a2e71d9c4993e7f44b0a359c3)
|
||||
* [cmd/puppeth: remove puppeth](https://github.com/bnb-chain/bsc/pull/1840/commits/8ded6a9fcd883d7d96ef695f5b312c509eae3a0a)
|
||||
* [cmd, eth, node: deprecate personal namespace (#26390)](https://github.com/bnb-chain/bsc/pull/1840/commits/d0a4989a8def7e6bad182d1513e8d4a093c1672d)
|
||||
* [accounts, build, mobile: remove Andriod and iOS support](https://github.com/bnb-chain/bsc/pull/1840/commits/d9699c8238307d5c3081c12078f78527468d7dbc)
|
||||
* [params: remove EIP150Hash from chainconfig (#27087)](https://github.com/bnb-chain/bsc/pull/1840/commits/5e4d726e2a05aee80a75e5f99fd699f220dd503e)
|
||||
* [all: remove notion of trusted checkpoints in the post-merge world (#2…](https://github.com/bnb-chain/bsc/pull/1840/commits/1e556d220c3a40286dd90b37a08bb5fc659ee6ee)
|
||||
* [all: remove ethash pow, only retain shims needed for consensus and te](https://github.com/bnb-chain/bsc/pull/1840/commits/dde2da0efb8e9a1812f470bc43254134cd1f8cc0)
|
||||
* [cmd, core, eth, graphql, trie: no persisted clean trie cache file (#2…](https://github.com/bnb-chain/bsc/pull/1840/commits/59f7b289c329b5a56fa6f4e9acee64e504c4cc0d)
|
||||
* [les: remove obsolete code related to PoW header syncing (#27737)](https://github.com/bnb-chain/bsc/pull/1840/commits/d4d88f9bce13ca9310bf28f5f26ea9f1915ba90d)
|
||||
* remove diffsync
|
||||
#### Others
|
||||
* [accounts/usbwallet: support Ledger Nano S Plus and FTS (#25933)](https://github.com/bnb-chain/bsc/pull/1840/commits/7eafbec741d124bc53896f6bfc2408b70ab9a82a)
|
||||
* [accounts/scwallet: fix keycard data signing error (#25331)](https://github.com/bnb-chain/bsc/pull/1840/commits/0c66d971e7f3557df297cbe450fe7fc7826017be)
|
||||
* [core/state: replace fastcache code cache with gc-friendly structure (…](https://github.com/bnb-chain/bsc/pull/1840/commits/5fded040372784985265f83f33f15cb6a51bebdb)
|
||||
* [internal/debug: add --log.file option (#26149)](https://github.com/bnb-chain/bsc/pull/1840/commits/5b4c149f97408ecefc7f440e86c12a30c4342620)
|
||||
* [ci: disable coverage reporting in appveyor and travis](https://github.com/bnb-chain/bsc/pull/1840/commits/a0d63bc69a659009a3884f50c563a0e58483cdd0)
|
||||
* [all: change chain head markers from block to header (#26777)](https://github.com/bnb-chain/bsc/pull/1840/commits/cd31f2dee2843776e485769ce85e0524716199bc)
|
||||
* [core, miner: revert block gas counter in case of invalid transaction](https://github.com/bnb-chain/bsc/pull/1840/commits/77e33e5a49be99130a02dc72d6a0e4739fdd44d6)
|
||||
* [accounts/usbwallet: mitigate ledger app chunking issue (#26773)](https://github.com/bnb-chain/bsc/pull/1840/commits/1e3177de220b1590704c96572fce820bfc87281e)
|
||||
* [signer/core: accept all solidity primitive types for EIP-712 signing](https://github.com/bnb-chain/bsc/pull/1840/commits/02796f6bee7e014fd16ad39f0bcd3b665b51e0bb)
|
||||
* [cmd/geth: enable log rotation (#26843)](https://github.com/bnb-chain/bsc/pull/1840/commits/7076ae00aa36ae250608455de928557ce4e5549f)
|
||||
* [internal/ethapi: make EstimateGas use[latest] block by default (#24363)](https://github.com/bnb-chain/bsc/pull/1840/commits/0b66d47449f61e9ebaf9e1db3ed290b59844d4c1)
|
||||
* [miner: suspend miner if node is syncing (#27218)](https://github.com/bnb-chain/bsc/pull/1840/commits/d4961881d7c92603f591f9cb8c705d00d8cbdfc0)
|
||||
* [all: move main transaction pool into a subpool (#27463)](https://github.com/bnb-chain/bsc/pull/1840/commits/d40a255e973775575d8d16456252f93ac75c09f0)
|
||||
* [core/txpool/blobpool: 4844 blob transaction pool (#26940)](https://github.com/bnb-chain/bsc/pull/1840/commits/1662228ac68325b4024e0cb6a4ce7dde27eb4c2d)
|
||||
* [eth: send big transactions by announce/retrieve only (#27618)](https://github.com/bnb-chain/bsc/pull/1840/commits/f5d3d486e459dce29130576ae88f2324ad586b50)
|
||||
* [core/rawdb: support freezer batch read with no size limit (#27687)](https://github.com/bnb-chain/bsc/pull/1840/commits/0b1f97e151e8b34a0a0d528a3472e27de1d12a9c)
|
||||
* disable pipeCommit, break now
|
||||
|
||||
## v1.2.12
|
||||
FEATURE
|
||||
* [\#1852](https://github.com/bnb-chain/bsc/pull/1852) discov: add hardcoded bootnodes
|
||||
|
||||
BUGFIX
|
||||
* [\#1844](https://github.com/bnb-chain/bsc/pull/1844) crypto: Update BLST to v0.3.11
|
||||
* [\#1854](https://github.com/bnb-chain/bsc/pull/1854) fetcher: no import blocks before or equal to the finalized height
|
||||
* [\#1855](https://github.com/bnb-chain/bsc/pull/1855) eth/tracers: trace system tx should add intrinsicGas
|
||||
|
||||
IMPROVEMENT
|
||||
* [\#1839](https://github.com/bnb-chain/bsc/pull/1839) Update init-network command
|
||||
* [\#1858](https://github.com/bnb-chain/bsc/pull/1858) vote: check consensus key match vote key before voting
|
||||
|
||||
## v1.2.11
|
||||
FEATURE
|
||||
* [\#1797](https://github.com/bnb-chain/bsc/pull/1797) client: add FinalizedHeader/Block to use the fast finality
|
||||
|
||||
@@ -4,7 +4,7 @@ ARG VERSION=""
|
||||
ARG BUILDNUM=""
|
||||
|
||||
# Build Geth in a stock Go builder container
|
||||
FROM golang:1.20-alpine as builder
|
||||
FROM golang:1.21-alpine as builder
|
||||
|
||||
RUN apk add --no-cache make cmake gcc musl-dev linux-headers git bash build-base libc-dev
|
||||
# Get dependencies - will also be cached if we won't change go.mod/go.sum
|
||||
|
||||
@@ -4,7 +4,7 @@ ARG VERSION=""
|
||||
ARG BUILDNUM=""
|
||||
|
||||
# Build Geth in a stock Go builder container
|
||||
FROM golang:1.20-alpine as builder
|
||||
FROM golang:1.21-alpine as builder
|
||||
|
||||
RUN apk add --no-cache gcc musl-dev linux-headers git
|
||||
# Get dependencies - will also be cached if we won't change go.mod/go.sum
|
||||
|
||||
21
README.md
21
README.md
@@ -61,7 +61,7 @@ Many of the below are the same as or similar to go-ethereum.
|
||||
|
||||
For prerequisites and detailed build instructions please read the [Installation Instructions](https://geth.ethereum.org/docs/getting-started/installing-geth).
|
||||
|
||||
Building `geth` requires both a Go (version 1.19 or later) and a C compiler (GCC 5 or higher). You can install
|
||||
Building `geth` requires both a Go (version 1.21 or later) and a C compiler (GCC 5 or higher). You can install
|
||||
them using your favourite package manager. Once the dependencies are installed, run
|
||||
|
||||
```shell
|
||||
@@ -110,15 +110,15 @@ on how you can run your own `geth` instance.
|
||||
|
||||
The hardware must meet certain requirements to run a full node on mainnet:
|
||||
- VPS running recent versions of Mac OS X, Linux, or Windows.
|
||||
- IMPORTANT 2.5 TB(May 2023) of free disk space, solid-state drive(SSD), gp3, 8k IOPS, 250 MB/S throughput, read latency <1ms. (if node is started with snap sync, it will need NVMe SSD)
|
||||
- IMPORTANT 3 TB(Dec 2023) of free disk space, solid-state drive(SSD), gp3, 8k IOPS, 500 MB/S throughput, read latency <1ms. (if node is started with snap sync, it will need NVMe SSD)
|
||||
- 16 cores of CPU and 64 GB of memory (RAM)
|
||||
- Suggest m5zn.3xlarge instance type on AWS, c2-standard-16 on Google cloud.
|
||||
- Suggest m5zn.6xlarge or r7iz.4xlarge instance type on AWS, c2-standard-16 on Google cloud.
|
||||
- A broadband Internet connection with upload/download speeds of 5 MB/S
|
||||
|
||||
The requirement for testnet:
|
||||
- VPS running recent versions of Mac OS X, Linux, or Windows.
|
||||
- 500G of storage for testnet.
|
||||
- 4 cores of CPU and 8 gigabytes of memory (RAM).
|
||||
- 4 cores of CPU and 16 gigabytes of memory (RAM).
|
||||
|
||||
### Steps to Run a Fullnode
|
||||
|
||||
@@ -149,14 +149,19 @@ unzip testnet.zip
|
||||
#### 3. Download snapshot
|
||||
Download latest chaindata snapshot from [here](https://github.com/bnb-chain/bsc-snapshots). Follow the guide to structure your files.
|
||||
|
||||
Note: if you can not download the chaindata snapshot and want to sync from genesis, you have to generate the genesis block first, you have already get the genesis.json in Step 2.
|
||||
So just run: `geth --datadir <datadir> init ./genesis.json`
|
||||
Note: If you encounter difficulties downloading the chaindata snapshot and prefer to synchronize from the genesis block on the Chapel testnet, remember to include the additional flag `--chapel` when initially launching Geth.
|
||||
|
||||
#### 4. Start a full node
|
||||
```shell
|
||||
./geth --config ./config.toml --datadir ./node --cache 8000 --rpc.allow-unprotected-txs --txlookuplimit 0
|
||||
./geth --config ./config.toml --datadir ./node --cache 8000 --rpc.allow-unprotected-txs --history.transactions 0
|
||||
|
||||
## It is recommand to run fullnode with `--tries-verify-mode none` if you want high performance and care little about state consistency
|
||||
./geth --config ./config.toml --datadir ./node --cache 8000 --rpc.allow-unprotected-txs --txlookuplimit 0 --tries-verify-mode none
|
||||
## It will run with Hash-Base Storage Scheme by default
|
||||
./geth --config ./config.toml --datadir ./node --cache 8000 --rpc.allow-unprotected-txs --history.transactions 0 --tries-verify-mode none
|
||||
|
||||
## It runs fullnode with Path-Base Storage Scheme.
|
||||
## It will enable inline state prune, keeping the latest 90000 blocks' history state by default.
|
||||
./geth --config ./config.toml --datadir ./node --cache 8000 --rpc.allow-unprotected-txs --history.transactions 0 --tries-verify-mode none --state.scheme path
|
||||
```
|
||||
|
||||
#### 5. Monitor node status
|
||||
|
||||
@@ -94,7 +94,7 @@ func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.Genesis
|
||||
|
||||
filterBackend := &filterBackend{database, blockchain, backend}
|
||||
backend.filterSystem = filters.NewFilterSystem(filterBackend, filters.Config{})
|
||||
backend.events = filters.NewEventSystem(backend.filterSystem, false)
|
||||
backend.events = filters.NewEventSystem(backend.filterSystem)
|
||||
|
||||
header := backend.blockchain.CurrentBlock()
|
||||
block := backend.blockchain.GetBlock(header.Hash(), header.Number.Uint64())
|
||||
|
||||
@@ -2127,7 +2127,7 @@ func TestGolangBindings(t *testing.T) {
|
||||
t.Fatalf("failed to replace binding test dependency to current source tree: %v\n%s", err, out)
|
||||
}
|
||||
|
||||
replacer = exec.Command(gocmd, "mod", "edit", "-x", "-require", "github.com/tendermint/tendermint@v0.0.0", "-replace", "github.com/tendermint/tendermint=github.com/bnb-chain/tendermint@v0.31.15") // Repo root
|
||||
replacer = exec.Command(gocmd, "mod", "edit", "-x", "-require", "github.com/tendermint/tendermint@v0.0.0", "-replace", "github.com/tendermint/tendermint=github.com/bnb-chain/tendermint@v0.31.16") // Repo root
|
||||
replacer.Dir = pkg
|
||||
if out, err := replacer.CombinedOutput(); err != nil {
|
||||
t.Fatalf("failed to replace tendermint dependency to bnb-chain source: %v\n%s", err, out)
|
||||
@@ -2145,7 +2145,7 @@ func TestGolangBindings(t *testing.T) {
|
||||
t.Fatalf("failed to replace cometbft dependency to bnb-chain source: %v\n%s", err, out)
|
||||
}
|
||||
|
||||
tidier := exec.Command(gocmd, "mod", "tidy", "-compat=1.19")
|
||||
tidier := exec.Command(gocmd, "mod", "tidy", "-compat=1.21")
|
||||
tidier.Dir = pkg
|
||||
if out, err := tidier.CombinedOutput(); err != nil {
|
||||
t.Fatalf("failed to tidy Go module file: %v\n%s", err, out)
|
||||
|
||||
@@ -72,11 +72,11 @@ func NewSecureChannelSession(card *pcsc.Card, keyData []byte) (*SecureChannelSes
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not unmarshal public key from card: %v", err)
|
||||
}
|
||||
secret, _ := key.Curve.ScalarMult(cardPublic.X, cardPublic.Y, key.D.Bytes())
|
||||
secret, _ := key.Curve.ScalarMult(cardPublic.X, cardPublic.Y, key.D.Bytes()) //nolint:all //TODO
|
||||
return &SecureChannelSession{
|
||||
card: card,
|
||||
secret: secret.Bytes(),
|
||||
publicKey: elliptic.Marshal(crypto.S256(), key.PublicKey.X, key.PublicKey.Y),
|
||||
publicKey: elliptic.Marshal(crypto.S256(), key.PublicKey.X, key.PublicKey.Y), //nolint:all //TODO
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,69 +1,60 @@
|
||||
# This file contains sha256 checksums of optional build dependencies.
|
||||
|
||||
2c5ee9c9ec1e733b0dbbc2bdfed3f62306e51d8172bf38f4f4e542b27520f597 go1.20.7.src.tar.gz
|
||||
785170eab380a8985d53896808b0a71336d0ea60e0a26099b4ccec77798b1cf4 go1.20.7.darwin-amd64.tar.gz
|
||||
eea1e7e4c2f75c72629050e6a6c7c46c446d64056732a7787fb3ba16ace1982e go1.20.7.darwin-arm64.tar.gz
|
||||
d8cff0357ac24eb06f3f280535397eeaacf95611d29f9b2abc3060f3d6dce3b4 go1.20.7.freebsd-386.tar.gz
|
||||
26918dcebf474a9e81ccf9f648cdf36968dfb76b481518cf615d78455dda4416 go1.20.7.freebsd-amd64.tar.gz
|
||||
ddb48145f05bda2f4617a22c979d4e94b22802cdb1a1fde1b1974e733b26f091 go1.20.7.linux-386.tar.gz
|
||||
f0a87f1bcae91c4b69f8dc2bc6d7e6bfcd7524fceec130af525058c0c17b1b44 go1.20.7.linux-amd64.tar.gz
|
||||
44781ae3b153c3b07651d93b6bc554e835a36e2d72a696281c1e4dad9efffe43 go1.20.7.linux-arm64.tar.gz
|
||||
7cc231b415b94f2f7065870a73f67dd2b0ec12b5a98052b7ee0121c42bc04f8d go1.20.7.linux-armv6l.tar.gz
|
||||
6318a1db307c12b8afe68808bd6fae4fba1e558a85b958216096869ed506dcb3 go1.20.7.linux-ppc64le.tar.gz
|
||||
26aea2ede8722ceecbd9db883328a8d963136fd96c11dacc356c44c4c19c6515 go1.20.7.linux-s390x.tar.gz
|
||||
5b0ef6f58d3e04d6cc003aa98e9172f41ba9e091b1c98e7339b41c4c87fb78a1 go1.20.7.windows-386.zip
|
||||
736dc6c7fcab1c96b682c8c93e38d7e371e62a17d34cb2c37d451a1147f66af9 go1.20.7.windows-amd64.zip
|
||||
fc6f79c1e1ed9e506c65f2112ac4e387479916f1accb0d046a6a19ff6938baa5 go1.20.7.windows-arm64.zip
|
||||
# version:golang 1.21.5
|
||||
# https://go.dev/dl/
|
||||
285cbbdf4b6e6e62ed58f370f3f6d8c30825d6e56c5853c66d3c23bcdb09db19 go1.21.5.src.tar.gz
|
||||
a2e1d5743e896e5fe1e7d96479c0a769254aed18cf216cf8f4c3a2300a9b3923 go1.21.5.darwin-amd64.tar.gz
|
||||
d0f8ac0c4fb3efc223a833010901d02954e3923cfe2c9a2ff0e4254a777cc9cc go1.21.5.darwin-arm64.tar.gz
|
||||
2c05bbe0dc62456b90b7ddd354a54f373b7c377a98f8b22f52ab694b4f6cca58 go1.21.5.freebsd-386.tar.gz
|
||||
30b6c64e9a77129605bc12f836422bf09eec577a8c899ee46130aeff81567003 go1.21.5.freebsd-amd64.tar.gz
|
||||
8f4dba9cf5c61757bbd7e9ebdb93b6a30a1b03f4a636a1ba0cc2f27b907ab8e1 go1.21.5.linux-386.tar.gz
|
||||
e2bc0b3e4b64111ec117295c088bde5f00eeed1567999ff77bc859d7df70078e go1.21.5.linux-amd64.tar.gz
|
||||
841cced7ecda9b2014f139f5bab5ae31785f35399f236b8b3e75dff2a2978d96 go1.21.5.linux-arm64.tar.gz
|
||||
837f4bf4e22fcdf920ffeaa4abf3d02d1314e03725431065f4d44c46a01b42fe go1.21.5.linux-armv6l.tar.gz
|
||||
907b8c6ec4be9b184952e5d3493be66b1746442394a8bc78556c56834cd7c38b go1.21.5.linux-ppc64le.tar.gz
|
||||
9c4a81b72ebe44368813cd03684e1080a818bf915d84163abae2ed325a1b2dc0 go1.21.5.linux-s390x.tar.gz
|
||||
6da2418889dfb37763d0eb149c4a8d728c029e12f0cd54fbca0a31ae547e2d34 go1.21.5.windows-386.zip
|
||||
bbe603cde7c9dee658f45164b4d06de1eff6e6e6b800100824e7c00d56a9a92f go1.21.5.windows-amd64.zip
|
||||
9b7acca50e674294e43202df4fbc26d5af4d8bc3170a3342a1514f09a2dab5e9 go1.21.5.windows-arm64.zip
|
||||
|
||||
000d4d58f1e25323aaf0da20b337d059d401c8c1fb31cef92ce50ef35c05e877 golangci-lint-1.52.2-linux-ppc64le.deb
|
||||
0970b2e3ecc20003a0fc78b078623ab27c61f0f809a44288e2cc438bfbbf5616 golangci-lint-1.52.2-linux-s390x.deb
|
||||
0bfe9b51f68a33cc4e43139151d8032b57b15e61a19f5a7554b687a3fa166ab8 golangci-lint-1.52.2-netbsd-armv7.tar.gz
|
||||
0e4e24085d364f4e03752c060d5f37b5ead52acd62f07392f4c9022515e0ecd8 golangci-lint-1.52.2-linux-armv7.rpm
|
||||
0f19ad6c037d45867f4978287a7a6d78bc761daf8e6cb3a5e6af86d5714b0258 golangci-lint-1.52.2-linux-armv6.tar.gz
|
||||
1506b19f3f0410f6d85d1e339a47fcc84646d552516c0f429dc8cd7f34b4069a golangci-lint-1.52.2-windows-armv6.zip
|
||||
1cc68baa226e186c15c5514a6e93b1cc8d47ff06aaf1a395b8266434cb01df29 golangci-lint-1.52.2-linux-386.rpm
|
||||
1d23661087ae686563e40d3b1e33f309dd3b4ba7d1c7e571ca7723f77a52a9e4 golangci-lint-1.52.2-linux-s390x.rpm
|
||||
227673a18d21b428f1768bb8ee46e38c36a0f002960bc6211ef6137b85d03f52 golangci-lint-1.52.2-freebsd-armv7.tar.gz
|
||||
24f0272e5741c05c59e7162b7ff0258cfa6beb0d9265bd87c386fe80ac25135d golangci-lint-1.52.2-linux-mips64.deb
|
||||
3abc8ad30b336ccbe3c5e3c65fa146f5b12d8e81e644345fa8d51cdbaa8cb570 golangci-lint-1.52.2-netbsd-amd64.tar.gz
|
||||
40a2645b4c7bd94c16618eb0f12b32cd54c17e5620f761cf477b256d3622f299 golangci-lint-1.52.2-windows-386.zip
|
||||
40b40002e07db81628d94108265525052c58fc9ce358bef26a36d27f0aea3d87 golangci-lint-1.52.2-windows-amd64.zip
|
||||
41e936b62ba4fc66c02daf6fa9cf74213bc2220745c7a796acbe197c05ed26bb golangci-lint-1.52.2-netbsd-armv6.tar.gz
|
||||
4bcbb4cf34bf3c8ae1ca880d12516a999499189326621599f8362ededd6e4229 golangci-lint-1.52.2-linux-riscv64.tar.gz
|
||||
4edb83f1433f7c57f06f79a7fc30bf3f920c1f86c334e481661ac6627d80293f golangci-lint-1.52.2-linux-arm64.deb
|
||||
50d662e86d094dbad6634d086eca4f670ffa8ea7142508d8da357a2d750ac21a golangci-lint-1.52.2-linux-armv7.tar.gz
|
||||
6891597bedbcd7e530d08ed198bab7eeb9b23f3f8161dc6e87505b783cb11593 golangci-lint-1.52.2-windows-arm64.zip
|
||||
6d79f4f3448b70e83952e746fcb9e251c6ba94ec2790a912806cc1704ade4d64 golangci-lint-1.52.2-linux-mips64.rpm
|
||||
6de51ae05d39002421caf6049e0dd0014a2f10961471c5547c905d33d8e6adf1 golangci-lint-1.52.2-linux-armv6.deb
|
||||
715dc0f0cf3538c3b2c75f084dde8dcdc3485b3494f42a6d0d9c0dc61e62b5a8 golangci-lint-1.52.2-linux-s390x.tar.gz
|
||||
7c559332a97ee49b80427aba5a7122e17cac18c57e700f48e6db5ffcbbb61b2b golangci-lint-1.52.2-linux-arm64.rpm
|
||||
81201bb5f19897fefb4380af2e187a0133dc5efda22254698c063cc36a601f43 golangci-lint-1.52.2-linux-386.deb
|
||||
89e523d45883903cfc472ab65621073f850abd4ffbb7720bbdd7ba66ee490bc8 golangci-lint-1.52.2-darwin-arm64.tar.gz
|
||||
8d60d63eee38f8de679e57b1a781de32987152f004f852f20cd47baa4c582209 golangci-lint-1.52.2-linux-mips64le.rpm
|
||||
9e22df0516cbd847910f353d92245e58eab2b6edacc669646bfa06eb032a65a3 golangci-lint-1.52.2-linux-riscv64.deb
|
||||
a1a74747a196d4ccd2394ea8a461508eb2edf1eb5a88010611debf572991961d golangci-lint-1.52.2-linux-loong64.tar.gz
|
||||
a7f076d0fb50e0f5bc24d0f3b2567f2cfe864441e6ad20323189b7fde7cc065d golangci-lint-1.52.2-freebsd-386.tar.gz
|
||||
abc100851a59cbcea2a7e9ff5ad2974a43270135520aeac9a302ca6c712a41e1 golangci-lint-1.52.2-linux-loong64.rpm
|
||||
adf11a1f7f43b5a431c19cccea260e6205e2e2b42a2d2d450e31c287fec199f2 golangci-lint-1.52.2-linux-amd64.rpm
|
||||
b2249e43e1624486398f41700dbe4094a4222bf50b2b1b3a740323adb9a1b66f golangci-lint-1.52.2-linux-386.tar.gz
|
||||
b8e81bf979dc8bf226cb592eb78c1792f1018c3dea1bbeb11517efc4cc3301bb golangci-lint-1.52.2-windows-armv7.zip
|
||||
bb9a6a0aabe39fb3d581cc200c639ce6598821a53b4d16ec59366c65f4cc2960 golangci-lint-1.52.2-source.tar.gz
|
||||
c152280b2e61c202614c1c476cf4458922cda0d2781e4492be2c22d45655cae0 golangci-lint-1.52.2-freebsd-armv6.tar.gz
|
||||
c8bf25c0bca142638ce4bfc921bf23d23038818d57658d69aa4a9947d514d48f golangci-lint-1.52.2-linux-ppc64le.rpm
|
||||
c9cf72d12058a131746edd409ed94ccd578fbd178899d1ed41ceae3ce5f54501 golangci-lint-1.52.2-linux-amd64.tar.gz
|
||||
d03f2b331b5139eddea5db2b49066d10a90094747b08d72d7b2d61cf91c79a27 golangci-lint-1.52.2-linux-mips64le.tar.gz
|
||||
d609c1d49591d714148e1f8c8b5ae9f9565c601aeabc44a5a53ba44b0eb99f36 golangci-lint-1.52.2-linux-riscv64.rpm
|
||||
d679adad29603ed7549372b64077cccad784e404deffe5c1e9495a06659cff33 golangci-lint-1.52.2-linux-mips64.tar.gz
|
||||
d91e8cb60920cf0e46958ed917fcdd059738c00d162189c2e878424ffc8ada75 golangci-lint-1.52.2-linux-ppc64le.tar.gz
|
||||
d9b5820b491e317fb1360775441d68bd3dc2f303439da5b6d536df23977e28c9 golangci-lint-1.52.2-freebsd-amd64.tar.gz
|
||||
ddeae781cf07c016898efd80eaed6853a91bfaf1f22c08fbbf5cf08a573b98c4 golangci-lint-1.52.2-linux-loong64.deb
|
||||
dfc5e755cfa95381f61f736780ff736a5b6c9cbccc88140348986c166d484f85 golangci-lint-1.52.2-linux-amd64.deb
|
||||
e57f2599de73c4da1d36d5255b9baec63f448b3d7fb726ebd3cd64dabbd3ee4a golangci-lint-1.52.2-darwin-amd64.tar.gz
|
||||
ebfb5b643ba73ef6007236b90f863ae49fc34fd366682c971b7d1308ab28f642 golangci-lint-1.52.2-netbsd-386.tar.gz
|
||||
f46b60a90fab5916a7de899ad9a3a4b3d77278c2e1737d070719d3ea27919557 golangci-lint-1.52.2-linux-armv7.deb
|
||||
f6e39d0ac4691c2b9f49d6d5819594f48bb03e18692fd6d100e7114077f710e6 golangci-lint-1.52.2-linux-armv6.rpm
|
||||
fa5da589075143628a49a0c123ccd76a8717bb6308fb3bdb6bf1df59435d921b golangci-lint-1.52.2-linux-mips64le.deb
|
||||
fc09a97f8888809fab83a316f7da70c8ed74d4863b7eed7d872cec41911a55e8 golangci-lint-1.52.2-linux-arm64.tar.gz
|
||||
# version:golangci 1.55.2
|
||||
# https://github.com/golangci/golangci-lint/releases/
|
||||
# https://github.com/golangci/golangci-lint/releases/download/v1.55.2/
|
||||
632e96e6d5294fbbe7b2c410a49c8fa01c60712a0af85a567de85bcc1623ea21 golangci-lint-1.55.2-darwin-amd64.tar.gz
|
||||
234463f059249f82045824afdcdd5db5682d0593052f58f6a3039a0a1c3899f6 golangci-lint-1.55.2-darwin-arm64.tar.gz
|
||||
2bdd105e2d4e003a9058c33a22bb191a1e0f30fa0790acca0d8fbffac1d6247c golangci-lint-1.55.2-freebsd-386.tar.gz
|
||||
e75056e8b082386676ce23eba455cf893931a792c0d87e1e3743c0aec33c7fb5 golangci-lint-1.55.2-freebsd-amd64.tar.gz
|
||||
5789b933facaf6136bd23f1d50add67b79bbcf8dfdfc9069a37f729395940a66 golangci-lint-1.55.2-freebsd-armv6.tar.gz
|
||||
7f21ab1008d05f32c954f99470fc86a83a059e530fe2add1d0b7d8ed4d8992a7 golangci-lint-1.55.2-freebsd-armv7.tar.gz
|
||||
33ab06139b9219a28251f10821da94423db30285cc2af97494cbb2a281927de9 golangci-lint-1.55.2-illumos-amd64.tar.gz
|
||||
57ce6f8ce3ad6ee45d7cc3d9a047545a851c2547637834a3fcb086c7b40b1e6b golangci-lint-1.55.2-linux-386.tar.gz
|
||||
ca21c961a33be3bc15e4292dc40c98c8dcc5463a7b6768a3afc123761630c09c golangci-lint-1.55.2-linux-amd64.tar.gz
|
||||
8eb0cee9b1dbf0eaa49871798c7f8a5b35f2960c52d776a5f31eb7d886b92746 golangci-lint-1.55.2-linux-arm64.tar.gz
|
||||
3195f3e0f37d353fd5bd415cabcd4e263f5c29d3d0ffb176c26ff3d2c75eb3bb golangci-lint-1.55.2-linux-armv6.tar.gz
|
||||
c823ee36eb1a719e171de1f2f5ca3068033dce8d9817232fd10ed71fd6650406 golangci-lint-1.55.2-linux-armv7.tar.gz
|
||||
758a5d2a356dc494bd13ed4c0d4bf5a54a4dc91267ea5ecdd87b86c7ca0624e7 golangci-lint-1.55.2-linux-loong64.tar.gz
|
||||
2c7b9abdce7cae802a67d583cd7c6dca520bff6d0e17c8535a918e2f2b437aa0 golangci-lint-1.55.2-linux-mips64.tar.gz
|
||||
024e0a15b85352cc27271285526e16a4ab66d3e67afbbe446c9808c06cb8dbed golangci-lint-1.55.2-linux-mips64le.tar.gz
|
||||
6b00f89ba5506c1de1efdd9fa17c54093013a294fefd8b9b31534db626a672ee golangci-lint-1.55.2-linux-ppc64le.tar.gz
|
||||
0faa0d047d9bf7b703ed3ea65b6117043c93504f9ca1de25ae929d3901c73d4a golangci-lint-1.55.2-linux-riscv64.tar.gz
|
||||
30dec9b22e7d5bb4e9d5ccea96da20f71cd7db3c8cf30b8ddc7cb9174c4d742a golangci-lint-1.55.2-linux-s390x.tar.gz
|
||||
5a0ede48f79ad707902fdb29be8cd2abd8302dc122b65ebae3fdfc86751c7698 golangci-lint-1.55.2-netbsd-386.tar.gz
|
||||
95af20a2e617126dd5b08122ece7819101070e1582a961067ce8c41172f901ad golangci-lint-1.55.2-netbsd-amd64.tar.gz
|
||||
94fb7dacb7527847cc95d7120904e19a2a0a81a0d50d61766c9e0251da72ab9d golangci-lint-1.55.2-netbsd-armv6.tar.gz
|
||||
ca906bce5fee9619400e4a321c56476fe4a4efb6ac4fc989d340eb5563348873 golangci-lint-1.55.2-netbsd-armv7.tar.gz
|
||||
45b442f69fc8915c4500201c0247b7f3f69544dbc9165403a61f9095f2c57355 golangci-lint-1.55.2-windows-386.zip
|
||||
f57d434d231d43417dfa631587522f8c1991220b43c8ffadb9c7bd279508bf81 golangci-lint-1.55.2-windows-amd64.zip
|
||||
fd7dc8f4c6829ee6fafb252a4d81d2155cd35da7833665cbb25d53ce7cecd990 golangci-lint-1.55.2-windows-arm64.zip
|
||||
1892c3c24f9e7ef44b02f6750c703864b6dc350129f3ec39510300007b2376f1 golangci-lint-1.55.2-windows-armv6.zip
|
||||
a5e68ae73d38748b5269fad36ac7575e3c162a5dc63ef58abdea03cc5da4522a golangci-lint-1.55.2-windows-armv7.zip
|
||||
|
||||
# This is the builder on PPA that will build Go itself (inception-y), don't modify!
|
||||
d7f0013f82e6d7f862cc6cb5c8cdb48eef5f2e239b35baa97e2f1a7466043767 go1.19.6.src.tar.gz
|
||||
#
|
||||
# This version is fine to be old and full of security holes, we just use it
|
||||
# to build the latest Go. Don't change it. If it ever becomes insufficient,
|
||||
# we need to switch over to a recursive builder to jump across supported
|
||||
# versions.
|
||||
#
|
||||
# version:ppa-builder 1.19.6
|
||||
# https://go.dev/dl/
|
||||
d7f0013f82e6d7f862cc6cb5c8cdb48eef5f2e239b35baa97e2f1a7466043767 go1.19.6.src.tar.gz
|
||||
@@ -139,7 +139,7 @@ var (
|
||||
// This is the version of Go that will be downloaded by
|
||||
//
|
||||
// go run ci.go install -dlgo
|
||||
dlgoVersion = "1.20.7"
|
||||
dlgoVersion = "1.21.5"
|
||||
|
||||
// This is the version of Go that will be used to bootstrap the PPA builder.
|
||||
//
|
||||
@@ -333,10 +333,7 @@ func doTest(cmdline []string) {
|
||||
gotest.Args = append(gotest.Args, "-race")
|
||||
}
|
||||
|
||||
packages := []string{"./accounts/...", "./cmd/geth/...", "./common/...", "./consensus/...", "./console/...",
|
||||
"./core/...", "./crypto/...", "./eth/...", "./ethstats/...", "./ethclient/...", "./ethdb/...", "./event/...",
|
||||
"./graphql/...", "./internal/...", "./les/...", "./light/...", "./log/...", "./metrics/...", "./miner/...",
|
||||
"./node/...", "./p2p/...", "./params/...", "./rlp/...", "./rpc/...", "./signer/...", "./tests/...", "./trie/..."}
|
||||
packages := []string{"./..."}
|
||||
if len(flag.CommandLine.Args()) > 0 {
|
||||
packages = flag.CommandLine.Args()
|
||||
}
|
||||
@@ -363,7 +360,7 @@ func doLint(cmdline []string) {
|
||||
|
||||
// downloadLinter downloads and unpacks golangci-lint.
|
||||
func downloadLinter(cachedir string) string {
|
||||
const version = "1.52.2"
|
||||
const version = "1.55.2"
|
||||
|
||||
csdb := build.MustLoadChecksums("build/checksums.txt")
|
||||
arch := runtime.GOARCH
|
||||
|
||||
@@ -1206,7 +1206,7 @@ func GenDoc(ctx *cli.Context) error {
|
||||
URL: accounts.URL{Path: ".. ignored .."},
|
||||
},
|
||||
{
|
||||
Address: common.HexToAddress("0xffffffffffffffffffffffffffffffffffffffff"),
|
||||
Address: common.MaxAddress,
|
||||
},
|
||||
}})
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ set to standard output. The following filters are supported:
|
||||
- `-limit <N>` limits the output set to N entries, taking the top N nodes by score
|
||||
- `-ip <CIDR>` filters nodes by IP subnet
|
||||
- `-min-age <duration>` filters nodes by 'first seen' time
|
||||
- `-eth-network <mainnet/goerli/sepolia>` filters nodes by "eth" ENR entry
|
||||
- `-eth-network <mainnet/goerli/sepolia/holesky>` filters nodes by "eth" ENR entry
|
||||
- `-les-server` filters nodes by LES server support
|
||||
- `-snap` filters nodes by snap protocol support
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/eth/protocols/eth"
|
||||
"github.com/ethereum/go-ethereum/internal/utesting"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/rlpx"
|
||||
)
|
||||
@@ -202,6 +203,29 @@ loop:
|
||||
if err := c.Write(status); err != nil {
|
||||
return nil, fmt.Errorf("write to connection failed: %v", err)
|
||||
}
|
||||
|
||||
// exchange UpgradeStatus
|
||||
if c.negotiatedProtoVersion >= eth.ETH67 {
|
||||
extensionRaw, _ := (ð.UpgradeStatusExtension{}).Encode()
|
||||
upgradeStatus := UpgradeStatus{
|
||||
Extension: extensionRaw,
|
||||
}
|
||||
if err := c.Write(upgradeStatus); err != nil {
|
||||
return nil, fmt.Errorf("write to connection failed: %v", err)
|
||||
}
|
||||
switch msg := c.Read().(type) {
|
||||
case *UpgradeStatus:
|
||||
log.Debug("receive UpgradeStatus")
|
||||
case *Disconnect:
|
||||
return nil, fmt.Errorf("disconnect received: %v", msg.Reason)
|
||||
case *Ping:
|
||||
c.Write(&Pong{}) // TODO (renaynay): in the future, this should be an error
|
||||
// (PINGs should not be a response upon fresh connection)
|
||||
default:
|
||||
return nil, fmt.Errorf("bad status message: %s", pretty.Sdump(msg))
|
||||
}
|
||||
}
|
||||
|
||||
return message, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ import (
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/eth/protocols/snap"
|
||||
"github.com/ethereum/go-ethereum/internal/utesting"
|
||||
"github.com/ethereum/go-ethereum/light"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
@@ -58,7 +58,7 @@ type accRangeTest struct {
|
||||
func (s *Suite) TestSnapGetAccountRange(t *utesting.T) {
|
||||
var (
|
||||
root = s.chain.RootAt(999)
|
||||
ffHash = common.HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
|
||||
ffHash = common.MaxHash
|
||||
zero = common.Hash{}
|
||||
firstKeyMinus1 = common.HexToHash("0x00bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf29")
|
||||
firstKey = common.HexToHash("0x00bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2a")
|
||||
@@ -125,7 +125,7 @@ type stRangesTest struct {
|
||||
// TestSnapGetStorageRanges various forms of GetStorageRanges requests.
|
||||
func (s *Suite) TestSnapGetStorageRanges(t *utesting.T) {
|
||||
var (
|
||||
ffHash = common.HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
|
||||
ffHash = common.MaxHash
|
||||
zero = common.Hash{}
|
||||
firstKey = common.HexToHash("0x00bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2a")
|
||||
secondKey = common.HexToHash("0x09e47cd5056a689e708f22fe1f932709a320518e444f5f7d8d46a3da523d6606")
|
||||
@@ -530,11 +530,11 @@ func (s *Suite) snapGetAccountRange(t *utesting.T, tc *accRangeTest) error {
|
||||
for i, key := range hashes {
|
||||
keys[i] = common.CopyBytes(key[:])
|
||||
}
|
||||
nodes := make(light.NodeList, len(proof))
|
||||
nodes := make(trienode.ProofList, len(proof))
|
||||
for i, node := range proof {
|
||||
nodes[i] = node
|
||||
}
|
||||
proofdb := nodes.NodeSet()
|
||||
proofdb := nodes.Set()
|
||||
|
||||
var end []byte
|
||||
if len(keys) > 0 {
|
||||
|
||||
@@ -80,10 +80,11 @@ func TestSnapSuite(t *testing.T) {
|
||||
func runGeth() (*node.Node, error) {
|
||||
stack, err := node.New(&node.Config{
|
||||
P2P: p2p.Config{
|
||||
ListenAddr: "127.0.0.1:0",
|
||||
NoDiscovery: true,
|
||||
MaxPeers: 10, // in case a test requires multiple connections, can be changed in the future
|
||||
NoDial: true,
|
||||
ListenAddr: "127.0.0.1:0",
|
||||
NoDiscovery: true,
|
||||
MaxPeers: 10, // in case a test requires multiple connections, can be changed in the future
|
||||
MaxPeersPerIP: 10,
|
||||
NoDial: true,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
@@ -116,6 +117,7 @@ func setupGeth(stack *node.Node) error {
|
||||
TrieDirtyCache: 16,
|
||||
TrieTimeout: 60 * time.Minute,
|
||||
SnapshotCache: 10,
|
||||
TriesInMemory: 128,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -87,6 +87,11 @@ type Status eth.StatusPacket
|
||||
func (msg Status) Code() int { return 16 }
|
||||
func (msg Status) ReqID() uint64 { return 0 }
|
||||
|
||||
type UpgradeStatus eth.UpgradeStatusPacket
|
||||
|
||||
func (msg UpgradeStatus) Code() int { return 27 } // p2p.baseProtocolLength + eth.UpgradeStatusMsg
|
||||
func (msg UpgradeStatus) ReqID() uint64 { return 0 }
|
||||
|
||||
// NewBlockHashes is the network packet for the block announcements.
|
||||
type NewBlockHashes eth.NewBlockHashesPacket
|
||||
|
||||
@@ -179,6 +184,8 @@ func (c *Conn) Read() Message {
|
||||
msg = new(Disconnect)
|
||||
case (Status{}).Code():
|
||||
msg = new(Status)
|
||||
case (UpgradeStatus{}).Code():
|
||||
msg = new(UpgradeStatus)
|
||||
case (GetBlockHeaders{}).Code():
|
||||
ethMsg := new(eth.GetBlockHeadersPacket66)
|
||||
if err := rlp.DecodeBytes(rawData, ethMsg); err != nil {
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
@@ -64,7 +65,7 @@ func blockTestCmd(ctx *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
for i, test := range tests {
|
||||
if err := test.Run(false, tracer); err != nil {
|
||||
if err := test.Run(false, rawdb.HashScheme, tracer); err != nil {
|
||||
return fmt.Errorf("test %v: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/ethereum/go-ethereum/trie/triedb/hashdb"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
@@ -142,12 +143,23 @@ func runCmd(ctx *cli.Context) error {
|
||||
gen := readGenesis(ctx.String(GenesisFlag.Name))
|
||||
genesisConfig = gen
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
genesis := gen.MustCommit(db)
|
||||
sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: preimages})
|
||||
triedb := trie.NewDatabase(db, &trie.Config{
|
||||
Preimages: preimages,
|
||||
HashDB: hashdb.Defaults,
|
||||
})
|
||||
defer triedb.Close()
|
||||
genesis := gen.MustCommit(db, triedb)
|
||||
sdb := state.NewDatabaseWithNodeDB(db, triedb)
|
||||
statedb, _ = state.New(genesis.Root(), sdb, nil)
|
||||
chainConfig = gen.Config
|
||||
} else {
|
||||
sdb := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &trie.Config{Preimages: preimages})
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
triedb := trie.NewDatabase(db, &trie.Config{
|
||||
Preimages: preimages,
|
||||
HashDB: hashdb.Defaults,
|
||||
})
|
||||
defer triedb.Close()
|
||||
sdb := state.NewDatabaseWithNodeDB(db, triedb)
|
||||
statedb, _ = state.New(types.EmptyRootHash, sdb, nil)
|
||||
genesisConfig = new(core.Genesis)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
@@ -104,25 +106,22 @@ func runStateTest(fname string, cfg vm.Config, jsonOut, dump bool) error {
|
||||
for _, st := range test.Subtests() {
|
||||
// Run the test and aggregate the result
|
||||
result := &StatetestResult{Name: key, Fork: st.Fork, Pass: true}
|
||||
_, s, err := test.Run(st, cfg, false)
|
||||
// print state root for evmlab tracing
|
||||
if s != nil {
|
||||
root := s.IntermediateRoot(false)
|
||||
result.Root = &root
|
||||
if jsonOut {
|
||||
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
|
||||
test.Run(st, cfg, false, rawdb.HashScheme, func(err error, snaps *snapshot.Tree, state *state.StateDB) {
|
||||
if err != nil {
|
||||
// Test failed, mark as so and dump any state to aid debugging
|
||||
result.Pass, result.Error = false, err.Error()
|
||||
if dump {
|
||||
dump := state.RawDump(nil)
|
||||
result.State = &dump
|
||||
}
|
||||
} else {
|
||||
root := state.IntermediateRoot(false)
|
||||
result.Root = &root
|
||||
if jsonOut {
|
||||
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
// Test failed, mark as so and dump any state to aid debugging
|
||||
result.Pass, result.Error = false, err.Error()
|
||||
if dump && s != nil {
|
||||
s, _ = state.New(*result.Root, s.Database(), nil)
|
||||
dump := s.RawDump(nil)
|
||||
result.State = &dump
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
results = append(results, *result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,14 +243,17 @@ func TestT8n(t *testing.T) {
|
||||
output: t8nOutput{alloc: false, result: false},
|
||||
expExitCode: 3,
|
||||
},
|
||||
{ // Test base fee calculation
|
||||
base: "./testdata/25",
|
||||
input: t8nInput{
|
||||
"alloc.json", "txs.json", "env.json", "Merge", "",
|
||||
// base fee logic is different with go-ethereum
|
||||
/*
|
||||
{ // Test base fee calculation
|
||||
base: "./testdata/25",
|
||||
input: t8nInput{
|
||||
"alloc.json", "txs.json", "env.json", "Merge", "",
|
||||
},
|
||||
output: t8nOutput{alloc: true, result: true},
|
||||
expOut: "exp.json",
|
||||
},
|
||||
output: t8nOutput{alloc: true, result: true},
|
||||
expOut: "exp.json",
|
||||
},
|
||||
*/
|
||||
{ // Test withdrawals transition
|
||||
base: "./testdata/26",
|
||||
input: t8nInput{
|
||||
@@ -259,14 +262,17 @@ func TestT8n(t *testing.T) {
|
||||
output: t8nOutput{alloc: true, result: true},
|
||||
expOut: "exp.json",
|
||||
},
|
||||
{ // Cancun tests
|
||||
base: "./testdata/28",
|
||||
input: t8nInput{
|
||||
"alloc.json", "txs.rlp", "env.json", "Cancun", "",
|
||||
// TODO(Nathan): Cancun not ready
|
||||
/*
|
||||
{ // Cancun tests
|
||||
base: "./testdata/28",
|
||||
input: t8nInput{
|
||||
"alloc.json", "txs.rlp", "env.json", "Cancun", "",
|
||||
},
|
||||
output: t8nOutput{alloc: true, result: true},
|
||||
expOut: "exp.json",
|
||||
},
|
||||
output: t8nOutput{alloc: true, result: true},
|
||||
expOut: "exp.json",
|
||||
},
|
||||
*/
|
||||
} {
|
||||
args := []string{"t8n"}
|
||||
args = append(args, tc.output.get()...)
|
||||
|
||||
@@ -11,10 +11,7 @@ The `faucet` is a single binary app (everything included) with all configuration
|
||||
First things first, the `faucet` needs to connect to an Ethereum network, for which it needs the necessary genesis and network infos. Each of the following flags must be set:
|
||||
|
||||
- `-genesis` is a path to a file containing the network `genesis.json`. or using:
|
||||
- `-network` is the devp2p network id used during connection
|
||||
- `-bootnodes` is a list of `enode://` ids to join the network through
|
||||
|
||||
The `faucet` will use the `les` protocol to join the configured Ethereum network and will store its data in `$HOME/.faucet` (currently not configurable).
|
||||
- `-ws` is ws endpoint to what faucet will connect to
|
||||
|
||||
## Funding
|
||||
|
||||
|
||||
@@ -42,21 +42,11 @@ import (
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/ethereum/go-ethereum/ethstats"
|
||||
"github.com/ethereum/go-ethereum/internal/version"
|
||||
"github.com/ethereum/go-ethereum/les"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
@@ -64,10 +54,7 @@ import (
|
||||
var (
|
||||
genesisFlag = flag.String("genesis", "", "Genesis json file to seed the chain with")
|
||||
apiPortFlag = flag.Int("apiport", 8080, "Listener port for the HTTP API connection")
|
||||
ethPortFlag = flag.Int("ethport", 30303, "Listener port for the devp2p connection")
|
||||
bootFlag = flag.String("bootnodes", "", "Comma separated bootnode enode URLs to seed with")
|
||||
netFlag = flag.Uint64("network", 0, "Network ID to use for the Ethereum protocol")
|
||||
statsFlag = flag.String("ethstats", "", "Ethstats network monitoring auth string")
|
||||
wsEndpoint = flag.String("ws", "http://127.0.0.1:7777/", "Url to ws endpoint")
|
||||
|
||||
netnameFlag = flag.String("faucet.name", "", "Network name to assign to the faucet")
|
||||
payoutFlag = flag.Int("faucet.amount", 1, "Number of Ethers to pay out per user request")
|
||||
@@ -163,15 +150,6 @@ func main() {
|
||||
if err != nil {
|
||||
log.Crit("Failed to read genesis block contents", "genesis", *genesisFlag, "err", err)
|
||||
}
|
||||
// Convert the bootnodes to internal enode representations
|
||||
var enodes []*enode.Node
|
||||
for _, boot := range strings.Split(*bootFlag, ",") {
|
||||
if url, err := enode.Parse(enode.ValidSchemes, boot); err == nil {
|
||||
enodes = append(enodes, url)
|
||||
} else {
|
||||
log.Error("Failed to parse bootnode URL", "url", boot, "err", err)
|
||||
}
|
||||
}
|
||||
// Load up the account key and decrypt its password
|
||||
blob, err := os.ReadFile(*accPassFlag)
|
||||
if err != nil {
|
||||
@@ -191,7 +169,7 @@ func main() {
|
||||
log.Crit("Failed to unlock faucet signer account", "err", err)
|
||||
}
|
||||
// Assemble and start the faucet light service
|
||||
faucet, err := newFaucet(genesis, *ethPortFlag, enodes, *netFlag, *statsFlag, ks, website.Bytes(), bep2eInfos)
|
||||
faucet, err := newFaucet(genesis, *wsEndpoint, ks, website.Bytes(), bep2eInfos)
|
||||
if err != nil {
|
||||
log.Crit("Failed to start faucet", "err", err)
|
||||
}
|
||||
@@ -219,7 +197,6 @@ type bep2eInfo struct {
|
||||
// faucet represents a crypto faucet backed by an Ethereum light client.
|
||||
type faucet struct {
|
||||
config *params.ChainConfig // Chain configurations for signing
|
||||
stack *node.Node // Ethereum protocol stack
|
||||
client *ethclient.Client // Client connection to the Ethereum chain
|
||||
index []byte // Index page to serve up on the web
|
||||
|
||||
@@ -248,65 +225,18 @@ type wsConn struct {
|
||||
wlock sync.Mutex
|
||||
}
|
||||
|
||||
func newFaucet(genesis *core.Genesis, port int, enodes []*enode.Node, network uint64, stats string, ks *keystore.KeyStore, index []byte, bep2eInfos map[string]bep2eInfo) (*faucet, error) {
|
||||
// Assemble the raw devp2p protocol stack
|
||||
git, _ := version.VCS()
|
||||
stack, err := node.New(&node.Config{
|
||||
Name: "geth",
|
||||
Version: params.VersionWithCommit(git.Commit, git.Date),
|
||||
DataDir: filepath.Join(os.Getenv("HOME"), ".faucet"),
|
||||
NoUSB: true,
|
||||
P2P: p2p.Config{
|
||||
NAT: nat.Any(),
|
||||
NoDiscovery: true,
|
||||
DiscoveryV5: true,
|
||||
ListenAddr: fmt.Sprintf(":%d", port),
|
||||
MaxPeers: 25,
|
||||
BootstrapNodesV5: enodes,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func newFaucet(genesis *core.Genesis, url string, ks *keystore.KeyStore, index []byte, bep2eInfos map[string]bep2eInfo) (*faucet, error) {
|
||||
bep2eAbi, err := abi.JSON(strings.NewReader(bep2eAbiJson))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Assemble the Ethereum light client protocol
|
||||
cfg := ethconfig.Defaults
|
||||
cfg.SyncMode = downloader.LightSync
|
||||
cfg.NetworkId = network
|
||||
cfg.Genesis = genesis
|
||||
utils.SetDNSDiscoveryDefaults(&cfg, genesis.ToBlock().Hash())
|
||||
|
||||
lesBackend, err := les.New(stack, &cfg)
|
||||
client, err := ethclient.Dial(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to register the Ethereum service: %w", err)
|
||||
}
|
||||
|
||||
// Assemble the ethstats monitoring and reporting service'
|
||||
if stats != "" {
|
||||
if err := ethstats.New(stack, lesBackend.ApiBackend, lesBackend.Engine(), stats); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Boot up the client and ensure it connects to bootnodes
|
||||
if err := stack.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, boot := range enodes {
|
||||
old, err := enode.Parse(enode.ValidSchemes, boot.String())
|
||||
if err == nil {
|
||||
stack.Server().AddPeer(old)
|
||||
}
|
||||
}
|
||||
// Attach to the client and retrieve and interesting metadatas
|
||||
api := stack.Attach()
|
||||
client := ethclient.NewClient(api)
|
||||
|
||||
return &faucet{
|
||||
config: genesis.Config,
|
||||
stack: stack,
|
||||
client: client,
|
||||
index: index,
|
||||
keystore: ks,
|
||||
@@ -319,8 +249,8 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*enode.Node, network ui
|
||||
}
|
||||
|
||||
// close terminates the Ethereum connection and tears down the faucet.
|
||||
func (f *faucet) close() error {
|
||||
return f.stack.Close()
|
||||
func (f *faucet) close() {
|
||||
f.client.Close()
|
||||
}
|
||||
|
||||
// listenAndServe registers the HTTP handlers for the faucet and boots it up
|
||||
@@ -342,7 +272,7 @@ func (f *faucet) webHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// apiHandler handles requests for Ether grants and transaction statuses.
|
||||
func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
|
||||
upgrader := websocket.Upgrader{}
|
||||
upgrader := websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -406,7 +336,6 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if err = send(wsconn, map[string]interface{}{
|
||||
"funds": new(big.Int).Div(balance, ether),
|
||||
"funded": nonce,
|
||||
"peers": f.stack.Server().PeerCount(),
|
||||
"requests": reqs,
|
||||
}, 3*time.Second); err != nil {
|
||||
log.Warn("Failed to send initial stats to client", "err", err)
|
||||
@@ -694,13 +623,11 @@ func (f *faucet) loop() {
|
||||
log.Info("Updated faucet state", "number", head.Number, "hash", head.Hash(), "age", common.PrettyAge(timestamp), "balance", f.balance, "nonce", f.nonce, "price", f.price)
|
||||
|
||||
balance := new(big.Int).Div(f.balance, ether)
|
||||
peers := f.stack.Server().PeerCount()
|
||||
|
||||
for _, conn := range f.conns {
|
||||
if err := send(conn, map[string]interface{}{
|
||||
"funds": balance,
|
||||
"funded": f.nonce,
|
||||
"peers": peers,
|
||||
"requests": f.reqs,
|
||||
}, time.Second); err != nil {
|
||||
log.Warn("Failed to send stats to client", "err", err)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -14,7 +15,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v4/crypto/bls"
|
||||
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/v4/io/prompt"
|
||||
"github.com/prysmaticlabs/prysm/v4/proto/eth/service"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1/validator-client"
|
||||
"github.com/prysmaticlabs/prysm/v4/validator/accounts"
|
||||
"github.com/prysmaticlabs/prysm/v4/validator/accounts/iface"
|
||||
"github.com/prysmaticlabs/prysm/v4/validator/accounts/petnames"
|
||||
@@ -26,6 +27,8 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/internal/flags"
|
||||
"github.com/ethereum/go-ethereum/signer/core"
|
||||
)
|
||||
|
||||
@@ -35,19 +38,20 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
au = aurora.NewAurora(true)
|
||||
privateKeyFlag = &cli.StringFlag{
|
||||
Name: "private-key",
|
||||
Usage: "Hex string for the BLS12-381 private key you wish encrypt into a keystore file",
|
||||
Value: "",
|
||||
}
|
||||
au = aurora.NewAurora(true)
|
||||
showPrivateKeyFlag = &cli.BoolFlag{
|
||||
Name: "show-private-key",
|
||||
Usage: "Show the BLS12-381 private key you will encrypt into a keystore file",
|
||||
Name: "show-private-key",
|
||||
Usage: "Show the BLS12-381 private key you will encrypt into a keystore file",
|
||||
Category: flags.AccountCategory,
|
||||
}
|
||||
BLSAccountPasswordFileFlag = &cli.StringFlag{
|
||||
Name: "blsaccountpassword",
|
||||
Usage: "File path for the BLS account password, which contains the password to encrypt private key into keystore file for managing votes in fast_finality feature",
|
||||
importedAccountPasswordFileFlag = &cli.StringFlag{
|
||||
Name: "importedaccountpassword",
|
||||
Usage: "Password file path for the imported BLS account , which contains the password to get the private key by decrypting the keystore file",
|
||||
Category: flags.AccountCategory,
|
||||
}
|
||||
chainIdFlag = &cli.Int64Flag{
|
||||
Name: "chain-id",
|
||||
Usage: "The chain id of the network that the validator will be created at",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -130,10 +134,8 @@ Make sure you backup your BLS keys regularly.`,
|
||||
Category: "BLS ACCOUNT COMMANDS",
|
||||
Flags: []cli.Flag{
|
||||
utils.DataDirFlag,
|
||||
privateKeyFlag,
|
||||
showPrivateKeyFlag,
|
||||
utils.BLSPasswordFileFlag,
|
||||
BLSAccountPasswordFileFlag,
|
||||
},
|
||||
Description: `
|
||||
geth bls account new
|
||||
@@ -149,17 +151,17 @@ You must remember this password to unlock your account in the future.`,
|
||||
Name: "import",
|
||||
Usage: "Import a BLS account",
|
||||
Action: blsAccountImport,
|
||||
ArgsUsage: "<keystore file>",
|
||||
ArgsUsage: "<keyFile>",
|
||||
Category: "BLS ACCOUNT COMMANDS",
|
||||
Flags: []cli.Flag{
|
||||
utils.DataDirFlag,
|
||||
utils.BLSPasswordFileFlag,
|
||||
BLSAccountPasswordFileFlag,
|
||||
importedAccountPasswordFileFlag,
|
||||
},
|
||||
Description: `
|
||||
geth bls account import <keyFile>
|
||||
|
||||
Import a encrypted BLS account from keystore file <keyFile> into the BLS wallet.
|
||||
Import a encrypted BLS account or a BLS12-381 private key from file <keyFile> into the BLS wallet.
|
||||
|
||||
If the BLS wallet not created yet, it will try to create BLS wallet first.`,
|
||||
},
|
||||
@@ -193,6 +195,22 @@ Print summary of existing BLS accounts in the current BLS wallet.`,
|
||||
|
||||
Delete the selected BLS account from the BLS wallet.`,
|
||||
},
|
||||
{
|
||||
Name: "generate-proof",
|
||||
Usage: "Generate ownership proof for the selected BLS account from the BLS wallet",
|
||||
Action: blsAccountGenerateProof,
|
||||
ArgsUsage: "<BLS pubkey>",
|
||||
Category: "BLS ACCOUNT COMMANDS",
|
||||
Flags: []cli.Flag{
|
||||
utils.DataDirFlag,
|
||||
utils.BLSPasswordFileFlag,
|
||||
chainIdFlag,
|
||||
},
|
||||
Description: `
|
||||
geth bls account generate-proof
|
||||
|
||||
Generate ownership proof for the selected BLS account from the BLS wallet. The proof is used to prove the ownership of the BLS account when creating validator on BSC after feynman upgrade.`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -219,7 +237,10 @@ func blsWalletCreate(ctx *cli.Context) error {
|
||||
utils.Fatalf("BLS wallet already exists in <DATADIR>/bls/wallet.")
|
||||
}
|
||||
|
||||
password := utils.GetPassPhraseWithList("Your new BLS wallet will be locked with a password. Please give a password. Do not forget this password.", true, 0, GetBLSPassword(ctx))
|
||||
password := utils.GetPassPhraseWithList("Your new BLS wallet will be locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordListFromPath(ctx.String(utils.BLSPasswordFileFlag.Name)))
|
||||
if err := core.ValidatePasswordFormat(password); err != nil {
|
||||
utils.Fatalf("Password invalid: %v.", err)
|
||||
}
|
||||
|
||||
opts := []accounts.Option{}
|
||||
opts = append(opts, accounts.WithWalletDir(dir))
|
||||
@@ -249,7 +270,10 @@ func openOrCreateBLSWallet(ctx *cli.Context, cfg *gethConfig) (*wallet.Wallet, e
|
||||
}
|
||||
if !dirExists {
|
||||
fmt.Println("BLS wallet not exists, creating BLS wallet...")
|
||||
password := utils.GetPassPhraseWithList("Your new BLS wallet will be locked with a password. Please give a password. Do not forget this password.", true, 0, GetBLSPassword(ctx))
|
||||
password := utils.GetPassPhraseWithList("Your new BLS wallet will be locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordListFromPath(ctx.String(utils.BLSPasswordFileFlag.Name)))
|
||||
if err := core.ValidatePasswordFormat(password); err != nil {
|
||||
utils.Fatalf("Password invalid: %v.", err)
|
||||
}
|
||||
|
||||
opts := []accounts.Option{}
|
||||
opts = append(opts, accounts.WithWalletDir(walletDir))
|
||||
@@ -269,7 +293,7 @@ func openOrCreateBLSWallet(ctx *cli.Context, cfg *gethConfig) (*wallet.Wallet, e
|
||||
return w, nil
|
||||
}
|
||||
|
||||
walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, GetBLSPassword(ctx))
|
||||
walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, utils.MakePasswordListFromPath(ctx.String(utils.BLSPasswordFileFlag.Name)))
|
||||
w, err = wallet.OpenWallet(context.Background(), &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
WalletPassword: walletPassword,
|
||||
@@ -309,27 +333,11 @@ func blsAccountCreate(ctx *cli.Context) error {
|
||||
if err := os.MkdirAll(keystoreDir, 0755); err != nil {
|
||||
utils.Fatalf("Could not access keystore dir: %v.", err)
|
||||
}
|
||||
accountPassword := utils.GetPassPhraseWithList("Your new BLS account will be encrypted with a password. Please give a password. Do not forget this password.", true, 0, GetBLSAccountPassword(ctx))
|
||||
if err := core.ValidatePasswordFormat(accountPassword); err != nil {
|
||||
utils.Fatalf("Password invalid: %v.", err)
|
||||
}
|
||||
accountPassword := w.Password()
|
||||
|
||||
encryptor := keystorev4.New()
|
||||
secretKey, err := bls.RandKey()
|
||||
privateKeyString := ctx.String(privateKeyFlag.Name)
|
||||
if privateKeyString != "" {
|
||||
if len(privateKeyString) > 2 && strings.Contains(privateKeyString, "0x") {
|
||||
privateKeyString = privateKeyString[2:] // Strip the 0x prefix, if any.
|
||||
}
|
||||
bytesValue, err := hex.DecodeString(privateKeyString)
|
||||
if err != nil {
|
||||
utils.Fatalf("could not decode as hex string: %s", privateKeyString)
|
||||
}
|
||||
secretKey, err = bls.SecretKeyFromBytes(bytesValue)
|
||||
if err != nil {
|
||||
utils.Fatalf("not a valid BLS12-381 private key")
|
||||
}
|
||||
} else if err != nil {
|
||||
if err != nil {
|
||||
utils.Fatalf("Could not generate BLS secret key: %v.", err)
|
||||
}
|
||||
|
||||
@@ -383,22 +391,6 @@ func blsAccountCreate(ctx *cli.Context) error {
|
||||
|
||||
// blsAccountImport imports a BLS account into the BLS wallet.
|
||||
func blsAccountImport(ctx *cli.Context) error {
|
||||
keyfile := ctx.Args().First()
|
||||
if len(keyfile) == 0 {
|
||||
utils.Fatalf("The keystore file must be given as argument.")
|
||||
}
|
||||
keyJSON, err := os.ReadFile(keyfile)
|
||||
if err != nil {
|
||||
utils.Fatalf("Could not read keystore file: %v", err)
|
||||
}
|
||||
keystore := &keymanager.Keystore{}
|
||||
if err := json.Unmarshal(keyJSON, keystore); err != nil {
|
||||
utils.Fatalf("Could not decode keystore file: %v.", err)
|
||||
}
|
||||
if keystore.Pubkey == "" {
|
||||
utils.Fatalf(" Missing public key, wrong keystore file.")
|
||||
}
|
||||
|
||||
cfg := gethConfig{Node: defaultNodeConfig()}
|
||||
// Load config file.
|
||||
if file := ctx.String(configFileFlag.Name); file != "" {
|
||||
@@ -421,19 +413,59 @@ func blsAccountImport(ctx *cli.Context) error {
|
||||
utils.Fatalf("The BLS keymanager cannot import keystores")
|
||||
}
|
||||
|
||||
password := utils.GetPassPhraseWithList("Enter the password for your imported account.", false, 0, GetBLSAccountPassword(ctx))
|
||||
keyfile := ctx.Args().First()
|
||||
if len(keyfile) == 0 {
|
||||
utils.Fatalf("The keystore file must be given as argument.")
|
||||
}
|
||||
keyInfo, err := os.ReadFile(keyfile)
|
||||
if err != nil {
|
||||
utils.Fatalf("Could not read keystore file: %v", err)
|
||||
}
|
||||
keystore := &keymanager.Keystore{}
|
||||
var importedAccountPassword string
|
||||
if err := json.Unmarshal(keyInfo, keystore); err != nil {
|
||||
secretKey, err := bls.SecretKeyFromBytes(common.FromHex(strings.TrimRight(string(keyInfo), "\r\n")))
|
||||
if err != nil {
|
||||
utils.Fatalf("keyFile is neither a keystore file or include a valid BLS12-381 private key: %v.", err)
|
||||
}
|
||||
pubKeyBytes := secretKey.PublicKey().Marshal()
|
||||
encryptor := keystorev4.New()
|
||||
importedAccountPassword = w.Password()
|
||||
cryptoFields, err := encryptor.Encrypt(secretKey.Marshal(), importedAccountPassword)
|
||||
if err != nil {
|
||||
utils.Fatalf("Could not encrypt secret key: %v.", err)
|
||||
}
|
||||
id, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
utils.Fatalf("Could not generate uuid: %v.", err)
|
||||
}
|
||||
keystore = &keymanager.Keystore{
|
||||
Crypto: cryptoFields,
|
||||
ID: id.String(),
|
||||
Pubkey: fmt.Sprintf("%x", pubKeyBytes),
|
||||
Version: encryptor.Version(),
|
||||
Name: encryptor.Name(),
|
||||
}
|
||||
}
|
||||
if keystore.Pubkey == "" {
|
||||
utils.Fatalf(" Missing public key, wrong keystore file.")
|
||||
}
|
||||
|
||||
if importedAccountPassword == "" {
|
||||
importedAccountPassword = utils.GetPassPhraseWithList("Enter the password for your imported account.", false, 0, utils.MakePasswordListFromPath(ctx.String(importedAccountPasswordFileFlag.Name)))
|
||||
}
|
||||
|
||||
fmt.Println("Importing BLS account, this may take a while...")
|
||||
statuses, err := accounts.ImportAccounts(context.Background(), &accounts.ImportAccountsConfig{
|
||||
Importer: k,
|
||||
Keystores: []*keymanager.Keystore{keystore},
|
||||
AccountPassword: password,
|
||||
AccountPassword: importedAccountPassword,
|
||||
})
|
||||
if err != nil {
|
||||
utils.Fatalf("Import BLS account failed: %v.", err)
|
||||
}
|
||||
// len(statuses)==len(Keystores) when err==nil
|
||||
if statuses[0].Status == service.ImportedKeystoreStatus_ERROR {
|
||||
if statuses[0].Status == keymanager.StatusError {
|
||||
fmt.Printf("Could not import keystore: %v.", statuses[0].Message)
|
||||
} else {
|
||||
fmt.Println("Successfully import BLS account.")
|
||||
@@ -458,7 +490,7 @@ func blsAccountList(ctx *cli.Context) error {
|
||||
utils.Fatalf("BLS wallet not exists.")
|
||||
}
|
||||
|
||||
walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, GetBLSPassword(ctx))
|
||||
walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, utils.MakePasswordListFromPath(ctx.String(utils.BLSPasswordFileFlag.Name)))
|
||||
w, err := wallet.OpenWallet(context.Background(), &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
WalletPassword: walletPassword,
|
||||
@@ -537,7 +569,7 @@ func blsAccountDelete(ctx *cli.Context) error {
|
||||
utils.Fatalf("BLS wallet not exists.")
|
||||
}
|
||||
|
||||
walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, GetBLSPassword(ctx))
|
||||
walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, utils.MakePasswordListFromPath(ctx.String(utils.BLSPasswordFileFlag.Name)))
|
||||
w, err := wallet.OpenWallet(context.Background(), &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
WalletPassword: walletPassword,
|
||||
@@ -599,26 +631,73 @@ func blsAccountDelete(ctx *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetBLSPassword(ctx *cli.Context) []string {
|
||||
path := ctx.String(utils.BLSPasswordFileFlag.Name)
|
||||
if path == "" {
|
||||
return nil
|
||||
// blsAccountGenerateProof generate ownership proof for a selected BLS account.
|
||||
func blsAccountGenerateProof(ctx *cli.Context) error {
|
||||
addrString := ctx.Args().First()
|
||||
if addrString == "" {
|
||||
utils.Fatalf("Operator account must be given as argument.")
|
||||
}
|
||||
text, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read wallet password file: %v", err)
|
||||
}
|
||||
return []string{string(text)}
|
||||
}
|
||||
addr := common.HexToAddress(addrString)
|
||||
|
||||
func GetBLSAccountPassword(ctx *cli.Context) []string {
|
||||
path := ctx.String(BLSAccountPasswordFileFlag.Name)
|
||||
if path == "" {
|
||||
return nil
|
||||
blsPubkeyString := ctx.Args().Get(1)
|
||||
if blsPubkeyString == "" {
|
||||
utils.Fatalf("BLS pubkey must be given as argument.")
|
||||
}
|
||||
text, err := os.ReadFile(path)
|
||||
blsPubkeyBz, err := hex.DecodeString(strings.TrimPrefix(blsPubkeyString, "0x"))
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read account password file: %v", err)
|
||||
utils.Fatalf("Could not decode string %s as hex.", blsPubkeyString)
|
||||
}
|
||||
return []string{string(text)}
|
||||
blsPublicKey, err := bls.PublicKeyFromBytes(blsPubkeyBz)
|
||||
if err != nil {
|
||||
utils.Fatalf("%#x is not a valid BLS public key.", blsPubkeyBz)
|
||||
}
|
||||
|
||||
cfg := gethConfig{Node: defaultNodeConfig()}
|
||||
// Load config file.
|
||||
if file := ctx.String(configFileFlag.Name); file != "" {
|
||||
if err := loadConfig(file, &cfg); err != nil {
|
||||
utils.Fatalf("%v", err)
|
||||
}
|
||||
}
|
||||
utils.SetNodeConfig(ctx, &cfg.Node)
|
||||
|
||||
walletDir := filepath.Join(cfg.Node.DataDir, BLSWalletPath)
|
||||
dirExists, err := wallet.Exists(walletDir)
|
||||
if err != nil || !dirExists {
|
||||
utils.Fatalf("BLS wallet not exists.")
|
||||
}
|
||||
|
||||
walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, utils.MakePasswordListFromPath(ctx.String(utils.BLSPasswordFileFlag.Name)))
|
||||
w, err := wallet.OpenWallet(context.Background(), &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
WalletPassword: walletPassword,
|
||||
})
|
||||
if err != nil {
|
||||
utils.Fatalf("Open BLS wallet failed: %v.", err)
|
||||
}
|
||||
km, err := w.InitializeKeymanager(context.Background(), iface.InitKeymanagerConfig{ListenForChanges: false})
|
||||
if err != nil {
|
||||
utils.Fatalf("Initialize key manager failed: %v.", err)
|
||||
}
|
||||
|
||||
chainIdInt64 := ctx.Int64(chainIdFlag.Name)
|
||||
if chainIdInt64 == 0 {
|
||||
utils.Fatalf("Chain id is required.")
|
||||
}
|
||||
chainId := new(big.Int).SetInt64(chainIdInt64)
|
||||
paddedChainIdBytes := make([]byte, 32)
|
||||
copy(paddedChainIdBytes[32-len(chainId.Bytes()):], chainId.Bytes())
|
||||
msgHash := crypto.Keccak256(append(addr.Bytes(), append(blsPublicKey.Marshal(), paddedChainIdBytes...)...))
|
||||
|
||||
req := &validatorpb.SignRequest{
|
||||
PublicKey: blsPublicKey.Marshal(),
|
||||
SigningRoot: msgHash,
|
||||
}
|
||||
sig, err := km.Sign(context.Background(), req)
|
||||
if err != nil {
|
||||
utils.Fatalf("Generate signature failed: %v.", err)
|
||||
}
|
||||
fmt.Printf("Proof: %#x\n", sig.Marshal())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -30,6 +30,9 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
@@ -45,7 +48,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -54,7 +57,10 @@ var (
|
||||
Name: "init",
|
||||
Usage: "Bootstrap and initialize a new genesis block",
|
||||
ArgsUsage: "<genesisPath>",
|
||||
Flags: flags.Merge([]cli.Flag{utils.CachePreimagesFlag}, utils.DatabasePathFlags),
|
||||
Flags: flags.Merge([]cli.Flag{
|
||||
utils.CachePreimagesFlag,
|
||||
utils.StateSchemeFlag,
|
||||
}, utils.DatabasePathFlags),
|
||||
Description: `
|
||||
The init command initializes a new genesis block and definition for the network.
|
||||
This is a destructive action and changes the network in which you will be
|
||||
@@ -116,6 +122,9 @@ if one is set. Otherwise it prints the genesis from the datadir.`,
|
||||
utils.MetricsInfluxDBBucketFlag,
|
||||
utils.MetricsInfluxDBOrganizationFlag,
|
||||
utils.TxLookupLimitFlag,
|
||||
utils.TransactionHistoryFlag,
|
||||
utils.StateSchemeFlag,
|
||||
utils.StateHistoryFlag,
|
||||
}, utils.DatabasePathFlags),
|
||||
Description: `
|
||||
The import command imports blocks from an RLP-encoded form. The form can be one file
|
||||
@@ -132,6 +141,7 @@ processing will proceed even if an individual RLP-file import failure occurs.`,
|
||||
Flags: flags.Merge([]cli.Flag{
|
||||
utils.CacheFlag,
|
||||
utils.SyncModeFlag,
|
||||
utils.StateSchemeFlag,
|
||||
}, utils.DatabasePathFlags),
|
||||
Description: `
|
||||
Requires a first argument of the file to write to.
|
||||
@@ -181,9 +191,25 @@ It's deprecated, please use "geth db export" instead.
|
||||
utils.IncludeIncompletesFlag,
|
||||
utils.StartKeyFlag,
|
||||
utils.DumpLimitFlag,
|
||||
utils.StateSchemeFlag,
|
||||
}, utils.DatabasePathFlags),
|
||||
Description: `
|
||||
This command dumps out the state for a given block (or latest, if none provided).
|
||||
If you use "dump" command in path mode, please firstly use "dump-roothash" command to get all available state root hash.
|
||||
`,
|
||||
}
|
||||
dumpRootHashCommand = &cli.Command{
|
||||
Action: dumpAllRootHashInPath,
|
||||
Name: "dump-roothash",
|
||||
Usage: "Dump all available state root hash in path mode",
|
||||
Flags: flags.Merge([]cli.Flag{
|
||||
utils.StateSchemeFlag,
|
||||
}, utils.DatabasePathFlags),
|
||||
Description: `
|
||||
The dump-roothash command dump all available state root hash in path mode.
|
||||
If you use "dump" command in path mode, please note that it only keeps at most 129 blocks which belongs to diffLayer or diskLayer.
|
||||
Therefore, you must specify the blockNumber or blockHash that locates in diffLayer or diskLayer.
|
||||
"geth" will print all available blockNumber and related block state root hash, and you can query block hash by block number.
|
||||
`,
|
||||
}
|
||||
)
|
||||
@@ -217,15 +243,16 @@ func initGenesis(ctx *cli.Context) error {
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to open database: %v", err)
|
||||
}
|
||||
triedb := trie.NewDatabaseWithConfig(chaindb, &trie.Config{
|
||||
Preimages: ctx.Bool(utils.CachePreimagesFlag.Name),
|
||||
})
|
||||
defer chaindb.Close()
|
||||
|
||||
triedb := utils.MakeTrieDatabase(ctx, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false)
|
||||
defer triedb.Close()
|
||||
|
||||
_, hash, err := core.SetupGenesisBlock(chaindb, triedb, genesis)
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to write genesis block: %v", err)
|
||||
}
|
||||
chaindb.Close()
|
||||
log.Info("Successfully wrote genesis state", "database", name, "hash", hash)
|
||||
log.Info(fmt.Sprintf("Successfully wrote genesis state database=%v hash=%v", name, hash))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -269,7 +296,7 @@ func createPorts(ipStr string, port int, size int) []int {
|
||||
// Create config for node i in the cluster
|
||||
func createNodeConfig(baseConfig gethConfig, enodes []*enode.Node, ip string, port int, size int, i int) gethConfig {
|
||||
baseConfig.Node.HTTPHost = ip
|
||||
baseConfig.Node.P2P.ListenAddr = fmt.Sprintf(":%d", port+i)
|
||||
baseConfig.Node.P2P.ListenAddr = fmt.Sprintf(":%d", port)
|
||||
baseConfig.Node.P2P.BootstrapNodes = make([]*enode.Node, size-1)
|
||||
// Set the P2P connections between this node and the other nodes
|
||||
for j := 0; j < i; j++ {
|
||||
@@ -286,11 +313,12 @@ func createNodeConfigs(baseConfig gethConfig, initDir string, ips []string, port
|
||||
// Create the nodes
|
||||
enodes := make([]*enode.Node, size)
|
||||
for i := 0; i < size; i++ {
|
||||
stack, err := node.New(&baseConfig.Node)
|
||||
nodeConfig := baseConfig.Node
|
||||
nodeConfig.DataDir = path.Join(initDir, fmt.Sprintf("node%d", i))
|
||||
stack, err := node.New(&nodeConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stack.Config().DataDir = path.Join(initDir, fmt.Sprintf("node%d", i))
|
||||
pk := stack.Config().NodeKey()
|
||||
enodes[i] = enode.NewV4(&pk.PublicKey, net.ParseIP(ips[i]), ports[i], ports[i])
|
||||
}
|
||||
@@ -422,7 +450,7 @@ func dumpGenesis(ctx *cli.Context) error {
|
||||
if ctx.IsSet(utils.DataDirFlag.Name) {
|
||||
utils.Fatalf("no existing datadir at %s", stack.Config().DataDir)
|
||||
}
|
||||
utils.Fatalf("no network preset provided. no exisiting genesis in the default datadir")
|
||||
utils.Fatalf("no network preset provided, no existing genesis in the default datadir")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -581,11 +609,20 @@ func exportPreimages(ctx *cli.Context) error {
|
||||
}
|
||||
|
||||
func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, ethdb.Database, common.Hash, error) {
|
||||
db := utils.MakeChainDatabase(ctx, stack, true, false)
|
||||
var header *types.Header
|
||||
if ctx.NArg() > 1 {
|
||||
return nil, nil, common.Hash{}, fmt.Errorf("expected 1 argument (number or hash), got %d", ctx.NArg())
|
||||
}
|
||||
|
||||
db := utils.MakeChainDatabase(ctx, stack, true, false)
|
||||
scheme, err := rawdb.ParseStateScheme(ctx.String(utils.StateSchemeFlag.Name), db)
|
||||
if err != nil {
|
||||
return nil, nil, common.Hash{}, err
|
||||
}
|
||||
if scheme == rawdb.PathScheme {
|
||||
fmt.Println("You are using geth dump in path mode, please use `geth dump-roothash` command to get all available blocks.")
|
||||
}
|
||||
|
||||
header := &types.Header{}
|
||||
if ctx.NArg() == 1 {
|
||||
arg := ctx.Args().First()
|
||||
if hashish(arg) {
|
||||
@@ -608,11 +645,22 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, eth
|
||||
}
|
||||
} else {
|
||||
// Use latest
|
||||
header = rawdb.ReadHeadHeader(db)
|
||||
if scheme == rawdb.PathScheme {
|
||||
triedb := trie.NewDatabase(db, &trie.Config{PathDB: pathdb.ReadOnly})
|
||||
defer triedb.Close()
|
||||
if stateRoot := triedb.Head(); stateRoot != (common.Hash{}) {
|
||||
header.Root = stateRoot
|
||||
} else {
|
||||
return nil, nil, common.Hash{}, fmt.Errorf("no top state root hash in path db")
|
||||
}
|
||||
} else {
|
||||
header = rawdb.ReadHeadHeader(db)
|
||||
}
|
||||
}
|
||||
if header == nil {
|
||||
return nil, nil, common.Hash{}, errors.New("no head block found")
|
||||
}
|
||||
|
||||
startArg := common.FromHex(ctx.String(utils.StartKeyFlag.Name))
|
||||
var start common.Hash
|
||||
switch len(startArg) {
|
||||
@@ -625,6 +673,7 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, eth
|
||||
default:
|
||||
return nil, nil, common.Hash{}, fmt.Errorf("invalid start argument: %x. 20 or 32 hex-encoded bytes required", startArg)
|
||||
}
|
||||
|
||||
var conf = &state.DumpConfig{
|
||||
SkipCode: ctx.Bool(utils.ExcludeCodeFlag.Name),
|
||||
SkipStorage: ctx.Bool(utils.ExcludeStorageFlag.Name),
|
||||
@@ -632,9 +681,10 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, eth
|
||||
Start: start.Bytes(),
|
||||
Max: ctx.Uint64(utils.DumpLimitFlag.Name),
|
||||
}
|
||||
conf.StateScheme = scheme
|
||||
log.Info("State dump configured", "block", header.Number, "hash", header.Hash().Hex(),
|
||||
"skipcode", conf.SkipCode, "skipstorage", conf.SkipStorage,
|
||||
"start", hexutil.Encode(conf.Start), "limit", conf.Max)
|
||||
"skipcode", conf.SkipCode, "skipstorage", conf.SkipStorage, "start", hexutil.Encode(conf.Start),
|
||||
"limit", conf.Max, "state scheme", conf.StateScheme)
|
||||
return conf, db, header.Root, nil
|
||||
}
|
||||
|
||||
@@ -646,10 +696,10 @@ func dump(ctx *cli.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config := &trie.Config{
|
||||
Preimages: true, // always enable preimage lookup
|
||||
}
|
||||
state, err := state.New(root, state.NewDatabaseWithConfig(db, config), nil)
|
||||
triedb := utils.MakeTrieDatabase(ctx, db, true, true) // always enable preimage lookup
|
||||
defer triedb.Close()
|
||||
|
||||
state, err := state.New(root, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -666,6 +716,29 @@ func dump(ctx *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func dumpAllRootHashInPath(ctx *cli.Context) error {
|
||||
stack, _ := makeConfigNode(ctx)
|
||||
defer stack.Close()
|
||||
db := utils.MakeChainDatabase(ctx, stack, true, false)
|
||||
defer db.Close()
|
||||
triedb := trie.NewDatabase(db, &trie.Config{PathDB: pathdb.ReadOnly})
|
||||
defer triedb.Close()
|
||||
|
||||
scheme, err := rawdb.ParseStateScheme(ctx.String(utils.StateSchemeFlag.Name), db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if scheme == rawdb.HashScheme {
|
||||
return errors.New("incorrect state scheme, you should use it in path mode")
|
||||
}
|
||||
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Block Number", "Block State Root Hash"})
|
||||
table.AppendBulk(triedb.GetAllRooHash())
|
||||
table.Render()
|
||||
return nil
|
||||
}
|
||||
|
||||
// hashish returns true for strings that look like hashes.
|
||||
func hashish(x string) bool {
|
||||
_, err := strconv.Atoi(x)
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"reflect"
|
||||
"unicode"
|
||||
|
||||
"github.com/naoina/toml"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
@@ -32,6 +33,8 @@ import (
|
||||
"github.com/ethereum/go-ethereum/accounts/scwallet"
|
||||
"github.com/ethereum/go-ethereum/accounts/usbwallet"
|
||||
"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/eth/ethconfig"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/internal/flags"
|
||||
@@ -40,7 +43,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/naoina/toml"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -54,8 +56,9 @@ var (
|
||||
}
|
||||
|
||||
configFileFlag = &cli.StringFlag{
|
||||
Name: "config",
|
||||
Usage: "TOML configuration file",
|
||||
Name: "config",
|
||||
Usage: "TOML configuration file",
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -135,6 +138,16 @@ func loadBaseConfig(ctx *cli.Context) gethConfig {
|
||||
}
|
||||
}
|
||||
|
||||
scheme := cfg.Eth.StateScheme
|
||||
if scheme != "" {
|
||||
if !rawdb.ValidateStateScheme(scheme) {
|
||||
utils.Fatalf("Invalid state scheme param in config: %s", scheme)
|
||||
}
|
||||
}
|
||||
if cfg.Eth.Genesis != nil && cfg.Eth.Genesis.Config != nil {
|
||||
log.Warn("Chain config in the configuration file is ignored!")
|
||||
}
|
||||
|
||||
// Apply flags.
|
||||
utils.SetNodeConfig(ctx, &cfg.Node)
|
||||
return cfg
|
||||
@@ -164,6 +177,19 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
|
||||
// makeFullNode loads geth configuration and creates the Ethereum backend.
|
||||
func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
|
||||
stack, cfg := makeConfigNode(ctx)
|
||||
if ctx.IsSet(utils.RialtoHash.Name) {
|
||||
v := ctx.String(utils.RialtoHash.Name)
|
||||
params.RialtoGenesisHash = common.HexToHash(v)
|
||||
}
|
||||
|
||||
if ctx.IsSet(utils.OverrideShanghai.Name) {
|
||||
v := ctx.Uint64(utils.OverrideShanghai.Name)
|
||||
cfg.Eth.OverrideShanghai = &v
|
||||
}
|
||||
if ctx.IsSet(utils.OverrideKepler.Name) {
|
||||
v := ctx.Uint64(utils.OverrideKepler.Name)
|
||||
cfg.Eth.OverrideKepler = &v
|
||||
}
|
||||
if ctx.IsSet(utils.OverrideCancun.Name) {
|
||||
v := ctx.Uint64(utils.OverrideCancun.Name)
|
||||
cfg.Eth.OverrideCancun = &v
|
||||
@@ -172,6 +198,10 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
|
||||
v := ctx.Uint64(utils.OverrideVerkle.Name)
|
||||
cfg.Eth.OverrideVerkle = &v
|
||||
}
|
||||
if ctx.IsSet(utils.OverrideFeynman.Name) {
|
||||
v := ctx.Uint64(utils.OverrideFeynman.Name)
|
||||
cfg.Eth.OverrideFeynman = &v
|
||||
}
|
||||
backend, _ := utils.RegisterEthService(stack, &cfg.Eth)
|
||||
|
||||
// Configure log filter RPC API.
|
||||
|
||||
@@ -30,7 +30,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
ipcAPIs = "admin:1.0 debug: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 eth:1.0 miner:1.0 net:1.0 parlia:1.0 rpc:1.0 txpool:1.0 web3:1.0"
|
||||
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
|
||||
)
|
||||
|
||||
@@ -60,7 +60,7 @@ func TestConsoleWelcome(t *testing.T) {
|
||||
geth.SetTemplateFunc("gover", runtime.Version)
|
||||
geth.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") })
|
||||
geth.SetTemplateFunc("niltime", func() string {
|
||||
return time.Unix(0, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
|
||||
return time.Unix(0x5e9da7ce, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
|
||||
})
|
||||
geth.SetTemplateFunc("apis", func() string { return ipcAPIs })
|
||||
|
||||
@@ -131,7 +131,7 @@ func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) {
|
||||
attach.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") })
|
||||
attach.SetTemplateFunc("etherbase", func() string { return geth.Etherbase })
|
||||
attach.SetTemplateFunc("niltime", func() string {
|
||||
return time.Unix(0, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
|
||||
return time.Unix(0x5e9da7ce, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
|
||||
})
|
||||
attach.SetTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") })
|
||||
attach.SetTemplateFunc("datadir", func() string { return geth.Datadir })
|
||||
|
||||
@@ -19,6 +19,7 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
@@ -38,6 +39,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/internal/flags"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -62,6 +64,7 @@ Remove blockchain and state databases`,
|
||||
dbCompactCmd,
|
||||
dbGetCmd,
|
||||
dbDeleteCmd,
|
||||
dbInspectTrieCmd,
|
||||
dbPutCmd,
|
||||
dbGetSlotsCmd,
|
||||
dbDumpFreezerIndex,
|
||||
@@ -72,6 +75,9 @@ Remove blockchain and state databases`,
|
||||
// no legacy stored receipts for bsc
|
||||
// dbMigrateFreezerCmd,
|
||||
dbCheckStateContentCmd,
|
||||
dbHbss2PbssCmd,
|
||||
dbTrieGetCmd,
|
||||
dbTrieDeleteCmd,
|
||||
},
|
||||
}
|
||||
dbInspectCmd = &cli.Command{
|
||||
@@ -84,6 +90,17 @@ Remove blockchain and state databases`,
|
||||
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.`,
|
||||
}
|
||||
dbInspectTrieCmd = &cli.Command{
|
||||
Action: inspectTrie,
|
||||
Name: "inspect-trie",
|
||||
ArgsUsage: "<blocknum> <jobnum>",
|
||||
Flags: []cli.Flag{
|
||||
utils.DataDirFlag,
|
||||
utils.SyncModeFlag,
|
||||
},
|
||||
Usage: "Inspect the MPT tree of the account and contract.",
|
||||
Description: `This commands iterates the entrie WorldState.`,
|
||||
}
|
||||
dbCheckStateContentCmd = &cli.Command{
|
||||
Action: checkStateContent,
|
||||
Name: "check-state-content",
|
||||
@@ -94,6 +111,47 @@ Remove blockchain and state databases`,
|
||||
For each trie node encountered, it checks that the key corresponds to the keccak256(value). If this is not true, this indicates
|
||||
a data corruption.`,
|
||||
}
|
||||
dbHbss2PbssCmd = &cli.Command{
|
||||
Action: hbss2pbss,
|
||||
Name: "hbss-to-pbss",
|
||||
ArgsUsage: "<jobnum (optional)>",
|
||||
Flags: []cli.Flag{
|
||||
utils.DataDirFlag,
|
||||
utils.SyncModeFlag,
|
||||
utils.ForceFlag,
|
||||
utils.AncientFlag,
|
||||
},
|
||||
Usage: "Convert Hash-Base to Path-Base trie node.",
|
||||
Description: `This command iterates the entire trie node database and convert the hash-base node to path-base node.`,
|
||||
}
|
||||
dbTrieGetCmd = &cli.Command{
|
||||
Action: dbTrieGet,
|
||||
Name: "trie-get",
|
||||
Usage: "Show the value of a trie node path key",
|
||||
ArgsUsage: "[trie owner] <path-base key>",
|
||||
Flags: []cli.Flag{
|
||||
utils.DataDirFlag,
|
||||
utils.SyncModeFlag,
|
||||
utils.BSCMainnetFlag,
|
||||
utils.ChapelFlag,
|
||||
utils.StateSchemeFlag,
|
||||
},
|
||||
Description: "This command looks up the specified trie node key from the database.",
|
||||
}
|
||||
dbTrieDeleteCmd = &cli.Command{
|
||||
Action: dbTrieDelete,
|
||||
Name: "trie-delete",
|
||||
Usage: "delete the specify trie node",
|
||||
ArgsUsage: "[trie owner] <hash-base key> | <path-base key>",
|
||||
Flags: []cli.Flag{
|
||||
utils.DataDirFlag,
|
||||
utils.SyncModeFlag,
|
||||
utils.BSCMainnetFlag,
|
||||
utils.ChapelFlag,
|
||||
utils.StateSchemeFlag,
|
||||
},
|
||||
Description: "This command delete the specify trie node from the database.",
|
||||
}
|
||||
dbStatCmd = &cli.Command{
|
||||
Action: dbStats,
|
||||
Name: "stats",
|
||||
@@ -154,6 +212,7 @@ WARNING: This is a low-level operation which may cause database corruption!`,
|
||||
ArgsUsage: "<hex-encoded state root> <hex-encoded account hash> <hex-encoded storage trie root> <hex-encoded start (optional)> <int max elements (optional)>",
|
||||
Flags: flags.Merge([]cli.Flag{
|
||||
utils.SyncModeFlag,
|
||||
utils.StateSchemeFlag,
|
||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
||||
Description: "This command looks up the specified database key from the database.",
|
||||
}
|
||||
@@ -268,6 +327,92 @@ func confirmAndRemoveDB(database string, kind string) {
|
||||
}
|
||||
}
|
||||
|
||||
func inspectTrie(ctx *cli.Context) error {
|
||||
if ctx.NArg() < 1 {
|
||||
return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
|
||||
}
|
||||
|
||||
if ctx.NArg() > 3 {
|
||||
return fmt.Errorf("Max 3 arguments: %v", ctx.Command.ArgsUsage)
|
||||
}
|
||||
|
||||
var (
|
||||
blockNumber uint64
|
||||
trieRootHash common.Hash
|
||||
jobnum uint64
|
||||
)
|
||||
|
||||
stack, _ := makeConfigNode(ctx)
|
||||
defer stack.Close()
|
||||
|
||||
db := utils.MakeChainDatabase(ctx, stack, true, false)
|
||||
defer db.Close()
|
||||
|
||||
var headerBlockHash common.Hash
|
||||
if ctx.NArg() >= 1 {
|
||||
if ctx.Args().Get(0) == "latest" {
|
||||
headerHash := rawdb.ReadHeadHeaderHash(db)
|
||||
blockNumber = *(rawdb.ReadHeaderNumber(db, headerHash))
|
||||
} else if ctx.Args().Get(0) == "snapshot" {
|
||||
trieRootHash = rawdb.ReadSnapshotRoot(db)
|
||||
blockNumber = math.MaxUint64
|
||||
} else {
|
||||
var err error
|
||||
blockNumber, 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 ctx.NArg() == 1 {
|
||||
jobnum = 1000
|
||||
} else {
|
||||
var err error
|
||||
jobnum, err = strconv.ParseUint(ctx.Args().Get(1), 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to Parse jobnum, Args[1]: %v, err: %v", ctx.Args().Get(1), err)
|
||||
}
|
||||
}
|
||||
|
||||
if blockNumber != math.MaxUint64 {
|
||||
headerBlockHash = rawdb.ReadCanonicalHash(db, blockNumber)
|
||||
if headerBlockHash == (common.Hash{}) {
|
||||
return fmt.Errorf("ReadHeadBlockHash empry hash")
|
||||
}
|
||||
blockHeader := rawdb.ReadHeader(db, headerBlockHash, blockNumber)
|
||||
trieRootHash = blockHeader.Root
|
||||
}
|
||||
if (trieRootHash == common.Hash{}) {
|
||||
log.Error("Empty root hash")
|
||||
}
|
||||
fmt.Printf("ReadBlockHeader, root: %v, blocknum: %v\n", trieRootHash, blockNumber)
|
||||
|
||||
dbScheme := rawdb.ReadStateScheme(db)
|
||||
var config *trie.Config
|
||||
if dbScheme == rawdb.PathScheme {
|
||||
config = &trie.Config{
|
||||
PathDB: pathdb.ReadOnly,
|
||||
}
|
||||
} else if dbScheme == rawdb.HashScheme {
|
||||
config = trie.HashDefaults
|
||||
}
|
||||
|
||||
triedb := trie.NewDatabase(db, config)
|
||||
theTrie, err := trie.New(trie.TrieID(trieRootHash), triedb)
|
||||
if err != nil {
|
||||
fmt.Printf("fail to new trie tree, err: %v, rootHash: %v\n", err, trieRootHash.String())
|
||||
return err
|
||||
}
|
||||
theInspect, err := trie.NewInspector(theTrie, triedb, trieRootHash, blockNumber, jobnum)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
theInspect.Run()
|
||||
theInspect.DisplayResult()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func inspect(ctx *cli.Context) error {
|
||||
var (
|
||||
prefix []byte
|
||||
@@ -432,6 +577,133 @@ func dbGet(ctx *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// dbTrieGet shows the value of a given database key
|
||||
func dbTrieGet(ctx *cli.Context) error {
|
||||
if ctx.NArg() < 1 || ctx.NArg() > 2 {
|
||||
return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
|
||||
}
|
||||
stack, _ := makeConfigNode(ctx)
|
||||
defer stack.Close()
|
||||
|
||||
db := utils.MakeChainDatabase(ctx, stack, false, false)
|
||||
defer db.Close()
|
||||
|
||||
scheme := ctx.String(utils.StateSchemeFlag.Name)
|
||||
if scheme == "" {
|
||||
scheme = rawdb.HashScheme
|
||||
}
|
||||
|
||||
if scheme == rawdb.PathScheme {
|
||||
var (
|
||||
pathKey []byte
|
||||
owner []byte
|
||||
err error
|
||||
)
|
||||
if ctx.NArg() == 1 {
|
||||
pathKey, err = hexutil.Decode(ctx.Args().Get(0))
|
||||
if err != nil {
|
||||
log.Info("Could not decode the value", "error", err)
|
||||
return err
|
||||
}
|
||||
nodeVal, hash := rawdb.ReadAccountTrieNode(db, pathKey)
|
||||
log.Info("TrieGet result ", "PathKey", common.Bytes2Hex(pathKey), "Hash: ", hash, "node: ", trie.NodeString(hash.Bytes(), nodeVal))
|
||||
} else if ctx.NArg() == 2 {
|
||||
owner, err = hexutil.Decode(ctx.Args().Get(0))
|
||||
if err != nil {
|
||||
log.Info("Could not decode the value", "error", err)
|
||||
return err
|
||||
}
|
||||
pathKey, err = hexutil.Decode(ctx.Args().Get(1))
|
||||
if err != nil {
|
||||
log.Info("Could not decode the value", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
nodeVal, hash := rawdb.ReadStorageTrieNode(db, common.BytesToHash(owner), pathKey)
|
||||
log.Info("TrieGet result ", "PathKey: ", common.Bytes2Hex(pathKey), "Owner: ", common.BytesToHash(owner), "Hash: ", hash, "node: ", trie.NodeString(hash.Bytes(), nodeVal))
|
||||
}
|
||||
} else if scheme == rawdb.HashScheme {
|
||||
if ctx.NArg() == 1 {
|
||||
hashKey, err := hexutil.Decode(ctx.Args().Get(0))
|
||||
if err != nil {
|
||||
log.Info("Could not decode the value", "error", err)
|
||||
return err
|
||||
}
|
||||
val, err := db.Get(hashKey)
|
||||
if err != nil {
|
||||
log.Error("db get failed, ", "error: ", err)
|
||||
return err
|
||||
}
|
||||
log.Info("TrieGet result ", "HashKey: ", common.BytesToHash(hashKey), "node: ", trie.NodeString(hashKey, val))
|
||||
} else {
|
||||
log.Error("args too much")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// dbTrieDelete delete the trienode of a given database key
|
||||
func dbTrieDelete(ctx *cli.Context) error {
|
||||
if ctx.NArg() < 1 || ctx.NArg() > 2 {
|
||||
return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
|
||||
}
|
||||
stack, _ := makeConfigNode(ctx)
|
||||
defer stack.Close()
|
||||
|
||||
db := utils.MakeChainDatabase(ctx, stack, false, false)
|
||||
defer db.Close()
|
||||
|
||||
scheme := ctx.String(utils.StateSchemeFlag.Name)
|
||||
if scheme == "" {
|
||||
scheme = rawdb.HashScheme
|
||||
}
|
||||
|
||||
if scheme == rawdb.PathScheme {
|
||||
var (
|
||||
pathKey []byte
|
||||
owner []byte
|
||||
err error
|
||||
)
|
||||
if ctx.NArg() == 1 {
|
||||
pathKey, err = hexutil.Decode(ctx.Args().Get(0))
|
||||
if err != nil {
|
||||
log.Info("Could not decode the value", "error", err)
|
||||
return err
|
||||
}
|
||||
rawdb.DeleteAccountTrieNode(db, pathKey)
|
||||
} else if ctx.NArg() == 2 {
|
||||
owner, err = hexutil.Decode(ctx.Args().Get(0))
|
||||
if err != nil {
|
||||
log.Info("Could not decode the value", "error", err)
|
||||
return err
|
||||
}
|
||||
pathKey, err = hexutil.Decode(ctx.Args().Get(1))
|
||||
if err != nil {
|
||||
log.Info("Could not decode the value", "error", err)
|
||||
return err
|
||||
}
|
||||
rawdb.DeleteStorageTrieNode(db, common.BytesToHash(owner), pathKey)
|
||||
}
|
||||
} else if scheme == rawdb.HashScheme {
|
||||
if ctx.NArg() == 1 {
|
||||
hashKey, err := hexutil.Decode(ctx.Args().Get(0))
|
||||
if err != nil {
|
||||
log.Info("Could not decode the value", "error", err)
|
||||
return err
|
||||
}
|
||||
err = db.Delete(hashKey)
|
||||
if err != nil {
|
||||
log.Error("db delete failed", "err", err)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Error("args too much")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// dbDelete deletes a key from the database
|
||||
func dbDelete(ctx *cli.Context) error {
|
||||
if ctx.NArg() != 1 {
|
||||
@@ -504,6 +776,9 @@ func dbDumpTrie(ctx *cli.Context) error {
|
||||
db := utils.MakeChainDatabase(ctx, stack, true, false)
|
||||
defer db.Close()
|
||||
|
||||
triedb := utils.MakeTrieDatabase(ctx, db, false, true)
|
||||
defer triedb.Close()
|
||||
|
||||
var (
|
||||
state []byte
|
||||
storage []byte
|
||||
@@ -537,7 +812,7 @@ func dbDumpTrie(ctx *cli.Context) error {
|
||||
}
|
||||
}
|
||||
id := trie.StorageTrieID(common.BytesToHash(state), common.BytesToHash(account), common.BytesToHash(storage))
|
||||
theTrie, err := trie.New(id, trie.NewDatabase(db))
|
||||
theTrie, err := trie.New(id, triedb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -739,3 +1014,101 @@ func showMetaData(ctx *cli.Context) error {
|
||||
table.Render()
|
||||
return nil
|
||||
}
|
||||
|
||||
func hbss2pbss(ctx *cli.Context) error {
|
||||
if ctx.NArg() > 1 {
|
||||
return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
|
||||
}
|
||||
|
||||
var jobnum uint64
|
||||
var err error
|
||||
if ctx.NArg() == 1 {
|
||||
jobnum, err = strconv.ParseUint(ctx.Args().Get(0), 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to Parse jobnum, Args[1]: %v, err: %v", ctx.Args().Get(1), err)
|
||||
}
|
||||
} else {
|
||||
// by default
|
||||
jobnum = 1000
|
||||
}
|
||||
|
||||
force := ctx.Bool(utils.ForceFlag.Name)
|
||||
|
||||
stack, _ := makeConfigNode(ctx)
|
||||
defer stack.Close()
|
||||
|
||||
db := utils.MakeChainDatabase(ctx, stack, false, false)
|
||||
db.Sync()
|
||||
defer db.Close()
|
||||
|
||||
// convert hbss trie node to pbss trie node
|
||||
lastStateID := rawdb.ReadPersistentStateID(db)
|
||||
if lastStateID == 0 || force {
|
||||
config := trie.HashDefaults
|
||||
triedb := trie.NewDatabase(db, config)
|
||||
triedb.Cap(0)
|
||||
log.Info("hbss2pbss triedb", "scheme", triedb.Scheme())
|
||||
defer triedb.Close()
|
||||
|
||||
headerHash := rawdb.ReadHeadHeaderHash(db)
|
||||
blockNumber := rawdb.ReadHeaderNumber(db, headerHash)
|
||||
if blockNumber == nil {
|
||||
log.Error("read header number failed.")
|
||||
return fmt.Errorf("read header number failed")
|
||||
}
|
||||
|
||||
log.Info("hbss2pbss converting", "HeaderHash: ", headerHash.String(), ", blockNumber: ", *blockNumber)
|
||||
|
||||
var headerBlockHash common.Hash
|
||||
var trieRootHash common.Hash
|
||||
|
||||
if *blockNumber != math.MaxUint64 {
|
||||
headerBlockHash = rawdb.ReadCanonicalHash(db, *blockNumber)
|
||||
if headerBlockHash == (common.Hash{}) {
|
||||
return fmt.Errorf("ReadHeadBlockHash empty hash")
|
||||
}
|
||||
blockHeader := rawdb.ReadHeader(db, headerBlockHash, *blockNumber)
|
||||
trieRootHash = blockHeader.Root
|
||||
fmt.Println("Canonical Hash: ", headerBlockHash.String(), ", TrieRootHash: ", trieRootHash.String())
|
||||
}
|
||||
if (trieRootHash == common.Hash{}) {
|
||||
log.Error("Empty root hash")
|
||||
return fmt.Errorf("Empty root hash.")
|
||||
}
|
||||
|
||||
id := trie.StateTrieID(trieRootHash)
|
||||
theTrie, err := trie.New(id, triedb)
|
||||
if err != nil {
|
||||
log.Error("fail to new trie tree", "err", err, "rootHash", err, trieRootHash.String())
|
||||
return err
|
||||
}
|
||||
|
||||
h2p, err := trie.NewHbss2Pbss(theTrie, triedb, trieRootHash, *blockNumber, jobnum)
|
||||
if err != nil {
|
||||
log.Error("fail to new hash2pbss", "err", err, "rootHash", err, trieRootHash.String())
|
||||
return err
|
||||
}
|
||||
h2p.Run()
|
||||
} else {
|
||||
log.Info("Convert hbss to pbss success. Nothing to do.")
|
||||
}
|
||||
|
||||
// repair state ancient offset
|
||||
lastStateID = rawdb.ReadPersistentStateID(db)
|
||||
if lastStateID == 0 {
|
||||
log.Error("Convert hbss to pbss trie node error. The last state id is still 0")
|
||||
}
|
||||
ancient := stack.ResolveAncient("chaindata", ctx.String(utils.AncientFlag.Name))
|
||||
err = rawdb.ResetStateFreezerTableOffset(ancient, lastStateID)
|
||||
if err != nil {
|
||||
log.Error("Reset state freezer table offset failed", "error", err)
|
||||
return err
|
||||
}
|
||||
// prune hbss trie node
|
||||
err = rawdb.PruneHashTrieNodeInDataBase(db)
|
||||
if err != nil {
|
||||
log.Error("Prune Hash trie node in database failed", "error", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ func TestCustomGenesis(t *testing.T) {
|
||||
|
||||
// Query the custom genesis block
|
||||
geth := runGeth(t, "--networkid", "1337", "--syncmode=full", "--cache", "16",
|
||||
"--datadir", datadir, "--maxpeers", "0", "--port", "0", "--authrpc.port", "0",
|
||||
"--datadir", datadir, "--maxpeers", "0", "--port", "0",
|
||||
"--nodiscover", "--nat", "none", "--ipcdisable",
|
||||
"--exec", tt.query, "console")
|
||||
geth.ExpectRegexp(tt.result)
|
||||
@@ -141,7 +141,7 @@ func TestCustomBackend(t *testing.T) {
|
||||
}
|
||||
{ // Exec + query
|
||||
args := append(tt.execArgs, "--networkid", "1337", "--syncmode=full", "--cache", "16",
|
||||
"--datadir", datadir, "--maxpeers", "0", "--port", "0", "--authrpc.port", "0",
|
||||
"--datadir", datadir, "--maxpeers", "0", "--port", "0",
|
||||
"--nodiscover", "--nat", "none", "--ipcdisable",
|
||||
"--exec", "eth.getBlock(0).nonce", "console")
|
||||
geth := runGeth(t, args...)
|
||||
@@ -188,7 +188,7 @@ func TestCustomBackend(t *testing.T) {
|
||||
initExpect: `Fatal: Invalid choice for db.engine 'mssql', allowed 'leveldb' or 'pebble'`,
|
||||
// Since the init fails, this will return the (default) mainnet genesis
|
||||
// block nonce
|
||||
execExpect: `0x0000000000000042`,
|
||||
execExpect: `0x0000000000000000`,
|
||||
},
|
||||
} {
|
||||
if err := testfunc(t, tt); err != nil {
|
||||
|
||||
147
cmd/geth/initnetwork_test.go
Normal file
147
cmd/geth/initnetwork_test.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var size int
|
||||
var basePort int
|
||||
var configPath string
|
||||
var genesisPath string
|
||||
|
||||
func setup(t *testing.T) {
|
||||
size = 4
|
||||
_, filename, _, ok := runtime.Caller(0)
|
||||
if !ok {
|
||||
t.Fatalf("error getting current file path")
|
||||
}
|
||||
currentDirectory := filepath.Dir(filename)
|
||||
configPath = filepath.Join(currentDirectory, "testdata/config.toml")
|
||||
genesisPath = filepath.Join(currentDirectory, "testdata/parlia.json")
|
||||
basePort = 30311
|
||||
}
|
||||
|
||||
func TestInitNetworkLocalhost(t *testing.T) {
|
||||
setup(t)
|
||||
ipStr := ""
|
||||
testInitNetwork(t, size, basePort, ipStr, configPath, genesisPath)
|
||||
}
|
||||
|
||||
func TestInitNetworkRemoteHosts(t *testing.T) {
|
||||
setup(t)
|
||||
ipStr := "192.168.24.103,172.15.67.89,10.0.17.36,203.113.45.76"
|
||||
testInitNetwork(t, size, basePort, ipStr, configPath, genesisPath)
|
||||
}
|
||||
|
||||
func testInitNetwork(t *testing.T, size, basePort int, ipStr, configPath, genesisPath string) {
|
||||
dir := t.TempDir()
|
||||
geth := runGeth(t, "init-network", "--init.dir", dir, "--init.size", strconv.Itoa(size),
|
||||
"--init.ips", ipStr, "--init.p2p-port", strconv.Itoa(basePort), "--config", configPath,
|
||||
genesisPath)
|
||||
// expect the command to complete first
|
||||
geth.WaitExit()
|
||||
|
||||
// Read the output of the command
|
||||
files, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(files) != size {
|
||||
t.Fatalf("expected %d node folders but found %d instead", size, len(files))
|
||||
}
|
||||
|
||||
for i, file := range files {
|
||||
if file.IsDir() {
|
||||
expectedNodeDirName := fmt.Sprintf("node%d", i)
|
||||
if file.Name() != expectedNodeDirName {
|
||||
t.Fatalf("node dir name is %s but %s was expected", file.Name(), expectedNodeDirName)
|
||||
}
|
||||
configFilePath := filepath.Join(dir, file.Name(), "config.toml")
|
||||
var config gethConfig
|
||||
err := loadConfig(configFilePath, &config)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to load config.toml : %v", err)
|
||||
}
|
||||
if ipStr == "" {
|
||||
verifyConfigFileLocalhost(t, &config, i, basePort, size)
|
||||
} else {
|
||||
verifyConfigFileRemoteHosts(t, &config, ipStr, i, basePort, size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func verifyConfigFileRemoteHosts(t *testing.T, config *gethConfig, ipStr string, i, basePort, size int) {
|
||||
// 1. check ip string
|
||||
ips := strings.Split(ipStr, ",")
|
||||
if len(ips) != size {
|
||||
t.Fatalf("found %d ips in ipStr=%s instead of %d", len(ips), ipStr, size)
|
||||
}
|
||||
|
||||
// 2. check listening port
|
||||
expectedListenAddr := fmt.Sprintf(":%d", basePort)
|
||||
if config.Node.P2P.ListenAddr != expectedListenAddr {
|
||||
t.Fatalf("expected ListenAddr to be %s but it is %s instead", expectedListenAddr, config.Node.P2P.ListenAddr)
|
||||
}
|
||||
|
||||
bootnodes := config.Node.P2P.BootstrapNodes
|
||||
|
||||
// 3. check correctness of peers' hosts
|
||||
for j := 0; j < i; j++ {
|
||||
ip := bootnodes[j].IP().String()
|
||||
if ip != ips[j] {
|
||||
t.Fatalf("expected IP of bootnode to be %s but found %s instead", ips[j], ip)
|
||||
}
|
||||
}
|
||||
|
||||
for j := i + 1; j < size; j++ {
|
||||
ip := bootnodes[j-1].IP().String()
|
||||
if ip != ips[j] {
|
||||
t.Fatalf("expected IP of bootnode to be %s but found %s instead", ips[j-1], ip)
|
||||
}
|
||||
}
|
||||
|
||||
// 4. check correctness of peer port numbers
|
||||
for j := 0; j < size-1; j++ {
|
||||
if bootnodes[j].UDP() != basePort {
|
||||
t.Fatalf("expected bootnode port at position %d to be %d but got %d instead", j, basePort, bootnodes[j].UDP())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func verifyConfigFileLocalhost(t *testing.T, config *gethConfig, i int, basePort int, size int) {
|
||||
// 1. check listening port
|
||||
expectedListenAddr := fmt.Sprintf(":%d", basePort+i)
|
||||
if config.Node.P2P.ListenAddr != expectedListenAddr {
|
||||
t.Fatalf("expected ListenAddr to be %s but it is %s instead", expectedListenAddr, config.Node.P2P.ListenAddr)
|
||||
}
|
||||
|
||||
bootnodes := config.Node.P2P.BootstrapNodes
|
||||
// 2. check correctness of peers' hosts
|
||||
localhost := "127.0.0.1"
|
||||
for j := 0; j < size-1; j++ {
|
||||
ip := bootnodes[j].IP().String()
|
||||
if ip != localhost {
|
||||
t.Fatalf("expected IP of bootnode to be %s but found %s instead", localhost, ip)
|
||||
}
|
||||
}
|
||||
|
||||
// 3. check correctness of peer port numbers
|
||||
for j := 0; j < i; j++ {
|
||||
if bootnodes[j].UDP() != basePort+j {
|
||||
t.Fatalf("expected bootnode port at position %d to be %d but got %d instead", j, basePort+j, bootnodes[j].UDP())
|
||||
}
|
||||
}
|
||||
for j := i + 1; j < size; j++ {
|
||||
if bootnodes[j-1].UDP() != basePort+j {
|
||||
t.Fatalf("expected bootnode port at position %d to be %d but got %d instead", j-1, basePort+j, bootnodes[j-1].UDP())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,205 +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 (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
type gethrpc struct {
|
||||
name string
|
||||
rpc *rpc.Client
|
||||
geth *testgeth
|
||||
nodeInfo *p2p.NodeInfo
|
||||
}
|
||||
|
||||
func (g *gethrpc) killAndWait() {
|
||||
g.geth.Kill()
|
||||
g.geth.WaitExit()
|
||||
}
|
||||
|
||||
func (g *gethrpc) callRPC(result interface{}, method string, args ...interface{}) {
|
||||
if err := g.rpc.Call(&result, method, args...); err != nil {
|
||||
g.geth.Fatalf("callRPC %v: %v", method, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *gethrpc) addPeer(peer *gethrpc) {
|
||||
g.geth.Logf("%v.addPeer(%v)", g.name, peer.name)
|
||||
enode := peer.getNodeInfo().Enode
|
||||
peerCh := make(chan *p2p.PeerEvent)
|
||||
sub, err := g.rpc.Subscribe(context.Background(), "admin", peerCh, "peerEvents")
|
||||
if err != nil {
|
||||
g.geth.Fatalf("subscribe %v: %v", g.name, err)
|
||||
}
|
||||
defer sub.Unsubscribe()
|
||||
g.callRPC(nil, "admin_addPeer", enode)
|
||||
dur := 14 * time.Second
|
||||
timeout := time.After(dur)
|
||||
select {
|
||||
case ev := <-peerCh:
|
||||
g.geth.Logf("%v received event: type=%v, peer=%v", g.name, ev.Type, ev.Peer)
|
||||
case err := <-sub.Err():
|
||||
g.geth.Fatalf("%v sub error: %v", g.name, err)
|
||||
case <-timeout:
|
||||
g.geth.Error("timeout adding peer after", dur)
|
||||
}
|
||||
}
|
||||
|
||||
// Use this function instead of `g.nodeInfo` directly
|
||||
func (g *gethrpc) getNodeInfo() *p2p.NodeInfo {
|
||||
if g.nodeInfo != nil {
|
||||
return g.nodeInfo
|
||||
}
|
||||
g.nodeInfo = &p2p.NodeInfo{}
|
||||
g.callRPC(&g.nodeInfo, "admin_nodeInfo")
|
||||
return g.nodeInfo
|
||||
}
|
||||
|
||||
// ipcEndpoint resolves an IPC endpoint based on a configured value, taking into
|
||||
// account the set data folders as well as the designated platform we're currently
|
||||
// running on.
|
||||
func ipcEndpoint(ipcPath, datadir string) string {
|
||||
// On windows we can only use plain top-level pipes
|
||||
if runtime.GOOS == "windows" {
|
||||
if strings.HasPrefix(ipcPath, `\\.\pipe\`) {
|
||||
return ipcPath
|
||||
}
|
||||
return `\\.\pipe\` + ipcPath
|
||||
}
|
||||
// Resolve names into the data directory full paths otherwise
|
||||
if filepath.Base(ipcPath) == ipcPath {
|
||||
if datadir == "" {
|
||||
return filepath.Join(os.TempDir(), ipcPath)
|
||||
}
|
||||
return filepath.Join(datadir, ipcPath)
|
||||
}
|
||||
return ipcPath
|
||||
}
|
||||
|
||||
// nextIPC ensures that each ipc pipe gets a unique name.
|
||||
// On linux, it works well to use ipc pipes all over the filesystem (in datadirs),
|
||||
// but windows require pipes to sit in "\\.\pipe\". Therefore, to run several
|
||||
// nodes simultaneously, we need to distinguish between them, which we do by
|
||||
// the pipe filename instead of folder.
|
||||
var nextIPC atomic.Uint32
|
||||
|
||||
func startGethWithIpc(t *testing.T, name string, args ...string) *gethrpc {
|
||||
ipcName := fmt.Sprintf("geth-%d.ipc", nextIPC.Add(1))
|
||||
args = append([]string{"--networkid=42", "--port=0", "--authrpc.port", "0", "--ipcpath", ipcName}, args...)
|
||||
t.Logf("Starting %v with rpc: %v", name, args)
|
||||
|
||||
g := &gethrpc{
|
||||
name: name,
|
||||
geth: runGeth(t, args...),
|
||||
}
|
||||
ipcpath := ipcEndpoint(ipcName, g.geth.Datadir)
|
||||
// We can't know exactly how long geth will take to start, so we try 10
|
||||
// times over a 5 second period.
|
||||
var err error
|
||||
for i := 0; i < 10; i++ {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
if g.rpc, err = rpc.Dial(ipcpath); err == nil {
|
||||
return g
|
||||
}
|
||||
}
|
||||
t.Fatalf("%v rpc connect to %v: %v", name, ipcpath, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
func initGeth(t *testing.T) string {
|
||||
args := []string{"--networkid=42", "init", "./testdata/clique.json"}
|
||||
t.Logf("Initializing geth: %v ", args)
|
||||
g := runGeth(t, args...)
|
||||
datadir := g.Datadir
|
||||
g.WaitExit()
|
||||
return datadir
|
||||
}
|
||||
|
||||
func startLightServer(t *testing.T) *gethrpc {
|
||||
datadir := initGeth(t)
|
||||
t.Logf("Importing keys to geth")
|
||||
runGeth(t, "account", "import", "--datadir", datadir, "--password", "./testdata/password.txt", "--lightkdf", "./testdata/key.prv").WaitExit()
|
||||
account := "0x02f0d131f1f97aef08aec6e3291b957d9efe7105"
|
||||
server := startGethWithIpc(t, "lightserver", "--allow-insecure-unlock", "--datadir", datadir, "--password", "./testdata/password.txt", "--unlock", account, "--miner.etherbase=0x02f0d131f1f97aef08aec6e3291b957d9efe7105", "--mine", "--light.serve=100", "--light.maxpeers=1", "--discv4=false", "--nat=extip:127.0.0.1", "--verbosity=4")
|
||||
return server
|
||||
}
|
||||
|
||||
func startClient(t *testing.T, name string) *gethrpc {
|
||||
datadir := initGeth(t)
|
||||
return startGethWithIpc(t, name, "--datadir", datadir, "--discv4=false", "--syncmode=light", "--nat=extip:127.0.0.1", "--verbosity=4")
|
||||
}
|
||||
|
||||
func TestPriorityClient(t *testing.T) {
|
||||
lightServer := startLightServer(t)
|
||||
defer lightServer.killAndWait()
|
||||
|
||||
// Start client and add lightServer as peer
|
||||
freeCli := startClient(t, "freeCli")
|
||||
defer freeCli.killAndWait()
|
||||
freeCli.addPeer(lightServer)
|
||||
|
||||
var peers []*p2p.PeerInfo
|
||||
freeCli.callRPC(&peers, "admin_peers")
|
||||
if len(peers) != 1 {
|
||||
t.Errorf("Expected: # of client peers == 1, actual: %v", len(peers))
|
||||
return
|
||||
}
|
||||
|
||||
// Set up priority client, get its nodeID, increase its balance on the lightServer
|
||||
prioCli := startClient(t, "prioCli")
|
||||
defer prioCli.killAndWait()
|
||||
// 3_000_000_000 once we move to Go 1.13
|
||||
tokens := uint64(3000000000)
|
||||
lightServer.callRPC(nil, "les_addBalance", prioCli.getNodeInfo().ID, tokens)
|
||||
prioCli.addPeer(lightServer)
|
||||
|
||||
// Check if priority client is actually syncing and the regular client got kicked out
|
||||
prioCli.callRPC(&peers, "admin_peers")
|
||||
if len(peers) != 1 {
|
||||
t.Errorf("Expected: # of prio peers == 1, actual: %v", len(peers))
|
||||
}
|
||||
|
||||
nodes := map[string]*gethrpc{
|
||||
lightServer.getNodeInfo().ID: lightServer,
|
||||
freeCli.getNodeInfo().ID: freeCli,
|
||||
prioCli.getNodeInfo().ID: prioCli,
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
lightServer.callRPC(&peers, "admin_peers")
|
||||
peersWithNames := make(map[string]string)
|
||||
for _, p := range peers {
|
||||
peersWithNames[nodes[p.ID].name] = p.ID
|
||||
}
|
||||
if _, freeClientFound := peersWithNames[freeCli.name]; freeClientFound {
|
||||
t.Error("client is still a peer of lightServer", peersWithNames)
|
||||
}
|
||||
if _, prioClientFound := peersWithNames[prioCli.name]; !prioClientFound {
|
||||
t.Error("prio client is not among lightServer peers", peersWithNames)
|
||||
}
|
||||
}
|
||||
@@ -61,7 +61,7 @@ var (
|
||||
utils.MinFreeDiskSpaceFlag,
|
||||
utils.KeyStoreDirFlag,
|
||||
utils.ExternalSignerFlag,
|
||||
utils.NoUSBFlag,
|
||||
utils.NoUSBFlag, // deprecated
|
||||
utils.DirectBroadcastFlag,
|
||||
utils.DisableSnapProtocolFlag,
|
||||
utils.EnableTrustProtocolFlag,
|
||||
@@ -69,8 +69,12 @@ var (
|
||||
utils.RangeLimitFlag,
|
||||
utils.USBFlag,
|
||||
utils.SmartCardDaemonPathFlag,
|
||||
utils.RialtoHash,
|
||||
utils.OverrideShanghai,
|
||||
utils.OverrideKepler,
|
||||
utils.OverrideCancun,
|
||||
utils.OverrideVerkle,
|
||||
utils.OverrideFeynman,
|
||||
utils.EnablePersonal,
|
||||
utils.TxPoolLocalsFlag,
|
||||
utils.TxPoolNoLocalsFlag,
|
||||
@@ -93,25 +97,30 @@ var (
|
||||
utils.ExitWhenSyncedFlag,
|
||||
utils.GCModeFlag,
|
||||
utils.SnapshotFlag,
|
||||
utils.TxLookupLimitFlag,
|
||||
utils.LightServeFlag,
|
||||
utils.LightIngressFlag,
|
||||
utils.LightEgressFlag,
|
||||
utils.LightMaxPeersFlag,
|
||||
utils.LightNoPruneFlag,
|
||||
utils.LightKDFFlag,
|
||||
utils.LightNoSyncServeFlag,
|
||||
utils.TxLookupLimitFlag, // deprecated
|
||||
utils.TransactionHistoryFlag,
|
||||
utils.StateSchemeFlag,
|
||||
utils.StateHistoryFlag,
|
||||
utils.PathDBSyncFlag,
|
||||
utils.LightServeFlag, // deprecated
|
||||
utils.LightIngressFlag, // deprecated
|
||||
utils.LightEgressFlag, // deprecated
|
||||
utils.LightMaxPeersFlag, // deprecated
|
||||
utils.LightNoPruneFlag, // deprecated
|
||||
utils.LightKDFFlag, // deprecated
|
||||
utils.LightNoSyncServeFlag, // deprecated
|
||||
utils.EthRequiredBlocksFlag,
|
||||
utils.LegacyWhitelistFlag,
|
||||
utils.LegacyWhitelistFlag, // deprecated
|
||||
utils.BloomFilterSizeFlag,
|
||||
utils.TriesInMemoryFlag,
|
||||
utils.CacheFlag,
|
||||
utils.CacheDatabaseFlag,
|
||||
utils.CacheTrieFlag,
|
||||
utils.CacheTrieJournalFlag,
|
||||
utils.CacheTrieRejournalFlag,
|
||||
utils.CacheTrieJournalFlag, // deprecated
|
||||
utils.CacheTrieRejournalFlag, // deprecated
|
||||
utils.CacheGCFlag,
|
||||
utils.CacheSnapshotFlag,
|
||||
// utils.CacheNoPrefetchFlag,
|
||||
utils.CachePreimagesFlag,
|
||||
utils.PersistDiffFlag,
|
||||
utils.DiffBlockFlag,
|
||||
@@ -131,12 +140,12 @@ var (
|
||||
utils.MinerExtraDataFlag,
|
||||
utils.MinerRecommitIntervalFlag,
|
||||
utils.MinerDelayLeftoverFlag,
|
||||
utils.MinerNewPayloadTimeout,
|
||||
// utils.MinerNewPayloadTimeout,
|
||||
utils.NATFlag,
|
||||
utils.NoDiscoverFlag,
|
||||
utils.DiscoveryV4Flag,
|
||||
utils.DiscoveryV5Flag,
|
||||
utils.LegacyDiscoveryV5Flag,
|
||||
utils.LegacyDiscoveryV5Flag, // deprecated
|
||||
utils.NetrestrictFlag,
|
||||
utils.NodeKeyFileFlag,
|
||||
utils.NodeKeyHexFlag,
|
||||
@@ -169,10 +178,10 @@ var (
|
||||
utils.HTTPListenAddrFlag,
|
||||
utils.HTTPPortFlag,
|
||||
utils.HTTPCORSDomainFlag,
|
||||
utils.AuthListenFlag,
|
||||
utils.AuthPortFlag,
|
||||
utils.AuthVirtualHostsFlag,
|
||||
utils.JWTSecretFlag,
|
||||
// utils.AuthListenFlag,
|
||||
// utils.AuthPortFlag,
|
||||
// utils.AuthVirtualHostsFlag,
|
||||
// utils.JWTSecretFlag,
|
||||
utils.HTTPVirtualHostsFlag,
|
||||
utils.GraphQLEnabledFlag,
|
||||
utils.GraphQLCORSDomainFlag,
|
||||
@@ -231,6 +240,7 @@ func init() {
|
||||
removedbCommand,
|
||||
dumpCommand,
|
||||
dumpGenesisCommand,
|
||||
dumpRootHashCommand,
|
||||
// See accountcmd.go:
|
||||
accountCommand,
|
||||
walletCommand,
|
||||
@@ -288,6 +298,9 @@ func main() {
|
||||
func prepare(ctx *cli.Context) {
|
||||
// If we're running a known preset, log it for convenience.
|
||||
switch {
|
||||
case ctx.IsSet(utils.ChapelFlag.Name):
|
||||
log.Info("Starting BSC on Chapel testnet...")
|
||||
|
||||
case ctx.IsSet(utils.DeveloperFlag.Name):
|
||||
log.Info("Starting Geth in ephemeral dev mode...")
|
||||
log.Warn(`You are running Geth in --dev mode. Please note the following:
|
||||
@@ -307,22 +320,18 @@ func prepare(ctx *cli.Context) {
|
||||
`)
|
||||
|
||||
case !ctx.IsSet(utils.NetworkIdFlag.Name):
|
||||
log.Info("Starting Geth on Ethereum mainnet...")
|
||||
log.Info("Starting Geth on BSC mainnet...")
|
||||
}
|
||||
// If we're a full node on mainnet without --cache specified, bump default cache allowance
|
||||
if ctx.String(utils.SyncModeFlag.Name) != "light" && !ctx.IsSet(utils.CacheFlag.Name) && !ctx.IsSet(utils.NetworkIdFlag.Name) {
|
||||
if !ctx.IsSet(utils.CacheFlag.Name) && !ctx.IsSet(utils.NetworkIdFlag.Name) {
|
||||
// Make sure we're not on any supported preconfigured testnet either
|
||||
if !ctx.IsSet(utils.DeveloperFlag.Name) {
|
||||
if !ctx.IsSet(utils.DeveloperFlag.Name) &&
|
||||
!ctx.IsSet(utils.ChapelFlag.Name) {
|
||||
// Nope, we're really on mainnet. Bump that cache up!
|
||||
log.Info("Bumping default cache on mainnet", "provided", ctx.Int(utils.CacheFlag.Name), "updated", 4096)
|
||||
ctx.Set(utils.CacheFlag.Name, strconv.Itoa(4096))
|
||||
}
|
||||
}
|
||||
// If we're running a light client on any network, drop the cache to some meaningfully low amount
|
||||
if ctx.String(utils.SyncModeFlag.Name) == "light" && !ctx.IsSet(utils.CacheFlag.Name) {
|
||||
log.Info("Dropping default light client cache", "provided", ctx.Int(utils.CacheFlag.Name), "updated", 128)
|
||||
ctx.Set(utils.CacheFlag.Name, strconv.Itoa(128))
|
||||
}
|
||||
}
|
||||
|
||||
// geth is the main entry point into the system if no special subcommand is run.
|
||||
|
||||
@@ -41,6 +41,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -136,7 +137,11 @@ func BlockchainCreator(t *testing.T, chaindbPath, AncientPath string, blockRemai
|
||||
t.Fatalf("failed to create database with ancient backend")
|
||||
}
|
||||
defer db.Close()
|
||||
genesis := gspec.MustCommit(db)
|
||||
|
||||
triedb := trie.NewDatabase(db, nil)
|
||||
defer triedb.Close()
|
||||
|
||||
genesis := gspec.MustCommit(db, triedb)
|
||||
// Initialize a fresh chain with only a genesis block
|
||||
blockchain, err := core.NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
|
||||
@@ -55,6 +55,15 @@ func TestMain(m *testing.M) {
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func initGeth(t *testing.T) string {
|
||||
args := []string{"--networkid=42", "init", "./testdata/clique.json"}
|
||||
t.Logf("Initializing geth: %v ", args)
|
||||
g := runGeth(t, args...)
|
||||
datadir := g.Datadir
|
||||
g.WaitExit()
|
||||
return datadir
|
||||
}
|
||||
|
||||
// spawns geth with the given command line args. If the args don't set --datadir, the
|
||||
// child g gets a temporary data directory.
|
||||
func runGeth(t *testing.T, args ...string) *testgeth {
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/tsdb/fileutil"
|
||||
@@ -71,10 +72,7 @@ two version states are available: genesis and the specific one.
|
||||
|
||||
The default pruning target is the HEAD-127 state.
|
||||
|
||||
WARNING: It's necessary to delete the trie clean cache after the pruning.
|
||||
If you specify another directory for the trie clean cache via "--cache.trie.journal"
|
||||
during the use of Geth, please also specify it here for correct deletion. Otherwise
|
||||
the trie clean cache with default directory will be deleted.
|
||||
WARNING: it's only supported in hash mode(--state.scheme=hash)".
|
||||
`,
|
||||
},
|
||||
{
|
||||
@@ -106,7 +104,9 @@ so it's very necessary to do block data prune, this feature will handle it.
|
||||
Usage: "Recalculate state hash based on the snapshot for verification",
|
||||
ArgsUsage: "<root>",
|
||||
Action: verifyState,
|
||||
Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags),
|
||||
Flags: flags.Merge([]cli.Flag{
|
||||
utils.StateSchemeFlag,
|
||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
||||
Description: `
|
||||
geth snapshot verify-state <state-root>
|
||||
will traverse the whole accounts and storages set based on the specified
|
||||
@@ -164,7 +164,9 @@ information about the specified address.
|
||||
Usage: "Traverse the state with given root hash and perform quick verification",
|
||||
ArgsUsage: "<root>",
|
||||
Action: traverseState,
|
||||
Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags),
|
||||
Flags: flags.Merge([]cli.Flag{
|
||||
utils.StateSchemeFlag,
|
||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
||||
Description: `
|
||||
geth snapshot traverse-state <state-root>
|
||||
will traverse the whole state from the given state root and will abort if any
|
||||
@@ -179,7 +181,9 @@ It's also usable without snapshot enabled.
|
||||
Usage: "Traverse the state with given root hash and perform detailed verification",
|
||||
ArgsUsage: "<root>",
|
||||
Action: traverseRawState,
|
||||
Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags),
|
||||
Flags: flags.Merge([]cli.Flag{
|
||||
utils.StateSchemeFlag,
|
||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
||||
Description: `
|
||||
geth snapshot traverse-rawstate <state-root>
|
||||
will traverse the whole state from the given root and will abort if any referenced
|
||||
@@ -201,6 +205,7 @@ It's also usable without snapshot enabled.
|
||||
utils.StartKeyFlag,
|
||||
utils.DumpLimitFlag,
|
||||
utils.TriesInMemoryFlag,
|
||||
utils.StateSchemeFlag,
|
||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
||||
Description: `
|
||||
This command is semantically equivalent to 'geth dump', but uses the snapshots
|
||||
@@ -235,7 +240,7 @@ func accessDb(ctx *cli.Context, stack *node.Node) (ethdb.Database, error) {
|
||||
NoBuild: true,
|
||||
AsyncBuild: false,
|
||||
}
|
||||
snaptree, err := snapshot.New(snapconfig, chaindb, trie.NewDatabase(chaindb), headBlock.Root(), TriesInMemory, false)
|
||||
snaptree, err := snapshot.New(snapconfig, chaindb, trie.NewDatabase(chaindb, nil), headBlock.Root(), TriesInMemory, false)
|
||||
if err != nil {
|
||||
log.Error("snaptree error", "err", err)
|
||||
return nil, err // The relevant snapshot(s) might not exist
|
||||
@@ -356,7 +361,21 @@ func pruneBlock(ctx *cli.Context) error {
|
||||
if path == "" {
|
||||
return errors.New("prune failed, did not specify the AncientPath")
|
||||
}
|
||||
newAncientPath = filepath.Join(path, "ancient_back")
|
||||
newVersionPath := false
|
||||
files, err := os.ReadDir(oldAncientPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, file := range files {
|
||||
if file.IsDir() && file.Name() == "chain" {
|
||||
newVersionPath = true
|
||||
}
|
||||
}
|
||||
if newVersionPath && !strings.HasSuffix(oldAncientPath, "geth/chaindata/ancient/chain") {
|
||||
log.Error("datadir.ancient subdirectory incorrect", "got path", oldAncientPath, "want subdirectory", "geth/chaindata/ancient/chain/")
|
||||
return errors.New("datadir.ancient subdirectory incorrect")
|
||||
}
|
||||
newAncientPath = filepath.Join(path, "chain_back")
|
||||
|
||||
blockpruner = pruner.NewBlockPruner(chaindb, stack, oldAncientPath, newAncientPath, blockAmountReserved)
|
||||
|
||||
@@ -413,6 +432,9 @@ func pruneState(ctx *cli.Context) error {
|
||||
chaindb := utils.MakeChainDatabase(ctx, stack, false, false)
|
||||
defer chaindb.Close()
|
||||
|
||||
if rawdb.ReadStateScheme(chaindb) != rawdb.HashScheme {
|
||||
log.Crit("Offline pruning is not required for path scheme")
|
||||
}
|
||||
prunerconfig := pruner.Config{
|
||||
Datadir: stack.ResolvePath(""),
|
||||
BloomSize: ctx.Uint64(utils.BloomFilterSizeFlag.Name),
|
||||
@@ -471,6 +493,7 @@ func pruneAllState(ctx *cli.Context) error {
|
||||
}
|
||||
|
||||
chaindb := utils.MakeChainDatabase(ctx, stack, false, false)
|
||||
defer chaindb.Close()
|
||||
pruner, err := pruner.NewAllPruner(chaindb)
|
||||
if err != nil {
|
||||
log.Error("Failed to open snapshot tree", "err", err)
|
||||
@@ -488,18 +511,22 @@ func verifyState(ctx *cli.Context) error {
|
||||
defer stack.Close()
|
||||
|
||||
chaindb := utils.MakeChainDatabase(ctx, stack, true, false)
|
||||
defer chaindb.Close()
|
||||
headBlock := rawdb.ReadHeadBlock(chaindb)
|
||||
if headBlock == nil {
|
||||
log.Error("Failed to load head block")
|
||||
return errors.New("no head block")
|
||||
}
|
||||
snapconfig := snapshot.Config{
|
||||
triedb := utils.MakeTrieDatabase(ctx, chaindb, false, true)
|
||||
defer triedb.Close()
|
||||
|
||||
snapConfig := snapshot.Config{
|
||||
CacheSize: 256,
|
||||
Recovery: false,
|
||||
NoBuild: true,
|
||||
AsyncBuild: false,
|
||||
}
|
||||
snaptree, err := snapshot.New(snapconfig, chaindb, trie.NewDatabase(chaindb), headBlock.Root(), 128, false)
|
||||
snaptree, err := snapshot.New(snapConfig, chaindb, triedb, headBlock.Root(), 128, false)
|
||||
if err != nil {
|
||||
log.Error("Failed to open snapshot tree", "err", err)
|
||||
return err
|
||||
@@ -541,6 +568,11 @@ func traverseState(ctx *cli.Context) error {
|
||||
defer stack.Close()
|
||||
|
||||
chaindb := utils.MakeChainDatabase(ctx, stack, true, false)
|
||||
defer chaindb.Close()
|
||||
|
||||
triedb := utils.MakeTrieDatabase(ctx, chaindb, false, true)
|
||||
defer triedb.Close()
|
||||
|
||||
headBlock := rawdb.ReadHeadBlock(chaindb)
|
||||
if headBlock == nil {
|
||||
log.Error("Failed to load head block")
|
||||
@@ -565,7 +597,6 @@ func traverseState(ctx *cli.Context) error {
|
||||
root = headBlock.Root()
|
||||
log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64())
|
||||
}
|
||||
triedb := trie.NewDatabase(chaindb)
|
||||
t, err := trie.NewStateTrie(trie.StateTrieID(root), triedb)
|
||||
if err != nil {
|
||||
log.Error("Failed to open trie", "root", root, "err", err)
|
||||
@@ -641,6 +672,11 @@ func traverseRawState(ctx *cli.Context) error {
|
||||
defer stack.Close()
|
||||
|
||||
chaindb := utils.MakeChainDatabase(ctx, stack, true, false)
|
||||
defer chaindb.Close()
|
||||
|
||||
triedb := utils.MakeTrieDatabase(ctx, chaindb, false, true)
|
||||
defer triedb.Close()
|
||||
|
||||
headBlock := rawdb.ReadHeadBlock(chaindb)
|
||||
if headBlock == nil {
|
||||
log.Error("Failed to load head block")
|
||||
@@ -665,7 +701,6 @@ func traverseRawState(ctx *cli.Context) error {
|
||||
root = headBlock.Root()
|
||||
log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64())
|
||||
}
|
||||
triedb := trie.NewDatabase(chaindb)
|
||||
t, err := trie.NewStateTrie(trie.StateTrieID(root), triedb)
|
||||
if err != nil {
|
||||
log.Error("Failed to open trie", "root", root, "err", err)
|
||||
@@ -686,6 +721,11 @@ func traverseRawState(ctx *cli.Context) error {
|
||||
log.Error("Failed to open iterator", "root", root, "err", err)
|
||||
return err
|
||||
}
|
||||
reader, err := triedb.Reader(root)
|
||||
if err != nil {
|
||||
log.Error("State is non-existent", "root", root)
|
||||
return nil
|
||||
}
|
||||
for accIter.Next(true) {
|
||||
nodes += 1
|
||||
node := accIter.Hash()
|
||||
@@ -693,7 +733,7 @@ func traverseRawState(ctx *cli.Context) error {
|
||||
// Check the present for non-empty hash node(embedded node doesn't
|
||||
// have their own hash).
|
||||
if node != (common.Hash{}) {
|
||||
blob := rawdb.ReadLegacyTrieNode(chaindb, node)
|
||||
blob, _ := reader.Node(common.Hash{}, accIter.Path(), node)
|
||||
if len(blob) == 0 {
|
||||
log.Error("Missing trie node(account)", "hash", node)
|
||||
return errors.New("missing account")
|
||||
@@ -734,7 +774,7 @@ func traverseRawState(ctx *cli.Context) error {
|
||||
// Check the presence for non-empty hash node(embedded node doesn't
|
||||
// have their own hash).
|
||||
if node != (common.Hash{}) {
|
||||
blob := rawdb.ReadLegacyTrieNode(chaindb, node)
|
||||
blob, _ := reader.Node(common.BytesToHash(accIter.LeafKey()), storageIter.Path(), node)
|
||||
if len(blob) == 0 {
|
||||
log.Error("Missing trie node(storage)", "hash", node)
|
||||
return errors.New("missing storage")
|
||||
@@ -794,6 +834,9 @@ func dumpState(ctx *cli.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
triedb := utils.MakeTrieDatabase(ctx, db, false, true)
|
||||
defer triedb.Close()
|
||||
|
||||
snapConfig := snapshot.Config{
|
||||
CacheSize: 256,
|
||||
Recovery: false,
|
||||
@@ -801,7 +844,7 @@ func dumpState(ctx *cli.Context) error {
|
||||
AsyncBuild: false,
|
||||
}
|
||||
triesInMemory := ctx.Uint64(utils.TriesInMemoryFlag.Name)
|
||||
snaptree, err := snapshot.New(snapConfig, db, trie.NewDatabase(db), root, int(triesInMemory), false)
|
||||
snaptree, err := snapshot.New(snapConfig, db, trie.NewDatabase(db, nil), root, int(triesInMemory), false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
33
cmd/geth/testdata/bls-account-usage-demo.sh
vendored
Normal file
33
cmd/geth/testdata/bls-account-usage-demo.sh
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo "0. prepare---------------------------------------------------------------------------------"
|
||||
echo 123abc7890 > bls-password.txt
|
||||
echo 123abc7891 > bls-password1.txt
|
||||
basedir=$(cd `dirname $0`; pwd)
|
||||
workspace=${basedir}/../../../
|
||||
|
||||
echo "1. create a bls account--------------------------------------------------------------------"
|
||||
${workspace}/build/bin/geth bls account new --blspassword ./bls-password.txt --datadir ./bls
|
||||
${workspace}/build/bin/geth bls account list --blspassword ./bls-password.txt --datadir ./bls
|
||||
|
||||
echo "2. import a bls account by passing file including a private key-----------------------------"
|
||||
secretKey=`${workspace}/build/bin/geth bls account new --show-private-key --blspassword ./bls-password1.txt --datadir ./bls1 | grep private | awk '{print $NF}'`
|
||||
echo ${secretKey} > ./bls1/secretKey
|
||||
${workspace}/build/bin/geth bls account import --blspassword ./bls-password.txt --datadir ./bls ./bls1/secretKey
|
||||
${workspace}/build/bin/geth bls account list --blspassword ./bls-password.txt --datadir ./bls
|
||||
|
||||
echo "3. delete the imported account above--------------------------------------------------------"
|
||||
publicKey=`${workspace}/build/bin/geth bls account list --blspassword ./bls-password.txt --datadir ./bls |grep public | tail -1 | awk '{print $NF}'`
|
||||
${workspace}/build/bin/geth bls account delete --blspassword ./bls-password.txt --datadir ./bls ${publicKey}
|
||||
${workspace}/build/bin/geth bls account list --blspassword ./bls-password.txt --datadir ./bls
|
||||
|
||||
echo "4. import a bls account by passing a keystore file------------------------------------------"
|
||||
keystoreFile=`ls bls1/bls/keystore`
|
||||
${workspace}/build/bin/geth bls account import --importedaccountpassword ./bls-password1.txt --blspassword ./bls-password.txt --datadir ./bls ./bls1/bls/keystore/${keystoreFile}
|
||||
${workspace}/build/bin/geth bls account list --blspassword ./bls-password.txt --datadir ./bls
|
||||
|
||||
echo "5. clearup----------------------------------------------------------------------------------"
|
||||
rm -rf bls
|
||||
rm -rf bls1
|
||||
rm -rf bls-password.txt
|
||||
rm -rf bls-password1.txt
|
||||
62
cmd/geth/testdata/config.toml
vendored
Normal file
62
cmd/geth/testdata/config.toml
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
[Eth]
|
||||
NetworkId = 714
|
||||
SyncMode = "full"
|
||||
NoPruning = false
|
||||
NoPrefetch = false
|
||||
LightPeers = 100
|
||||
DatabaseCache = 512
|
||||
DatabaseFreezer = ""
|
||||
TrieCleanCache = 256
|
||||
TrieDirtyCache = 256
|
||||
TriesInMemory = 128
|
||||
TrieTimeout = 3600000000000
|
||||
EnablePreimageRecording = false
|
||||
|
||||
[Eth.Miner]
|
||||
GasFloor = 30000000
|
||||
GasCeil = 40000000
|
||||
GasPrice = 10000000000
|
||||
Recommit = 10000000000
|
||||
|
||||
[Eth.TxPool]
|
||||
Locals = []
|
||||
NoLocals = true
|
||||
Journal = "transactions.rlp"
|
||||
Rejournal = 3600000000000
|
||||
PriceLimit = 10000000000
|
||||
PriceBump = 10
|
||||
AccountSlots = 16
|
||||
GlobalSlots = 4096
|
||||
AccountQueue = 64
|
||||
GlobalQueue = 1024
|
||||
Lifetime = 10800000000000
|
||||
|
||||
|
||||
[Node]
|
||||
IPCPath = "geth.ipc"
|
||||
HTTPHost = "0.0.0.0"
|
||||
NoUSB = true
|
||||
InsecureUnlockAllowed = true
|
||||
HTTPPort = 8545
|
||||
HTTPVirtualHosts = ["*"]
|
||||
HTTPModules = ["eth", "net", "web3", "txpool", "parlia"]
|
||||
WSHost = "0.0.0.0"
|
||||
WSPort = 8545
|
||||
|
||||
[Node.P2P]
|
||||
MaxPeers = 50
|
||||
NoDiscovery = false
|
||||
StaticNodes = []
|
||||
TrustedNodes = []
|
||||
EnableMsgEvents = false
|
||||
|
||||
[Node.HTTPTimeouts]
|
||||
ReadTimeout = 30000000000
|
||||
WriteTimeout = 30000000000
|
||||
IdleTimeout = 120000000000
|
||||
|
||||
[Node.LogConfig]
|
||||
FilePath = "bsc.log"
|
||||
MaxBytesSize = 10485760
|
||||
Level = "info"
|
||||
FileRoot = ""
|
||||
33
cmd/geth/testdata/parlia.json
vendored
Normal file
33
cmd/geth/testdata/parlia.json
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"config": {
|
||||
"chainId": 714,
|
||||
"homesteadBlock": 0,
|
||||
"eip150Block": 0,
|
||||
"eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"eip155Block": 0,
|
||||
"eip158Block": 0,
|
||||
"byzantiumBlock": 0,
|
||||
"constantinopleBlock": 0,
|
||||
"petersburgBlock": 0,
|
||||
"istanbulBlock": 0,
|
||||
"muirGlacierBlock": 0,
|
||||
"ramanujanBlock": 0,
|
||||
"nielsBlock": 0,
|
||||
"mirrorSyncBlock":1,
|
||||
"brunoBlock": 1,
|
||||
"eulerBlock": 2,
|
||||
"gibbsBlock": 3,
|
||||
"parlia": {
|
||||
"period": 3,
|
||||
"epoch": 200
|
||||
}
|
||||
},
|
||||
"nonce": "0x0",
|
||||
"timestamp": "0x5e9da7ce",
|
||||
"extraData": "0x00000000000000000000000000000000000000000000000000000000000000009fb29aac15b9a4b7f17c3385939b007540f4d7910000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"gasLimit": "0x2625a00",
|
||||
"difficulty": "0x1",
|
||||
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"coinbase": "0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE",
|
||||
"alloc": {}
|
||||
}
|
||||
25
cmd/jsutils/README.md
Normal file
25
cmd/jsutils/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
## Requirement
|
||||
|
||||
- nodejs >= v16.20.2
|
||||
- npm >= v8.19.4
|
||||
|
||||
## Prepare
|
||||
Recommend use [nvm](https://github.com/nvm-sh/nvm) to manage node version.
|
||||
|
||||
Install node.js dependency:
|
||||
```shell script
|
||||
npm install
|
||||
```
|
||||
## Run
|
||||
mainnet validators version
|
||||
```bash
|
||||
npm run startMainnet
|
||||
```
|
||||
testnet validators version
|
||||
```bash
|
||||
npm run startTestnet
|
||||
```
|
||||
Transaction count
|
||||
```bash
|
||||
node gettxcount.js --rpc ${url} --startNum ${start} --endNum ${end} --miner ${miner} (optional)
|
||||
```
|
||||
38
cmd/jsutils/gettxcount.js
Normal file
38
cmd/jsutils/gettxcount.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import { ethers } from "ethers";
|
||||
import program from "commander";
|
||||
|
||||
program.option("--rpc <rpc>", "Rpc");
|
||||
program.option("--startNum <startNum>", "start num")
|
||||
program.option("--endNum <endNum>", "end num")
|
||||
program.option("--miner <miner>", "miner", "")
|
||||
program.parse(process.argv);
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(program.rpc)
|
||||
|
||||
const main = async () => {
|
||||
let txCount = 0;
|
||||
let num = 0;
|
||||
console.log("Find the max txs count between", program.startNum, "and", program.endNum);
|
||||
for (let i = program.startNum; i < program.endNum; i++) {
|
||||
if (program.miner !== "") {
|
||||
let blockData = await provider.getBlock(Number(i))
|
||||
if (program.miner !== blockData.miner) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
let x = await provider.send("eth_getBlockTransactionCountByNumber", [
|
||||
ethers.toQuantity(i)]);
|
||||
let a = ethers.toNumber(x)
|
||||
if (a > txCount) {
|
||||
num = i;
|
||||
txCount = a;
|
||||
}
|
||||
}
|
||||
console.log("BlockNum = ", num, "TxCount =", txCount);
|
||||
};
|
||||
|
||||
main().then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
25
cmd/jsutils/getvalidatorversion.js
Normal file
25
cmd/jsutils/getvalidatorversion.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import { ethers } from "ethers";
|
||||
import program from "commander";
|
||||
|
||||
program.option("--Rpc <Rpc>", "Rpc");
|
||||
program.option("--Num <Num>", "validator num", 21)
|
||||
program.parse(process.argv);
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(program.Rpc);
|
||||
|
||||
const main = async () => {
|
||||
const blockNum = await provider.getBlockNumber();
|
||||
console.log(blockNum);
|
||||
for (let i = 0; i < program.Num; i++) {
|
||||
let blockData = await provider.getBlock(blockNum - i);
|
||||
let major = ethers.toNumber(ethers.dataSlice(blockData.extraData, 2, 3))
|
||||
let minor = ethers.toNumber(ethers.dataSlice(blockData.extraData, 3, 4))
|
||||
let patch = ethers.toNumber(ethers.dataSlice(blockData.extraData, 4, 5))
|
||||
console.log(blockData.miner, "version =", major + "." + minor + "." + patch)
|
||||
}
|
||||
};
|
||||
main().then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
16
cmd/jsutils/package.json
Normal file
16
cmd/jsutils/package.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "jsutils",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"description": "jsUtils for bsc",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"startMainnet": "node getvalidatorversion.js --Rpc https://bsc-dataseed.bnbchain.org --Num 21",
|
||||
"startTestnet": "node getvalidatorversion.js --Rpc https://bsc-testnet-dataseed.bnbchain.org --Num 7"
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": "^3.0.1",
|
||||
"ethers": "^6.2.3"
|
||||
},
|
||||
"author": "BNB Chain"
|
||||
}
|
||||
@@ -62,7 +62,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/graphql"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/internal/flags"
|
||||
"github.com/ethereum/go-ethereum/les"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/metrics/exp"
|
||||
@@ -75,6 +74,9 @@ import (
|
||||
"github.com/ethereum/go-ethereum/p2p/netutil"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/ethereum/go-ethereum/trie/triedb/hashdb"
|
||||
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
|
||||
)
|
||||
|
||||
// These are all the command line flags we support.
|
||||
@@ -93,28 +95,34 @@ var (
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
DirectBroadcastFlag = &cli.BoolFlag{
|
||||
Name: "directbroadcast",
|
||||
Usage: "Enable directly broadcast mined block to all peers",
|
||||
Name: "directbroadcast",
|
||||
Usage: "Enable directly broadcast mined block to all peers",
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
DisableSnapProtocolFlag = &cli.BoolFlag{
|
||||
Name: "disablesnapprotocol",
|
||||
Usage: "Disable snap protocol",
|
||||
Name: "disablesnapprotocol",
|
||||
Usage: "Disable snap protocol",
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
EnableTrustProtocolFlag = &cli.BoolFlag{
|
||||
Name: "enabletrustprotocol",
|
||||
Usage: "Enable trust protocol",
|
||||
Name: "enabletrustprotocol",
|
||||
Usage: "Enable trust protocol",
|
||||
Category: flags.FastNodeCategory,
|
||||
}
|
||||
PipeCommitFlag = &cli.BoolFlag{
|
||||
Name: "pipecommit",
|
||||
Usage: "Enable MPT pipeline commit, it will improve syncing performance. It is an experimental feature(default is false)",
|
||||
Name: "pipecommit",
|
||||
Usage: "Enable MPT pipeline commit, it will improve syncing performance. It is an experimental feature(default is false)",
|
||||
Category: flags.DeprecatedCategory,
|
||||
}
|
||||
RangeLimitFlag = &cli.BoolFlag{
|
||||
Name: "rangelimit",
|
||||
Usage: "Enable 5000 blocks limit for range query",
|
||||
Name: "rangelimit",
|
||||
Usage: "Enable 5000 blocks limit for range query",
|
||||
Category: flags.APICategory,
|
||||
}
|
||||
DiffFlag = flags.DirectoryFlag{
|
||||
Name: "datadir.diff",
|
||||
Usage: "Data directory for difflayer segments (default = inside chaindata)",
|
||||
Name: "datadir.diff",
|
||||
Usage: "Data directory for difflayer segments (default = inside chaindata)",
|
||||
Category: flags.FastNodeCategory,
|
||||
}
|
||||
RemoteDBFlag = &cli.StringFlag{
|
||||
Name: "remotedb",
|
||||
@@ -155,18 +163,24 @@ var (
|
||||
}
|
||||
NetworkIdFlag = &cli.Uint64Flag{
|
||||
Name: "networkid",
|
||||
Usage: "Explicitly set network id (integer)(For testnets: use --goerli, --sepolia instead)",
|
||||
Usage: "Explicitly set network id (integer)(For testnets: use --chapel instead)",
|
||||
Value: ethconfig.Defaults.NetworkId,
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
MainnetFlag = &cli.BoolFlag{
|
||||
BSCMainnetFlag = &cli.BoolFlag{
|
||||
Name: "mainnet",
|
||||
Usage: "Ethereum mainnet",
|
||||
Usage: "BSC mainnet",
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
ChapelFlag = &cli.BoolFlag{
|
||||
Name: "chapel",
|
||||
Usage: "Chapel network: pre-configured Proof-of-Stake-Authority BSC test network",
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
DeveloperFlag = &cli.BoolFlag{
|
||||
Name: "dev",
|
||||
Usage: "Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled",
|
||||
Name: "dev",
|
||||
Usage: "Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled",
|
||||
Category: flags.DevCategory,
|
||||
}
|
||||
DeveloperPeriodFlag = &cli.Uint64Flag{
|
||||
Name: "dev.period",
|
||||
@@ -196,7 +210,12 @@ var (
|
||||
Usage: "Exits after block synchronisation completes",
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
|
||||
// hbss2pbss command options
|
||||
ForceFlag = &cli.BoolFlag{
|
||||
Name: "force",
|
||||
Usage: "Force convert hbss trie node to pbss trie node. Ingore any metadata",
|
||||
Value: false,
|
||||
}
|
||||
// Dump command options.
|
||||
IterativeOutputFlag = &cli.BoolFlag{
|
||||
Name: "iterative",
|
||||
@@ -227,30 +246,12 @@ var (
|
||||
}
|
||||
|
||||
defaultSyncMode = ethconfig.Defaults.SyncMode
|
||||
SyncModeFlag = &flags.TextMarshalerFlag{
|
||||
Name: "syncmode",
|
||||
Usage: `Blockchain sync mode ("snap", "full" or "light")`,
|
||||
Value: &defaultSyncMode,
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
GCModeFlag = &cli.StringFlag{
|
||||
Name: "gcmode",
|
||||
Usage: `Blockchain garbage collection mode ("full", "archive")`,
|
||||
Value: "full",
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
SnapshotFlag = &cli.BoolFlag{
|
||||
SnapshotFlag = &cli.BoolFlag{
|
||||
Name: "snapshot",
|
||||
Usage: `Enables snapshot-database mode (default = enable)`,
|
||||
Value: true,
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
TxLookupLimitFlag = &cli.Uint64Flag{
|
||||
Name: "txlookuplimit",
|
||||
Usage: "Number of recent blocks to maintain transactions index for (default = about one year, 0 = entire chain)",
|
||||
Value: ethconfig.Defaults.TxLookupLimit,
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
LightKDFFlag = &cli.BoolFlag{
|
||||
Name: "lightkdf",
|
||||
Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength",
|
||||
@@ -268,9 +269,10 @@ var (
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
TriesInMemoryFlag = &cli.Uint64Flag{
|
||||
Name: "triesInMemory",
|
||||
Usage: "The layer of tries trees that keep in memory",
|
||||
Value: 128,
|
||||
Name: "triesInMemory",
|
||||
Usage: "The layer of tries trees that keep in memory",
|
||||
Value: 128,
|
||||
Category: flags.PerfCategory,
|
||||
}
|
||||
defaultVerifyMode = ethconfig.Defaults.TriesVerifyMode
|
||||
TriesVerifyModeFlag = &flags.TextMarshalerFlag{
|
||||
@@ -284,7 +286,23 @@ var (
|
||||
"none: no merkle state root verification at all, there is no need to setup or connect remote verify node at all,
|
||||
it is more light comparing to full and insecure mode, but get a very small chance that the state is not consistent
|
||||
with other peers."`,
|
||||
Value: &defaultVerifyMode,
|
||||
Value: &defaultVerifyMode,
|
||||
Category: flags.FastNodeCategory,
|
||||
}
|
||||
RialtoHash = &cli.StringFlag{
|
||||
Name: "rialtohash",
|
||||
Usage: "Manually specify the Rialto Genesis Hash, to trigger builtin network logic",
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
OverrideShanghai = &cli.Uint64Flag{
|
||||
Name: "override.shanghai",
|
||||
Usage: "Manually specify the Shanghai fork timestamp, overriding the bundled setting",
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
OverrideKepler = &cli.Uint64Flag{
|
||||
Name: "override.kepler",
|
||||
Usage: "Manually specify the Kepler fork timestamp, overriding the bundled setting",
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
OverrideCancun = &cli.Uint64Flag{
|
||||
Name: "override.cancun",
|
||||
@@ -296,40 +314,45 @@ var (
|
||||
Usage: "Manually specify the Verkle fork timestamp, overriding the bundled setting",
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
// Light server and client settings
|
||||
LightServeFlag = &cli.IntFlag{
|
||||
Name: "light.serve",
|
||||
Usage: "Maximum percentage of time allowed for serving LES requests (multi-threaded processing allows values over 100)",
|
||||
Value: ethconfig.Defaults.LightServ,
|
||||
Category: flags.LightCategory,
|
||||
OverrideFeynman = &cli.Uint64Flag{
|
||||
Name: "override.feynman",
|
||||
Usage: "Manually specify the Feynman fork timestamp, overriding the bundled setting",
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
LightIngressFlag = &cli.IntFlag{
|
||||
Name: "light.ingress",
|
||||
Usage: "Incoming bandwidth limit for serving light clients (kilobytes/sec, 0 = unlimited)",
|
||||
Value: ethconfig.Defaults.LightIngress,
|
||||
Category: flags.LightCategory,
|
||||
SyncModeFlag = &flags.TextMarshalerFlag{
|
||||
Name: "syncmode",
|
||||
Usage: `Blockchain sync mode ("snap" or "full")`,
|
||||
Value: &defaultSyncMode,
|
||||
Category: flags.StateCategory,
|
||||
}
|
||||
LightEgressFlag = &cli.IntFlag{
|
||||
Name: "light.egress",
|
||||
Usage: "Outgoing bandwidth limit for serving light clients (kilobytes/sec, 0 = unlimited)",
|
||||
Value: ethconfig.Defaults.LightEgress,
|
||||
Category: flags.LightCategory,
|
||||
GCModeFlag = &cli.StringFlag{
|
||||
Name: "gcmode",
|
||||
Usage: `Blockchain garbage collection mode, only relevant in state.scheme=hash ("full", "archive")`,
|
||||
Value: "full",
|
||||
Category: flags.StateCategory,
|
||||
}
|
||||
LightMaxPeersFlag = &cli.IntFlag{
|
||||
Name: "light.maxpeers",
|
||||
Usage: "Maximum number of light clients to serve, or light servers to attach to",
|
||||
Value: ethconfig.Defaults.LightPeers,
|
||||
Category: flags.LightCategory,
|
||||
StateSchemeFlag = &cli.StringFlag{
|
||||
Name: "state.scheme",
|
||||
Usage: "Scheme to use for storing ethereum state ('hash' or 'path')",
|
||||
Category: flags.StateCategory,
|
||||
}
|
||||
LightNoPruneFlag = &cli.BoolFlag{
|
||||
Name: "light.nopruning",
|
||||
Usage: "Disable ancient light chain data pruning",
|
||||
Category: flags.LightCategory,
|
||||
PathDBSyncFlag = &cli.BoolFlag{
|
||||
Name: "pathdb.sync",
|
||||
Usage: "sync flush nodes cache to disk in path schema",
|
||||
Value: false,
|
||||
Category: flags.StateCategory,
|
||||
}
|
||||
LightNoSyncServeFlag = &cli.BoolFlag{
|
||||
Name: "light.nosyncserve",
|
||||
Usage: "Enables serving light clients before syncing",
|
||||
Category: flags.LightCategory,
|
||||
StateHistoryFlag = &cli.Uint64Flag{
|
||||
Name: "history.state",
|
||||
Usage: "Number of recent blocks to retain state history for (default = 90,000 blocks, 0 = entire chain)",
|
||||
Value: ethconfig.Defaults.StateHistory,
|
||||
Category: flags.StateCategory,
|
||||
}
|
||||
TransactionHistoryFlag = &cli.Uint64Flag{
|
||||
Name: "history.transactions",
|
||||
Usage: "Number of recent blocks to maintain transactions index for (default = about one year, 0 = entire chain)",
|
||||
Value: ethconfig.Defaults.TransactionHistory,
|
||||
Category: flags.StateCategory,
|
||||
}
|
||||
// Transaction pool settings
|
||||
TxPoolLocalsFlag = &cli.StringFlag{
|
||||
@@ -397,9 +420,10 @@ var (
|
||||
Category: flags.TxPoolCategory,
|
||||
}
|
||||
TxPoolReannounceTimeFlag = &cli.DurationFlag{
|
||||
Name: "txpool.reannouncetime",
|
||||
Usage: "Duration for announcing local pending transactions again (default = 10 years, minimum = 1 minute)",
|
||||
Value: ethconfig.Defaults.TxPool.ReannounceTime,
|
||||
Name: "txpool.reannouncetime",
|
||||
Usage: "Duration for announcing local pending transactions again (default = 10 years, minimum = 1 minute)",
|
||||
Value: ethconfig.Defaults.TxPool.ReannounceTime,
|
||||
Category: flags.TxPoolCategory,
|
||||
}
|
||||
// Blob transaction pool settings
|
||||
BlobPoolDataDirFlag = &cli.StringFlag{
|
||||
@@ -462,17 +486,20 @@ var (
|
||||
Category: flags.PerfCategory,
|
||||
}
|
||||
PersistDiffFlag = &cli.BoolFlag{
|
||||
Name: "persistdiff",
|
||||
Usage: "Enable persistence of the diff layer",
|
||||
Name: "persistdiff",
|
||||
Usage: "Enable persistence of the diff layer",
|
||||
Category: flags.FastNodeCategory,
|
||||
}
|
||||
DiffBlockFlag = &cli.Uint64Flag{
|
||||
Name: "diffblock",
|
||||
Usage: "The number of blocks should be persisted in db (default = 86400)",
|
||||
Value: uint64(86400),
|
||||
Name: "diffblock",
|
||||
Usage: "The number of blocks should be persisted in db (default = 86400)",
|
||||
Value: uint64(86400),
|
||||
Category: flags.FastNodeCategory,
|
||||
}
|
||||
PruneAncientDataFlag = &cli.BoolFlag{
|
||||
Name: "pruneancient",
|
||||
Usage: "Prune ancient data, is an optional config and disabled by default. Only keep the latest 9w blocks' data,the older blocks' data will be permanently pruned. Notice:the geth/chaindata/ancient dir will be removed, if restart without the flag, the ancient data will start with the previous point that the oldest unpruned block number. Recommends to the user who don't care about the ancient data.",
|
||||
Name: "pruneancient",
|
||||
Usage: "Prune ancient data, is an optional config and disabled by default. Only keep the latest 9w blocks' data,the older blocks' data will be permanently pruned. Notice:the geth/chaindata/ancient dir will be removed, if restart without the flag, the ancient data will start with the previous point that the oldest unpruned block number. Recommends to the user who don't care about the ancient data.",
|
||||
Category: flags.BlockHistoryCategory,
|
||||
}
|
||||
CacheLogSizeFlag = &cli.IntFlag{
|
||||
Name: "cache.blocklogs",
|
||||
@@ -527,9 +554,10 @@ var (
|
||||
Category: flags.MinerCategory,
|
||||
}
|
||||
MinerDelayLeftoverFlag = &cli.DurationFlag{
|
||||
Name: "miner.delayleftover",
|
||||
Usage: "Time reserved to finalize a block",
|
||||
Value: ethconfig.Defaults.Miner.DelayLeftOver,
|
||||
Name: "miner.delayleftover",
|
||||
Usage: "Time reserved to finalize a block",
|
||||
Value: ethconfig.Defaults.Miner.DelayLeftOver,
|
||||
Category: flags.MinerCategory,
|
||||
}
|
||||
MinerNewPayloadTimeout = &cli.DurationFlag{
|
||||
Name: "miner.newpayload-timeout",
|
||||
@@ -591,27 +619,27 @@ var (
|
||||
}
|
||||
// Authenticated RPC HTTP settings
|
||||
AuthListenFlag = &cli.StringFlag{
|
||||
Name: "authrpc.addr",
|
||||
Usage: "Listening address for authenticated APIs",
|
||||
Value: node.DefaultConfig.AuthAddr,
|
||||
Category: flags.APICategory,
|
||||
Name: "authrpc.addr",
|
||||
Usage: "Listening address for authenticated APIs",
|
||||
Value: node.DefaultConfig.AuthAddr,
|
||||
// Category: flags.APICategory,
|
||||
}
|
||||
AuthPortFlag = &cli.IntFlag{
|
||||
Name: "authrpc.port",
|
||||
Usage: "Listening port for authenticated APIs",
|
||||
Value: node.DefaultConfig.AuthPort,
|
||||
Category: flags.APICategory,
|
||||
Name: "authrpc.port",
|
||||
Usage: "Listening port for authenticated APIs",
|
||||
Value: node.DefaultConfig.AuthPort,
|
||||
// Category: flags.APICategory,
|
||||
}
|
||||
AuthVirtualHostsFlag = &cli.StringFlag{
|
||||
Name: "authrpc.vhosts",
|
||||
Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
|
||||
Value: strings.Join(node.DefaultConfig.AuthVirtualHosts, ","),
|
||||
Category: flags.APICategory,
|
||||
Name: "authrpc.vhosts",
|
||||
Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
|
||||
Value: strings.Join(node.DefaultConfig.AuthVirtualHosts, ","),
|
||||
// Category: flags.APICategory,
|
||||
}
|
||||
JWTSecretFlag = &flags.DirectoryFlag{
|
||||
Name: "authrpc.jwtsecret",
|
||||
Usage: "Path to a JWT secret to use for authenticated RPC endpoints",
|
||||
Category: flags.APICategory,
|
||||
Name: "authrpc.jwtsecret",
|
||||
Usage: "Path to a JWT secret to use for authenticated RPC endpoints",
|
||||
// Category: flags.APICategory,
|
||||
}
|
||||
|
||||
// Logging and debug settings
|
||||
@@ -780,9 +808,10 @@ var (
|
||||
}
|
||||
|
||||
MaxPeersPerIPFlag = &cli.IntFlag{
|
||||
Name: "maxpeersperip",
|
||||
Usage: "Maximum number of network peers from a single IP address, (default used if set to <= 0, which is same as MaxPeers)",
|
||||
Value: node.DefaultConfig.P2P.MaxPeersPerIP,
|
||||
Name: "maxpeersperip",
|
||||
Usage: "Maximum number of network peers from a single IP address, (default used if set to <= 0, which is same as MaxPeers)",
|
||||
Value: node.DefaultConfig.P2P.MaxPeersPerIP,
|
||||
Category: flags.NetworkingCategory,
|
||||
}
|
||||
|
||||
MaxPendingPeersFlag = &cli.IntFlag{
|
||||
@@ -1014,72 +1043,78 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
|
||||
}
|
||||
|
||||
BlockAmountReserved = &cli.Uint64Flag{
|
||||
Name: "block-amount-reserved",
|
||||
Usage: "Sets the expected remained amount of blocks for offline block prune",
|
||||
Name: "block-amount-reserved",
|
||||
Usage: "Sets the expected remained amount of blocks for offline block prune",
|
||||
Category: flags.BlockHistoryCategory,
|
||||
}
|
||||
|
||||
CheckSnapshotWithMPT = &cli.BoolFlag{
|
||||
Name: "check-snapshot-with-mpt",
|
||||
Usage: "Enable checking between snapshot and MPT ",
|
||||
Name: "check-snapshot-with-mpt",
|
||||
Usage: "Enable checking between snapshot and MPT ",
|
||||
Category: flags.FastNodeCategory,
|
||||
}
|
||||
|
||||
EnableDoubleSignMonitorFlag = &cli.BoolFlag{
|
||||
Name: "monitor.doublesign",
|
||||
Usage: "Enable double sign monitor to check whether any validator signs multiple blocks",
|
||||
Name: "monitor.doublesign",
|
||||
Usage: "Enable double sign monitor to check whether any validator signs multiple blocks",
|
||||
Category: flags.MinerCategory,
|
||||
}
|
||||
|
||||
VotingEnabledFlag = &cli.BoolFlag{
|
||||
Name: "vote",
|
||||
Usage: "Enable voting when mining",
|
||||
Name: "vote",
|
||||
Usage: "Enable voting when mining",
|
||||
Category: flags.FastFinalityCategory,
|
||||
}
|
||||
|
||||
DisableVoteAttestationFlag = &cli.BoolFlag{
|
||||
Name: "disablevoteattestation",
|
||||
Usage: "Disable assembling vote attestation ",
|
||||
Name: "disablevoteattestation",
|
||||
Usage: "Disable assembling vote attestation ",
|
||||
Category: flags.FastFinalityCategory,
|
||||
}
|
||||
|
||||
EnableMaliciousVoteMonitorFlag = &cli.BoolFlag{
|
||||
Name: "monitor.maliciousvote",
|
||||
Usage: "Enable malicious vote monitor to check whether any validator violates the voting rules of fast finality",
|
||||
Name: "monitor.maliciousvote",
|
||||
Usage: "Enable malicious vote monitor to check whether any validator violates the voting rules of fast finality",
|
||||
Category: flags.FastFinalityCategory,
|
||||
}
|
||||
|
||||
BLSPasswordFileFlag = &cli.StringFlag{
|
||||
Name: "blspassword",
|
||||
Usage: "File path for the BLS password, which contains the password to unlock BLS wallet for managing votes in fast_finality feature",
|
||||
Name: "blspassword",
|
||||
Usage: "Password file path for the BLS wallet, which contains the password to unlock BLS wallet for managing votes in fast_finality feature",
|
||||
Category: flags.AccountCategory,
|
||||
}
|
||||
|
||||
BLSWalletDirFlag = &flags.DirectoryFlag{
|
||||
Name: "blswallet",
|
||||
Usage: "Path for the blsWallet dir in fast finality feature (default = inside the datadir)",
|
||||
Name: "blswallet",
|
||||
Usage: "Path for the blsWallet dir in fast finality feature (default = inside the datadir)",
|
||||
Category: flags.AccountCategory,
|
||||
}
|
||||
|
||||
VoteJournalDirFlag = &flags.DirectoryFlag{
|
||||
Name: "vote-journal-path",
|
||||
Usage: "Path for the voteJournal dir in fast finality feature (default = inside the datadir)",
|
||||
Name: "vote-journal-path",
|
||||
Usage: "Path for the voteJournal dir in fast finality feature (default = inside the datadir)",
|
||||
Category: flags.FastFinalityCategory,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
// TestnetFlags is the flag group of all built-in supported testnets.
|
||||
TestnetFlags = []cli.Flag{}
|
||||
TestnetFlags = []cli.Flag{
|
||||
ChapelFlag,
|
||||
}
|
||||
// NetworkFlags is the flag group of all built-in supported networks.
|
||||
NetworkFlags = append([]cli.Flag{MainnetFlag}, TestnetFlags...)
|
||||
NetworkFlags = append([]cli.Flag{BSCMainnetFlag}, TestnetFlags...)
|
||||
|
||||
// DatabasePathFlags is the flag group of all database path flags.
|
||||
DatabasePathFlags = []cli.Flag{
|
||||
DataDirFlag,
|
||||
AncientFlag,
|
||||
RemoteDBFlag,
|
||||
DBEngineFlag,
|
||||
HttpHeaderFlag,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
if rawdb.PebbleEnabled {
|
||||
DatabasePathFlags = append(DatabasePathFlags, DBEngineFlag)
|
||||
}
|
||||
}
|
||||
|
||||
// MakeDataDir retrieves the currently requested data directory, terminating
|
||||
// if none (or the empty string) is specified. If the node is starting a testnet,
|
||||
// then a subdirectory of the specified datadir will be used.
|
||||
@@ -1209,8 +1244,10 @@ func SplitAndTrim(input string) (ret []string) {
|
||||
// setHTTP creates the HTTP RPC listener interface string from the set
|
||||
// command line flags, returning empty if the HTTP endpoint is disabled.
|
||||
func setHTTP(ctx *cli.Context, cfg *node.Config) {
|
||||
if ctx.Bool(HTTPEnabledFlag.Name) && cfg.HTTPHost == "" {
|
||||
cfg.HTTPHost = "127.0.0.1"
|
||||
if ctx.Bool(HTTPEnabledFlag.Name) {
|
||||
if cfg.HTTPHost == "" {
|
||||
cfg.HTTPHost = "127.0.0.1"
|
||||
}
|
||||
if ctx.IsSet(HTTPListenAddrFlag.Name) {
|
||||
cfg.HTTPHost = ctx.String(HTTPListenAddrFlag.Name)
|
||||
}
|
||||
@@ -1274,8 +1311,10 @@ func setGraphQL(ctx *cli.Context, cfg *node.Config) {
|
||||
// setWS creates the WebSocket RPC listener interface string from the set
|
||||
// command line flags, returning empty if the HTTP endpoint is disabled.
|
||||
func setWS(ctx *cli.Context, cfg *node.Config) {
|
||||
if ctx.Bool(WSEnabledFlag.Name) && cfg.WSHost == "" {
|
||||
cfg.WSHost = "127.0.0.1"
|
||||
if ctx.Bool(WSEnabledFlag.Name) {
|
||||
if cfg.WSHost == "" {
|
||||
cfg.WSHost = "127.0.0.1"
|
||||
}
|
||||
if ctx.IsSet(WSListenAddrFlag.Name) {
|
||||
cfg.WSHost = ctx.String(WSListenAddrFlag.Name)
|
||||
}
|
||||
@@ -1309,25 +1348,25 @@ func setIPC(ctx *cli.Context, cfg *node.Config) {
|
||||
}
|
||||
}
|
||||
|
||||
// setLes configures the les server and ultra light client settings from the command line flags.
|
||||
// setLes shows the deprecation warnings for LES flags.
|
||||
func setLes(ctx *cli.Context, cfg *ethconfig.Config) {
|
||||
if ctx.IsSet(LightServeFlag.Name) {
|
||||
cfg.LightServ = ctx.Int(LightServeFlag.Name)
|
||||
log.Warn("The light server has been deprecated, please remove this flag", "flag", LightServeFlag.Name)
|
||||
}
|
||||
if ctx.IsSet(LightIngressFlag.Name) {
|
||||
cfg.LightIngress = ctx.Int(LightIngressFlag.Name)
|
||||
log.Warn("The light server has been deprecated, please remove this flag", "flag", LightIngressFlag.Name)
|
||||
}
|
||||
if ctx.IsSet(LightEgressFlag.Name) {
|
||||
cfg.LightEgress = ctx.Int(LightEgressFlag.Name)
|
||||
log.Warn("The light server has been deprecated, please remove this flag", "flag", LightEgressFlag.Name)
|
||||
}
|
||||
if ctx.IsSet(LightMaxPeersFlag.Name) {
|
||||
cfg.LightPeers = ctx.Int(LightMaxPeersFlag.Name)
|
||||
log.Warn("The light server has been deprecated, please remove this flag", "flag", LightMaxPeersFlag.Name)
|
||||
}
|
||||
if ctx.IsSet(LightNoPruneFlag.Name) {
|
||||
cfg.LightNoPrune = ctx.Bool(LightNoPruneFlag.Name)
|
||||
log.Warn("The light server has been deprecated, please remove this flag", "flag", LightNoPruneFlag.Name)
|
||||
}
|
||||
if ctx.IsSet(LightNoSyncServeFlag.Name) {
|
||||
cfg.LightNoSyncServe = ctx.Bool(LightNoSyncServeFlag.Name)
|
||||
log.Warn("The light server has been deprecated, please remove this flag", "flag", LightNoSyncServeFlag.Name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1412,7 +1451,10 @@ func setEtherbase(ctx *cli.Context, cfg *ethconfig.Config) {
|
||||
|
||||
// MakePasswordList reads password lines from the file specified by the global --password flag.
|
||||
func MakePasswordList(ctx *cli.Context) []string {
|
||||
path := ctx.Path(PasswordFileFlag.Name)
|
||||
return MakePasswordListFromPath(ctx.Path(PasswordFileFlag.Name))
|
||||
}
|
||||
|
||||
func MakePasswordListFromPath(path string) []string {
|
||||
if path == "" {
|
||||
return nil
|
||||
}
|
||||
@@ -1435,27 +1477,8 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
|
||||
setBootstrapNodes(ctx, cfg)
|
||||
setBootstrapNodesV5(ctx, cfg)
|
||||
|
||||
lightClient := ctx.String(SyncModeFlag.Name) == "light"
|
||||
lightServer := (ctx.Int(LightServeFlag.Name) != 0)
|
||||
|
||||
lightPeers := ctx.Int(LightMaxPeersFlag.Name)
|
||||
if lightClient && !ctx.IsSet(LightMaxPeersFlag.Name) {
|
||||
// dynamic default - for clients we use 1/10th of the default for servers
|
||||
lightPeers /= 10
|
||||
}
|
||||
|
||||
if ctx.IsSet(MaxPeersFlag.Name) {
|
||||
cfg.MaxPeers = ctx.Int(MaxPeersFlag.Name)
|
||||
if lightServer && !ctx.IsSet(LightMaxPeersFlag.Name) {
|
||||
cfg.MaxPeers += lightPeers
|
||||
}
|
||||
} else {
|
||||
if lightServer {
|
||||
cfg.MaxPeers += lightPeers
|
||||
}
|
||||
if lightClient && ctx.IsSet(LightMaxPeersFlag.Name) && cfg.MaxPeers < lightPeers {
|
||||
cfg.MaxPeers = lightPeers
|
||||
}
|
||||
}
|
||||
// if max peers per ip is not set, use max peers
|
||||
if cfg.MaxPeersPerIP <= 0 {
|
||||
@@ -1466,36 +1489,21 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
|
||||
cfg.MaxPeersPerIP = ctx.Int(MaxPeersPerIPFlag.Name)
|
||||
}
|
||||
|
||||
if !(lightClient || lightServer) {
|
||||
lightPeers = 0
|
||||
}
|
||||
ethPeers := cfg.MaxPeers - lightPeers
|
||||
if lightClient {
|
||||
ethPeers = 0
|
||||
}
|
||||
log.Info("Maximum peer count", "ETH", ethPeers, "LES", lightPeers, "total", cfg.MaxPeers)
|
||||
ethPeers := cfg.MaxPeers
|
||||
log.Info("Maximum peer count", "ETH", ethPeers, "total", cfg.MaxPeers)
|
||||
|
||||
if ctx.IsSet(MaxPendingPeersFlag.Name) {
|
||||
cfg.MaxPendingPeers = ctx.Int(MaxPendingPeersFlag.Name)
|
||||
}
|
||||
if ctx.IsSet(NoDiscoverFlag.Name) || lightClient {
|
||||
if ctx.IsSet(NoDiscoverFlag.Name) {
|
||||
cfg.NoDiscovery = true
|
||||
}
|
||||
|
||||
// Disallow --nodiscover when used in conjunction with light mode.
|
||||
if (lightClient || lightServer) && ctx.Bool(NoDiscoverFlag.Name) {
|
||||
Fatalf("Cannot use --" + NoDiscoverFlag.Name + " in light client or light server mode")
|
||||
}
|
||||
CheckExclusive(ctx, DiscoveryV4Flag, NoDiscoverFlag)
|
||||
CheckExclusive(ctx, DiscoveryV5Flag, NoDiscoverFlag)
|
||||
cfg.DiscoveryV4 = ctx.Bool(DiscoveryV4Flag.Name)
|
||||
cfg.DiscoveryV5 = ctx.Bool(DiscoveryV5Flag.Name)
|
||||
|
||||
// If we're running a light client or server, force enable the v5 peer discovery.
|
||||
if lightClient || lightServer {
|
||||
cfg.DiscoveryV5 = true
|
||||
}
|
||||
|
||||
if netrestrict := ctx.String(NetrestrictFlag.Name); netrestrict != "" {
|
||||
list, err := netutil.ParseNetlist(netrestrict)
|
||||
if err != nil {
|
||||
@@ -1627,12 +1635,7 @@ func setBLSWalletDir(ctx *cli.Context, cfg *node.Config) {
|
||||
}
|
||||
}
|
||||
|
||||
func setGPO(ctx *cli.Context, cfg *gasprice.Config, light bool) {
|
||||
// If we are running the light client, apply another group
|
||||
// settings for gas oracle.
|
||||
if light {
|
||||
*cfg = ethconfig.LightClientGPO
|
||||
}
|
||||
func setGPO(ctx *cli.Context, cfg *gasprice.Config) {
|
||||
if ctx.IsSet(GpoBlocksFlag.Name) {
|
||||
cfg.Blocks = ctx.Int(GpoBlocksFlag.Name)
|
||||
}
|
||||
@@ -1792,18 +1795,12 @@ func CheckExclusive(ctx *cli.Context, args ...interface{}) {
|
||||
// SetEthConfig applies eth-related command line flags to the config.
|
||||
func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||
// Avoid conflicting network flags
|
||||
CheckExclusive(ctx, MainnetFlag, DeveloperFlag)
|
||||
CheckExclusive(ctx, LightServeFlag, SyncModeFlag, "light")
|
||||
CheckExclusive(ctx, BSCMainnetFlag, DeveloperFlag)
|
||||
CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer
|
||||
if ctx.String(GCModeFlag.Name) == "archive" && ctx.Uint64(TxLookupLimitFlag.Name) != 0 {
|
||||
ctx.Set(TxLookupLimitFlag.Name, "0")
|
||||
log.Warn("Disable transaction unindexing for archive node")
|
||||
}
|
||||
if ctx.IsSet(LightServeFlag.Name) && ctx.Uint64(TxLookupLimitFlag.Name) != 0 {
|
||||
log.Warn("LES server cannot serve old transaction status and cannot connect below les/4 protocol version if transaction lookup index is limited")
|
||||
}
|
||||
|
||||
// Set configurations from CLI flags
|
||||
setEtherbase(ctx, cfg)
|
||||
setGPO(ctx, &cfg.GPO, ctx.String(SyncModeFlag.Name) == "light")
|
||||
setGPO(ctx, &cfg.GPO)
|
||||
setTxPool(ctx, &cfg.TxPool)
|
||||
setMiner(ctx, &cfg.Miner)
|
||||
setRequiredBlocks(ctx, cfg)
|
||||
@@ -1855,7 +1852,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||
if cfg.SyncMode == downloader.FullSync {
|
||||
cfg.PruneAncientData = ctx.Bool(PruneAncientDataFlag.Name)
|
||||
} else {
|
||||
log.Crit("pruneancient parameter didn't take effect for current syncmode")
|
||||
log.Crit("pruneancient parameter can only be used with syncmode=full")
|
||||
}
|
||||
}
|
||||
if gcmode := ctx.String(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
|
||||
@@ -1874,7 +1871,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||
cfg.EnableTrustProtocol = ctx.IsSet(EnableTrustProtocolFlag.Name)
|
||||
}
|
||||
if ctx.IsSet(PipeCommitFlag.Name) {
|
||||
cfg.PipeCommit = ctx.Bool(PipeCommitFlag.Name)
|
||||
log.Warn("The --pipecommit flag is deprecated and could be removed in the future!")
|
||||
}
|
||||
if ctx.IsSet(RangeLimitFlag.Name) {
|
||||
cfg.RangeLimit = ctx.Bool(RangeLimitFlag.Name)
|
||||
@@ -1888,8 +1885,30 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||
cfg.Preimages = true
|
||||
log.Info("Enabling recording of key preimages since archive mode is used")
|
||||
}
|
||||
if ctx.IsSet(TxLookupLimitFlag.Name) {
|
||||
cfg.TxLookupLimit = ctx.Uint64(TxLookupLimitFlag.Name)
|
||||
if ctx.IsSet(StateHistoryFlag.Name) {
|
||||
cfg.StateHistory = ctx.Uint64(StateHistoryFlag.Name)
|
||||
}
|
||||
scheme, err := ParseCLIAndConfigStateScheme(ctx.String(StateSchemeFlag.Name), cfg.StateScheme)
|
||||
if err != nil {
|
||||
Fatalf("%v", err)
|
||||
}
|
||||
cfg.StateScheme = scheme
|
||||
// Parse transaction history flag, if user is still using legacy config
|
||||
// file with 'TxLookupLimit' configured, copy the value to 'TransactionHistory'.
|
||||
if cfg.TransactionHistory == ethconfig.Defaults.TransactionHistory && cfg.TxLookupLimit != ethconfig.Defaults.TxLookupLimit {
|
||||
log.Crit("The config option 'TxLookupLimit' is deprecated and may cause unexpected performance degradation issues, please use 'TransactionHistory' instead")
|
||||
}
|
||||
if ctx.IsSet(TransactionHistoryFlag.Name) {
|
||||
cfg.TransactionHistory = ctx.Uint64(TransactionHistoryFlag.Name)
|
||||
} else if ctx.IsSet(TxLookupLimitFlag.Name) {
|
||||
log.Crit("The flag --txlookuplimit is deprecated and may cause unexpected performance degradation issues. Please use --history.transactions instead")
|
||||
}
|
||||
if ctx.IsSet(PathDBSyncFlag.Name) {
|
||||
cfg.PathSyncFlush = true
|
||||
}
|
||||
if ctx.String(GCModeFlag.Name) == "archive" && cfg.TransactionHistory != 0 {
|
||||
cfg.TransactionHistory = 0
|
||||
log.Warn("Disabled transaction unindexing for archive node")
|
||||
}
|
||||
if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheTrieFlag.Name) {
|
||||
cfg.TrieCleanCache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheTrieFlag.Name) / 100
|
||||
@@ -1957,12 +1976,18 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||
}
|
||||
// Override any default configs for hard coded networks.
|
||||
switch {
|
||||
case ctx.Bool(MainnetFlag.Name):
|
||||
case ctx.Bool(BSCMainnetFlag.Name):
|
||||
if !ctx.IsSet(NetworkIdFlag.Name) {
|
||||
cfg.NetworkId = 1
|
||||
cfg.NetworkId = 56
|
||||
}
|
||||
cfg.Genesis = core.DefaultGenesisBlock()
|
||||
SetDNSDiscoveryDefaults(cfg, params.MainnetGenesisHash)
|
||||
cfg.Genesis = core.DefaultBSCGenesisBlock()
|
||||
SetDNSDiscoveryDefaults(cfg, params.BSCGenesisHash)
|
||||
case ctx.Bool(ChapelFlag.Name):
|
||||
if !ctx.IsSet(NetworkIdFlag.Name) {
|
||||
cfg.NetworkId = 97
|
||||
}
|
||||
cfg.Genesis = core.DefaultChapelGenesisBlock()
|
||||
SetDNSDiscoveryDefaults(cfg, params.ChapelGenesisHash)
|
||||
case ctx.Bool(DeveloperFlag.Name):
|
||||
if !ctx.IsSet(NetworkIdFlag.Name) {
|
||||
cfg.NetworkId = 1337
|
||||
@@ -2021,7 +2046,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||
readonly = false
|
||||
}
|
||||
// Check if we have an already initialized chain and fall back to
|
||||
// that if so. Otherwise we need to generate a new genesis spec.
|
||||
// that if so. Otherwise, we need to generate a new genesis spec.
|
||||
chaindb := MakeChainDatabase(ctx, stack, readonly, false)
|
||||
if rawdb.ReadCanonicalHash(chaindb, 0) != (common.Hash{}) {
|
||||
cfg.Genesis = nil // fallback to db content
|
||||
@@ -2053,9 +2078,6 @@ func SetDNSDiscoveryDefaults(cfg *ethconfig.Config, genesis common.Hash) {
|
||||
return // already set through flags/config
|
||||
}
|
||||
protocol := "all"
|
||||
if cfg.SyncMode == downloader.LightSync {
|
||||
protocol = "les"
|
||||
}
|
||||
if url := params.KnownDNSNetwork(genesis, protocol); url != "" {
|
||||
cfg.EthDiscoveryURLs = []string{url}
|
||||
cfg.SnapDiscoveryURLs = cfg.EthDiscoveryURLs
|
||||
@@ -2065,27 +2087,12 @@ func SetDNSDiscoveryDefaults(cfg *ethconfig.Config, genesis common.Hash) {
|
||||
}
|
||||
|
||||
// RegisterEthService adds an Ethereum client to the stack.
|
||||
// The second return value is the full node instance, which may be nil if the
|
||||
// node is running as a light client.
|
||||
// The second return value is the full node instance.
|
||||
func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (ethapi.Backend, *eth.Ethereum) {
|
||||
if cfg.SyncMode == downloader.LightSync {
|
||||
backend, err := les.New(stack, cfg)
|
||||
if err != nil {
|
||||
Fatalf("Failed to register the Ethereum service: %v", err)
|
||||
}
|
||||
stack.RegisterAPIs(tracers.APIs(backend.ApiBackend))
|
||||
return backend.ApiBackend, nil
|
||||
}
|
||||
backend, err := eth.New(stack, cfg)
|
||||
if err != nil {
|
||||
Fatalf("Failed to register the Ethereum service: %v", err)
|
||||
}
|
||||
if cfg.LightServ > 0 {
|
||||
_, err := les.NewLesServer(stack, backend, cfg)
|
||||
if err != nil {
|
||||
Fatalf("Failed to create the LES server: %v", err)
|
||||
}
|
||||
}
|
||||
stack.RegisterAPIs(tracers.APIs(backend.APIBackend))
|
||||
return backend.APIBackend, backend
|
||||
}
|
||||
@@ -2134,13 +2141,12 @@ func EnableMinerInfo(ctx *cli.Context, minerConfig miner.Config) SetupMetricsOpt
|
||||
|
||||
// RegisterFilterAPI adds the eth log filtering RPC API to the node.
|
||||
func RegisterFilterAPI(stack *node.Node, backend ethapi.Backend, ethcfg *ethconfig.Config) *filters.FilterSystem {
|
||||
isLightClient := ethcfg.SyncMode == downloader.LightSync
|
||||
filterSystem := filters.NewFilterSystem(backend, filters.Config{
|
||||
LogCacheSize: ethcfg.FilterLogCacheSize,
|
||||
})
|
||||
stack.RegisterAPIs([]rpc.API{{
|
||||
Namespace: "eth",
|
||||
Service: filters.NewFilterAPI(filterSystem, isLightClient, ethcfg.RangeLimit),
|
||||
Service: filters.NewFilterAPI(filterSystem, ethcfg.RangeLimit),
|
||||
}})
|
||||
return filterSystem
|
||||
}
|
||||
@@ -2273,6 +2279,20 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly, disableFree
|
||||
return chainDb
|
||||
}
|
||||
|
||||
// tryMakeReadOnlyDatabase try to open the chain database in read-only mode,
|
||||
// or fallback to write mode if the database is not initialized.
|
||||
//
|
||||
//nolint:unused
|
||||
func tryMakeReadOnlyDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
|
||||
// If datadir doesn't exist we need to open db in write-mode
|
||||
// so database engine can create files.
|
||||
readonly := true
|
||||
if !common.FileExist(stack.ResolvePath("chaindata")) || ctx.Bool(PruneAncientDataFlag.Name) {
|
||||
readonly = false
|
||||
}
|
||||
return MakeChainDatabase(ctx, stack, readonly, false)
|
||||
}
|
||||
|
||||
func IsNetworkPreset(ctx *cli.Context) bool {
|
||||
for _, flag := range NetworkFlags {
|
||||
bFlag, _ := flag.(*cli.BoolFlag)
|
||||
@@ -2310,8 +2330,10 @@ func DialRPCWithHeaders(endpoint string, headers []string) (*rpc.Client, error)
|
||||
func MakeGenesis(ctx *cli.Context) *core.Genesis {
|
||||
var genesis *core.Genesis
|
||||
switch {
|
||||
case ctx.Bool(MainnetFlag.Name):
|
||||
genesis = core.DefaultGenesisBlock()
|
||||
case ctx.Bool(BSCMainnetFlag.Name):
|
||||
genesis = core.DefaultBSCGenesisBlock()
|
||||
case ctx.Bool(ChapelFlag.Name):
|
||||
genesis = core.DefaultChapelGenesisBlock()
|
||||
case ctx.Bool(DeveloperFlag.Name):
|
||||
Fatalf("Developer chains are ephemeral")
|
||||
}
|
||||
@@ -2335,14 +2357,21 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
|
||||
if gcmode := ctx.String(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
|
||||
Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
|
||||
}
|
||||
scheme, err := rawdb.ParseStateScheme(ctx.String(StateSchemeFlag.Name), chainDb)
|
||||
if err != nil {
|
||||
Fatalf("%v", err)
|
||||
}
|
||||
cache := &core.CacheConfig{
|
||||
TrieCleanLimit: ethconfig.Defaults.TrieCleanCache,
|
||||
TrieDirtyLimit: ethconfig.Defaults.TrieDirtyCache,
|
||||
TrieDirtyDisabled: ctx.String(GCModeFlag.Name) == "archive",
|
||||
TrieTimeLimit: ethconfig.Defaults.TrieTimeout,
|
||||
TriesInMemory: ethconfig.Defaults.TriesInMemory,
|
||||
SnapshotLimit: ethconfig.Defaults.SnapshotCache,
|
||||
Preimages: ctx.Bool(CachePreimagesFlag.Name),
|
||||
TrieCleanLimit: ethconfig.Defaults.TrieCleanCache,
|
||||
TrieCleanNoPrefetch: ctx.Bool(CacheNoPrefetchFlag.Name),
|
||||
TrieDirtyLimit: ethconfig.Defaults.TrieDirtyCache,
|
||||
TrieDirtyDisabled: ctx.String(GCModeFlag.Name) == "archive",
|
||||
TrieTimeLimit: ethconfig.Defaults.TrieTimeout,
|
||||
TriesInMemory: ethconfig.Defaults.TriesInMemory,
|
||||
SnapshotLimit: ethconfig.Defaults.SnapshotCache,
|
||||
Preimages: ctx.Bool(CachePreimagesFlag.Name),
|
||||
StateScheme: scheme,
|
||||
StateHistory: ctx.Uint64(StateHistoryFlag.Name),
|
||||
}
|
||||
if cache.TrieDirtyDisabled && !cache.Preimages {
|
||||
cache.Preimages = true
|
||||
@@ -2390,3 +2419,46 @@ func MakeConsolePreloads(ctx *cli.Context) []string {
|
||||
}
|
||||
return preloads
|
||||
}
|
||||
|
||||
// MakeTrieDatabase constructs a trie database based on the configured scheme.
|
||||
func MakeTrieDatabase(ctx *cli.Context, disk ethdb.Database, preimage bool, readOnly bool) *trie.Database {
|
||||
config := &trie.Config{
|
||||
Preimages: preimage,
|
||||
}
|
||||
scheme, err := rawdb.ParseStateScheme(ctx.String(StateSchemeFlag.Name), disk)
|
||||
if err != nil {
|
||||
Fatalf("%v", err)
|
||||
}
|
||||
if scheme == rawdb.HashScheme {
|
||||
// Read-only mode is not implemented in hash mode,
|
||||
// ignore the parameter silently. TODO(rjl493456442)
|
||||
// please config it if read mode is implemented.
|
||||
config.HashDB = hashdb.Defaults
|
||||
return trie.NewDatabase(disk, config)
|
||||
}
|
||||
if readOnly {
|
||||
config.PathDB = pathdb.ReadOnly
|
||||
} else {
|
||||
config.PathDB = pathdb.Defaults
|
||||
}
|
||||
return trie.NewDatabase(disk, config)
|
||||
}
|
||||
|
||||
// ParseCLIAndConfigStateScheme parses state scheme in CLI and config.
|
||||
func ParseCLIAndConfigStateScheme(cliScheme, cfgScheme string) (string, error) {
|
||||
if cliScheme == "" {
|
||||
if cfgScheme != "" {
|
||||
log.Info("Use config state scheme", "config", cfgScheme)
|
||||
}
|
||||
return cfgScheme, nil
|
||||
}
|
||||
|
||||
if !rawdb.ValidateStateScheme(cliScheme) {
|
||||
return "", fmt.Errorf("invalid state scheme in CLI: %s", cliScheme)
|
||||
}
|
||||
if cfgScheme == "" || cliScheme == cfgScheme {
|
||||
log.Info("Use CLI state scheme", "CLI", cliScheme)
|
||||
return cliScheme, nil
|
||||
}
|
||||
return "", fmt.Errorf("incompatible state scheme, CLI: %s, config: %s", cliScheme, cfgScheme)
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package utils
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||
"github.com/ethereum/go-ethereum/internal/flags"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -37,6 +38,13 @@ var DeprecatedFlags = []cli.Flag{
|
||||
CacheTrieJournalFlag,
|
||||
CacheTrieRejournalFlag,
|
||||
LegacyDiscoveryV5Flag,
|
||||
TxLookupLimitFlag,
|
||||
LightServeFlag,
|
||||
LightIngressFlag,
|
||||
LightEgressFlag,
|
||||
LightMaxPeersFlag,
|
||||
LightNoPruneFlag,
|
||||
LightNoSyncServeFlag,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -68,6 +76,48 @@ var (
|
||||
Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism (deprecated, use --discv5 instead)",
|
||||
Category: flags.DeprecatedCategory,
|
||||
}
|
||||
// Deprecated August 2023
|
||||
TxLookupLimitFlag = &cli.Uint64Flag{
|
||||
Name: "txlookuplimit",
|
||||
Usage: "Number of recent blocks to maintain transactions index for (default = about one year, 0 = entire chain) (deprecated, use history.transactions instead)",
|
||||
Value: ethconfig.Defaults.TransactionHistory,
|
||||
Category: flags.DeprecatedCategory,
|
||||
}
|
||||
// Light server and client settings, Deprecated November 2023
|
||||
LightServeFlag = &cli.IntFlag{
|
||||
Name: "light.serve",
|
||||
Usage: "Maximum percentage of time allowed for serving LES requests (deprecated)",
|
||||
Value: ethconfig.Defaults.LightServ,
|
||||
Category: flags.LightCategory,
|
||||
}
|
||||
LightIngressFlag = &cli.IntFlag{
|
||||
Name: "light.ingress",
|
||||
Usage: "Incoming bandwidth limit for serving light clients (deprecated)",
|
||||
Value: ethconfig.Defaults.LightIngress,
|
||||
Category: flags.LightCategory,
|
||||
}
|
||||
LightEgressFlag = &cli.IntFlag{
|
||||
Name: "light.egress",
|
||||
Usage: "Outgoing bandwidth limit for serving light clients (deprecated)",
|
||||
Value: ethconfig.Defaults.LightEgress,
|
||||
Category: flags.LightCategory,
|
||||
}
|
||||
LightMaxPeersFlag = &cli.IntFlag{
|
||||
Name: "light.maxpeers",
|
||||
Usage: "Maximum number of light clients to serve, or light servers to attach to (deprecated)",
|
||||
Value: ethconfig.Defaults.LightPeers,
|
||||
Category: flags.LightCategory,
|
||||
}
|
||||
LightNoPruneFlag = &cli.BoolFlag{
|
||||
Name: "light.nopruning",
|
||||
Usage: "Disable ancient light chain data pruning (deprecated)",
|
||||
Category: flags.LightCategory,
|
||||
}
|
||||
LightNoSyncServeFlag = &cli.BoolFlag{
|
||||
Name: "light.nosyncserve",
|
||||
Usage: "Enables serving light clients before syncing (deprecated)",
|
||||
Category: flags.LightCategory,
|
||||
}
|
||||
)
|
||||
|
||||
// showDeprecated displays deprecated flags that will be soon removed from the codebase.
|
||||
|
||||
@@ -44,6 +44,12 @@ const (
|
||||
var (
|
||||
hashT = reflect.TypeOf(Hash{})
|
||||
addressT = reflect.TypeOf(Address{})
|
||||
|
||||
// MaxAddress represents the maximum possible address value.
|
||||
MaxAddress = HexToAddress("0xffffffffffffffffffffffffffffffffffffffff")
|
||||
|
||||
// MaxHash represents the maximum possible hash value.
|
||||
MaxHash = HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
|
||||
)
|
||||
|
||||
// Hash represents the 32 byte Keccak256 hash of arbitrary data.
|
||||
|
||||
@@ -150,7 +150,7 @@ type PoSA interface {
|
||||
IsSystemContract(to *common.Address) bool
|
||||
EnoughDistance(chain ChainReader, header *types.Header) bool
|
||||
IsLocalBlock(header *types.Header) bool
|
||||
GetJustifiedNumberAndHash(chain ChainHeaderReader, header *types.Header) (uint64, common.Hash, error)
|
||||
GetJustifiedNumberAndHash(chain ChainHeaderReader, headers []*types.Header) (uint64, common.Hash, error)
|
||||
GetFinalizedHeader(chain ChainHeaderReader, header *types.Header) *types.Header
|
||||
VerifyVote(chain ChainHeaderReader, vote *types.VoteEnvelope) error
|
||||
IsActiveValidatorAt(chain ChainHeaderReader, header *types.Header, checkVoteKeyFn func(bLSPublicKey *types.BLSPublicKey) bool) bool
|
||||
|
||||
@@ -21,6 +21,9 @@ import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
@@ -29,6 +32,16 @@ import (
|
||||
// - gas limit check
|
||||
// - basefee check
|
||||
func VerifyEIP1559Header(config *params.ChainConfig, parent, header *types.Header) error {
|
||||
if config.Parlia == nil {
|
||||
// Verify that the gas limit remains within allowed bounds
|
||||
parentGasLimit := parent.GasLimit
|
||||
if !config.IsLondon(parent.Number) {
|
||||
parentGasLimit = parent.GasLimit * config.ElasticityMultiplier()
|
||||
}
|
||||
if err := misc.VerifyGaslimit(parentGasLimit, header.GasLimit); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Verify the header is not malformed
|
||||
if header.BaseFee == nil {
|
||||
return errors.New("header is missing baseFee")
|
||||
@@ -45,5 +58,45 @@ func VerifyEIP1559Header(config *params.ChainConfig, parent, header *types.Heade
|
||||
|
||||
// CalcBaseFee calculates the basefee of the header.
|
||||
func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int {
|
||||
return new(big.Int).SetUint64(params.InitialBaseFee)
|
||||
if config.Parlia != nil {
|
||||
return new(big.Int).SetUint64(params.InitialBaseFee)
|
||||
}
|
||||
|
||||
// If the current block is the first EIP-1559 block, return the InitialBaseFee.
|
||||
if !config.IsLondon(parent.Number) {
|
||||
return new(big.Int).SetUint64(params.InitialBaseFee)
|
||||
}
|
||||
|
||||
parentGasTarget := parent.GasLimit / config.ElasticityMultiplier()
|
||||
// If the parent gasUsed is the same as the target, the baseFee remains unchanged.
|
||||
if parent.GasUsed == parentGasTarget {
|
||||
return new(big.Int).Set(parent.BaseFee)
|
||||
}
|
||||
|
||||
var (
|
||||
num = new(big.Int)
|
||||
denom = new(big.Int)
|
||||
)
|
||||
|
||||
if parent.GasUsed > parentGasTarget {
|
||||
// If the parent block used more gas than its target, the baseFee should increase.
|
||||
// max(1, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator)
|
||||
num.SetUint64(parent.GasUsed - parentGasTarget)
|
||||
num.Mul(num, parent.BaseFee)
|
||||
num.Div(num, denom.SetUint64(parentGasTarget))
|
||||
num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator()))
|
||||
baseFeeDelta := math.BigMax(num, common.Big1)
|
||||
|
||||
return num.Add(parent.BaseFee, baseFeeDelta)
|
||||
} else {
|
||||
// Otherwise if the parent block used less gas than its target, the baseFee should decrease.
|
||||
// max(0, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator)
|
||||
num.SetUint64(parentGasTarget - parent.GasUsed)
|
||||
num.Mul(num, parent.BaseFee)
|
||||
num.Div(num, denom.SetUint64(parentGasTarget))
|
||||
num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator()))
|
||||
baseFee := num.Sub(parent.BaseFee, num)
|
||||
|
||||
return math.BigMax(baseFee, common.Big0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,11 @@ func copyConfig(original *params.ChainConfig) *params.ChainConfig {
|
||||
|
||||
func config() *params.ChainConfig {
|
||||
config := copyConfig(params.TestChainConfig)
|
||||
config.Ethash = nil
|
||||
config.Parlia = ¶ms.ParliaConfig{
|
||||
Period: 3,
|
||||
Epoch: 200,
|
||||
}
|
||||
config.LondonBlock = big.NewInt(5)
|
||||
return config
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
235
consensus/parlia/feynmanfork.go
Normal file
235
consensus/parlia/feynmanfork.go
Normal file
@@ -0,0 +1,235 @@
|
||||
package parlia
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/systemcontracts"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
const SecondsPerDay uint64 = 86400
|
||||
|
||||
// the params should be two blocks' time(timestamp)
|
||||
func sameDayInUTC(first, second uint64) bool {
|
||||
return first/SecondsPerDay == second/SecondsPerDay
|
||||
}
|
||||
|
||||
func isBreatheBlock(lastBlockTime, blockTime uint64) bool {
|
||||
return lastBlockTime != 0 && !sameDayInUTC(lastBlockTime, blockTime)
|
||||
}
|
||||
|
||||
// initializeFeynmanContract initialize new contracts of Feynman fork
|
||||
func (p *Parlia) initializeFeynmanContract(state *state.StateDB, header *types.Header, chain core.ChainContext,
|
||||
txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mining bool,
|
||||
) error {
|
||||
// method
|
||||
method := "initialize"
|
||||
|
||||
// initialize contracts
|
||||
contracts := []string{
|
||||
systemcontracts.StakeHubContract,
|
||||
systemcontracts.GovernorContract,
|
||||
systemcontracts.GovTokenContract,
|
||||
systemcontracts.TimelockContract,
|
||||
systemcontracts.TokenRecoverPortalContract,
|
||||
}
|
||||
// get packed data
|
||||
data, err := p.stakeHubABI.Pack(method)
|
||||
if err != nil {
|
||||
log.Error("Unable to pack tx for initialize feynman contracts", "error", err)
|
||||
return err
|
||||
}
|
||||
for _, c := range contracts {
|
||||
msg := p.getSystemMessage(header.Coinbase, common.HexToAddress(c), data, common.Big0)
|
||||
// apply message
|
||||
log.Info("initialize feynman contract", "block number", header.Number.Uint64(), "contract", c)
|
||||
err = p.applyTransaction(msg, state, header, chain, txs, receipts, receivedTxs, usedGas, mining)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ValidatorItem struct {
|
||||
address common.Address
|
||||
votingPower *big.Int
|
||||
voteAddress []byte
|
||||
}
|
||||
|
||||
// An ValidatorHeap is a max-heap of validator's votingPower.
|
||||
type ValidatorHeap []ValidatorItem
|
||||
|
||||
func (h *ValidatorHeap) Len() int { return len(*h) }
|
||||
|
||||
func (h *ValidatorHeap) Less(i, j int) bool {
|
||||
// We want topK validators with max voting power, so we need a max-heap
|
||||
if (*h)[i].votingPower.Cmp((*h)[j].votingPower) == 0 {
|
||||
return (*h)[i].address.Hex() < (*h)[j].address.Hex()
|
||||
} else {
|
||||
return (*h)[i].votingPower.Cmp((*h)[j].votingPower) == 1
|
||||
}
|
||||
}
|
||||
|
||||
func (h *ValidatorHeap) Swap(i, j int) { (*h)[i], (*h)[j] = (*h)[j], (*h)[i] }
|
||||
|
||||
func (h *ValidatorHeap) Push(x interface{}) {
|
||||
*h = append(*h, x.(ValidatorItem))
|
||||
}
|
||||
|
||||
func (h *ValidatorHeap) Pop() interface{} {
|
||||
old := *h
|
||||
n := len(old)
|
||||
x := old[n-1]
|
||||
*h = old[0 : n-1]
|
||||
return x
|
||||
}
|
||||
|
||||
func (p *Parlia) updateValidatorSetV2(state *state.StateDB, header *types.Header, chain core.ChainContext,
|
||||
txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mining bool,
|
||||
) error {
|
||||
// 1. get all validators and its voting power
|
||||
blockNr := rpc.BlockNumberOrHashWithHash(header.ParentHash, false)
|
||||
validatorItems, err := p.getValidatorElectionInfo(blockNr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
maxElectedValidators, err := p.getMaxElectedValidators(blockNr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 2. sort by voting power
|
||||
eValidators, eVotingPowers, eVoteAddrs := getTopValidatorsByVotingPower(validatorItems, maxElectedValidators)
|
||||
|
||||
// 3. update validator set to system contract
|
||||
method := "updateValidatorSetV2"
|
||||
data, err := p.validatorSetABI.Pack(method, eValidators, eVotingPowers, eVoteAddrs)
|
||||
if err != nil {
|
||||
log.Error("Unable to pack tx for updateValidatorSetV2", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// get system message
|
||||
msg := p.getSystemMessage(header.Coinbase, common.HexToAddress(systemcontracts.ValidatorContract), data, common.Big0)
|
||||
// apply message
|
||||
return p.applyTransaction(msg, state, header, chain, txs, receipts, receivedTxs, usedGas, mining)
|
||||
}
|
||||
|
||||
func (p *Parlia) getValidatorElectionInfo(blockNr rpc.BlockNumberOrHash) ([]ValidatorItem, error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
method := "getValidatorElectionInfo"
|
||||
toAddress := common.HexToAddress(systemcontracts.StakeHubContract)
|
||||
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
|
||||
|
||||
data, err := p.stakeHubABI.Pack(method, big.NewInt(0), big.NewInt(0))
|
||||
if err != nil {
|
||||
log.Error("Unable to pack tx for getValidatorElectionInfo", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
msgData := (hexutil.Bytes)(data)
|
||||
|
||||
result, err := p.ethAPI.Call(ctx, ethapi.TransactionArgs{
|
||||
Gas: &gas,
|
||||
To: &toAddress,
|
||||
Data: &msgData,
|
||||
}, blockNr, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var validators []common.Address
|
||||
var votingPowers []*big.Int
|
||||
var voteAddrs [][]byte
|
||||
var totalLength *big.Int
|
||||
if err := p.stakeHubABI.UnpackIntoInterface(&[]interface{}{&validators, &votingPowers, &voteAddrs, &totalLength}, method, result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if totalLength.Int64() != int64(len(validators)) || totalLength.Int64() != int64(len(votingPowers)) || totalLength.Int64() != int64(len(voteAddrs)) {
|
||||
return nil, fmt.Errorf("validator length not match")
|
||||
}
|
||||
|
||||
validatorItems := make([]ValidatorItem, len(validators))
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validatorItems[i] = ValidatorItem{
|
||||
address: validators[i],
|
||||
votingPower: votingPowers[i],
|
||||
voteAddress: voteAddrs[i],
|
||||
}
|
||||
}
|
||||
|
||||
return validatorItems, nil
|
||||
}
|
||||
|
||||
func (p *Parlia) getMaxElectedValidators(blockNr rpc.BlockNumberOrHash) (maxElectedValidators *big.Int, err error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
method := "maxElectedValidators"
|
||||
toAddress := common.HexToAddress(systemcontracts.StakeHubContract)
|
||||
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
|
||||
|
||||
data, err := p.stakeHubABI.Pack(method)
|
||||
if err != nil {
|
||||
log.Error("Unable to pack tx for maxElectedValidators", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
msgData := (hexutil.Bytes)(data)
|
||||
|
||||
result, err := p.ethAPI.Call(ctx, ethapi.TransactionArgs{
|
||||
Gas: &gas,
|
||||
To: &toAddress,
|
||||
Data: &msgData,
|
||||
}, blockNr, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := p.stakeHubABI.UnpackIntoInterface(&maxElectedValidators, method, result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return maxElectedValidators, nil
|
||||
}
|
||||
|
||||
func getTopValidatorsByVotingPower(validatorItems []ValidatorItem, maxElectedValidators *big.Int) ([]common.Address, []uint64, [][]byte) {
|
||||
var validatorHeap ValidatorHeap
|
||||
for i := 0; i < len(validatorItems); i++ {
|
||||
// only keep validators with voting power > 0
|
||||
if validatorItems[i].votingPower.Cmp(big.NewInt(0)) == 1 {
|
||||
validatorHeap = append(validatorHeap, validatorItems[i])
|
||||
}
|
||||
}
|
||||
hp := &validatorHeap
|
||||
heap.Init(hp)
|
||||
|
||||
topN := int(maxElectedValidators.Int64())
|
||||
if topN > len(validatorHeap) {
|
||||
topN = len(validatorHeap)
|
||||
}
|
||||
eValidators := make([]common.Address, topN)
|
||||
eVotingPowers := make([]uint64, topN)
|
||||
eVoteAddrs := make([][]byte, topN)
|
||||
for i := 0; i < topN; i++ {
|
||||
item := heap.Pop(hp).(ValidatorItem)
|
||||
eValidators[i] = item.address
|
||||
// as the decimal in BNB Beacon Chain is 1e8 and in BNB Smart Chain is 1e18, we need to divide it by 1e10
|
||||
eVotingPowers[i] = new(big.Int).Div(item.votingPower, big.NewInt(1e10)).Uint64()
|
||||
eVoteAddrs[i] = item.voteAddress
|
||||
}
|
||||
|
||||
return eValidators, eVotingPowers, eVoteAddrs
|
||||
}
|
||||
166
consensus/parlia/feynmanfork_test.go
Normal file
166
consensus/parlia/feynmanfork_test.go
Normal file
@@ -0,0 +1,166 @@
|
||||
package parlia
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
func TestValidatorHeap(t *testing.T) {
|
||||
testCases := []struct {
|
||||
description string
|
||||
k int64
|
||||
validators []ValidatorItem
|
||||
expected []common.Address
|
||||
}{
|
||||
{
|
||||
description: "normal case",
|
||||
k: 2,
|
||||
validators: []ValidatorItem{
|
||||
{
|
||||
address: common.HexToAddress("0x1"),
|
||||
votingPower: new(big.Int).Mul(big.NewInt(300), big.NewInt(1e10)),
|
||||
voteAddress: []byte("0x1"),
|
||||
},
|
||||
{
|
||||
address: common.HexToAddress("0x2"),
|
||||
votingPower: new(big.Int).Mul(big.NewInt(200), big.NewInt(1e10)),
|
||||
voteAddress: []byte("0x2"),
|
||||
},
|
||||
{
|
||||
address: common.HexToAddress("0x3"),
|
||||
votingPower: new(big.Int).Mul(big.NewInt(100), big.NewInt(1e10)),
|
||||
voteAddress: []byte("0x3"),
|
||||
},
|
||||
},
|
||||
expected: []common.Address{
|
||||
common.HexToAddress("0x1"),
|
||||
common.HexToAddress("0x2"),
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "same voting power",
|
||||
k: 2,
|
||||
validators: []ValidatorItem{
|
||||
{
|
||||
address: common.HexToAddress("0x1"),
|
||||
votingPower: new(big.Int).Mul(big.NewInt(300), big.NewInt(1e10)),
|
||||
voteAddress: []byte("0x1"),
|
||||
},
|
||||
{
|
||||
address: common.HexToAddress("0x2"),
|
||||
votingPower: new(big.Int).Mul(big.NewInt(100), big.NewInt(1e10)),
|
||||
voteAddress: []byte("0x2"),
|
||||
},
|
||||
{
|
||||
address: common.HexToAddress("0x3"),
|
||||
votingPower: new(big.Int).Mul(big.NewInt(100), big.NewInt(1e10)),
|
||||
voteAddress: []byte("0x3"),
|
||||
},
|
||||
},
|
||||
expected: []common.Address{
|
||||
common.HexToAddress("0x1"),
|
||||
common.HexToAddress("0x2"),
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "zero voting power and k > len(validators)",
|
||||
k: 5,
|
||||
validators: []ValidatorItem{
|
||||
{
|
||||
address: common.HexToAddress("0x1"),
|
||||
votingPower: new(big.Int).Mul(big.NewInt(300), big.NewInt(1e10)),
|
||||
voteAddress: []byte("0x1"),
|
||||
},
|
||||
{
|
||||
address: common.HexToAddress("0x2"),
|
||||
votingPower: big.NewInt(0),
|
||||
voteAddress: []byte("0x2"),
|
||||
},
|
||||
{
|
||||
address: common.HexToAddress("0x3"),
|
||||
votingPower: big.NewInt(0),
|
||||
voteAddress: []byte("0x3"),
|
||||
},
|
||||
{
|
||||
address: common.HexToAddress("0x4"),
|
||||
votingPower: big.NewInt(0),
|
||||
voteAddress: []byte("0x4"),
|
||||
},
|
||||
},
|
||||
expected: []common.Address{
|
||||
common.HexToAddress("0x1"),
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "zero voting power and k < len(validators)",
|
||||
k: 2,
|
||||
validators: []ValidatorItem{
|
||||
{
|
||||
address: common.HexToAddress("0x1"),
|
||||
votingPower: new(big.Int).Mul(big.NewInt(300), big.NewInt(1e10)),
|
||||
voteAddress: []byte("0x1"),
|
||||
},
|
||||
{
|
||||
address: common.HexToAddress("0x2"),
|
||||
votingPower: big.NewInt(0),
|
||||
voteAddress: []byte("0x2"),
|
||||
},
|
||||
{
|
||||
address: common.HexToAddress("0x3"),
|
||||
votingPower: big.NewInt(0),
|
||||
voteAddress: []byte("0x3"),
|
||||
},
|
||||
{
|
||||
address: common.HexToAddress("0x4"),
|
||||
votingPower: big.NewInt(0),
|
||||
voteAddress: []byte("0x4"),
|
||||
},
|
||||
},
|
||||
expected: []common.Address{
|
||||
common.HexToAddress("0x1"),
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "all zero voting power",
|
||||
k: 2,
|
||||
validators: []ValidatorItem{
|
||||
{
|
||||
address: common.HexToAddress("0x1"),
|
||||
votingPower: big.NewInt(0),
|
||||
voteAddress: []byte("0x1"),
|
||||
},
|
||||
{
|
||||
address: common.HexToAddress("0x2"),
|
||||
votingPower: big.NewInt(0),
|
||||
voteAddress: []byte("0x2"),
|
||||
},
|
||||
{
|
||||
address: common.HexToAddress("0x3"),
|
||||
votingPower: big.NewInt(0),
|
||||
voteAddress: []byte("0x3"),
|
||||
},
|
||||
{
|
||||
address: common.HexToAddress("0x4"),
|
||||
votingPower: big.NewInt(0),
|
||||
voteAddress: []byte("0x4"),
|
||||
},
|
||||
},
|
||||
expected: []common.Address{},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
eligibleValidators, _, _ := getTopValidatorsByVotingPower(tc.validators, big.NewInt(tc.k))
|
||||
|
||||
// check
|
||||
if len(eligibleValidators) != len(tc.expected) {
|
||||
t.Errorf("expected %d, got %d", len(tc.expected), len(eligibleValidators))
|
||||
}
|
||||
for i := 0; i < len(tc.expected); i++ {
|
||||
if eligibleValidators[i] != tc.expected[i] {
|
||||
t.Errorf("expected %s, got %s", tc.expected[i].Hex(), eligibleValidators[i].Hex())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
@@ -29,6 +28,7 @@ import (
|
||||
cmath "github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/forkid"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
@@ -47,7 +47,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
inMemorySnapshots = 128 // Number of recent snapshots to keep in memory
|
||||
inMemorySnapshots = 256 // Number of recent snapshots to keep in memory
|
||||
inMemorySignatures = 4096 // Number of recent block signatures to keep in memory
|
||||
|
||||
checkpointInterval = 1024 // Number of blocks after which to save the snapshot to the database
|
||||
@@ -90,6 +90,11 @@ var (
|
||||
common.HexToAddress(systemcontracts.TokenHubContract): true,
|
||||
common.HexToAddress(systemcontracts.RelayerIncentivizeContract): true,
|
||||
common.HexToAddress(systemcontracts.CrossChainContract): true,
|
||||
common.HexToAddress(systemcontracts.StakeHubContract): true,
|
||||
common.HexToAddress(systemcontracts.GovernorContract): true,
|
||||
common.HexToAddress(systemcontracts.GovTokenContract): true,
|
||||
common.HexToAddress(systemcontracts.TimelockContract): true,
|
||||
common.HexToAddress(systemcontracts.TokenRecoverPortalContract): true,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -179,7 +184,7 @@ func ecrecover(header *types.Header, sigCache *lru.ARCCache, chainId *big.Int) (
|
||||
signature := header.Extra[len(header.Extra)-extraSeal:]
|
||||
|
||||
// Recover the public key and the Ethereum address
|
||||
pubkey, err := crypto.Ecrecover(SealHash(header, chainId).Bytes(), signature)
|
||||
pubkey, err := crypto.Ecrecover(types.SealHash(header, chainId).Bytes(), signature)
|
||||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
@@ -199,7 +204,7 @@ func ecrecover(header *types.Header, sigCache *lru.ARCCache, chainId *big.Int) (
|
||||
// or not), which could be abused to produce different hashes for the same header.
|
||||
func ParliaRLP(header *types.Header, chainId *big.Int) []byte {
|
||||
b := new(bytes.Buffer)
|
||||
encodeSigHeader(b, header, chainId)
|
||||
types.EncodeSigHeader(b, header, chainId)
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
@@ -226,6 +231,7 @@ type Parlia struct {
|
||||
validatorSetABIBeforeLuban abi.ABI
|
||||
validatorSetABI abi.ABI
|
||||
slashABI abi.ABI
|
||||
stakeHubABI abi.ABI
|
||||
|
||||
// The fields below are for testing only
|
||||
fakeDiff bool // Skip difficulty verifications
|
||||
@@ -240,6 +246,7 @@ func New(
|
||||
) *Parlia {
|
||||
// get parlia config
|
||||
parliaConfig := chainConfig.Parlia
|
||||
log.Info("Parlia", "chainConfig", chainConfig)
|
||||
|
||||
// Set any missing consensus parameters to their defaults
|
||||
if parliaConfig != nil && parliaConfig.Epoch == 0 {
|
||||
@@ -267,6 +274,10 @@ func New(
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
stABI, err := abi.JSON(strings.NewReader(stakeABI))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
c := &Parlia{
|
||||
chainConfig: chainConfig,
|
||||
config: parliaConfig,
|
||||
@@ -278,6 +289,7 @@ func New(
|
||||
validatorSetABIBeforeLuban: vABIBeforeLuban,
|
||||
validatorSetABI: vABI,
|
||||
slashABI: sABI,
|
||||
stakeHubABI: stABI,
|
||||
signer: types.LatestSigner(chainConfig),
|
||||
}
|
||||
|
||||
@@ -445,7 +457,11 @@ func (p *Parlia) verifyVoteAttestation(chain consensus.ChainHeaderReader, header
|
||||
// The source block should be the highest justified block.
|
||||
sourceNumber := attestation.Data.SourceNumber
|
||||
sourceHash := attestation.Data.SourceHash
|
||||
justifiedBlockNumber, justifiedBlockHash, err := p.GetJustifiedNumberAndHash(chain, parent)
|
||||
headers := []*types.Header{parent}
|
||||
if len(parents) > 0 {
|
||||
headers = parents
|
||||
}
|
||||
justifiedBlockNumber, justifiedBlockHash, err := p.GetJustifiedNumberAndHash(chain, headers)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unexpected error when getting the highest justified number and hash")
|
||||
}
|
||||
@@ -566,6 +582,24 @@ func (p *Parlia) verifyHeader(chain consensus.ChainHeaderReader, header *types.H
|
||||
return err
|
||||
}
|
||||
|
||||
// Verify existence / non-existence of withdrawalsHash.
|
||||
if header.WithdrawalsHash != nil {
|
||||
return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash)
|
||||
}
|
||||
// Verify the existence / non-existence of excessBlobGas
|
||||
cancun := chain.Config().IsCancun(header.Number, header.Time)
|
||||
if !cancun && header.ExcessBlobGas != nil {
|
||||
return fmt.Errorf("invalid excessBlobGas: have %d, expected nil", header.ExcessBlobGas)
|
||||
}
|
||||
if !cancun && header.BlobGasUsed != nil {
|
||||
return fmt.Errorf("invalid blobGasUsed: have %d, expected nil", header.BlobGasUsed)
|
||||
}
|
||||
if cancun {
|
||||
if err := eip4844.VerifyEIP4844Header(parent, header); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// All basic checks passed, verify cascading fields
|
||||
return p.verifyCascadingFields(chain, header, parents)
|
||||
}
|
||||
@@ -661,7 +695,7 @@ func (p *Parlia) snapshot(chain consensus.ChainHeaderReader, number uint64, hash
|
||||
// If we're at the genesis, snapshot the initial state. Alternatively if we have
|
||||
// piled up more headers than allowed to be reorged (chain reinit from a freezer),
|
||||
// consider the checkpoint trusted and snapshot it.
|
||||
if number == 0 || (number%p.config.Epoch == 0 && (len(headers) > params.FullImmutabilityThreshold)) {
|
||||
if number == 0 || (number%p.config.Epoch == 0 && (len(headers) > params.FullImmutabilityThreshold/10)) {
|
||||
checkpoint := chain.GetHeaderByNumber(number)
|
||||
if checkpoint != nil {
|
||||
// get checkpoint data
|
||||
@@ -675,10 +709,12 @@ func (p *Parlia) snapshot(chain consensus.ChainHeaderReader, number uint64, hash
|
||||
|
||||
// new snapshot
|
||||
snap = newSnapshot(p.config, p.signatures, number, hash, validators, voteAddrs, p.ethAPI)
|
||||
if err := snap.store(p.db); err != nil {
|
||||
return nil, err
|
||||
if snap.Number%checkpointInterval == 0 { // snapshot will only be loaded when snap.Number%checkpointInterval == 0
|
||||
if err := snap.store(p.db); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Info("Stored checkpoint snapshot to disk", "number", number, "hash", hash)
|
||||
}
|
||||
log.Info("Stored checkpoint snapshot to disk", "number", number, "hash", hash)
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -809,6 +845,13 @@ func (p *Parlia) prepareValidators(header *types.Header) error {
|
||||
}
|
||||
} else {
|
||||
header.Extra = append(header.Extra, byte(len(newValidators)))
|
||||
if p.chainConfig.IsOnLuban(header.Number) {
|
||||
voteAddressMap = make(map[common.Address]*types.BLSPublicKey, len(newValidators))
|
||||
var zeroBlsKey types.BLSPublicKey
|
||||
for _, validator := range newValidators {
|
||||
voteAddressMap[validator] = &zeroBlsKey
|
||||
}
|
||||
}
|
||||
for _, validator := range newValidators {
|
||||
header.Extra = append(header.Extra, validator.Bytes()...)
|
||||
header.Extra = append(header.Extra, voteAddressMap[validator].Bytes()...)
|
||||
@@ -842,7 +885,7 @@ func (p *Parlia) assembleVoteAttestation(chain consensus.ChainHeaderReader, head
|
||||
|
||||
// Prepare vote attestation
|
||||
// Prepare vote data
|
||||
justifiedBlockNumber, justifiedBlockHash, err := p.GetJustifiedNumberAndHash(chain, parent)
|
||||
justifiedBlockNumber, justifiedBlockHash, err := p.GetJustifiedNumberAndHash(chain, []*types.Header{parent})
|
||||
if err != nil {
|
||||
return fmt.Errorf("unexpected error when getting the highest justified number and hash")
|
||||
}
|
||||
@@ -875,7 +918,7 @@ func (p *Parlia) assembleVoteAttestation(chain consensus.ChainHeaderReader, head
|
||||
// Prepare vote address bitset.
|
||||
for _, valInfo := range snap.Validators {
|
||||
if _, ok := voteAddrSet[valInfo.VoteAddress]; ok {
|
||||
attestation.VoteAddressSet |= 1 << (valInfo.Index - 1) //Index is offset by 1
|
||||
attestation.VoteAddressSet |= 1 << (valInfo.Index - 1) // Index is offset by 1
|
||||
}
|
||||
}
|
||||
validatorsBitSet := bitset.From([]uint64{uint64(attestation.VoteAddressSet)})
|
||||
@@ -931,7 +974,7 @@ func (p *Parlia) Prepare(chain consensus.ChainHeaderReader, header *types.Header
|
||||
}
|
||||
|
||||
header.Extra = header.Extra[:extraVanity-nextForkHashSize]
|
||||
nextForkHash := forkid.NewID(p.chainConfig, p.genesisHash, number, header.Time).Hash
|
||||
nextForkHash := forkid.NextForkHash(p.chainConfig, p.genesisHash, number, header.Time)
|
||||
header.Extra = append(header.Extra, nextForkHash[:]...)
|
||||
|
||||
if err := p.prepareValidators(header); err != nil {
|
||||
@@ -970,6 +1013,13 @@ func (p *Parlia) verifyValidators(header *types.Header) error {
|
||||
return errMismatchingEpochValidators
|
||||
}
|
||||
validatorsBytes = make([]byte, validatorsNumber*validatorBytesLength)
|
||||
if p.chainConfig.IsOnLuban(header.Number) {
|
||||
voteAddressMap = make(map[common.Address]*types.BLSPublicKey, len(newValidators))
|
||||
var zeroBlsKey types.BLSPublicKey
|
||||
for _, validator := range newValidators {
|
||||
voteAddressMap[validator] = &zeroBlsKey
|
||||
}
|
||||
}
|
||||
for i, validator := range newValidators {
|
||||
copy(validatorsBytes[i*validatorBytesLength:], validator.Bytes())
|
||||
copy(validatorsBytes[i*validatorBytesLength+common.AddressLength:], voteAddressMap[validator].Bytes())
|
||||
@@ -1065,7 +1115,7 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nextForkHash := forkid.NewID(p.chainConfig, p.genesisHash, number, header.Time).Hash
|
||||
nextForkHash := forkid.NextForkHash(p.chainConfig, p.genesisHash, number, header.Time)
|
||||
if !snap.isMajorityFork(hex.EncodeToString(nextForkHash[:])) {
|
||||
log.Debug("there is a possible fork, and your client is not the majority. Please check...", "nextForkHash", hex.EncodeToString(nextForkHash[:]))
|
||||
}
|
||||
@@ -1077,6 +1127,22 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade
|
||||
|
||||
cx := chainContext{Chain: chain, parlia: p}
|
||||
|
||||
parent := chain.GetHeaderByHash(header.ParentHash)
|
||||
if parent == nil {
|
||||
return errors.New("parent not found")
|
||||
}
|
||||
|
||||
if p.chainConfig.IsFeynman(header.Number, header.Time) {
|
||||
systemcontracts.UpgradeBuildInSystemContract(p.chainConfig, header.Number, parent.Time, header.Time, state)
|
||||
}
|
||||
|
||||
if p.chainConfig.IsOnFeynman(header.Number, parent.Time, header.Time) {
|
||||
err := p.initializeFeynmanContract(state, header, cx, txs, receipts, systemTxs, usedGas, false)
|
||||
if err != nil {
|
||||
log.Error("init feynman contract failed", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
// No block rewards in PoA, so the state remains as is and uncles are dropped
|
||||
if header.Number.Cmp(common.Big1) == 0 {
|
||||
err := p.initContract(state, header, cx, txs, receipts, systemTxs, usedGas, false)
|
||||
@@ -1118,6 +1184,17 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// update validators every day
|
||||
if p.chainConfig.IsFeynman(header.Number, header.Time) && isBreatheBlock(parent.Time, header.Time) {
|
||||
// we should avoid update validators in the Feynman upgrade block
|
||||
if !p.chainConfig.IsOnFeynman(header.Number, parent.Time, header.Time) {
|
||||
if err := p.updateValidatorSetV2(state, header, cx, txs, receipts, systemTxs, usedGas, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(*systemTxs) > 0 {
|
||||
return errors.New("the length of systemTxs do not match")
|
||||
}
|
||||
@@ -1136,6 +1213,23 @@ func (p *Parlia) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *
|
||||
if receipts == nil {
|
||||
receipts = make([]*types.Receipt, 0)
|
||||
}
|
||||
|
||||
parent := chain.GetHeaderByHash(header.ParentHash)
|
||||
if parent == nil {
|
||||
return nil, nil, errors.New("parent not found")
|
||||
}
|
||||
|
||||
if p.chainConfig.IsFeynman(header.Number, header.Time) {
|
||||
systemcontracts.UpgradeBuildInSystemContract(p.chainConfig, header.Number, parent.Time, header.Time, state)
|
||||
}
|
||||
|
||||
if p.chainConfig.IsOnFeynman(header.Number, parent.Time, header.Time) {
|
||||
err := p.initializeFeynmanContract(state, header, cx, &txs, &receipts, nil, &header.GasUsed, true)
|
||||
if err != nil {
|
||||
log.Error("init feynman contract failed", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
if header.Number.Cmp(common.Big1) == 0 {
|
||||
err := p.initContract(state, header, cx, &txs, &receipts, nil, &header.GasUsed, true)
|
||||
if err != nil {
|
||||
@@ -1180,6 +1274,16 @@ func (p *Parlia) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *
|
||||
}
|
||||
}
|
||||
|
||||
// update validators every day
|
||||
if p.chainConfig.IsFeynman(header.Number, header.Time) && isBreatheBlock(parent.Time, header.Time) {
|
||||
// we should avoid update validators in the Feynman upgrade block
|
||||
if !p.chainConfig.IsOnFeynman(header.Number, parent.Time, header.Time) {
|
||||
if err := p.updateValidatorSetV2(state, header, cx, &txs, &receipts, nil, &header.GasUsed, true); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// should not happen. Once happen, stop the node is better than broadcast the block
|
||||
if header.GasLimit < header.GasUsed {
|
||||
return nil, nil, errors.New("gas consumption of system txs exceed the gas limit")
|
||||
@@ -1230,7 +1334,7 @@ func (p *Parlia) VerifyVote(chain consensus.ChainHeaderReader, vote *types.VoteE
|
||||
return fmt.Errorf("target number mismatch")
|
||||
}
|
||||
|
||||
justifiedBlockNumber, justifiedBlockHash, err := p.GetJustifiedNumberAndHash(chain, header)
|
||||
justifiedBlockNumber, justifiedBlockHash, err := p.GetJustifiedNumberAndHash(chain, []*types.Header{header})
|
||||
if err != nil {
|
||||
log.Error("failed to get the highest justified number and hash", "headerNumber", header.Number, "headerHash", header.Hash())
|
||||
return fmt.Errorf("unexpected error when getting the highest justified number and hash")
|
||||
@@ -1382,7 +1486,7 @@ func (p *Parlia) Seal(chain consensus.ChainHeaderReader, block *types.Block, res
|
||||
select {
|
||||
case results <- block.WithSeal(header):
|
||||
default:
|
||||
log.Warn("Sealing result is not read by miner", "sealhash", SealHash(header, p.chainConfig.ChainID))
|
||||
log.Warn("Sealing result is not read by miner", "sealhash", types.SealHash(header, p.chainConfig.ChainID))
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -1456,7 +1560,7 @@ func CalcDifficulty(snap *Snapshot, signer common.Address) *big.Int {
|
||||
// So it's not the real hash of a block, just used as unique id to distinguish task
|
||||
func (p *Parlia) SealHash(header *types.Header) (hash common.Hash) {
|
||||
hasher := sha3.NewLegacyKeccak256()
|
||||
encodeSigHeaderWithoutVoteAttestation(hasher, header, p.chainConfig.ChainID)
|
||||
types.EncodeSigHeaderWithoutVoteAttestation(hasher, header, p.chainConfig.ChainID)
|
||||
hasher.Sum(hash[:0])
|
||||
return hash
|
||||
}
|
||||
@@ -1514,19 +1618,18 @@ func (p *Parlia) getCurrentValidators(blockHash common.Hash, blockNum *big.Int)
|
||||
|
||||
var valSet []common.Address
|
||||
var voteAddrSet []types.BLSPublicKey
|
||||
|
||||
if err := p.validatorSetABI.UnpackIntoInterface(&[]interface{}{&valSet, &voteAddrSet}, method, result); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
voteAddrmap := make(map[common.Address]*types.BLSPublicKey, len(valSet))
|
||||
voteAddrMap := make(map[common.Address]*types.BLSPublicKey, len(valSet))
|
||||
for i := 0; i < len(valSet); i++ {
|
||||
voteAddrmap[valSet[i]] = &(voteAddrSet)[i]
|
||||
voteAddrMap[valSet[i]] = &(voteAddrSet)[i]
|
||||
}
|
||||
return valSet, voteAddrmap, nil
|
||||
return valSet, voteAddrMap, nil
|
||||
}
|
||||
|
||||
// slash spoiled validators
|
||||
// distributeIncoming distributes system incoming of the block
|
||||
func (p *Parlia) distributeIncoming(val common.Address, state *state.StateDB, header *types.Header, chain core.ChainContext,
|
||||
txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mining bool) error {
|
||||
coinbase := header.Coinbase
|
||||
@@ -1537,9 +1640,10 @@ func (p *Parlia) distributeIncoming(val common.Address, state *state.StateDB, he
|
||||
state.SetBalance(consensus.SystemAddress, big.NewInt(0))
|
||||
state.AddBalance(coinbase, balance)
|
||||
|
||||
doDistributeSysReward := state.GetBalance(common.HexToAddress(systemcontracts.SystemRewardContract)).Cmp(maxSystemBalance) < 0
|
||||
doDistributeSysReward := !p.chainConfig.IsKepler(header.Number, header.Time) &&
|
||||
state.GetBalance(common.HexToAddress(systemcontracts.SystemRewardContract)).Cmp(maxSystemBalance) < 0
|
||||
if doDistributeSysReward {
|
||||
var rewards = new(big.Int)
|
||||
rewards := new(big.Int)
|
||||
rewards = rewards.Rsh(balance, systemRewardPercent)
|
||||
if rewards.Cmp(common.Big0) > 0 {
|
||||
err := p.distributeToSystem(rewards, state, header, chain, txs, receipts, receivedTxs, usedGas, mining)
|
||||
@@ -1615,7 +1719,7 @@ func (p *Parlia) distributeToSystem(amount *big.Int, state *state.StateDB, heade
|
||||
return p.applyTransaction(msg, state, header, chain, txs, receipts, receivedTxs, usedGas, mining)
|
||||
}
|
||||
|
||||
// slash spoiled validators
|
||||
// distributeToValidator deposits validator reward to validator contract
|
||||
func (p *Parlia) distributeToValidator(amount *big.Int, validator common.Address,
|
||||
state *state.StateDB, header *types.Header, chain core.ChainContext,
|
||||
txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mining bool) error {
|
||||
@@ -1710,24 +1814,25 @@ func (p *Parlia) applyTransaction(
|
||||
receipt.BlockNumber = header.Number
|
||||
receipt.TransactionIndex = uint(state.TxIndex())
|
||||
*receipts = append(*receipts, receipt)
|
||||
state.SetNonce(msg.From(), nonce+1)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetJustifiedNumberAndHash returns the highest justified block's number and hash on the branch including and before `header`
|
||||
func (p *Parlia) GetJustifiedNumberAndHash(chain consensus.ChainHeaderReader, header *types.Header) (uint64, common.Hash, error) {
|
||||
if chain == nil || header == nil {
|
||||
// GetJustifiedNumberAndHash retrieves the number and hash of the highest justified block
|
||||
// within the branch including `headers` and utilizing the latest element as the head.
|
||||
func (p *Parlia) GetJustifiedNumberAndHash(chain consensus.ChainHeaderReader, headers []*types.Header) (uint64, common.Hash, error) {
|
||||
if chain == nil || len(headers) == 0 || headers[len(headers)-1] == nil {
|
||||
return 0, common.Hash{}, fmt.Errorf("illegal chain or header")
|
||||
}
|
||||
snap, err := p.snapshot(chain, header.Number.Uint64(), header.Hash(), nil)
|
||||
head := headers[len(headers)-1]
|
||||
snap, err := p.snapshot(chain, head.Number.Uint64(), head.Hash(), headers)
|
||||
if err != nil {
|
||||
log.Error("Unexpected error when getting snapshot",
|
||||
"error", err, "blockNumber", header.Number.Uint64(), "blockHash", header.Hash())
|
||||
"error", err, "blockNumber", head.Number.Uint64(), "blockHash", head.Hash())
|
||||
return 0, common.Hash{}, err
|
||||
}
|
||||
|
||||
if snap.Attestation == nil {
|
||||
if p.chainConfig.IsLuban(header.Number) {
|
||||
if p.chainConfig.IsLuban(head.Number) {
|
||||
log.Debug("once one attestation generated, attestation of snap would not be nil forever basically")
|
||||
}
|
||||
return 0, chain.GetHeaderByNumber(0).Hash(), nil
|
||||
@@ -1759,62 +1864,6 @@ func (p *Parlia) GetFinalizedHeader(chain consensus.ChainHeaderReader, header *t
|
||||
}
|
||||
|
||||
// =========================== utility function ==========================
|
||||
// SealHash returns the hash of a block prior to it being sealed.
|
||||
func SealHash(header *types.Header, chainId *big.Int) (hash common.Hash) {
|
||||
hasher := sha3.NewLegacyKeccak256()
|
||||
encodeSigHeader(hasher, header, chainId)
|
||||
hasher.Sum(hash[:0])
|
||||
return hash
|
||||
}
|
||||
|
||||
func encodeSigHeader(w io.Writer, header *types.Header, chainId *big.Int) {
|
||||
err := rlp.Encode(w, []interface{}{
|
||||
chainId,
|
||||
header.ParentHash,
|
||||
header.UncleHash,
|
||||
header.Coinbase,
|
||||
header.Root,
|
||||
header.TxHash,
|
||||
header.ReceiptHash,
|
||||
header.Bloom,
|
||||
header.Difficulty,
|
||||
header.Number,
|
||||
header.GasLimit,
|
||||
header.GasUsed,
|
||||
header.Time,
|
||||
header.Extra[:len(header.Extra)-extraSeal], // this will panic if extra is too short, should check before calling encodeSigHeader
|
||||
header.MixDigest,
|
||||
header.Nonce,
|
||||
})
|
||||
if err != nil {
|
||||
panic("can't encode: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func encodeSigHeaderWithoutVoteAttestation(w io.Writer, header *types.Header, chainId *big.Int) {
|
||||
err := rlp.Encode(w, []interface{}{
|
||||
chainId,
|
||||
header.ParentHash,
|
||||
header.UncleHash,
|
||||
header.Coinbase,
|
||||
header.Root,
|
||||
header.TxHash,
|
||||
header.ReceiptHash,
|
||||
header.Bloom,
|
||||
header.Difficulty,
|
||||
header.Number,
|
||||
header.GasLimit,
|
||||
header.GasUsed,
|
||||
header.Time,
|
||||
header.Extra[:extraVanity], // this will panic if extra is too short, should check before calling encodeSigHeaderWithoutVoteAttestation
|
||||
header.MixDigest,
|
||||
header.Nonce,
|
||||
})
|
||||
if err != nil {
|
||||
panic("can't encode: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parlia) backOffTime(snap *Snapshot, header *types.Header, val common.Address) uint64 {
|
||||
if snap.inturn(val) {
|
||||
return 0
|
||||
@@ -1924,7 +1973,7 @@ func applyMessage(
|
||||
chainConfig *params.ChainConfig,
|
||||
chainContext core.ChainContext,
|
||||
) (uint64, error) {
|
||||
// TODO: state.Prepare should be called here, now accessList related EIP not affect systemtxs
|
||||
// TODO(Nathan): state.Prepare should be called here, now accessList related EIP not affect systemtxs
|
||||
// EIP1153 may cause a critical issue in the future
|
||||
// Create a new context to be used in the EVM environment
|
||||
context := core.NewEVMBlockContext(header, chainContext, nil)
|
||||
@@ -1932,6 +1981,8 @@ func applyMessage(
|
||||
// about the transaction and calling mechanisms.
|
||||
vmenv := vm.NewEVM(context, vm.TxContext{Origin: msg.From(), GasPrice: big.NewInt(0)}, state, chainConfig, vm.Config{})
|
||||
// Apply the transaction to the current state (included in the env)
|
||||
// Increment the nonce for the next transaction
|
||||
state.SetNonce(msg.From(), state.GetNonce(msg.From())+1)
|
||||
ret, returnGas, err := vmenv.Call(
|
||||
vm.AccountRef(msg.From()),
|
||||
*msg.To(),
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package parlia
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
mrand "math/rand"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/crypto/sha3"
|
||||
@@ -47,7 +48,7 @@ func simulateValidatorOutOfService(totalValidators int, downValidators int) {
|
||||
validators[i] = true
|
||||
down[i] = i
|
||||
}
|
||||
rand.Shuffle(totalValidators, func(i, j int) {
|
||||
mrand.Shuffle(totalValidators, func(i, j int) {
|
||||
down[i], down[j] = down[j], down[i]
|
||||
})
|
||||
for i := 0; i < downValidators; i++ {
|
||||
@@ -125,8 +126,8 @@ func simulateValidatorOutOfService(totalValidators int, downValidators int) {
|
||||
}
|
||||
|
||||
func producerBlockDelay(candidates map[int]bool, height, numOfValidators int) (int, uint64) {
|
||||
s := rand.NewSource(int64(height))
|
||||
r := rand.New(s)
|
||||
s := mrand.NewSource(int64(height))
|
||||
r := mrand.New(s)
|
||||
n := numOfValidators
|
||||
backOffSteps := make([]int, 0, n)
|
||||
for idx := 0; idx < n; idx++ {
|
||||
|
||||
@@ -199,6 +199,9 @@ func (s *Snapshot) updateAttestation(header *types.Header, chainConfig *params.C
|
||||
}
|
||||
|
||||
// Update attestation
|
||||
// Two scenarios for s.Attestation being nil:
|
||||
// 1) The first attestation is assembled.
|
||||
// 2) The snapshot on disk is missing, prompting the creation of a new snapshot using `newSnapshot`.
|
||||
if s.Attestation != nil && attestation.Data.SourceNumber+1 != attestation.Data.TargetNumber {
|
||||
s.Attestation.TargetNumber = attestation.Data.TargetNumber
|
||||
s.Attestation.TargetHash = attestation.Data.TargetHash
|
||||
|
||||
@@ -35,6 +35,11 @@ import (
|
||||
|
||||
// Tests that simple header verification works, for both good and bad blocks.
|
||||
func TestHeaderVerification(t *testing.T) {
|
||||
testHeaderVerification(t, rawdb.HashScheme)
|
||||
testHeaderVerification(t, rawdb.PathScheme)
|
||||
}
|
||||
|
||||
func testHeaderVerification(t *testing.T, scheme string) {
|
||||
// Create a simple chain to verify
|
||||
var (
|
||||
gspec = &Genesis{Config: params.TestChainConfig}
|
||||
@@ -45,7 +50,7 @@ func TestHeaderVerification(t *testing.T) {
|
||||
headers[i] = block.Header()
|
||||
}
|
||||
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
|
||||
chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
defer chain.Stop()
|
||||
|
||||
for i := 0; i < len(blocks); i++ {
|
||||
|
||||
@@ -24,11 +24,11 @@ import (
|
||||
"math/big"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
mapset "github.com/deckarep/golang-set/v2"
|
||||
exlru "github.com/hashicorp/golang-lru"
|
||||
"golang.org/x/crypto/sha3"
|
||||
|
||||
@@ -42,6 +42,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||
"github.com/ethereum/go-ethereum/core/systemcontracts"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
@@ -53,10 +54,16 @@ import (
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/ethereum/go-ethereum/trie/triedb/hashdb"
|
||||
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
var (
|
||||
badBlockRecords = mapset.NewSet[common.Hash]()
|
||||
badBlockRecordslimit = 1000
|
||||
badBlockGauge = metrics.NewRegisteredGauge("chain/insert/badBlock", nil)
|
||||
|
||||
headBlockGauge = metrics.NewRegisteredGauge("chain/head/block", nil)
|
||||
headHeaderGauge = metrics.NewRegisteredGauge("chain/head/header", nil)
|
||||
headFastBlockGauge = metrics.NewRegisteredGauge("chain/head/receipt", nil)
|
||||
@@ -141,7 +148,7 @@ const (
|
||||
)
|
||||
|
||||
// CacheConfig contains the configuration values for the trie database
|
||||
// that's resident in a blockchain.
|
||||
// and state snapshot these are resident in a blockchain.
|
||||
type CacheConfig struct {
|
||||
TrieCleanLimit int // Memory allowance (MB) to use for caching trie nodes in memory
|
||||
TrieCleanNoPrefetch bool // Whether to disable heuristic state prefetching for followup blocks
|
||||
@@ -152,11 +159,37 @@ type CacheConfig struct {
|
||||
Preimages bool // Whether to store preimage of trie key to the disk
|
||||
TriesInMemory uint64 // How many tries keeps in memory
|
||||
NoTries bool // Insecure settings. Do not have any tries in databases if enabled.
|
||||
StateHistory uint64 // Number of blocks from head whose state histories are reserved.
|
||||
StateScheme string // Scheme used to store ethereum states and merkle tree nodes on top
|
||||
PathSyncFlush bool // Whether sync flush the trienodebuffer of pathdb to disk.
|
||||
|
||||
SnapshotNoBuild bool // Whether the background generation is allowed
|
||||
SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it
|
||||
}
|
||||
|
||||
// triedbConfig derives the configures for trie database.
|
||||
func (c *CacheConfig) triedbConfig() *trie.Config {
|
||||
config := &trie.Config{
|
||||
Cache: c.TrieCleanLimit,
|
||||
Preimages: c.Preimages,
|
||||
NoTries: c.NoTries,
|
||||
}
|
||||
if c.StateScheme == rawdb.HashScheme {
|
||||
config.HashDB = &hashdb.Config{
|
||||
CleanCacheSize: c.TrieCleanLimit * 1024 * 1024,
|
||||
}
|
||||
}
|
||||
if c.StateScheme == rawdb.PathScheme {
|
||||
config.PathDB = &pathdb.Config{
|
||||
SyncFlush: c.PathSyncFlush,
|
||||
StateHistory: c.StateHistory,
|
||||
CleanCacheSize: c.TrieCleanLimit * 1024 * 1024,
|
||||
DirtyCacheSize: c.TrieDirtyLimit * 1024 * 1024,
|
||||
}
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
// defaultCacheConfig are the default caching values if none are specified by the
|
||||
// user (also used during testing).
|
||||
var defaultCacheConfig = &CacheConfig{
|
||||
@@ -166,6 +199,15 @@ var defaultCacheConfig = &CacheConfig{
|
||||
SnapshotLimit: 256,
|
||||
TriesInMemory: 128,
|
||||
SnapshotWait: true,
|
||||
StateScheme: rawdb.HashScheme,
|
||||
}
|
||||
|
||||
// DefaultCacheConfigWithScheme returns a deep copied default cache config with
|
||||
// a provided trie node scheme.
|
||||
func DefaultCacheConfigWithScheme(scheme string) *CacheConfig {
|
||||
config := *defaultCacheConfig
|
||||
config.StateScheme = scheme
|
||||
return &config
|
||||
}
|
||||
|
||||
type BlockChainOption func(*BlockChain) (*BlockChain, error)
|
||||
@@ -279,11 +321,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||
diffLayerChanCache, _ := exlru.New(diffLayerCacheLimit)
|
||||
|
||||
// Open trie database with provided config
|
||||
triedb := trie.NewDatabaseWithConfig(db, &trie.Config{
|
||||
Cache: cacheConfig.TrieCleanLimit,
|
||||
Preimages: cacheConfig.Preimages,
|
||||
NoTries: cacheConfig.NoTries,
|
||||
})
|
||||
triedb := trie.NewDatabase(db, cacheConfig.triedbConfig())
|
||||
// Setup the genesis block, commit the provided genesis specification
|
||||
// to database if the genesis block is not present yet, or load the
|
||||
// stored one from database.
|
||||
@@ -291,13 +329,18 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||
if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
|
||||
return nil, genesisErr
|
||||
}
|
||||
log.Info("")
|
||||
log.Info(strings.Repeat("-", 153))
|
||||
for _, line := range strings.Split(chainConfig.Description(), "\n") {
|
||||
log.Info(line)
|
||||
}
|
||||
log.Info(strings.Repeat("-", 153))
|
||||
log.Info("")
|
||||
systemcontracts.GenesisHash = genesisHash
|
||||
log.Info("Initialised chain configuration", "config", chainConfig)
|
||||
// Description of chainConfig is empty now
|
||||
/*
|
||||
log.Info("")
|
||||
log.Info(strings.Repeat("-", 153))
|
||||
for _, line := range strings.Split(chainConfig.Description(), "\n") {
|
||||
log.Info(line)
|
||||
}
|
||||
log.Info(strings.Repeat("-", 153))
|
||||
log.Info("")
|
||||
*/
|
||||
|
||||
bc := &BlockChain{
|
||||
chainConfig: chainConfig,
|
||||
@@ -355,7 +398,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||
}
|
||||
// Make sure the state associated with the block is available
|
||||
head := bc.CurrentBlock()
|
||||
if !bc.HasState(head.Root) {
|
||||
if !bc.stateCache.NoTries() && !bc.HasState(head.Root) {
|
||||
// Head state is missing, before the state recovery, find out the
|
||||
// disk layer point of snapshot(if it's enabled). Make sure the
|
||||
// rewound point is lower than disk layer.
|
||||
@@ -363,8 +406,14 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||
if bc.cacheConfig.SnapshotLimit > 0 {
|
||||
diskRoot = rawdb.ReadSnapshotRoot(bc.db)
|
||||
}
|
||||
if bc.triedb.Scheme() == rawdb.PathScheme {
|
||||
recoverable, _ := bc.triedb.Recoverable(diskRoot)
|
||||
if !bc.HasState(diskRoot) && !recoverable {
|
||||
diskRoot = bc.triedb.Head()
|
||||
}
|
||||
}
|
||||
if diskRoot != (common.Hash{}) {
|
||||
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash(), "snaproot", diskRoot)
|
||||
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash(), "diskRoot", diskRoot)
|
||||
|
||||
snapDisk, err := bc.setHeadBeyondRoot(head.Number.Uint64(), 0, diskRoot, true)
|
||||
if err != nil {
|
||||
@@ -510,7 +559,7 @@ func (bc *BlockChain) GetVMConfig() *vm.Config {
|
||||
return &bc.vmConfig
|
||||
}
|
||||
|
||||
func (bc *BlockChain) cacheReceipts(hash common.Hash, receipts types.Receipts) {
|
||||
func (bc *BlockChain) cacheReceipts(hash common.Hash, receipts types.Receipts, block *types.Block) {
|
||||
// TODO, This is a hot fix for the block hash of logs is `0x0000000000000000000000000000000000000000000000000000000000000000` for system tx
|
||||
// Please check details in https://github.com/bnb-chain/bsc/issues/443
|
||||
// This is a temporary fix, the official fix should be a hard fork.
|
||||
@@ -521,6 +570,16 @@ func (bc *BlockChain) cacheReceipts(hash common.Hash, receipts types.Receipts) {
|
||||
receipts[i].Logs[j].BlockHash = hash
|
||||
}
|
||||
}
|
||||
|
||||
txs := block.Transactions()
|
||||
if len(txs) != len(receipts) {
|
||||
log.Warn("transaction and receipt count mismatch")
|
||||
return
|
||||
}
|
||||
for i, receipt := range receipts {
|
||||
receipt.EffectiveGasPrice = txs[i].EffectiveGasTipValue(block.BaseFee()) // basefee is supposed to be nil or zero
|
||||
}
|
||||
|
||||
bc.receiptsCache.Add(hash, receipts)
|
||||
}
|
||||
|
||||
@@ -580,7 +639,7 @@ func (bc *BlockChain) empty() bool {
|
||||
// GetJustifiedNumber returns the highest justified blockNumber on the branch including and before `header`.
|
||||
func (bc *BlockChain) GetJustifiedNumber(header *types.Header) uint64 {
|
||||
if p, ok := bc.engine.(consensus.PoSA); ok {
|
||||
justifiedBlockNumber, _, err := p.GetJustifiedNumberAndHash(bc, header)
|
||||
justifiedBlockNumber, _, err := p.GetJustifiedNumberAndHash(bc, []*types.Header{header})
|
||||
if err == nil {
|
||||
return justifiedBlockNumber
|
||||
}
|
||||
@@ -653,18 +712,18 @@ func (bc *BlockChain) loadLastState() error {
|
||||
blockTd = bc.GetTd(headBlock.Hash(), headBlock.NumberU64())
|
||||
)
|
||||
if headHeader.Hash() != headBlock.Hash() {
|
||||
log.Info("Loaded most recent local header", "number", headHeader.Number, "hash", headHeader.Hash(), "td", headerTd, "age", common.PrettyAge(time.Unix(int64(headHeader.Time), 0)))
|
||||
log.Info("Loaded most recent local header", "number", headHeader.Number, "hash", headHeader.Hash(), "hash", headHeader.Root, "td", headerTd, "age", common.PrettyAge(time.Unix(int64(headHeader.Time), 0)))
|
||||
}
|
||||
log.Info("Loaded most recent local block", "number", headBlock.Number(), "hash", headBlock.Hash(), "td", blockTd, "age", common.PrettyAge(time.Unix(int64(headBlock.Time()), 0)))
|
||||
log.Info("Loaded most recent local block", "number", headBlock.Number(), "hash", headBlock.Hash(), "root", headBlock.Root(), "td", blockTd, "age", common.PrettyAge(time.Unix(int64(headBlock.Time()), 0)))
|
||||
if headBlock.Hash() != currentSnapBlock.Hash() {
|
||||
snapTd := bc.GetTd(currentSnapBlock.Hash(), currentSnapBlock.Number.Uint64())
|
||||
log.Info("Loaded most recent local snap block", "number", currentSnapBlock.Number, "hash", currentSnapBlock.Hash(), "td", snapTd, "age", common.PrettyAge(time.Unix(int64(currentSnapBlock.Time), 0)))
|
||||
log.Info("Loaded most recent local snap block", "number", currentSnapBlock.Number, "hash", currentSnapBlock.Hash(), "root", currentSnapBlock.Root, "td", snapTd, "age", common.PrettyAge(time.Unix(int64(currentSnapBlock.Time), 0)))
|
||||
}
|
||||
if posa, ok := bc.engine.(consensus.PoSA); ok {
|
||||
if currentFinalizedHeader := posa.GetFinalizedHeader(bc, headHeader); currentFinalizedHeader != nil {
|
||||
if currentFinalizedBlock := bc.GetBlockByHash(currentFinalizedHeader.Hash()); currentFinalizedBlock != nil {
|
||||
finalTd := bc.GetTd(currentFinalizedBlock.Hash(), currentFinalizedBlock.NumberU64())
|
||||
log.Info("Loaded most recent local finalized block", "number", currentFinalizedBlock.Number(), "hash", currentFinalizedBlock.Hash(), "td", finalTd, "age", common.PrettyAge(time.Unix(int64(currentFinalizedBlock.Time()), 0)))
|
||||
log.Info("Loaded most recent local finalized block", "number", currentFinalizedBlock.Number(), "hash", currentFinalizedBlock.Hash(), "root", currentFinalizedBlock.Root(), "td", finalTd, "age", common.PrettyAge(time.Unix(int64(currentFinalizedBlock.Time()), 0)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -764,33 +823,48 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
|
||||
pivot := rawdb.ReadLastPivotNumber(bc.db)
|
||||
frozen, _ := bc.db.Ancients()
|
||||
|
||||
// resetState resets the persistent state to genesis if it's not available.
|
||||
resetState := func() {
|
||||
log.Info("Reset to block with genesis state", "number", bc.genesisBlock.NumberU64(), "hash", bc.genesisBlock.Hash())
|
||||
// Short circuit if the genesis state is already present.
|
||||
if bc.HasState(bc.genesisBlock.Root()) {
|
||||
return
|
||||
}
|
||||
// Reset the state database to empty for committing genesis state.
|
||||
// Note, it should only happen in path-based scheme and Reset function
|
||||
// is also only call-able in this mode.
|
||||
if bc.triedb.Scheme() == rawdb.PathScheme {
|
||||
if err := bc.triedb.Reset(types.EmptyRootHash); err != nil {
|
||||
log.Crit("Failed to clean state", "err", err) // Shouldn't happen
|
||||
}
|
||||
}
|
||||
// Write genesis state into database.
|
||||
if err := CommitGenesisState(bc.db, bc.triedb, bc.genesisBlock.Hash()); err != nil {
|
||||
log.Crit("Failed to commit genesis state", "err", err)
|
||||
}
|
||||
}
|
||||
updateFn := func(db ethdb.KeyValueWriter, header *types.Header) (*types.Header, bool) {
|
||||
// Rewind the blockchain, ensuring we don't end up with a stateless head
|
||||
// block. Note, depth equality is permitted to allow using SetHead as a
|
||||
// chain reparation mechanism without deleting any data!
|
||||
if currentBlock := bc.CurrentBlock(); currentBlock != nil && header.Number.Uint64() <= currentBlock.Number.Uint64() {
|
||||
newHeadBlock := bc.GetBlock(header.Hash(), header.Number.Uint64())
|
||||
lastBlockNum := header.Number.Uint64()
|
||||
if newHeadBlock == nil {
|
||||
log.Error("Gap in the chain, rewinding to genesis", "number", header.Number, "hash", header.Hash())
|
||||
newHeadBlock = bc.genesisBlock
|
||||
resetState()
|
||||
} else {
|
||||
// Block exists, keep rewinding until we find one with state,
|
||||
// keeping rewinding until we exceed the optional threshold
|
||||
// root hash
|
||||
beyondRoot := (root == common.Hash{}) // Flag whether we're beyond the requested root (no root, always true)
|
||||
enoughBeyondCount := false
|
||||
beyondCount := 0
|
||||
|
||||
for {
|
||||
beyondCount++
|
||||
// If a root threshold was requested but not yet crossed, check
|
||||
if root != (common.Hash{}) && !beyondRoot && newHeadBlock.Root() == root {
|
||||
beyondRoot, rootNumber = true, newHeadBlock.NumberU64()
|
||||
}
|
||||
|
||||
enoughBeyondCount = beyondCount > maxBeyondBlocks
|
||||
|
||||
if !bc.HasState(newHeadBlock.Root()) {
|
||||
if !bc.HasState(newHeadBlock.Root()) && !bc.stateRecoverable(newHeadBlock.Root()) {
|
||||
log.Trace("Block state missing, rewinding further", "number", newHeadBlock.NumberU64(), "hash", newHeadBlock.Hash())
|
||||
if pivot == nil || newHeadBlock.NumberU64() > *pivot {
|
||||
parent := bc.GetBlock(newHeadBlock.ParentHash(), newHeadBlock.NumberU64()-1)
|
||||
@@ -801,38 +875,21 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
|
||||
log.Error("Missing block in the middle, aiming genesis", "number", newHeadBlock.NumberU64()-1, "hash", newHeadBlock.ParentHash())
|
||||
newHeadBlock = bc.genesisBlock
|
||||
} else {
|
||||
log.Trace("Rewind passed pivot, aiming genesis", "number", newHeadBlock.NumberU64(), "hash", newHeadBlock.Hash(), "pivot", *pivot)
|
||||
log.Info("Rewind passed pivot, aiming genesis", "number", newHeadBlock.NumberU64(), "hash", newHeadBlock.Hash(), "pivot", *pivot)
|
||||
newHeadBlock = bc.genesisBlock
|
||||
}
|
||||
}
|
||||
if beyondRoot || (enoughBeyondCount && root != common.Hash{}) || newHeadBlock.NumberU64() == 0 {
|
||||
if enoughBeyondCount && (root != common.Hash{}) && rootNumber == 0 {
|
||||
for {
|
||||
lastBlockNum++
|
||||
block := bc.GetBlockByNumber(lastBlockNum)
|
||||
if block == nil {
|
||||
break
|
||||
}
|
||||
if block.Root() == root {
|
||||
rootNumber = block.NumberU64()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if beyondRoot || newHeadBlock.NumberU64() == 0 {
|
||||
if newHeadBlock.NumberU64() == 0 {
|
||||
// Recommit the genesis state into disk in case the rewinding destination
|
||||
// is genesis block and the relevant state is gone. In the future this
|
||||
// rewinding destination can be the earliest block stored in the chain
|
||||
// if the historical chain pruning is enabled. In that case the logic
|
||||
// needs to be improved here.
|
||||
if !bc.HasState(bc.genesisBlock.Root()) {
|
||||
if err := CommitGenesisState(bc.db, bc.triedb, bc.genesisBlock.Hash()); err != nil {
|
||||
log.Crit("Failed to commit genesis state", "err", err)
|
||||
}
|
||||
log.Debug("Recommitted genesis state to disk")
|
||||
resetState()
|
||||
} else if !bc.HasState(newHeadBlock.Root()) {
|
||||
// Rewind to a block with recoverable state. If the state is
|
||||
// missing, run the state recovery here.
|
||||
if err := bc.triedb.Recover(newHeadBlock.Root()); err != nil {
|
||||
log.Crit("Failed to rollback state", "err", err) // Shouldn't happen
|
||||
}
|
||||
}
|
||||
log.Debug("Rewound to block with state", "number", newHeadBlock.NumberU64(), "hash", newHeadBlock.Hash())
|
||||
log.Info("Rewound to block with state", "number", newHeadBlock.NumberU64(), "hash", newHeadBlock.Hash())
|
||||
break
|
||||
}
|
||||
log.Debug("Skipping block with threshold state", "number", newHeadBlock.NumberU64(), "hash", newHeadBlock.Hash(), "root", newHeadBlock.Root())
|
||||
@@ -936,7 +993,13 @@ func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error {
|
||||
if block == nil {
|
||||
return fmt.Errorf("non existent block [%x..]", hash[:4])
|
||||
}
|
||||
// Reset the trie database with the fresh snap synced state.
|
||||
root := block.Root()
|
||||
if bc.triedb.Scheme() == rawdb.PathScheme {
|
||||
if err := bc.triedb.Reset(root); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !bc.HasState(root) {
|
||||
return fmt.Errorf("non existent state [%x..]", root[:4])
|
||||
}
|
||||
@@ -959,11 +1022,6 @@ func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// StateAtWithSharedPool returns a new mutable state based on a particular point in time with sharedStorage
|
||||
func (bc *BlockChain) StateAtWithSharedPool(root common.Hash) (*state.StateDB, error) {
|
||||
return state.NewWithSharedPool(root, bc.stateCache, bc.snaps)
|
||||
}
|
||||
|
||||
// Reset purges the entire blockchain, restoring it to its genesis state.
|
||||
func (bc *BlockChain) Reset() error {
|
||||
return bc.ResetWithGenesisBlock(bc.genesisBlock)
|
||||
@@ -1112,45 +1170,62 @@ func (bc *BlockChain) Stop() {
|
||||
log.Error("Failed to journal state snapshot", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the state of a recent block is also stored to disk before exiting.
|
||||
// We're writing three different states to catch different restart scenarios:
|
||||
// - HEAD: So we don't need to reprocess any blocks in the general case
|
||||
// - HEAD-1: So we don't do large reorgs if our HEAD becomes an uncle
|
||||
// - HEAD-127: So we have a hard limit on the number of blocks reexecuted
|
||||
if !bc.cacheConfig.TrieDirtyDisabled {
|
||||
triedb := bc.triedb
|
||||
|
||||
for _, offset := range []uint64{0, 1, bc.triesInMemory - 1} {
|
||||
if number := bc.CurrentBlock().Number.Uint64(); number > offset {
|
||||
recent := bc.GetBlockByNumber(number - offset)
|
||||
|
||||
log.Info("Writing cached state to disk", "block", recent.Number(), "hash", recent.Hash(), "root", recent.Root())
|
||||
if err := triedb.Commit(recent.Root(), true); err != nil {
|
||||
log.Error("Failed to commit recent state trie", "err", err)
|
||||
} else {
|
||||
rawdb.WriteSafePointBlockNumber(bc.db, recent.NumberU64())
|
||||
if bc.triedb.Scheme() == rawdb.PathScheme {
|
||||
// Ensure that the in-memory trie nodes are journaled to disk properly.
|
||||
if err := bc.triedb.Journal(bc.CurrentBlock().Root); err != nil {
|
||||
log.Info("Failed to journal in-memory trie nodes", "err", err)
|
||||
}
|
||||
} else {
|
||||
// Ensure the state of a recent block is also stored to disk before exiting.
|
||||
// We're writing three different states to catch different restart scenarios:
|
||||
// - HEAD: So we don't need to reprocess any blocks in the general case
|
||||
// - HEAD-1: So we don't do large reorgs if our HEAD becomes an uncle
|
||||
// - HEAD-127: So we have a hard limit on the number of blocks reexecuted
|
||||
if !bc.cacheConfig.TrieDirtyDisabled {
|
||||
triedb := bc.triedb
|
||||
var once sync.Once
|
||||
for _, offset := range []uint64{0, 1, TriesInMemory - 1} {
|
||||
if number := bc.CurrentBlock().Number.Uint64(); number > offset {
|
||||
recent := bc.GetBlockByNumber(number - offset)
|
||||
log.Info("Writing cached state to disk", "block", recent.Number(), "hash", recent.Hash(), "root", recent.Root())
|
||||
if err := triedb.Commit(recent.Root(), true); err != nil {
|
||||
log.Error("Failed to commit recent state trie", "err", err)
|
||||
} else {
|
||||
rawdb.WriteSafePointBlockNumber(bc.db, recent.NumberU64())
|
||||
once.Do(func() {
|
||||
rawdb.WriteHeadBlockHash(bc.db, recent.Hash())
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if snapBase != (common.Hash{}) {
|
||||
log.Info("Writing snapshot state to disk", "root", snapBase)
|
||||
if err := triedb.Commit(snapBase, true); err != nil {
|
||||
log.Error("Failed to commit recent state trie", "err", err)
|
||||
} else {
|
||||
rawdb.WriteSafePointBlockNumber(bc.db, bc.CurrentBlock().Number.Uint64())
|
||||
if snapBase != (common.Hash{}) {
|
||||
log.Info("Writing snapshot state to disk", "root", snapBase)
|
||||
if err := triedb.Commit(snapBase, true); err != nil {
|
||||
log.Error("Failed to commit recent state trie", "err", err)
|
||||
} else {
|
||||
rawdb.WriteSafePointBlockNumber(bc.db, bc.CurrentBlock().Number.Uint64())
|
||||
}
|
||||
}
|
||||
|
||||
if snapBase != (common.Hash{}) {
|
||||
log.Info("Writing snapshot state to disk", "root", snapBase)
|
||||
if err := bc.triedb.Commit(snapBase, true); err != nil {
|
||||
log.Error("Failed to commit recent state trie", "err", err)
|
||||
} else {
|
||||
rawdb.WriteSafePointBlockNumber(bc.db, bc.CurrentBlock().Number.Uint64())
|
||||
}
|
||||
}
|
||||
for !bc.triegc.Empty() {
|
||||
triedb.Dereference(bc.triegc.PopItem())
|
||||
}
|
||||
if _, size, _, _ := triedb.Size(); size != 0 {
|
||||
log.Error("Dangling trie nodes after full cleanup")
|
||||
}
|
||||
}
|
||||
for !bc.triegc.Empty() {
|
||||
go triedb.Dereference(bc.triegc.PopItem())
|
||||
}
|
||||
if size, _ := triedb.Size(); size != 0 {
|
||||
log.Error("Dangling trie nodes after full cleanup")
|
||||
}
|
||||
}
|
||||
// Flush the collected preimages to disk
|
||||
if err := bc.stateCache.TrieDB().Close(); err != nil {
|
||||
log.Error("Failed to close trie db", "err", err)
|
||||
// Close the trie database, release all the held resources as the last step.
|
||||
if err := bc.triedb.Close(); err != nil {
|
||||
log.Error("Failed to close trie database", "err", err)
|
||||
}
|
||||
log.Info("Blockchain stopped")
|
||||
}
|
||||
@@ -1526,6 +1601,12 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
|
||||
bc.commitLock.Lock()
|
||||
defer bc.commitLock.Unlock()
|
||||
|
||||
// If node is running in path mode, skip explicit gc operation
|
||||
// which is unnecessary in this mode.
|
||||
if bc.triedb.Scheme() == rawdb.PathScheme {
|
||||
return nil
|
||||
}
|
||||
|
||||
triedb := bc.stateCache.TrieDB()
|
||||
// If we're running an archive node, always flush
|
||||
if bc.cacheConfig.TrieDirtyDisabled {
|
||||
@@ -1541,8 +1622,8 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
|
||||
if current := block.NumberU64(); current > bc.triesInMemory {
|
||||
// If we exceeded our memory allowance, flush matured singleton nodes to disk
|
||||
var (
|
||||
nodes, imgs = triedb.Size()
|
||||
limit = common.StorageSize(bc.cacheConfig.TrieDirtyLimit) * 1024 * 1024
|
||||
_, nodes, _, imgs = triedb.Size()
|
||||
limit = common.StorageSize(bc.cacheConfig.TrieDirtyLimit) * 1024 * 1024
|
||||
)
|
||||
if nodes > limit || imgs > 4*1024*1024 {
|
||||
triedb.Cap(limit - ethdb.IdealBatchSize)
|
||||
@@ -1980,7 +2061,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
||||
vtime := time.Since(vstart)
|
||||
proctime := time.Since(start) // processing + validation
|
||||
|
||||
bc.cacheReceipts(block.Hash(), receipts)
|
||||
bc.cacheBlock(block.Hash(), block)
|
||||
|
||||
// Update the metrics touched during block processing and validation
|
||||
@@ -2013,6 +2093,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
||||
if err != nil {
|
||||
return it.index, err
|
||||
}
|
||||
|
||||
bc.cacheReceipts(block.Hash(), receipts, block)
|
||||
|
||||
// Update the metrics touched during block commit
|
||||
accountCommitTimer.Update(statedb.AccountCommits) // Account commits are complete, we can mark them
|
||||
storageCommitTimer.Update(statedb.StorageCommits) // Storage commits are complete, we can mark them
|
||||
@@ -2026,8 +2109,8 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
||||
stats.processed++
|
||||
stats.usedGas += usedGas
|
||||
|
||||
dirty, _ := bc.triedb.Size()
|
||||
stats.report(chain, it.index, dirty, setHead)
|
||||
trieDiffNodes, trieBufNodes, trieImmutableBufNodes, _ := bc.triedb.Size()
|
||||
stats.report(chain, it.index, trieDiffNodes, trieBufNodes, trieImmutableBufNodes, setHead)
|
||||
|
||||
if !setHead {
|
||||
// After merge we expect few side chains. Simply count
|
||||
@@ -2201,6 +2284,12 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
||||
)
|
||||
parent := it.previous()
|
||||
for parent != nil && !bc.HasState(parent.Root) {
|
||||
if bc.stateRecoverable(parent.Root) {
|
||||
if err := bc.triedb.Recover(parent.Root); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
break
|
||||
}
|
||||
hashes = append(hashes, parent.Hash())
|
||||
numbers = append(numbers, parent.Number.Uint64())
|
||||
|
||||
@@ -2260,6 +2349,12 @@ func (bc *BlockChain) recoverAncestors(block *types.Block) (common.Hash, error)
|
||||
parent = block
|
||||
)
|
||||
for parent != nil && !bc.HasState(parent.Root()) {
|
||||
if bc.stateRecoverable(parent.Root()) {
|
||||
if err := bc.triedb.Recover(parent.Root()); err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
break
|
||||
}
|
||||
hashes = append(hashes, parent.Hash())
|
||||
numbers = append(numbers, parent.NumberU64())
|
||||
parent = bc.GetBlock(parent.ParentHash(), parent.NumberU64()-1)
|
||||
@@ -2773,6 +2868,7 @@ func (bc *BlockChain) maintainTxIndex() {
|
||||
return
|
||||
}
|
||||
defer sub.Unsubscribe()
|
||||
log.Info("Initialized transaction indexer", "limit", bc.TxLookupLimit())
|
||||
|
||||
for {
|
||||
select {
|
||||
@@ -2824,15 +2920,22 @@ func summarizeBadBlock(block *types.Block, receipts []*types.Receipt, config *pa
|
||||
if vcs != "" {
|
||||
vcs = fmt.Sprintf("\nVCS: %s", vcs)
|
||||
}
|
||||
|
||||
if badBlockRecords.Cardinality() < badBlockRecordslimit {
|
||||
badBlockRecords.Add(block.Hash())
|
||||
badBlockGauge.Update(int64(badBlockRecords.Cardinality()))
|
||||
}
|
||||
|
||||
return fmt.Sprintf(`
|
||||
########## BAD BLOCK #########
|
||||
Block: %v (%#x)
|
||||
Miner: %v
|
||||
Error: %v
|
||||
Platform: %v%v
|
||||
Chain config: %#v
|
||||
Receipts: %v
|
||||
##############################
|
||||
`, block.Number(), block.Hash(), err, platform, vcs, config, receiptString)
|
||||
`, block.Number(), block.Hash(), block.Coinbase(), err, platform, vcs, config, receiptString)
|
||||
}
|
||||
|
||||
// InsertHeaderChain attempts to insert the given header chain in to the local
|
||||
|
||||
@@ -39,7 +39,7 @@ const statsReportLimit = 8 * time.Second
|
||||
|
||||
// report prints statistics if some number of blocks have been processed
|
||||
// or more than a few seconds have passed since the last message.
|
||||
func (st *insertStats) report(chain []*types.Block, index int, dirty common.StorageSize, setHead bool) {
|
||||
func (st *insertStats) report(chain []*types.Block, index int, trieDiffNodes, trieBufNodes, trieImmutableBufNodes common.StorageSize, setHead bool) {
|
||||
// Fetch the timings for the batch
|
||||
var (
|
||||
now = mclock.Now()
|
||||
@@ -56,14 +56,20 @@ func (st *insertStats) report(chain []*types.Block, index int, dirty common.Stor
|
||||
|
||||
// Assemble the log context and send it to the logger
|
||||
context := []interface{}{
|
||||
"number", end.Number(), "hash", end.Hash(),
|
||||
"number", end.Number(), "hash", end.Hash(), "miner", end.Coinbase(),
|
||||
"blocks", st.processed, "txs", txs, "mgas", float64(st.usedGas) / 1000000,
|
||||
"elapsed", common.PrettyDuration(elapsed), "mgasps", float64(st.usedGas) * 1000 / float64(elapsed),
|
||||
}
|
||||
if timestamp := time.Unix(int64(end.Time()), 0); time.Since(timestamp) > time.Minute {
|
||||
context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...)
|
||||
}
|
||||
context = append(context, []interface{}{"dirty", dirty}...)
|
||||
if trieDiffNodes != 0 { // pathdb
|
||||
context = append(context, []interface{}{"triediffs", trieDiffNodes}...)
|
||||
context = append(context, []interface{}{"triedirty", trieBufNodes}...)
|
||||
context = append(context, []interface{}{"trieimutabledirty", trieImmutableBufNodes}...)
|
||||
} else {
|
||||
context = append(context, []interface{}{"triedirty", trieBufNodes}...)
|
||||
}
|
||||
|
||||
if st.queued > 0 {
|
||||
context = append(context, []interface{}{"queued", st.queued}...)
|
||||
|
||||
@@ -71,7 +71,7 @@ func (bc *BlockChain) CurrentSafeBlock() *types.Header {
|
||||
if currentHeader == nil {
|
||||
return nil
|
||||
}
|
||||
_, justifiedBlockHash, err := p.GetJustifiedNumberAndHash(bc, currentHeader)
|
||||
_, justifiedBlockHash, err := p.GetJustifiedNumberAndHash(bc, []*types.Header{currentHeader})
|
||||
if err == nil {
|
||||
return bc.GetHeaderByHash(justifiedBlockHash)
|
||||
}
|
||||
@@ -319,10 +319,16 @@ func (bc *BlockChain) HasBlockAndState(hash common.Hash, number uint64) bool {
|
||||
return bc.HasState(block.Root())
|
||||
}
|
||||
|
||||
// TrieNode retrieves a blob of data associated with a trie node
|
||||
// either from ephemeral in-memory cache, or from persistent storage.
|
||||
func (bc *BlockChain) TrieNode(hash common.Hash) ([]byte, error) {
|
||||
return bc.stateCache.TrieDB().Node(hash)
|
||||
// stateRecoverable checks if the specified state is recoverable.
|
||||
// Note, this function assumes the state is not present, because
|
||||
// state is not treated as recoverable if it's available, thus
|
||||
// false will be returned in this case.
|
||||
func (bc *BlockChain) stateRecoverable(root common.Hash) bool {
|
||||
if bc.triedb.Scheme() == rawdb.HashScheme {
|
||||
return false
|
||||
}
|
||||
result, _ := bc.triedb.Recoverable(root)
|
||||
return result
|
||||
}
|
||||
|
||||
// ContractCodeWithPrefix retrieves a blob of data associated with a contract
|
||||
|
||||
@@ -22,6 +22,7 @@ package core
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -1749,16 +1750,23 @@ func testLongReorgedSnapSyncingDeepRepair(t *testing.T, snapshots bool) {
|
||||
}
|
||||
|
||||
func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||
for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} {
|
||||
testRepairWithScheme(t, tt, snapshots, scheme)
|
||||
}
|
||||
}
|
||||
|
||||
func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme string) {
|
||||
// It's hard to follow the test case, visualize the input
|
||||
//log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||
// fmt.Println(tt.dump(true))
|
||||
|
||||
// Create a temporary persistent database
|
||||
datadir := t.TempDir()
|
||||
ancient := path.Join(datadir, "ancient")
|
||||
|
||||
db, err := rawdb.Open(rawdb.OpenOptions{
|
||||
Directory: datadir,
|
||||
AncientsDirectory: datadir,
|
||||
AncientsDirectory: ancient,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create persistent database: %v", err)
|
||||
@@ -1777,6 +1785,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||
TrieDirtyLimit: 256,
|
||||
TrieTimeLimit: 5 * time.Minute,
|
||||
SnapshotLimit: 0, // Disable snapshot by default
|
||||
StateScheme: scheme,
|
||||
}
|
||||
)
|
||||
defer engine.Close()
|
||||
@@ -1807,7 +1816,9 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
||||
}
|
||||
if tt.commitBlock > 0 {
|
||||
chain.stateCache.TrieDB().Commit(canonblocks[tt.commitBlock-1].Root(), false)
|
||||
if err := chain.triedb.Commit(canonblocks[tt.commitBlock-1].Root(), false); err != nil {
|
||||
t.Fatalf("Failed to flush trie state: %v", err)
|
||||
}
|
||||
if snapshots {
|
||||
if err := chain.snaps.Cap(canonblocks[tt.commitBlock-1].Root(), 0); err != nil {
|
||||
t.Fatalf("Failed to flatten snapshots: %v", err)
|
||||
@@ -1830,21 +1841,21 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||
rawdb.WriteLastPivotNumber(db, *tt.pivotBlock)
|
||||
}
|
||||
// Pull the plug on the database, simulating a hard crash
|
||||
chain.triedb.Close()
|
||||
db.Close()
|
||||
chain.stopWithoutSaving()
|
||||
|
||||
// Start a new blockchain back up and see where the repair leads us
|
||||
db, err = rawdb.Open(rawdb.OpenOptions{
|
||||
Directory: datadir,
|
||||
AncientsDirectory: datadir,
|
||||
AncientsDirectory: ancient,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to reopen persistent database: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
newChain, err := NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
newChain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
@@ -1887,17 +1898,22 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||
// In this case the snapshot layer of B3 is not created because of existent
|
||||
// state.
|
||||
func TestIssue23496(t *testing.T) {
|
||||
testIssue23496(t, rawdb.HashScheme)
|
||||
testIssue23496(t, rawdb.PathScheme)
|
||||
}
|
||||
|
||||
func testIssue23496(t *testing.T, scheme string) {
|
||||
// It's hard to follow the test case, visualize the input
|
||||
//log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||
|
||||
// Create a temporary persistent database
|
||||
datadir := t.TempDir()
|
||||
ancient := path.Join(datadir, "ancient")
|
||||
|
||||
db, err := rawdb.Open(rawdb.OpenOptions{
|
||||
Directory: datadir,
|
||||
AncientsDirectory: datadir,
|
||||
AncientsDirectory: ancient,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create persistent database: %v", err)
|
||||
}
|
||||
@@ -1910,16 +1926,8 @@ func TestIssue23496(t *testing.T) {
|
||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
}
|
||||
engine = ethash.NewFullFaker()
|
||||
config = &CacheConfig{
|
||||
TrieCleanLimit: 256,
|
||||
TrieDirtyLimit: 256,
|
||||
TriesInMemory: 128,
|
||||
TrieTimeLimit: 5 * time.Minute,
|
||||
SnapshotLimit: 256,
|
||||
SnapshotWait: true,
|
||||
}
|
||||
)
|
||||
chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create chain: %v", err)
|
||||
}
|
||||
@@ -1932,7 +1940,7 @@ func TestIssue23496(t *testing.T) {
|
||||
if _, err := chain.InsertChain(blocks[:1]); err != nil {
|
||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
||||
}
|
||||
chain.stateCache.TrieDB().Commit(blocks[0].Root(), false)
|
||||
chain.triedb.Commit(blocks[0].Root(), false)
|
||||
|
||||
// Insert block B2 and commit the snapshot into disk
|
||||
if _, err := chain.InsertChain(blocks[1:2]); err != nil {
|
||||
@@ -1946,7 +1954,7 @@ func TestIssue23496(t *testing.T) {
|
||||
if _, err := chain.InsertChain(blocks[2:3]); err != nil {
|
||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
||||
}
|
||||
chain.stateCache.TrieDB().Commit(blocks[2].Root(), false)
|
||||
chain.triedb.Commit(blocks[2].Root(), false)
|
||||
|
||||
// Insert the remaining blocks
|
||||
if _, err := chain.InsertChain(blocks[3:]); err != nil {
|
||||
@@ -1954,20 +1962,21 @@ func TestIssue23496(t *testing.T) {
|
||||
}
|
||||
|
||||
// Pull the plug on the database, simulating a hard crash
|
||||
chain.triedb.Close()
|
||||
db.Close()
|
||||
chain.stopWithoutSaving()
|
||||
|
||||
// Start a new blockchain back up and see where the repair leads us
|
||||
db, err = rawdb.Open(rawdb.OpenOptions{
|
||||
Directory: datadir,
|
||||
AncientsDirectory: datadir,
|
||||
AncientsDirectory: ancient,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to reopen persistent database: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
chain, err = NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err = NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
@@ -1979,8 +1988,12 @@ func TestIssue23496(t *testing.T) {
|
||||
if head := chain.CurrentSnapBlock(); head.Number.Uint64() != uint64(4) {
|
||||
t.Errorf("Head fast block mismatch: have %d, want %d", head.Number, uint64(4))
|
||||
}
|
||||
if head := chain.CurrentBlock(); head.Number.Uint64() != uint64(1) {
|
||||
t.Errorf("Head block mismatch: have %d, want %d", head.Number, uint64(1))
|
||||
expHead := uint64(1)
|
||||
if scheme == rawdb.PathScheme {
|
||||
expHead = uint64(2)
|
||||
}
|
||||
if head := chain.CurrentBlock(); head.Number.Uint64() != expHead {
|
||||
t.Errorf("Head block mismatch: have %d, want %d", head.Number, expHead)
|
||||
}
|
||||
|
||||
// Reinsert B2-B4
|
||||
|
||||
@@ -22,6 +22,7 @@ package core
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -29,9 +30,13 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"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/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/ethereum/go-ethereum/trie/triedb/hashdb"
|
||||
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
|
||||
)
|
||||
|
||||
// rewindTest is a test case for chain rollback upon user request.
|
||||
@@ -1949,16 +1954,23 @@ func testLongReorgedSnapSyncingDeepSetHead(t *testing.T, snapshots bool) {
|
||||
}
|
||||
|
||||
func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||
for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} {
|
||||
testSetHeadWithScheme(t, tt, snapshots, scheme)
|
||||
}
|
||||
}
|
||||
|
||||
func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme string) {
|
||||
// It's hard to follow the test case, visualize the input
|
||||
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||
// fmt.Println(tt.dump(false))
|
||||
|
||||
// Create a temporary persistent database
|
||||
datadir := t.TempDir()
|
||||
ancient := path.Join(datadir, "ancient")
|
||||
|
||||
db, err := rawdb.Open(rawdb.OpenOptions{
|
||||
Directory: datadir,
|
||||
AncientsDirectory: datadir,
|
||||
AncientsDirectory: ancient,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create persistent database: %v", err)
|
||||
@@ -1977,6 +1989,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||
TrieDirtyLimit: 256,
|
||||
TrieTimeLimit: 5 * time.Minute,
|
||||
SnapshotLimit: 0, // Disable snapshot
|
||||
StateScheme: scheme,
|
||||
}
|
||||
)
|
||||
if snapshots {
|
||||
@@ -2008,7 +2021,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||
t.Fatalf("Failed to import canonical chain start: %v", err)
|
||||
}
|
||||
if tt.commitBlock > 0 {
|
||||
chain.stateCache.TrieDB().Commit(canonblocks[tt.commitBlock-1].Root(), false)
|
||||
chain.triedb.Commit(canonblocks[tt.commitBlock-1].Root(), false)
|
||||
if snapshots {
|
||||
if err := chain.snaps.Cap(canonblocks[tt.commitBlock-1].Root(), 0); err != nil {
|
||||
t.Fatalf("Failed to flatten snapshots: %v", err)
|
||||
@@ -2018,14 +2031,17 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||
if _, err := chain.InsertChain(canonblocks[tt.commitBlock:]); err != nil {
|
||||
t.Fatalf("Failed to import canonical chain tail: %v", err)
|
||||
}
|
||||
// Manually dereference anything not committed to not have to work with 128+ tries
|
||||
for _, block := range sideblocks {
|
||||
chain.stateCache.TrieDB().Dereference(block.Root())
|
||||
// Reopen the trie database without persisting in-memory dirty nodes.
|
||||
chain.triedb.Close()
|
||||
dbconfig := &trie.Config{}
|
||||
if scheme == rawdb.PathScheme {
|
||||
dbconfig.PathDB = pathdb.Defaults
|
||||
} else {
|
||||
dbconfig.HashDB = hashdb.Defaults
|
||||
}
|
||||
for _, block := range canonblocks {
|
||||
chain.stateCache.TrieDB().Dereference(block.Root())
|
||||
}
|
||||
chain.stateCache.Purge()
|
||||
chain.triedb = trie.NewDatabase(chain.db, dbconfig)
|
||||
chain.stateCache = state.NewDatabaseWithNodeDB(chain.db, chain.triedb)
|
||||
|
||||
// Force run a freeze cycle
|
||||
type freezer interface {
|
||||
Freeze(threshold uint64) error
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -39,6 +40,7 @@ import (
|
||||
|
||||
// snapshotTestBasic wraps the common testing fields in the snapshot tests.
|
||||
type snapshotTestBasic struct {
|
||||
scheme string // Disk scheme used for storing trie nodes
|
||||
chainBlocks int // Number of blocks to generate for the canonical chain
|
||||
snapshotBlock uint64 // Block number of the relevant snapshot disk layer
|
||||
commitBlock uint64 // Block number for which to commit the state to disk
|
||||
@@ -51,6 +53,7 @@ type snapshotTestBasic struct {
|
||||
|
||||
// share fields, set in runtime
|
||||
datadir string
|
||||
ancient string
|
||||
db ethdb.Database
|
||||
genDb ethdb.Database
|
||||
engine consensus.Engine
|
||||
@@ -60,10 +63,11 @@ type snapshotTestBasic struct {
|
||||
func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Block) {
|
||||
// Create a temporary persistent database
|
||||
datadir := t.TempDir()
|
||||
ancient := path.Join(datadir, "ancient")
|
||||
|
||||
db, err := rawdb.Open(rawdb.OpenOptions{
|
||||
Directory: datadir,
|
||||
AncientsDirectory: datadir,
|
||||
AncientsDirectory: ancient,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create persistent database: %v", err)
|
||||
@@ -75,13 +79,8 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo
|
||||
Config: params.AllEthashProtocolChanges,
|
||||
}
|
||||
engine = ethash.NewFullFaker()
|
||||
|
||||
// Snapshot is enabled, the first snapshot is created from the Genesis.
|
||||
// The snapshot memory allowance is 256MB, it means no snapshot flush
|
||||
// will happen during the block insertion.
|
||||
cacheConfig = defaultCacheConfig
|
||||
)
|
||||
chain, err := NewBlockChain(db, cacheConfig, gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(basic.scheme), gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create chain: %v", err)
|
||||
}
|
||||
@@ -102,7 +101,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo
|
||||
startPoint = point
|
||||
|
||||
if basic.commitBlock > 0 && basic.commitBlock == point {
|
||||
chain.stateCache.TrieDB().Commit(blocks[point-1].Root(), false)
|
||||
chain.TrieDB().Commit(blocks[point-1].Root(), false)
|
||||
}
|
||||
if basic.snapshotBlock > 0 && basic.snapshotBlock == point {
|
||||
// Flushing the entire snap tree into the disk, the
|
||||
@@ -121,6 +120,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo
|
||||
|
||||
// Set runtime fields
|
||||
basic.datadir = datadir
|
||||
basic.ancient = ancient
|
||||
basic.db = db
|
||||
basic.genDb = genDb
|
||||
basic.engine = engine
|
||||
@@ -210,6 +210,7 @@ func (basic *snapshotTestBasic) teardown() {
|
||||
basic.db.Close()
|
||||
basic.genDb.Close()
|
||||
os.RemoveAll(basic.datadir)
|
||||
os.RemoveAll(basic.ancient)
|
||||
}
|
||||
|
||||
// snapshotTest is a test case type for normal snapshot recovery.
|
||||
@@ -226,7 +227,7 @@ func (snaptest *snapshotTest) test(t *testing.T) {
|
||||
|
||||
// Restart the chain normally
|
||||
chain.Stop()
|
||||
newchain, err := NewBlockChain(snaptest.db, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil)
|
||||
newchain, err := NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
@@ -235,7 +236,7 @@ func (snaptest *snapshotTest) test(t *testing.T) {
|
||||
snaptest.verify(t, newchain, blocks)
|
||||
}
|
||||
|
||||
// crashSnapshotTest is a test case type for innormal snapshot recovery.
|
||||
// crashSnapshotTest is a test case type for irregular snapshot recovery.
|
||||
// It can be used for testing that restart Geth after the crash.
|
||||
type crashSnapshotTest struct {
|
||||
snapshotTestBasic
|
||||
@@ -251,13 +252,13 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) {
|
||||
db := chain.db
|
||||
db.Close()
|
||||
chain.stopWithoutSaving()
|
||||
chain.triedb.Close()
|
||||
|
||||
// Start a new blockchain back up and see where the repair leads us
|
||||
newdb, err := rawdb.Open(rawdb.OpenOptions{
|
||||
Directory: snaptest.datadir,
|
||||
AncientsDirectory: snaptest.datadir,
|
||||
AncientsDirectory: snaptest.ancient,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to reopen persistent database: %v", err)
|
||||
}
|
||||
@@ -267,13 +268,13 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) {
|
||||
// the crash, we do restart twice here: one after the crash and one
|
||||
// after the normal stop. It's used to ensure the broken snapshot
|
||||
// can be detected all the time.
|
||||
newchain, err := NewBlockChain(newdb, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil)
|
||||
newchain, err := NewBlockChain(newdb, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
newchain.Stop()
|
||||
|
||||
newchain, err = NewBlockChain(newdb, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil)
|
||||
newchain, err = NewBlockChain(newdb, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
@@ -300,7 +301,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) {
|
||||
|
||||
// Insert blocks without enabling snapshot if gapping is required.
|
||||
chain.Stop()
|
||||
gappedBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.genDb, snaptest.gapped, func(i int, b *BlockGen) {})
|
||||
gappedBlocks, _ := GenerateChain(snaptest.gspec.Config, blocks[len(blocks)-1], snaptest.engine, snaptest.genDb, snaptest.gapped, func(i int, b *BlockGen) {})
|
||||
|
||||
// Insert a few more blocks without enabling snapshot
|
||||
var cacheConfig = &CacheConfig{
|
||||
@@ -309,6 +310,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) {
|
||||
TrieTimeLimit: 5 * time.Minute,
|
||||
TriesInMemory: 128,
|
||||
SnapshotLimit: 0,
|
||||
StateScheme: snaptest.scheme,
|
||||
}
|
||||
newchain, err := NewBlockChain(snaptest.db, cacheConfig, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
@@ -318,7 +320,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) {
|
||||
newchain.Stop()
|
||||
|
||||
// Restart the chain with enabling the snapshot
|
||||
newchain, err = NewBlockChain(snaptest.db, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil)
|
||||
newchain, err = NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
@@ -346,7 +348,7 @@ func (snaptest *setHeadSnapshotTest) test(t *testing.T) {
|
||||
chain.SetHead(snaptest.setHead)
|
||||
chain.Stop()
|
||||
|
||||
newchain, err := NewBlockChain(snaptest.db, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil)
|
||||
newchain, err := NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
@@ -381,16 +383,17 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
|
||||
TrieTimeLimit: 5 * time.Minute,
|
||||
SnapshotLimit: 0,
|
||||
TriesInMemory: 128,
|
||||
StateScheme: snaptest.scheme,
|
||||
}
|
||||
newchain, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
newBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.genDb, snaptest.newBlocks, func(i int, b *BlockGen) {})
|
||||
newBlocks, _ := GenerateChain(snaptest.gspec.Config, blocks[len(blocks)-1], snaptest.engine, snaptest.genDb, snaptest.newBlocks, func(i int, b *BlockGen) {})
|
||||
newchain.InsertChain(newBlocks)
|
||||
newchain.Stop()
|
||||
|
||||
// Restart the chain, the wiper should starts working
|
||||
// Restart the chain, the wiper should start working
|
||||
config = &CacheConfig{
|
||||
TrieCleanLimit: 256,
|
||||
TrieDirtyLimit: 256,
|
||||
@@ -398,6 +401,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
|
||||
SnapshotLimit: 256,
|
||||
SnapshotWait: false, // Don't wait rebuild
|
||||
TriesInMemory: 128,
|
||||
StateScheme: snaptest.scheme,
|
||||
}
|
||||
tmp, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
@@ -405,14 +409,15 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
|
||||
}
|
||||
|
||||
// Simulate the blockchain crash.
|
||||
tmp.triedb.Close()
|
||||
tmp.stopWithoutSaving()
|
||||
|
||||
newchain, err = NewBlockChain(snaptest.db, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil)
|
||||
newchain, err = NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
defer newchain.Stop()
|
||||
snaptest.verify(t, newchain, blocks)
|
||||
newchain.Stop()
|
||||
}
|
||||
|
||||
// Tests a Geth restart with valid snapshot. Before the shutdown, all snapshot
|
||||
@@ -436,20 +441,23 @@ func TestRestartWithNewSnapshot(t *testing.T) {
|
||||
// Expected head fast block: C8
|
||||
// Expected head block : C8
|
||||
// Expected snapshot disk : G
|
||||
test := &snapshotTest{
|
||||
snapshotTestBasic{
|
||||
chainBlocks: 8,
|
||||
snapshotBlock: 0,
|
||||
commitBlock: 0,
|
||||
expCanonicalBlocks: 8,
|
||||
expHeadHeader: 8,
|
||||
expHeadFastBlock: 8,
|
||||
expHeadBlock: 8,
|
||||
expSnapshotBottom: 0, // Initial disk layer built from genesis
|
||||
},
|
||||
for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} {
|
||||
test := &snapshotTest{
|
||||
snapshotTestBasic{
|
||||
scheme: scheme,
|
||||
chainBlocks: 8,
|
||||
snapshotBlock: 0,
|
||||
commitBlock: 0,
|
||||
expCanonicalBlocks: 8,
|
||||
expHeadHeader: 8,
|
||||
expHeadFastBlock: 8,
|
||||
expHeadBlock: 8,
|
||||
expSnapshotBottom: 0, // Initial disk layer built from genesis
|
||||
},
|
||||
}
|
||||
test.test(t)
|
||||
test.teardown()
|
||||
}
|
||||
test.test(t)
|
||||
test.teardown()
|
||||
}
|
||||
|
||||
// Tests a Geth was crashed and restarts with a broken snapshot. In this case the
|
||||
@@ -475,20 +483,24 @@ func TestNoCommitCrashWithNewSnapshot(t *testing.T) {
|
||||
// Expected head fast block: C8
|
||||
// Expected head block : G
|
||||
// Expected snapshot disk : C4
|
||||
test := &crashSnapshotTest{
|
||||
snapshotTestBasic{
|
||||
chainBlocks: 8,
|
||||
snapshotBlock: 4,
|
||||
commitBlock: 0,
|
||||
expCanonicalBlocks: 8,
|
||||
expHeadHeader: 8,
|
||||
expHeadFastBlock: 8,
|
||||
expHeadBlock: 0,
|
||||
expSnapshotBottom: 4, // Last committed disk layer, wait recovery
|
||||
},
|
||||
//for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} {
|
||||
for _, scheme := range []string{rawdb.HashScheme} {
|
||||
test := &crashSnapshotTest{
|
||||
snapshotTestBasic{
|
||||
scheme: scheme,
|
||||
chainBlocks: 8,
|
||||
snapshotBlock: 4,
|
||||
commitBlock: 0,
|
||||
expCanonicalBlocks: 8,
|
||||
expHeadHeader: 8,
|
||||
expHeadFastBlock: 8,
|
||||
expHeadBlock: 0,
|
||||
expSnapshotBottom: 4, // Last committed disk layer, wait recovery
|
||||
},
|
||||
}
|
||||
test.test(t)
|
||||
test.teardown()
|
||||
}
|
||||
test.test(t)
|
||||
test.teardown()
|
||||
}
|
||||
|
||||
// Tests a Geth was crashed and restarts with a broken snapshot. In this case the
|
||||
@@ -514,20 +526,24 @@ func TestLowCommitCrashWithNewSnapshot(t *testing.T) {
|
||||
// Expected head fast block: C8
|
||||
// Expected head block : C2
|
||||
// Expected snapshot disk : C4
|
||||
test := &crashSnapshotTest{
|
||||
snapshotTestBasic{
|
||||
chainBlocks: 8,
|
||||
snapshotBlock: 4,
|
||||
commitBlock: 2,
|
||||
expCanonicalBlocks: 8,
|
||||
expHeadHeader: 8,
|
||||
expHeadFastBlock: 8,
|
||||
expHeadBlock: 2,
|
||||
expSnapshotBottom: 4, // Last committed disk layer, wait recovery
|
||||
},
|
||||
//for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} {
|
||||
for _, scheme := range []string{rawdb.HashScheme} {
|
||||
test := &crashSnapshotTest{
|
||||
snapshotTestBasic{
|
||||
scheme: scheme,
|
||||
chainBlocks: 8,
|
||||
snapshotBlock: 4,
|
||||
commitBlock: 2,
|
||||
expCanonicalBlocks: 8,
|
||||
expHeadHeader: 8,
|
||||
expHeadFastBlock: 8,
|
||||
expHeadBlock: 2,
|
||||
expSnapshotBottom: 4, // Last committed disk layer, wait recovery
|
||||
},
|
||||
}
|
||||
test.test(t)
|
||||
test.teardown()
|
||||
}
|
||||
test.test(t)
|
||||
test.teardown()
|
||||
}
|
||||
|
||||
// Tests a Geth was crashed and restarts with a broken snapshot. In this case
|
||||
@@ -553,20 +569,27 @@ func TestHighCommitCrashWithNewSnapshot(t *testing.T) {
|
||||
// Expected head fast block: C8
|
||||
// Expected head block : G
|
||||
// Expected snapshot disk : C4
|
||||
test := &crashSnapshotTest{
|
||||
snapshotTestBasic{
|
||||
chainBlocks: 8,
|
||||
snapshotBlock: 4,
|
||||
commitBlock: 6,
|
||||
expCanonicalBlocks: 8,
|
||||
expHeadHeader: 8,
|
||||
expHeadFastBlock: 8,
|
||||
expHeadBlock: 0,
|
||||
expSnapshotBottom: 4, // Last committed disk layer, wait recovery
|
||||
},
|
||||
for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} {
|
||||
expHead := uint64(0)
|
||||
if scheme == rawdb.PathScheme {
|
||||
expHead = uint64(4)
|
||||
}
|
||||
test := &crashSnapshotTest{
|
||||
snapshotTestBasic{
|
||||
scheme: scheme,
|
||||
chainBlocks: 8,
|
||||
snapshotBlock: 4,
|
||||
commitBlock: 6,
|
||||
expCanonicalBlocks: 8,
|
||||
expHeadHeader: 8,
|
||||
expHeadFastBlock: 8,
|
||||
expHeadBlock: expHead,
|
||||
expSnapshotBottom: 4, // Last committed disk layer, wait recovery
|
||||
},
|
||||
}
|
||||
test.test(t)
|
||||
test.teardown()
|
||||
}
|
||||
test.test(t)
|
||||
test.teardown()
|
||||
}
|
||||
|
||||
// Tests a Geth was running with snapshot enabled. Then restarts without
|
||||
@@ -590,21 +613,24 @@ func TestGappedNewSnapshot(t *testing.T) {
|
||||
// Expected head fast block: C10
|
||||
// Expected head block : C10
|
||||
// Expected snapshot disk : C10
|
||||
test := &gappedSnapshotTest{
|
||||
snapshotTestBasic: snapshotTestBasic{
|
||||
chainBlocks: 8,
|
||||
snapshotBlock: 0,
|
||||
commitBlock: 0,
|
||||
expCanonicalBlocks: 10,
|
||||
expHeadHeader: 10,
|
||||
expHeadFastBlock: 10,
|
||||
expHeadBlock: 10,
|
||||
expSnapshotBottom: 10, // Rebuilt snapshot from the latest HEAD
|
||||
},
|
||||
gapped: 2,
|
||||
for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} {
|
||||
test := &gappedSnapshotTest{
|
||||
snapshotTestBasic: snapshotTestBasic{
|
||||
scheme: scheme,
|
||||
chainBlocks: 8,
|
||||
snapshotBlock: 0,
|
||||
commitBlock: 0,
|
||||
expCanonicalBlocks: 10,
|
||||
expHeadHeader: 10,
|
||||
expHeadFastBlock: 10,
|
||||
expHeadBlock: 10,
|
||||
expSnapshotBottom: 10, // Rebuilt snapshot from the latest HEAD
|
||||
},
|
||||
gapped: 2,
|
||||
}
|
||||
test.test(t)
|
||||
test.teardown()
|
||||
}
|
||||
test.test(t)
|
||||
test.teardown()
|
||||
}
|
||||
|
||||
// Tests the Geth was running with snapshot enabled and resetHead is applied.
|
||||
@@ -628,21 +654,24 @@ func TestSetHeadWithNewSnapshot(t *testing.T) {
|
||||
// Expected head fast block: C4
|
||||
// Expected head block : C4
|
||||
// Expected snapshot disk : G
|
||||
test := &setHeadSnapshotTest{
|
||||
snapshotTestBasic: snapshotTestBasic{
|
||||
chainBlocks: 8,
|
||||
snapshotBlock: 0,
|
||||
commitBlock: 0,
|
||||
expCanonicalBlocks: 4,
|
||||
expHeadHeader: 4,
|
||||
expHeadFastBlock: 4,
|
||||
expHeadBlock: 4,
|
||||
expSnapshotBottom: 0, // The initial disk layer is built from the genesis
|
||||
},
|
||||
setHead: 4,
|
||||
for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} {
|
||||
test := &setHeadSnapshotTest{
|
||||
snapshotTestBasic: snapshotTestBasic{
|
||||
scheme: scheme,
|
||||
chainBlocks: 8,
|
||||
snapshotBlock: 0,
|
||||
commitBlock: 0,
|
||||
expCanonicalBlocks: 4,
|
||||
expHeadHeader: 4,
|
||||
expHeadFastBlock: 4,
|
||||
expHeadBlock: 4,
|
||||
expSnapshotBottom: 0, // The initial disk layer is built from the genesis
|
||||
},
|
||||
setHead: 4,
|
||||
}
|
||||
test.test(t)
|
||||
test.teardown()
|
||||
}
|
||||
test.test(t)
|
||||
test.teardown()
|
||||
}
|
||||
|
||||
// Tests the Geth was running with a complete snapshot and then imports a few
|
||||
@@ -666,19 +695,22 @@ func TestRecoverSnapshotFromWipingCrash(t *testing.T) {
|
||||
// Expected head fast block: C10
|
||||
// Expected head block : C8
|
||||
// Expected snapshot disk : C10
|
||||
test := &wipeCrashSnapshotTest{
|
||||
snapshotTestBasic: snapshotTestBasic{
|
||||
chainBlocks: 8,
|
||||
snapshotBlock: 4,
|
||||
commitBlock: 0,
|
||||
expCanonicalBlocks: 10,
|
||||
expHeadHeader: 10,
|
||||
expHeadFastBlock: 10,
|
||||
expHeadBlock: 10,
|
||||
expSnapshotBottom: 10,
|
||||
},
|
||||
newBlocks: 2,
|
||||
for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} {
|
||||
test := &wipeCrashSnapshotTest{
|
||||
snapshotTestBasic: snapshotTestBasic{
|
||||
scheme: scheme,
|
||||
chainBlocks: 8,
|
||||
snapshotBlock: 4,
|
||||
commitBlock: 0,
|
||||
expCanonicalBlocks: 10,
|
||||
expHeadHeader: 10,
|
||||
expHeadFastBlock: 10,
|
||||
expHeadBlock: 10,
|
||||
expSnapshotBottom: 10,
|
||||
},
|
||||
newBlocks: 2,
|
||||
}
|
||||
test.test(t)
|
||||
test.teardown()
|
||||
}
|
||||
test.test(t)
|
||||
test.teardown()
|
||||
}
|
||||
|
||||
@@ -1807,7 +1807,7 @@ func TestTrieForkGC(t *testing.T) {
|
||||
chain.stateCache.TrieDB().Dereference(blocks[len(blocks)-1-i].Root())
|
||||
chain.stateCache.TrieDB().Dereference(forks[len(blocks)-1-i].Root())
|
||||
}
|
||||
if nodes, _ := chain.TrieDB().Size(); nodes > 0 {
|
||||
if _, nodes, _, _ := chain.TrieDB().Size(); nodes > 0 {
|
||||
t.Fatalf("stale tries still alive after garbase collection")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -633,13 +633,16 @@ func (s *MatcherSession) Multiplex(batch int, wait time.Duration, mux chan chan
|
||||
request <- &Retrieval{Bit: bit, Sections: sections, Context: s.ctx}
|
||||
|
||||
result := <-request
|
||||
|
||||
// Deliver a result before s.Close() to avoid a deadlock
|
||||
s.deliverSections(result.Bit, result.Sections, result.Bitsets)
|
||||
|
||||
if result.Error != nil {
|
||||
s.errLock.Lock()
|
||||
s.err = result.Error
|
||||
s.errLock.Unlock()
|
||||
s.Close()
|
||||
}
|
||||
s.deliverSections(result.Bit, result.Sections, result.Bitsets)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,6 +205,10 @@ func (b *BlockGen) AddUncle(h *types.Header) {
|
||||
h.GasLimit = parent.GasLimit
|
||||
if b.config.IsLondon(h.Number) {
|
||||
h.BaseFee = eip1559.CalcBaseFee(b.config, parent)
|
||||
if b.config.Parlia == nil && !b.config.IsLondon(parent.Number) {
|
||||
parentGasLimit := parent.GasLimit * b.config.ElasticityMultiplier()
|
||||
h.GasLimit = CalcGasLimit(parentGasLimit, parentGasLimit)
|
||||
}
|
||||
}
|
||||
b.uncles = append(b.uncles, h)
|
||||
}
|
||||
@@ -280,7 +284,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||
}
|
||||
blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
|
||||
chainreader := &fakeChainReader{config: config}
|
||||
genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) {
|
||||
genblock := func(i int, parent *types.Block, triedb *trie.Database, statedb *state.StateDB) (*types.Block, types.Receipts) {
|
||||
b := &BlockGen{i: i, chain: blocks, parent: parent, statedb: statedb, config: config, engine: engine}
|
||||
b.header = makeHeader(chainreader, parent, statedb, b.engine)
|
||||
|
||||
@@ -308,7 +312,11 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||
if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(b.header.Number) == 0 {
|
||||
misc.ApplyDAOHardFork(statedb)
|
||||
}
|
||||
systemcontracts.UpgradeBuildInSystemContract(config, b.header.Number, statedb)
|
||||
|
||||
if !config.IsFeynman(b.header.Number, b.header.Time) {
|
||||
systemcontracts.UpgradeBuildInSystemContract(config, b.header.Number, parent.Time(), b.header.Time, statedb)
|
||||
}
|
||||
|
||||
// Execute any user modifications to the block
|
||||
if gen != nil {
|
||||
gen(i, b)
|
||||
@@ -324,19 +332,23 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("state write error: %v", err))
|
||||
}
|
||||
if err := statedb.Database().TrieDB().Commit(root, false); err != nil {
|
||||
if err = triedb.Commit(root, false); err != nil {
|
||||
panic(fmt.Sprintf("trie write error: %v", err))
|
||||
}
|
||||
return block, b.receipts
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
// Forcibly use hash-based state scheme for retaining all nodes in disk.
|
||||
triedb := trie.NewDatabase(db, trie.HashDefaults)
|
||||
defer triedb.Close()
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
statedb, err := state.New(parent.Root(), state.NewDatabase(db), nil)
|
||||
statedb, err := state.New(parent.Root(), state.NewDatabaseWithNodeDB(db, triedb), nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
block, receipt := genblock(i, parent, statedb)
|
||||
block, receipt := genblock(i, parent, triedb, statedb)
|
||||
blocks[i] = block
|
||||
receipts[i] = receipt
|
||||
parent = block
|
||||
@@ -349,7 +361,9 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||
// then generate chain on top.
|
||||
func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, gen func(int, *BlockGen)) (ethdb.Database, []*types.Block, []types.Receipts) {
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
_, err := genesis.Commit(db, trie.NewDatabase(db))
|
||||
triedb := trie.NewDatabase(db, trie.HashDefaults)
|
||||
defer triedb.Close()
|
||||
_, err := genesis.Commit(db, triedb)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -380,6 +394,10 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S
|
||||
}
|
||||
if chain.Config().IsLondon(header.Number) {
|
||||
header.BaseFee = eip1559.CalcBaseFee(chain.Config(), parent.Header())
|
||||
if chain.Config().Parlia == nil && !chain.Config().IsLondon(parent.Number()) {
|
||||
parentGasLimit := parent.GasLimit() * chain.Config().ElasticityMultiplier()
|
||||
header.GasLimit = CalcGasLimit(parentGasLimit, parentGasLimit)
|
||||
}
|
||||
}
|
||||
return header
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
|
||||
func TestGenerateWithdrawalChain(t *testing.T) {
|
||||
@@ -74,8 +75,7 @@ func TestGenerateWithdrawalChain(t *testing.T) {
|
||||
Storage: storage,
|
||||
Code: common.Hex2Bytes("600154600354"),
|
||||
}
|
||||
|
||||
genesis := gspec.MustCommit(gendb)
|
||||
genesis := gspec.MustCommit(gendb, trie.NewDatabase(gendb, trie.HashDefaults))
|
||||
|
||||
chain, _ := GenerateChain(gspec.Config, genesis, beacon.NewFaker(), gendb, 4, func(i int, gen *BlockGen) {
|
||||
tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(address), address, big.NewInt(1000), params.TxGas, new(big.Int).Add(gen.BaseFee(), common.Big1), nil), signer, key)
|
||||
@@ -146,6 +146,7 @@ func ExampleGenerateChain() {
|
||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
genDb = rawdb.NewMemoryDatabase()
|
||||
)
|
||||
|
||||
// Ensure that key1 has some funds in the genesis block.
|
||||
@@ -153,13 +154,13 @@ func ExampleGenerateChain() {
|
||||
Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)},
|
||||
Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}},
|
||||
}
|
||||
genesis := gspec.MustCommit(db)
|
||||
genesis := gspec.MustCommit(genDb, trie.NewDatabase(genDb, trie.HashDefaults))
|
||||
|
||||
// This call generates a chain of 5 blocks. The function runs for
|
||||
// each block and adds different features to gen based on the
|
||||
// block index.
|
||||
signer := types.HomesteadSigner{}
|
||||
chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 5, func(i int, gen *BlockGen) {
|
||||
chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), genDb, 5, func(i int, gen *BlockGen) {
|
||||
switch i {
|
||||
case 0:
|
||||
// In block 1, addr1 sends addr2 some ether.
|
||||
@@ -188,7 +189,7 @@ func ExampleGenerateChain() {
|
||||
})
|
||||
|
||||
// Import the chain. This runs all block validation rules.
|
||||
blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
blockchain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(rawdb.HashScheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
defer blockchain.Stop()
|
||||
|
||||
if i, err := blockchain.InsertChain(chain); err != nil {
|
||||
|
||||
@@ -83,7 +83,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||
if _, err := bc.InsertChain(blocks); err != nil {
|
||||
t.Fatalf("failed to import contra-fork chain for expansion: %v", err)
|
||||
}
|
||||
if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil {
|
||||
if err := bc.triedb.Commit(bc.CurrentHeader().Root, false); err != nil {
|
||||
t.Fatalf("failed to commit contra-fork head for expansion: %v", err)
|
||||
}
|
||||
bc.Stop()
|
||||
@@ -106,7 +106,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||
if _, err := bc.InsertChain(blocks); err != nil {
|
||||
t.Fatalf("failed to import pro-fork chain for expansion: %v", err)
|
||||
}
|
||||
if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil {
|
||||
if err := bc.triedb.Commit(bc.CurrentHeader().Root, false); err != nil {
|
||||
t.Fatalf("failed to commit pro-fork head for expansion: %v", err)
|
||||
}
|
||||
bc.Stop()
|
||||
@@ -131,7 +131,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||
if _, err := bc.InsertChain(blocks); err != nil {
|
||||
t.Fatalf("failed to import contra-fork chain for expansion: %v", err)
|
||||
}
|
||||
if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil {
|
||||
if err := bc.triedb.Commit(bc.CurrentHeader().Root, false); err != nil {
|
||||
t.Fatalf("failed to commit contra-fork head for expansion: %v", err)
|
||||
}
|
||||
blocks, _ = GenerateChain(&proConf, conBc.GetBlockByHash(conBc.CurrentBlock().Hash()), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {})
|
||||
@@ -149,7 +149,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||
if _, err := bc.InsertChain(blocks); err != nil {
|
||||
t.Fatalf("failed to import pro-fork chain for expansion: %v", err)
|
||||
}
|
||||
if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil {
|
||||
if err := bc.triedb.Commit(bc.CurrentHeader().Root, false); err != nil {
|
||||
t.Fatalf("failed to commit pro-fork head for expansion: %v", err)
|
||||
}
|
||||
blocks, _ = GenerateChain(&conConf, proBc.GetBlockByHash(proBc.CurrentBlock().Hash()), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {})
|
||||
|
||||
@@ -19,6 +19,7 @@ func preHertzConfig() *params.ChainConfig {
|
||||
config.LondonBlock = nil
|
||||
config.BerlinBlock = nil
|
||||
config.HertzBlock = nil
|
||||
config.HertzfixBlock = nil
|
||||
return &config
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
|
||||
func newGwei(n int64) *big.Int {
|
||||
@@ -42,7 +43,7 @@ func TestGasUsage(t *testing.T, config *params.ChainConfig, engine consensus.Eng
|
||||
},
|
||||
},
|
||||
}
|
||||
genesis = gspec.MustCommit(db)
|
||||
genesis = gspec.MustCommit(db, trie.NewDatabase(db, nil))
|
||||
)
|
||||
|
||||
blocks, _ := core.GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *core.BlockGen) {
|
||||
@@ -61,7 +62,7 @@ func TestGasUsage(t *testing.T, config *params.ChainConfig, engine consensus.Eng
|
||||
|
||||
// Import the canonical chain
|
||||
diskdb := rawdb.NewMemoryDatabase()
|
||||
gspec.MustCommit(diskdb)
|
||||
gspec.MustCommit(diskdb, trie.NewDatabase(diskdb, nil))
|
||||
|
||||
chain, err := core.NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
|
||||
@@ -137,5 +137,9 @@ func (f *ForkChoice) ReorgNeededWithFastFinality(current *types.Header, header *
|
||||
return f.ReorgNeeded(current, header)
|
||||
}
|
||||
|
||||
if justifiedNumber > curJustifiedNumber && header.Number.Cmp(current.Number) <= 0 {
|
||||
log.Info("Chain find higher justifiedNumber", "fromHeight", current.Number, "fromHash", current.Hash(), "fromMiner", current.Coinbase, "fromJustified", curJustifiedNumber,
|
||||
"toHeight", header.Number, "toHash", header.Hash(), "toMiner", header.Coinbase, "toJustified", justifiedNumber)
|
||||
}
|
||||
return justifiedNumber > curJustifiedNumber, nil
|
||||
}
|
||||
|
||||
@@ -98,6 +98,32 @@ func NewID(config *params.ChainConfig, genesis common.Hash, head, time uint64) I
|
||||
return ID{Hash: checksumToBytes(hash), Next: 0}
|
||||
}
|
||||
|
||||
// NextForkHash calculates the forkHash from genesis to the next fork block number or time
|
||||
func NextForkHash(config *params.ChainConfig, genesis common.Hash, head uint64, time uint64) [4]byte {
|
||||
// Calculate the starting checksum from the genesis hash
|
||||
hash := crc32.ChecksumIEEE(genesis[:])
|
||||
|
||||
// Calculate the next fork checksum
|
||||
forksByBlock, forksByTime := gatherForks(config)
|
||||
for _, fork := range forksByBlock {
|
||||
if fork > head {
|
||||
// Checksum the previous hash and nextFork number and return
|
||||
return checksumToBytes(checksumUpdate(hash, fork))
|
||||
}
|
||||
// Fork already passed, checksum the previous hash and the fork number
|
||||
hash = checksumUpdate(hash, fork)
|
||||
}
|
||||
for _, fork := range forksByTime {
|
||||
if fork > time {
|
||||
// Checksum the previous hash and nextFork time and return
|
||||
return checksumToBytes(checksumUpdate(hash, fork))
|
||||
}
|
||||
// Fork already passed, checksum the previous hash and the fork time
|
||||
hash = checksumUpdate(hash, fork)
|
||||
}
|
||||
return checksumToBytes(hash)
|
||||
}
|
||||
|
||||
// NewIDWithChain calculates the Ethereum fork ID from an existing chain instance.
|
||||
func NewIDWithChain(chain Blockchain) ID {
|
||||
head := chain.CurrentHeader()
|
||||
|
||||
206
core/genesis.go
206
core/genesis.go
@@ -23,8 +23,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@@ -32,7 +30,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/systemcontracts"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
@@ -65,9 +62,9 @@ type Genesis struct {
|
||||
Number uint64 `json:"number"`
|
||||
GasUsed uint64 `json:"gasUsed"`
|
||||
ParentHash common.Hash `json:"parentHash"`
|
||||
BaseFee *big.Int `json:"baseFeePerGas"` // EIP-1559
|
||||
ExcessBlobGas *uint64 `json:"excessBlobGas,omitempty" toml:",omitempty"` // EIP-4844, TODO: remove tag `omitempty` after cancun fork
|
||||
BlobGasUsed *uint64 `json:"blobGasUsed,omitempty" toml:",omitempty"` // EIP-4844, TODO: remove tag `omitempty` after cancun fork
|
||||
BaseFee *big.Int `json:"baseFeePerGas"` // EIP-1559
|
||||
ExcessBlobGas *uint64 `json:"excessBlobGas,omitempty"` // EIP-4844, TODO(Nathan): remove tag `omitempty` after cancun fork
|
||||
BlobGasUsed *uint64 `json:"blobGasUsed,omitempty"` // EIP-4844, TODO(Nathan): remove tag `omitempty` after cancun fork
|
||||
}
|
||||
|
||||
func ReadGenesis(db ethdb.Database) (*Genesis, error) {
|
||||
@@ -123,8 +120,8 @@ func (ga *GenesisAlloc) UnmarshalJSON(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// deriveHash computes the state root according to the genesis specification.
|
||||
func (ga *GenesisAlloc) deriveHash() (common.Hash, error) {
|
||||
// hash computes the state root according to the genesis specification.
|
||||
func (ga *GenesisAlloc) hash() (common.Hash, error) {
|
||||
// Create an ephemeral in-memory database for computing hash,
|
||||
// all the derived states will be discarded to not pollute disk.
|
||||
db := state.NewDatabase(rawdb.NewMemoryDatabase())
|
||||
@@ -145,9 +142,9 @@ func (ga *GenesisAlloc) deriveHash() (common.Hash, error) {
|
||||
return root, err
|
||||
}
|
||||
|
||||
// flush is very similar with deriveHash, but the main difference is
|
||||
// all the generated states will be persisted into the given database.
|
||||
// Also, the genesis state specification will be flushed as well.
|
||||
// flush is very similar with hash, but the main difference is all the generated
|
||||
// states will be persisted into the given database. Also, the genesis state
|
||||
// specification will be flushed as well.
|
||||
func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhash common.Hash) error {
|
||||
trieConfig := triedb.Config()
|
||||
if trieConfig != nil {
|
||||
@@ -202,8 +199,8 @@ func CommitGenesisState(db ethdb.Database, triedb *trie.Database, blockhash comm
|
||||
// - private network, can't recover
|
||||
var genesis *Genesis
|
||||
switch blockhash {
|
||||
case params.MainnetGenesisHash:
|
||||
genesis = DefaultGenesisBlock()
|
||||
case params.BSCGenesisHash:
|
||||
genesis = DefaultBSCGenesisBlock()
|
||||
}
|
||||
if genesis != nil {
|
||||
alloc = genesis.Alloc
|
||||
@@ -276,10 +273,15 @@ func (e *GenesisMismatchError) Error() string {
|
||||
return fmt.Sprintf("database contains incompatible genesis (have %x, new %x)", e.Stored, e.New)
|
||||
}
|
||||
|
||||
// ChainOverrides contains the changes to chain config.
|
||||
// ChainOverrides contains the changes to chain config
|
||||
// Typically, these modifications involve hardforks that are not enabled on the BSC mainnet, intended for testing purposes.
|
||||
type ChainOverrides struct {
|
||||
OverrideCancun *uint64
|
||||
OverrideVerkle *uint64
|
||||
OverrideShanghai *uint64
|
||||
OverrideKepler *uint64
|
||||
OverrideCancun *uint64
|
||||
OverrideVerkle *uint64
|
||||
OverrideFeynman *uint64
|
||||
OverrideFeynmanFix *uint64
|
||||
}
|
||||
|
||||
// SetupGenesisBlock writes or updates the genesis block in db.
|
||||
@@ -305,21 +307,32 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen
|
||||
}
|
||||
applyOverrides := func(config *params.ChainConfig) {
|
||||
if config != nil {
|
||||
if overrides != nil && overrides.OverrideShanghai != nil {
|
||||
config.ShanghaiTime = overrides.OverrideShanghai
|
||||
}
|
||||
if overrides != nil && overrides.OverrideKepler != nil {
|
||||
config.KeplerTime = overrides.OverrideKepler
|
||||
}
|
||||
if overrides != nil && overrides.OverrideCancun != nil {
|
||||
config.CancunTime = overrides.OverrideCancun
|
||||
}
|
||||
if overrides != nil && overrides.OverrideVerkle != nil {
|
||||
config.VerkleTime = overrides.OverrideVerkle
|
||||
}
|
||||
if overrides != nil && overrides.OverrideFeynman != nil {
|
||||
config.FeynmanTime = overrides.OverrideFeynman
|
||||
}
|
||||
if overrides != nil && overrides.OverrideFeynmanFix != nil {
|
||||
config.FeynmanFixTime = overrides.OverrideFeynmanFix
|
||||
}
|
||||
}
|
||||
}
|
||||
// Just commit the new block if there is no stored genesis block.
|
||||
stored := rawdb.ReadCanonicalHash(db, 0)
|
||||
systemcontracts.GenesisHash = stored
|
||||
if (stored == common.Hash{}) {
|
||||
if genesis == nil {
|
||||
log.Info("Writing default main-net genesis block")
|
||||
genesis = DefaultGenesisBlock()
|
||||
log.Info("Writing default BSC mainnet genesis block")
|
||||
genesis = DefaultBSCGenesisBlock()
|
||||
} else {
|
||||
log.Info("Writing custom genesis block")
|
||||
}
|
||||
@@ -328,14 +341,17 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen
|
||||
return genesis.Config, common.Hash{}, err
|
||||
}
|
||||
applyOverrides(genesis.Config)
|
||||
log.Info("genesis block hash", "hash", block.Hash())
|
||||
return genesis.Config, block.Hash(), nil
|
||||
}
|
||||
// We have the genesis block in database(perhaps in ancient database)
|
||||
// but the corresponding state is missing.
|
||||
// The genesis block is present(perhaps in ancient database) while the
|
||||
// state database is not initialized yet. It can happen that the node
|
||||
// is initialized with an external ancient store. Commit genesis state
|
||||
// in this case.
|
||||
header := rawdb.ReadHeader(db, stored, 0)
|
||||
if header.Root != types.EmptyRootHash && !rawdb.HasLegacyTrieNode(db, header.Root) {
|
||||
if header.Root != types.EmptyRootHash && !triedb.Initialized(header.Root) {
|
||||
if genesis == nil {
|
||||
genesis = DefaultGenesisBlock()
|
||||
genesis = DefaultBSCGenesisBlock()
|
||||
}
|
||||
// Ensure the stored genesis matches with the given one.
|
||||
hash := genesis.ToBlock().Hash()
|
||||
@@ -396,14 +412,19 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen
|
||||
return newcfg, stored, nil
|
||||
}
|
||||
|
||||
// LoadChainConfig loads the stored chain config if it is already present in
|
||||
// database, otherwise, return the config in the provided genesis specification.
|
||||
// LoadChainConfig retrieves the predefined chain configuration for the built-in network.
|
||||
// For non-built-in networks, it first attempts to load the stored chain configuration from the database.
|
||||
// If the configuration is not present, it returns the configuration specified in the provided genesis specification.
|
||||
func LoadChainConfig(db ethdb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) {
|
||||
// Load the stored chain config from the database. It can be nil
|
||||
// in case the database is empty. Notably, we only care about the
|
||||
// chain config corresponds to the canonical chain.
|
||||
stored := rawdb.ReadCanonicalHash(db, 0)
|
||||
if stored != (common.Hash{}) {
|
||||
builtInConf := params.GetBuiltInChainConfig(stored)
|
||||
if builtInConf != nil {
|
||||
return builtInConf, stored, nil
|
||||
}
|
||||
storedcfg := rawdb.ReadChainConfig(db, stored)
|
||||
if storedcfg != nil {
|
||||
return storedcfg, stored, nil
|
||||
@@ -429,76 +450,20 @@ func LoadChainConfig(db ethdb.Database, genesis *Genesis) (*params.ChainConfig,
|
||||
return params.BSCChainConfig, params.BSCGenesisHash, nil
|
||||
}
|
||||
|
||||
// For any block in g.Config which is nil but the same block in defaultConfig is not
|
||||
// set the block in genesis config to the block in defaultConfig.
|
||||
// Reflection is used to avoid a long series of if statements with hardcoded block names.
|
||||
func (g *Genesis) setDefaultBlockValues(defaultConfig *params.ChainConfig) {
|
||||
// Regex to match block names
|
||||
blockRegex := regexp.MustCompile(`.*Block$`)
|
||||
|
||||
// Get reflect values
|
||||
gConfigElem := reflect.ValueOf(g.Config).Elem()
|
||||
defaultConfigElem := reflect.ValueOf(defaultConfig).Elem()
|
||||
|
||||
// Iterate over fields in config
|
||||
for i := 0; i < gConfigElem.NumField(); i++ {
|
||||
gConfigField := gConfigElem.Field(i)
|
||||
defaultConfigField := defaultConfigElem.Field(i)
|
||||
fieldName := gConfigElem.Type().Field(i).Name
|
||||
|
||||
// Use the regex to check if the field is a Block field
|
||||
if gConfigField.Kind() == reflect.Ptr && blockRegex.MatchString(fieldName) {
|
||||
if gConfigField.IsNil() {
|
||||
gConfigField.Set(defaultConfigField)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hard fork block height specified in config.toml has higher priority, but
|
||||
// if it is not specified in config.toml, use the default height in code.
|
||||
func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
|
||||
var defaultConfig *params.ChainConfig
|
||||
switch {
|
||||
case ghash == params.MainnetGenesisHash:
|
||||
defaultConfig = params.MainnetChainConfig
|
||||
case ghash == params.BSCGenesisHash:
|
||||
defaultConfig = params.BSCChainConfig
|
||||
case ghash == params.ChapelGenesisHash:
|
||||
defaultConfig = params.ChapelChainConfig
|
||||
case ghash == params.RialtoGenesisHash:
|
||||
defaultConfig = params.RialtoChainConfig
|
||||
default:
|
||||
if g != nil {
|
||||
// it could be a custom config for QA test, just return
|
||||
return g.Config
|
||||
}
|
||||
defaultConfig = params.AllEthashProtocolChanges
|
||||
conf := params.GetBuiltInChainConfig(ghash)
|
||||
if conf != nil {
|
||||
return conf
|
||||
}
|
||||
if g == nil || g.Config == nil {
|
||||
return defaultConfig
|
||||
if g != nil {
|
||||
return g.Config // it could be a custom config for QA test, just return
|
||||
}
|
||||
|
||||
g.setDefaultBlockValues(defaultConfig)
|
||||
|
||||
// BSC Parlia set up
|
||||
if g.Config.Parlia == nil {
|
||||
g.Config.Parlia = defaultConfig.Parlia
|
||||
} else {
|
||||
if g.Config.Parlia.Period == 0 {
|
||||
g.Config.Parlia.Period = defaultConfig.Parlia.Period
|
||||
}
|
||||
if g.Config.Parlia.Epoch == 0 {
|
||||
g.Config.Parlia.Epoch = defaultConfig.Parlia.Epoch
|
||||
}
|
||||
}
|
||||
|
||||
return g.Config
|
||||
return params.AllEthashProtocolChanges
|
||||
}
|
||||
|
||||
// ToBlock returns the genesis block according to genesis specification.
|
||||
func (g *Genesis) ToBlock() *types.Block {
|
||||
root, err := g.Alloc.deriveHash()
|
||||
root, err := g.Alloc.hash()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -532,7 +497,7 @@ func (g *Genesis) ToBlock() *types.Block {
|
||||
var withdrawals []*types.Withdrawal
|
||||
if conf := g.Config; conf != nil {
|
||||
num := big.NewInt(int64(g.Number))
|
||||
if conf.IsShanghai(num, g.Timestamp) {
|
||||
if conf.Parlia == nil && conf.IsShanghai(num, g.Timestamp) {
|
||||
head.WithdrawalsHash = &types.EmptyWithdrawalsHash
|
||||
withdrawals = make([]*types.Withdrawal, 0)
|
||||
}
|
||||
@@ -586,10 +551,8 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database) (*types.Block
|
||||
|
||||
// MustCommit writes the genesis block and state to db, panicking on error.
|
||||
// The block is committed as the canonical head block.
|
||||
// Note the state changes will be committed in hash-based scheme, use Commit
|
||||
// if path-scheme is preferred.
|
||||
func (g *Genesis) MustCommit(db ethdb.Database) *types.Block {
|
||||
block, err := g.Commit(db, trie.NewDatabase(db))
|
||||
func (g *Genesis) MustCommit(db ethdb.Database, triedb *trie.Database) *types.Block {
|
||||
block, err := g.Commit(db, triedb)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -608,6 +571,38 @@ func DefaultGenesisBlock() *Genesis {
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultBSCGenesisBlock returns the BSC mainnet genesis block.
|
||||
func DefaultBSCGenesisBlock() *Genesis {
|
||||
alloc := decodePrealloc(bscMainnetAllocData)
|
||||
return &Genesis{
|
||||
Config: params.BSCChainConfig,
|
||||
Nonce: 0,
|
||||
ExtraData: hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000002a7cdd959bfe8d9487b2a43b33565295a698f7e26488aa4d1955ee33403f8ccb1d4de5fb97c7ade29ef9f4360c606c7ab4db26b016007d3ad0ab86a0ee01c3b1283aa067c58eab4709f85e99d46de5fe685b1ded8013785d6623cc18d214320b6bb6475978f3adfc719c99674c072166708589033e2d9afec2be4ec20253b8642161bc3f444f53679c1f3d472f7be8361c80a4c1e7e9aaf001d0877f1cfde218ce2fd7544e0b2cc94692d4a704debef7bcb61328b8f7166496996a7da21cf1f1b04d9b3e26a3d0772d4c407bbe49438ed859fe965b140dcf1aab71a96bbad7cf34b5fa511d8e963dbba288b1960e75d64430b3230294d12c6ab2aac5c2cd68e80b16b581ea0a6e3c511bbd10f4519ece37dc24887e11b55d7ae2f5b9e386cd1b50a4550696d957cb4900f03a82012708dafc9e1b880fd083b32182b869be8e0922b81f8e175ffde54d797fe11eb03f9e3bf75f1d68bf0b8b6fb4e317a0f9d6f03eaf8ce6675bc60d8c4d90829ce8f72d0163c1d5cf348a862d55063035e7a025f4da968de7e4d7e4004197917f4070f1d6caa02bbebaebb5d7e581e4b66559e635f805ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
|
||||
GasLimit: 40000000,
|
||||
Difficulty: big.NewInt(1),
|
||||
Mixhash: common.Hash(hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000000000")),
|
||||
Coinbase: common.HexToAddress("0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE"),
|
||||
Timestamp: 0x5e9da7ce,
|
||||
Alloc: alloc,
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultChapelGenesisBlock returns the BSC mainnet genesis block.
|
||||
func DefaultChapelGenesisBlock() *Genesis {
|
||||
alloc := decodePrealloc(bscChapelAllocData)
|
||||
return &Genesis{
|
||||
Config: params.ChapelChainConfig,
|
||||
Nonce: 0,
|
||||
ExtraData: hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000001284214b9b9c85549ab3d2b972df0deef66ac2c9b71b214cb885500844365e95cd9942c7276e7fd8a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0980a75ecd1309ea12fa2ed87a8744fbfc9b863d535552c16704d214347f29fa77f77da6d75d7c752f474cf03cceff28abc65c9cbae594f725c80e12d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
|
||||
GasLimit: 40000000,
|
||||
Difficulty: big.NewInt(1),
|
||||
Mixhash: common.Hash(hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000000000")),
|
||||
Coinbase: common.HexToAddress("0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE"),
|
||||
Timestamp: 0x5e9da7ce,
|
||||
Alloc: alloc,
|
||||
}
|
||||
}
|
||||
|
||||
// DeveloperGenesisBlock returns the 'geth --dev' genesis block.
|
||||
func DeveloperGenesisBlock(gasLimit uint64, faucet common.Address) *Genesis {
|
||||
// Override the default period to the user requested one
|
||||
@@ -635,13 +630,34 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet common.Address) *Genesis {
|
||||
}
|
||||
|
||||
func decodePrealloc(data string) GenesisAlloc {
|
||||
var p []struct{ Addr, Balance *big.Int }
|
||||
var p []struct {
|
||||
Addr *big.Int
|
||||
Balance *big.Int
|
||||
Misc *struct {
|
||||
Nonce uint64
|
||||
Code []byte
|
||||
Slots []struct {
|
||||
Key common.Hash
|
||||
Val common.Hash
|
||||
}
|
||||
} `rlp:"optional"`
|
||||
}
|
||||
if err := rlp.NewStream(strings.NewReader(data), 0).Decode(&p); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ga := make(GenesisAlloc, len(p))
|
||||
for _, account := range p {
|
||||
ga[common.BigToAddress(account.Addr)] = GenesisAccount{Balance: account.Balance}
|
||||
acc := GenesisAccount{Balance: account.Balance}
|
||||
if account.Misc != nil {
|
||||
acc.Nonce = account.Misc.Nonce
|
||||
acc.Code = account.Misc.Code
|
||||
|
||||
acc.Storage = make(map[common.Hash]common.Hash)
|
||||
for _, slot := range account.Misc.Slots {
|
||||
acc.Storage[slot.Key] = slot.Val
|
||||
}
|
||||
}
|
||||
ga[common.BigToAddress(account.Addr)] = acc
|
||||
}
|
||||
return ga
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -30,9 +30,15 @@ import (
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
|
||||
)
|
||||
|
||||
func TestSetupGenesis(t *testing.T) {
|
||||
testSetupGenesis(t, rawdb.HashScheme)
|
||||
testSetupGenesis(t, rawdb.PathScheme)
|
||||
}
|
||||
|
||||
func testSetupGenesis(t *testing.T, scheme string) {
|
||||
var (
|
||||
customghash = common.HexToHash("0x89c99d90b79719238d2645c7642f2c9295246e80775b38cfd162b696817fbd50")
|
||||
customg = Genesis{
|
||||
@@ -44,6 +50,7 @@ func TestSetupGenesis(t *testing.T) {
|
||||
oldcustomg = customg
|
||||
)
|
||||
oldcustomg.Config = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(2)}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fn func(ethdb.Database) (*params.ChainConfig, common.Hash, error)
|
||||
@@ -54,7 +61,7 @@ func TestSetupGenesis(t *testing.T) {
|
||||
{
|
||||
name: "genesis without ChainConfig",
|
||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
return SetupGenesisBlock(db, trie.NewDatabase(db), new(Genesis))
|
||||
return SetupGenesisBlock(db, trie.NewDatabase(db, newDbConfig(scheme)), new(Genesis))
|
||||
},
|
||||
wantErr: errGenesisNoConfig,
|
||||
wantConfig: params.AllEthashProtocolChanges,
|
||||
@@ -62,16 +69,16 @@ func TestSetupGenesis(t *testing.T) {
|
||||
{
|
||||
name: "no block in DB, genesis == nil",
|
||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
return SetupGenesisBlock(db, trie.NewDatabase(db), nil)
|
||||
return SetupGenesisBlock(db, trie.NewDatabase(db, newDbConfig(scheme)), nil)
|
||||
},
|
||||
wantHash: params.MainnetGenesisHash,
|
||||
wantConfig: params.MainnetChainConfig,
|
||||
wantHash: params.BSCGenesisHash,
|
||||
wantConfig: params.BSCChainConfig,
|
||||
},
|
||||
{
|
||||
name: "mainnet block in DB, genesis == nil",
|
||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
DefaultGenesisBlock().MustCommit(db)
|
||||
return SetupGenesisBlock(db, trie.NewDatabase(db), nil)
|
||||
DefaultGenesisBlock().MustCommit(db, trie.NewDatabase(db, newDbConfig(scheme)))
|
||||
return SetupGenesisBlock(db, trie.NewDatabase(db, newDbConfig(scheme)), nil)
|
||||
},
|
||||
wantHash: params.MainnetGenesisHash,
|
||||
wantConfig: params.MainnetChainConfig,
|
||||
@@ -79,8 +86,9 @@ func TestSetupGenesis(t *testing.T) {
|
||||
{
|
||||
name: "custom block in DB, genesis == nil",
|
||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
customg.MustCommit(db)
|
||||
return SetupGenesisBlock(db, trie.NewDatabase(db), nil)
|
||||
tdb := trie.NewDatabase(db, newDbConfig(scheme))
|
||||
customg.Commit(db, tdb)
|
||||
return SetupGenesisBlock(db, tdb, nil)
|
||||
},
|
||||
wantHash: customghash,
|
||||
wantConfig: customg.Config,
|
||||
@@ -88,8 +96,9 @@ func TestSetupGenesis(t *testing.T) {
|
||||
{
|
||||
name: "compatible config in DB",
|
||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
oldcustomg.MustCommit(db)
|
||||
return SetupGenesisBlock(db, trie.NewDatabase(db), &customg)
|
||||
tdb := trie.NewDatabase(db, newDbConfig(scheme))
|
||||
oldcustomg.Commit(db, tdb)
|
||||
return SetupGenesisBlock(db, tdb, &customg)
|
||||
},
|
||||
wantHash: customghash,
|
||||
wantConfig: customg.Config,
|
||||
@@ -99,16 +108,17 @@ func TestSetupGenesis(t *testing.T) {
|
||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
// Commit the 'old' genesis block with Homestead transition at #2.
|
||||
// Advance to block #4, past the homestead transition block of customg.
|
||||
genesis := oldcustomg.MustCommit(db)
|
||||
tdb := trie.NewDatabase(db, newDbConfig(scheme))
|
||||
oldcustomg.Commit(db, tdb)
|
||||
|
||||
bc, _ := NewBlockChain(db, nil, &oldcustomg, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil)
|
||||
bc, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), &oldcustomg, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil)
|
||||
defer bc.Stop()
|
||||
|
||||
blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil)
|
||||
_, blocks, _ := GenerateChainWithGenesis(&oldcustomg, ethash.NewFaker(), 4, nil)
|
||||
bc.InsertChain(blocks)
|
||||
|
||||
// This should return a compatibility error.
|
||||
return SetupGenesisBlock(db, trie.NewDatabase(db), &customg)
|
||||
return SetupGenesisBlock(db, tdb, &customg)
|
||||
},
|
||||
wantHash: customghash,
|
||||
wantConfig: customg.Config,
|
||||
@@ -154,7 +164,8 @@ func TestGenesisHashes(t *testing.T) {
|
||||
{DefaultGenesisBlock(), params.MainnetGenesisHash},
|
||||
} {
|
||||
// Test via MustCommit
|
||||
if have := c.genesis.MustCommit(rawdb.NewMemoryDatabase()).Hash(); have != c.want {
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
if have := c.genesis.MustCommit(db, trie.NewDatabase(db, trie.HashDefaults)).Hash(); have != c.want {
|
||||
t.Errorf("case: %d a), want: %s, got: %s", i, c.want.Hex(), have.Hex())
|
||||
}
|
||||
// Test via ToBlock
|
||||
@@ -172,7 +183,7 @@ func TestGenesis_Commit(t *testing.T) {
|
||||
}
|
||||
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
genesisBlock := genesis.MustCommit(db)
|
||||
genesisBlock := genesis.MustCommit(db, trie.NewDatabase(db, trie.HashDefaults))
|
||||
|
||||
if genesis.Difficulty != nil {
|
||||
t.Fatalf("assumption wrong")
|
||||
@@ -198,7 +209,7 @@ func TestReadWriteGenesisAlloc(t *testing.T) {
|
||||
{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
|
||||
{2}: {Balance: big.NewInt(2), Storage: map[common.Hash]common.Hash{{2}: {2}}},
|
||||
}
|
||||
hash, _ = alloc.deriveHash()
|
||||
hash, _ = alloc.hash()
|
||||
)
|
||||
blob, _ := json.Marshal(alloc)
|
||||
rawdb.WriteGenesisStateSpec(db, hash, blob)
|
||||
@@ -221,6 +232,7 @@ func TestReadWriteGenesisAlloc(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigOrDefault(t *testing.T) {
|
||||
defaultGenesis := DefaultGenesisBlock()
|
||||
if defaultGenesis.Config.PlanckBlock != nil {
|
||||
@@ -229,12 +241,12 @@ func TestConfigOrDefault(t *testing.T) {
|
||||
gHash := params.BSCGenesisHash
|
||||
config := defaultGenesis.configOrDefault(gHash)
|
||||
|
||||
if config.ChainID.Cmp(params.MainnetChainConfig.ChainID) != 0 {
|
||||
if config.ChainID.Cmp(params.BSCChainConfig.ChainID) != 0 {
|
||||
t.Errorf("ChainID of resulting config should be %v, but is %v instead", params.BSCChainConfig.ChainID, config.ChainID)
|
||||
}
|
||||
|
||||
if config.HomesteadBlock.Cmp(params.MainnetChainConfig.HomesteadBlock) != 0 {
|
||||
t.Errorf("resulting config should have HomesteadBlock = %v, but instead is %v", params.MainnetChainConfig, config.HomesteadBlock)
|
||||
if config.HomesteadBlock.Cmp(params.BSCChainConfig.HomesteadBlock) != 0 {
|
||||
t.Errorf("resulting config should have HomesteadBlock = %v, but instead is %v", params.BSCChainConfig, config.HomesteadBlock)
|
||||
}
|
||||
|
||||
if config.PlanckBlock == nil {
|
||||
@@ -246,30 +258,9 @@ func TestConfigOrDefault(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetDefaultBlockValues(t *testing.T) {
|
||||
genesis := &Genesis{Config: ¶ms.ChainConfig{ChainID: big.NewInt(66), HomesteadBlock: big.NewInt(11)}}
|
||||
genesis.setDefaultBlockValues(params.BSCChainConfig)
|
||||
|
||||
// Make sure the non-nil block was not modified
|
||||
if genesis.Config.HomesteadBlock.Cmp(big.NewInt(11)) != 0 {
|
||||
t.Errorf("Homestead block should not have been modified. HomesteadBlock = %v", genesis.Config.HomesteadBlock)
|
||||
}
|
||||
|
||||
// Spot check a few blocks
|
||||
if genesis.Config.NielsBlock.Cmp(params.BSCChainConfig.NielsBlock) != 0 {
|
||||
t.Errorf("Niels block not matching: in genesis = %v , in defaultConfig = %v", genesis.Config.NielsBlock, params.BSCChainConfig.NielsBlock)
|
||||
}
|
||||
|
||||
if genesis.Config.NanoBlock.Cmp(params.BSCChainConfig.NanoBlock) != 0 {
|
||||
t.Errorf("Nano block not matching: in genesis = %v , in defaultConfig = %v", genesis.Config.NanoBlock, params.BSCChainConfig.NanoBlock)
|
||||
}
|
||||
|
||||
if genesis.Config.PlanckBlock.Cmp(params.BSCChainConfig.PlanckBlock) != 0 {
|
||||
t.Errorf("Nano block not matching: in genesis = %v , in defaultConfig = %v", genesis.Config.PlanckBlock, params.BSCChainConfig.PlanckBlock)
|
||||
}
|
||||
|
||||
// Lastly make sure non-block fields such as ChainID have not been modified
|
||||
if genesis.Config.ChainID.Cmp(big.NewInt(66)) != 0 {
|
||||
t.Errorf("ChainID should not have been modified. ChainID = %v", genesis.Config.ChainID)
|
||||
func newDbConfig(scheme string) *trie.Config {
|
||||
if scheme == rawdb.HashScheme {
|
||||
return trie.HashDefaults
|
||||
}
|
||||
return &trie.Config{PathDB: pathdb.Defaults}
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c
|
||||
// GetJustifiedNumber returns the highest justified blockNumber on the branch including and before `header`.
|
||||
func (hc *HeaderChain) GetJustifiedNumber(header *types.Header) uint64 {
|
||||
if p, ok := hc.engine.(consensus.PoSA); ok {
|
||||
justifiedBlockNumber, _, err := p.GetJustifiedNumberAndHash(hc, header)
|
||||
justifiedBlockNumber, _, err := p.GetJustifiedNumberAndHash(hc, []*types.Header{header})
|
||||
if err == nil {
|
||||
return justifiedBlockNumber
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ func TestHeaderInsertion(t *testing.T) {
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
gspec = &Genesis{BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges}
|
||||
)
|
||||
gspec.Commit(db, trie.NewDatabase(db))
|
||||
gspec.Commit(db, trie.NewDatabase(db, nil))
|
||||
hc, err := NewHeaderChain(db, gspec.Config, ethash.NewFaker(), func() bool { return false })
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -32,24 +32,51 @@ import (
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
type allocItem struct{ Addr, Balance *big.Int }
|
||||
type allocItem struct {
|
||||
Addr *big.Int
|
||||
Balance *big.Int
|
||||
Misc *allocItemMisc `rlp:"optional"`
|
||||
}
|
||||
|
||||
type allocItemMisc struct {
|
||||
Nonce uint64
|
||||
Code []byte
|
||||
Slots []allocItemStorageItem
|
||||
}
|
||||
|
||||
type allocItemStorageItem struct {
|
||||
Key common.Hash
|
||||
Val common.Hash
|
||||
}
|
||||
|
||||
func makelist(g *core.Genesis) []allocItem {
|
||||
items := make([]allocItem, 0, len(g.Alloc))
|
||||
for addr, account := range g.Alloc {
|
||||
var misc *allocItemMisc
|
||||
if len(account.Storage) > 0 || len(account.Code) > 0 || account.Nonce != 0 {
|
||||
panic(fmt.Sprintf("can't encode account %x", addr))
|
||||
misc = &allocItemMisc{
|
||||
Nonce: account.Nonce,
|
||||
Code: account.Code,
|
||||
Slots: make([]allocItemStorageItem, 0, len(account.Storage)),
|
||||
}
|
||||
for key, val := range account.Storage {
|
||||
misc.Slots = append(misc.Slots, allocItemStorageItem{key, val})
|
||||
}
|
||||
slices.SortFunc(misc.Slots, func(a, b allocItemStorageItem) int {
|
||||
return a.Key.Cmp(b.Key)
|
||||
})
|
||||
}
|
||||
bigAddr := new(big.Int).SetBytes(addr.Bytes())
|
||||
items = append(items, allocItem{bigAddr, account.Balance})
|
||||
items = append(items, allocItem{bigAddr, account.Balance, misc})
|
||||
}
|
||||
slices.SortFunc(items, func(a, b allocItem) bool {
|
||||
return a.Addr.Cmp(b.Addr) < 0
|
||||
slices.SortFunc(items, func(a, b allocItem) int {
|
||||
return a.Addr.Cmp(b.Addr)
|
||||
})
|
||||
return items
|
||||
}
|
||||
|
||||
@@ -435,12 +435,12 @@ func checkReceiptsRLP(have, want types.Receipts) error {
|
||||
func TestAncientStorage(t *testing.T) {
|
||||
// Freezer style fast import the chain.
|
||||
frdir := t.TempDir()
|
||||
|
||||
db, err := NewDatabaseWithFreezer(NewMemoryDatabase(), frdir, "", false, false, false, false)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create database with ancient backend")
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Create a test block
|
||||
block := types.NewBlockWithHeader(&types.Header{
|
||||
Number: big.NewInt(0),
|
||||
|
||||
@@ -256,11 +256,31 @@ func ReadStateHistory(db ethdb.AncientReaderOp, id uint64) ([]byte, []byte, []by
|
||||
// history starts from one(zero for initial state).
|
||||
func WriteStateHistory(db ethdb.AncientWriter, id uint64, meta []byte, accountIndex []byte, storageIndex []byte, accounts []byte, storages []byte) {
|
||||
db.ModifyAncients(func(op ethdb.AncientWriteOp) error {
|
||||
op.AppendRaw(stateHistoryMeta, id-1, meta)
|
||||
op.AppendRaw(stateHistoryAccountIndex, id-1, accountIndex)
|
||||
op.AppendRaw(stateHistoryStorageIndex, id-1, storageIndex)
|
||||
op.AppendRaw(stateHistoryAccountData, id-1, accounts)
|
||||
op.AppendRaw(stateHistoryStorageData, id-1, storages)
|
||||
err := op.AppendRaw(stateHistoryMeta, id-1, meta)
|
||||
if err != nil {
|
||||
log.Error("WriteStateHistory failed", "err", err)
|
||||
return err
|
||||
}
|
||||
err = op.AppendRaw(stateHistoryAccountIndex, id-1, accountIndex)
|
||||
if err != nil {
|
||||
log.Error("WriteStateHistory failed", "err", err)
|
||||
return err
|
||||
}
|
||||
err = op.AppendRaw(stateHistoryStorageIndex, id-1, storageIndex)
|
||||
if err != nil {
|
||||
log.Error("WriteStateHistory failed", "err", err)
|
||||
return err
|
||||
}
|
||||
err = op.AppendRaw(stateHistoryAccountData, id-1, accounts)
|
||||
if err != nil {
|
||||
log.Error("WriteStateHistory failed", "err", err)
|
||||
return err
|
||||
}
|
||||
err = op.AppendRaw(stateHistoryStorageData, id-1, storages)
|
||||
if err != nil {
|
||||
log.Error("WriteStateHistory failed", "err", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ import (
|
||||
//
|
||||
// Now this scheme is still kept for backward compatibility, and it will be used
|
||||
// for archive node and some other tries(e.g. light trie).
|
||||
const HashScheme = "hashScheme"
|
||||
const HashScheme = "hash"
|
||||
|
||||
// PathScheme is the new path-based state scheme with which trie nodes are stored
|
||||
// in the disk with node path as the database key. This scheme will only store one
|
||||
@@ -44,7 +44,7 @@ const HashScheme = "hashScheme"
|
||||
// is native. At the same time, this scheme will put adjacent trie nodes in the same
|
||||
// area of the disk with good data locality property. But this scheme needs to rely
|
||||
// on extra state diffs to survive deep reorg.
|
||||
const PathScheme = "pathScheme"
|
||||
const PathScheme = "path"
|
||||
|
||||
// hasher is used to compute the sha256 hash of the provided data.
|
||||
type hasher struct{ sha crypto.KeccakState }
|
||||
@@ -89,6 +89,16 @@ func HasAccountTrieNode(db ethdb.KeyValueReader, path []byte, hash common.Hash)
|
||||
return h.hash(data) == hash
|
||||
}
|
||||
|
||||
// ExistsAccountTrieNode checks the presence of the account trie node with the
|
||||
// specified node path, regardless of the node hash.
|
||||
func ExistsAccountTrieNode(db ethdb.KeyValueReader, path []byte) bool {
|
||||
has, err := db.Has(accountTrieNodeKey(path))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return has
|
||||
}
|
||||
|
||||
// WriteAccountTrieNode writes the provided account trie node into database.
|
||||
func WriteAccountTrieNode(db ethdb.KeyValueWriter, path []byte, node []byte) {
|
||||
if err := db.Put(accountTrieNodeKey(path), node); err != nil {
|
||||
@@ -127,6 +137,16 @@ func HasStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path [
|
||||
return h.hash(data) == hash
|
||||
}
|
||||
|
||||
// ExistsStorageTrieNode checks the presence of the storage trie node with the
|
||||
// specified account hash and node path, regardless of the node hash.
|
||||
func ExistsStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte) bool {
|
||||
has, err := db.Has(storageTrieNodeKey(accountHash, path))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return has
|
||||
}
|
||||
|
||||
// WriteStorageTrieNode writes the provided storage trie node into database.
|
||||
func WriteStorageTrieNode(db ethdb.KeyValueWriter, accountHash common.Hash, path []byte, node []byte) {
|
||||
if err := db.Put(storageTrieNodeKey(accountHash, path), node); err != nil {
|
||||
@@ -263,3 +283,69 @@ func DeleteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, has
|
||||
panic(fmt.Sprintf("Unknown scheme %v", scheme))
|
||||
}
|
||||
}
|
||||
|
||||
// ReadStateScheme reads the state scheme of persistent state, or none
|
||||
// if the state is not present in database.
|
||||
func ReadStateScheme(db ethdb.Reader) string {
|
||||
// Check if state in path-based scheme is present
|
||||
blob, _ := ReadAccountTrieNode(db, nil)
|
||||
if len(blob) != 0 {
|
||||
return PathScheme
|
||||
}
|
||||
// In a hash-based scheme, the genesis state is consistently stored
|
||||
// on the disk. To assess the scheme of the persistent state, it
|
||||
// suffices to inspect the scheme of the genesis state.
|
||||
header := ReadHeader(db, ReadCanonicalHash(db, 0), 0)
|
||||
if header == nil {
|
||||
return "" // empty datadir
|
||||
}
|
||||
blob = ReadLegacyTrieNode(db, header.Root)
|
||||
if len(blob) == 0 {
|
||||
return "" // no state in disk
|
||||
}
|
||||
return HashScheme
|
||||
}
|
||||
|
||||
// ValidateStateScheme used to check state scheme whether is valid.
|
||||
// Valid state scheme: hash and path.
|
||||
func ValidateStateScheme(stateScheme string) bool {
|
||||
if stateScheme == HashScheme || stateScheme == PathScheme {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ParseStateScheme checks if the specified state scheme is compatible with
|
||||
// the stored state.
|
||||
//
|
||||
// - If the provided scheme is none, use the scheme consistent with persistent
|
||||
// state, or fallback to hash-based scheme if state is empty.
|
||||
//
|
||||
// - If the provided scheme is hash, use hash-based scheme or error out if not
|
||||
// compatible with persistent state scheme.
|
||||
//
|
||||
// - If the provided scheme is path: use path-based scheme or error out if not
|
||||
// compatible with persistent state scheme.
|
||||
func ParseStateScheme(provided string, disk ethdb.Database) (string, error) {
|
||||
// If state scheme is not specified, use the scheme consistent
|
||||
// with persistent state, or fallback to hash mode if database
|
||||
// is empty.
|
||||
stored := ReadStateScheme(disk)
|
||||
if provided == "" {
|
||||
if stored == "" {
|
||||
// use default scheme for empty database, flip it when
|
||||
// path mode is chosen as default
|
||||
log.Info("State scheme set to default", "scheme", "hash")
|
||||
return HashScheme, nil
|
||||
}
|
||||
log.Info("State scheme set to already existing disk db", "scheme", stored)
|
||||
return stored, nil // reuse scheme of persistent scheme
|
||||
}
|
||||
// If state scheme is specified, ensure it's compatible with
|
||||
// persistent state.
|
||||
if stored == "" || provided == stored {
|
||||
log.Info("State scheme set by user", "scheme", provided)
|
||||
return provided, nil
|
||||
}
|
||||
return "", fmt.Errorf("incompatible state scheme, stored: %s, user provided: %s", stored, provided)
|
||||
}
|
||||
|
||||
34
core/rawdb/accessors_trie_test.go
Normal file
34
core/rawdb/accessors_trie_test.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package rawdb
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestValidateStateScheme(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
arg string
|
||||
wantResult bool
|
||||
}{
|
||||
{
|
||||
name: "hash scheme",
|
||||
arg: HashScheme,
|
||||
wantResult: true,
|
||||
},
|
||||
{
|
||||
name: "path scheme",
|
||||
arg: PathScheme,
|
||||
wantResult: true,
|
||||
},
|
||||
{
|
||||
name: "invalid scheme",
|
||||
arg: "mockScheme",
|
||||
wantResult: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := ValidateStateScheme(tt.arg); got != tt.wantResult {
|
||||
t.Errorf("ValidateStateScheme() = %v, want %v", got, tt.wantResult)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ const (
|
||||
stateHistoryStorageData = "storage.data"
|
||||
)
|
||||
|
||||
var stateHistoryFreezerNoSnappy = map[string]bool{
|
||||
var stateFreezerNoSnappy = map[string]bool{
|
||||
stateHistoryMeta: true,
|
||||
stateHistoryAccountIndex: false,
|
||||
stateHistoryStorageIndex: false,
|
||||
@@ -75,7 +75,7 @@ var (
|
||||
// freezers the collections of all builtin freezers.
|
||||
var freezers = []string{chainFreezerName, stateFreezerName}
|
||||
|
||||
// NewStateHistoryFreezer initializes the freezer for state history.
|
||||
func NewStateHistoryFreezer(ancientDir string, readOnly bool, offset uint64) (*ResettableFreezer, error) {
|
||||
return NewResettableFreezer(filepath.Join(ancientDir, stateFreezerName), "eth/db/state", readOnly, offset, stateHistoryTableSize, stateHistoryFreezerNoSnappy)
|
||||
// NewStateFreezer initializes the freezer for state history.
|
||||
func NewStateFreezer(ancientDir string, readOnly bool, offset uint64) (*ResettableFreezer, error) {
|
||||
return NewResettableFreezer(filepath.Join(ancientDir, stateFreezerName), "eth/db/state", readOnly, offset, stateHistoryTableSize, stateFreezerNoSnappy)
|
||||
}
|
||||
|
||||
@@ -18,9 +18,12 @@ package rawdb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
)
|
||||
|
||||
type tableSize struct {
|
||||
@@ -50,36 +53,61 @@ func (info *freezerInfo) size() common.StorageSize {
|
||||
return total
|
||||
}
|
||||
|
||||
func inspect(name string, order map[string]bool, reader ethdb.AncientReader) (freezerInfo, error) {
|
||||
info := freezerInfo{name: name}
|
||||
for t := range order {
|
||||
size, err := reader.AncientSize(t)
|
||||
if err != nil {
|
||||
return freezerInfo{}, err
|
||||
}
|
||||
info.sizes = append(info.sizes, tableSize{name: t, size: common.StorageSize(size)})
|
||||
}
|
||||
// Retrieve the number of last stored item
|
||||
ancients, err := reader.Ancients()
|
||||
if err != nil {
|
||||
return freezerInfo{}, err
|
||||
}
|
||||
info.head = ancients - 1
|
||||
|
||||
// Retrieve the number of first stored item
|
||||
tail, err := reader.Tail()
|
||||
if err != nil {
|
||||
return freezerInfo{}, err
|
||||
}
|
||||
info.tail = tail
|
||||
return info, nil
|
||||
}
|
||||
|
||||
// inspectFreezers inspects all freezers registered in the system.
|
||||
func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) {
|
||||
var infos []freezerInfo
|
||||
for _, freezer := range freezers {
|
||||
switch freezer {
|
||||
case chainFreezerName:
|
||||
// Chain ancient store is a bit special. It's always opened along
|
||||
// with the key-value store, inspect the chain store directly.
|
||||
info := freezerInfo{name: freezer}
|
||||
// Retrieve storage size of every contained table.
|
||||
for table := range chainFreezerNoSnappy {
|
||||
size, err := db.AncientSize(table)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
info.sizes = append(info.sizes, tableSize{name: table, size: common.StorageSize(size)})
|
||||
}
|
||||
// Retrieve the number of last stored item
|
||||
ancients, err := db.Ancients()
|
||||
info, err := inspect(chainFreezerName, chainFreezerNoSnappy, db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
info.head = ancients - 1
|
||||
infos = append(infos, info)
|
||||
|
||||
// Retrieve the number of first stored item
|
||||
tail, err := db.Tail()
|
||||
case stateFreezerName:
|
||||
if ReadStateScheme(db) != PathScheme {
|
||||
continue
|
||||
}
|
||||
datadir, err := db.AncientDatadir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err := NewStateFreezer(datadir, true, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
info, err := inspect(stateFreezerName, stateFreezerNoSnappy, f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
info.tail = tail
|
||||
infos = append(infos, info)
|
||||
|
||||
default:
|
||||
@@ -101,6 +129,8 @@ func InspectFreezerTable(ancient string, freezerName string, tableName string, s
|
||||
switch freezerName {
|
||||
case chainFreezerName:
|
||||
path, tables = resolveChainFreezerDir(ancient), chainFreezerNoSnappy
|
||||
case stateFreezerName:
|
||||
path, tables = filepath.Join(ancient, freezerName), stateFreezerNoSnappy
|
||||
default:
|
||||
return fmt.Errorf("unknown freezer, supported ones: %v", freezers)
|
||||
}
|
||||
@@ -119,3 +149,23 @@ func InspectFreezerTable(ancient string, freezerName string, tableName string, s
|
||||
table.dumpIndexStdout(start, end)
|
||||
return nil
|
||||
}
|
||||
|
||||
func ResetStateFreezerTableOffset(ancient string, virtualTail uint64) error {
|
||||
path, tables := filepath.Join(ancient, stateFreezerName), stateFreezerNoSnappy
|
||||
|
||||
for name, disableSnappy := range tables {
|
||||
log.Info("Handle table", "name", name, "disableSnappy", disableSnappy)
|
||||
table, err := newTable(path, name, metrics.NilMeter{}, metrics.NilMeter{}, metrics.NilGauge{}, freezerTableSize, disableSnappy, false)
|
||||
if err != nil {
|
||||
log.Error("New table failed", "error", err)
|
||||
return err
|
||||
}
|
||||
// Reset the metadata of the freezer table
|
||||
err = table.ResetItemsOffset(virtualTail)
|
||||
if err != nil {
|
||||
log.Error("Reset items offset of the table", "name", name, "error", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/ethdb/leveldb"
|
||||
"github.com/ethereum/go-ethereum/ethdb/memorydb"
|
||||
"github.com/ethereum/go-ethereum/ethdb/pebble"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
@@ -218,25 +219,28 @@ func NewFreezerDb(db ethdb.KeyValueStore, frz, namespace string, readonly bool,
|
||||
|
||||
// resolveChainFreezerDir is a helper function which resolves the absolute path
|
||||
// of chain freezer by considering backward compatibility.
|
||||
//
|
||||
// rules:
|
||||
// 1. in path mode, block data is stored in chain dir and state data is in state dir.
|
||||
// 2. in hash mode, block data is stored in chain dir or ancient dir(before big merge), no state dir.
|
||||
func resolveChainFreezerDir(ancient string) string {
|
||||
// Check if the chain freezer is already present in the specified
|
||||
// sub folder, if not then two possibilities:
|
||||
// - chain freezer is not initialized
|
||||
// - chain freezer exists in legacy location (root ancient folder)
|
||||
freezer := path.Join(ancient, chainFreezerName)
|
||||
if !common.FileExist(freezer) {
|
||||
if !common.FileExist(ancient) {
|
||||
// The entire ancient store is not initialized, still use the sub
|
||||
// folder for initialization.
|
||||
} else {
|
||||
// Ancient root is already initialized, then we hold the assumption
|
||||
// that chain freezer is also initialized and located in root folder.
|
||||
// In this case fallback to legacy location.
|
||||
freezer = ancient
|
||||
log.Info("Found legacy ancient chain path", "location", ancient)
|
||||
}
|
||||
chain := path.Join(ancient, chainFreezerName)
|
||||
state := path.Join(ancient, stateFreezerName)
|
||||
if common.FileExist(chain) {
|
||||
return chain
|
||||
}
|
||||
return freezer
|
||||
if common.FileExist(state) {
|
||||
return chain
|
||||
}
|
||||
if common.FileExist(ancient) {
|
||||
log.Info("Found legacy ancient chain path", "location", ancient)
|
||||
chain = ancient
|
||||
}
|
||||
return chain
|
||||
}
|
||||
|
||||
// NewDatabaseWithFreezer creates a high level database on top of a given key-
|
||||
@@ -263,6 +267,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
|
||||
WriteAncientType(db, PruneFreezerType)
|
||||
}
|
||||
return &freezerdb{
|
||||
ancientRoot: ancient,
|
||||
KeyValueStore: db,
|
||||
AncientStore: frdb,
|
||||
}, nil
|
||||
@@ -335,7 +340,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
|
||||
break
|
||||
}
|
||||
}
|
||||
// We are about to exit on error. Print database metdata beore exiting
|
||||
// We are about to exit on error. Print database metdata before exiting
|
||||
printChainMetadata(db)
|
||||
return nil, fmt.Errorf("gap in the chain between ancients [0 - #%d] and leveldb [#%d - #%d] ",
|
||||
frozen-1, number, head)
|
||||
@@ -364,7 +369,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
|
||||
// freezer.
|
||||
}
|
||||
}
|
||||
// no prune ancinet start success
|
||||
// no prune ancient start success
|
||||
if !readonly {
|
||||
WriteAncientType(db, EntireFreezerType)
|
||||
}
|
||||
@@ -425,6 +430,16 @@ func NewLevelDBDatabaseWithFreezer(file string, cache int, handles int, ancient
|
||||
return frdb, nil
|
||||
}
|
||||
|
||||
// NewPebbleDBDatabase creates a persistent key-value database without a freezer
|
||||
// moving immutable chain segments into cold storage.
|
||||
func NewPebbleDBDatabase(file string, cache int, handles int, namespace string, readonly bool) (ethdb.Database, error) {
|
||||
db, err := pebble.New(file, cache, handles, namespace, readonly)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewDatabase(db), nil
|
||||
}
|
||||
|
||||
const (
|
||||
dbPebble = "pebble"
|
||||
dbLeveldb = "leveldb"
|
||||
@@ -480,12 +495,8 @@ func openKeyValueDatabase(o OpenOptions) (ethdb.Database, error) {
|
||||
return nil, fmt.Errorf("db.engine choice was %v but found pre-existing %v database in specified data directory", o.Type, existingDb)
|
||||
}
|
||||
if o.Type == dbPebble || existingDb == dbPebble {
|
||||
if PebbleEnabled {
|
||||
log.Info("Using pebble as the backing database")
|
||||
return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly)
|
||||
} else {
|
||||
return nil, errors.New("db.engine 'pebble' not supported on this platform")
|
||||
}
|
||||
log.Info("Using pebble as the backing database")
|
||||
return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly)
|
||||
}
|
||||
if o.Type == dbLeveldb || existingDb == dbLeveldb {
|
||||
log.Info("Using leveldb as the backing database")
|
||||
@@ -493,10 +504,8 @@ func openKeyValueDatabase(o OpenOptions) (ethdb.Database, error) {
|
||||
}
|
||||
// No pre-existing database, no user-requested one either. Default to Pebble
|
||||
// on supported platforms and LevelDB on anything else.
|
||||
// if PebbleEnabled {
|
||||
// log.Info("Defaulting to pebble as the backing database")
|
||||
// return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly)
|
||||
// }
|
||||
log.Info("Defaulting to leveldb as the backing database")
|
||||
return NewLevelDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly)
|
||||
}
|
||||
@@ -511,6 +520,11 @@ func Open(o OpenOptions) (ethdb.Database, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ReadAncientType(kvdb) == PruneFreezerType {
|
||||
if !o.PruneAncientData {
|
||||
log.Warn("Disk db is pruned")
|
||||
}
|
||||
}
|
||||
if len(o.AncientsDirectory) == 0 {
|
||||
return kvdb, nil
|
||||
}
|
||||
@@ -551,6 +565,7 @@ func (s *stat) Size() string {
|
||||
func (s *stat) Count() string {
|
||||
return s.count.String()
|
||||
}
|
||||
|
||||
func AncientInspect(db ethdb.Database) error {
|
||||
offset := counter(ReadOffSetOfCurrentAncientFreezer(db))
|
||||
// Get number of ancient rows inside the freezer.
|
||||
@@ -581,6 +596,28 @@ func AncientInspect(db ethdb.Database) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func PruneHashTrieNodeInDataBase(db ethdb.Database) error {
|
||||
it := db.NewIterator([]byte{}, []byte{})
|
||||
defer it.Release()
|
||||
|
||||
total_num := 0
|
||||
for it.Next() {
|
||||
var key = it.Key()
|
||||
switch {
|
||||
case IsLegacyTrieNode(key, it.Value()):
|
||||
db.Delete(key)
|
||||
total_num++
|
||||
if total_num%100000 == 0 {
|
||||
log.Info("Pruning hash-base state trie nodes", "Complete progress: ", total_num)
|
||||
}
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
log.Info("Pruning hash-base state trie nodes", "Complete progress", total_num)
|
||||
return nil
|
||||
}
|
||||
|
||||
// InspectDatabase traverses the entire database and checks the size
|
||||
// of all different categories of data.
|
||||
func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
|
||||
@@ -599,7 +636,10 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
|
||||
tds stat
|
||||
numHashPairings stat
|
||||
hashNumPairings stat
|
||||
tries stat
|
||||
legacyTries stat
|
||||
stateLookups stat
|
||||
accountTries stat
|
||||
storageTries stat
|
||||
codes stat
|
||||
txLookups stat
|
||||
accountSnaps stat
|
||||
@@ -640,8 +680,14 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
|
||||
numHashPairings.Add(size)
|
||||
case bytes.HasPrefix(key, headerNumberPrefix) && len(key) == (len(headerNumberPrefix)+common.HashLength):
|
||||
hashNumPairings.Add(size)
|
||||
case len(key) == common.HashLength:
|
||||
tries.Add(size)
|
||||
case IsLegacyTrieNode(key, it.Value()):
|
||||
legacyTries.Add(size)
|
||||
case bytes.HasPrefix(key, stateIDPrefix) && len(key) == len(stateIDPrefix)+common.HashLength:
|
||||
stateLookups.Add(size)
|
||||
case IsAccountTrieNode(key):
|
||||
accountTries.Add(size)
|
||||
case IsStorageTrieNode(key):
|
||||
storageTries.Add(size)
|
||||
case bytes.HasPrefix(key, CodePrefix) && len(key) == len(CodePrefix)+common.HashLength:
|
||||
codes.Add(size)
|
||||
case bytes.HasPrefix(key, txLookupPrefix) && len(key) == (len(txLookupPrefix)+common.HashLength):
|
||||
@@ -678,7 +724,8 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
|
||||
databaseVersionKey, headHeaderKey, headBlockKey, headFastBlockKey,
|
||||
lastPivotKey, fastTrieProgressKey, snapshotDisabledKey, SnapshotRootKey, snapshotJournalKey,
|
||||
snapshotGeneratorKey, snapshotRecoveryKey, txIndexTailKey, fastTxLookupLimitKey,
|
||||
uncleanShutdownKey, badBlockKey, transitionStatusKey,
|
||||
uncleanShutdownKey, badBlockKey, transitionStatusKey, skeletonSyncStatusKey,
|
||||
persistentStateIDKey, trieJournalKey, snapshotSyncStatusKey,
|
||||
} {
|
||||
if bytes.Equal(key, meta) {
|
||||
metadata.Add(size)
|
||||
@@ -707,7 +754,10 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
|
||||
{"Key-Value store", "Transaction index", txLookups.Size(), txLookups.Count()},
|
||||
{"Key-Value store", "Bloombit index", bloomBits.Size(), bloomBits.Count()},
|
||||
{"Key-Value store", "Contract codes", codes.Size(), codes.Count()},
|
||||
{"Key-Value store", "Trie nodes", tries.Size(), tries.Count()},
|
||||
{"Key-Value store", "Hash trie nodes", legacyTries.Size(), legacyTries.Count()},
|
||||
{"Key-Value store", "Path trie state lookups", stateLookups.Size(), stateLookups.Count()},
|
||||
{"Key-Value store", "Path trie account nodes", accountTries.Size(), accountTries.Count()},
|
||||
{"Key-Value store", "Path trie storage nodes", storageTries.Size(), storageTries.Count()},
|
||||
{"Key-Value store", "Trie preimages", preimages.Size(), preimages.Count()},
|
||||
{"Key-Value store", "Account snapshot", accountSnaps.Size(), accountSnaps.Count()},
|
||||
{"Key-Value store", "Storage snapshot", storageSnaps.Size(), storageSnaps.Count()},
|
||||
|
||||
@@ -15,3 +15,80 @@
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package rawdb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
mockChainFreezerPath = "/geth/chaindata/ancient/chain"
|
||||
mockStateFreezerPath = "/geth/chaindata/ancient/state"
|
||||
mockAncientFreezerPath = "/geth/chaindata/ancient"
|
||||
)
|
||||
|
||||
func Test_resolveChainFreezerDir(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
fn func(dir string) string
|
||||
ancient string
|
||||
wantedResult string
|
||||
}{
|
||||
{
|
||||
// chain dir is existent, so it should be returned.
|
||||
name: "1",
|
||||
fn: func(dir string) string {
|
||||
path := fmt.Sprintf("%s%s", dir, mockChainFreezerPath)
|
||||
if err := os.MkdirAll(path, 0700); err != nil {
|
||||
t.Fatalf("Failed to mkdir all dirs, error: %v", err)
|
||||
}
|
||||
return fmt.Sprintf("%s%s", dir, mockAncientFreezerPath)
|
||||
},
|
||||
wantedResult: mockChainFreezerPath,
|
||||
},
|
||||
{
|
||||
// chain dir is nonexistent and state dir is existent; so chain
|
||||
// dir should be returned.
|
||||
name: "2",
|
||||
fn: func(dir string) string {
|
||||
path := fmt.Sprintf("%s%s", dir, mockStateFreezerPath)
|
||||
if err := os.MkdirAll(path, 0700); err != nil {
|
||||
t.Fatalf("Failed to mkdir all dirs, error: %v", err)
|
||||
}
|
||||
return fmt.Sprintf("%s%s", dir, mockAncientFreezerPath)
|
||||
},
|
||||
wantedResult: mockChainFreezerPath,
|
||||
},
|
||||
{
|
||||
// both chain dir and state dir are nonexistent, if ancient dir is
|
||||
// existent, so ancient dir should be returned.
|
||||
name: "3",
|
||||
fn: func(dir string) string {
|
||||
path := fmt.Sprintf("%s%s", dir, mockAncientFreezerPath)
|
||||
if err := os.MkdirAll(path, 0700); err != nil {
|
||||
t.Fatalf("Failed to mkdir all dirs, error: %v", err)
|
||||
}
|
||||
return path
|
||||
},
|
||||
wantedResult: mockAncientFreezerPath,
|
||||
},
|
||||
{
|
||||
// ancient dir is nonexistent, so chain dir should be returned.
|
||||
name: "4",
|
||||
fn: func(dir string) string {
|
||||
return fmt.Sprintf("%s%s", dir, mockAncientFreezerPath)
|
||||
},
|
||||
wantedResult: mockChainFreezerPath,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
got := resolveChainFreezerDir(tt.fn(tempDir))
|
||||
if got != fmt.Sprintf("%s%s", tempDir, tt.wantedResult) {
|
||||
t.Fatalf("resolveChainFreezerDir() = %s, wanted = %s", got, tt.wantedResult)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
// Copyright 2023 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/>
|
||||
|
||||
//go:build (arm64 || amd64) && !openbsd
|
||||
|
||||
package rawdb
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/ethdb/pebble"
|
||||
)
|
||||
|
||||
// Pebble is unsuported on 32bit architecture
|
||||
const PebbleEnabled = true
|
||||
|
||||
// NewPebbleDBDatabase creates a persistent key-value database without a freezer
|
||||
// moving immutable chain segments into cold storage.
|
||||
func NewPebbleDBDatabase(file string, cache int, handles int, namespace string, readonly bool) (ethdb.Database, error) {
|
||||
db, err := pebble.New(file, cache, handles, namespace, readonly)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewDatabase(db), nil
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright 2023 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/>.
|
||||
|
||||
//go:build !((arm64 || amd64) && !openbsd)
|
||||
|
||||
package rawdb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
)
|
||||
|
||||
// Pebble is unsuported on 32bit architecture
|
||||
const PebbleEnabled = false
|
||||
|
||||
// NewPebbleDBDatabase creates a persistent key-value database without a freezer
|
||||
// moving immutable chain segments into cold storage.
|
||||
func NewPebbleDBDatabase(file string, cache int, handles int, namespace string, readonly bool) (ethdb.Database, error) {
|
||||
return nil, errors.New("pebble is not supported on this platform")
|
||||
}
|
||||
@@ -152,7 +152,7 @@ func NewFreezer(datadir string, namespace string, readonly bool, offset uint64,
|
||||
}
|
||||
|
||||
// Some blocks in ancientDB may have already been frozen and been pruned, so adding the offset to
|
||||
// reprensent the absolute number of blocks already frozen.
|
||||
// represent the absolute number of blocks already frozen.
|
||||
freezer.frozen.Add(offset)
|
||||
freezer.tail.Add(offset)
|
||||
|
||||
|
||||
@@ -188,19 +188,27 @@ func (batch *freezerTableBatch) maybeCommit() error {
|
||||
|
||||
// commit writes the batched items to the backing freezerTable.
|
||||
func (batch *freezerTableBatch) commit() error {
|
||||
// Write data.
|
||||
// Write data. The head file is fsync'd after write to ensure the
|
||||
// data is truly transferred to disk.
|
||||
_, err := batch.t.head.Write(batch.dataBuffer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := batch.t.head.Sync(); err != nil {
|
||||
return err
|
||||
}
|
||||
dataSize := int64(len(batch.dataBuffer))
|
||||
batch.dataBuffer = batch.dataBuffer[:0]
|
||||
|
||||
// Write indices.
|
||||
// Write indices. The index file is fsync'd after write to ensure the
|
||||
// data indexes are truly transferred to disk.
|
||||
_, err = batch.t.index.Write(batch.indexBuffer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := batch.t.index.Sync(); err != nil {
|
||||
return err
|
||||
}
|
||||
indexSize := int64(len(batch.indexBuffer))
|
||||
batch.indexBuffer = batch.indexBuffer[:0]
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
const tmpSuffix = ".tmp"
|
||||
@@ -240,6 +241,7 @@ func cleanup(path string) error {
|
||||
}
|
||||
for _, name := range names {
|
||||
if name == filepath.Base(path)+tmpSuffix {
|
||||
log.Info("Removed leftover freezer directory", "name", name)
|
||||
return os.RemoveAll(filepath.Join(parent, name))
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user